黑客编程入门(1)从简单木马到平台: Windows
环境: VS6.0
语言: c
基本功能:
获取目标主机(服务端)的计算机名称和用户名
当客户端发送命令“获取pcname”时,在客户端上打印计算机名称
客户端发送" getusername "命令时在客户端上打印用户名
知识储备:
什么是C/S结构
C/S结构是客户端-服务器结构,简单来说,我们的木马种植在服务端,可以获取服务端的信息。 我们在客户端进行一系列操作来控制木马活动,让我们的小马
可以控制服务器。 顺便问一下,我们的浏览器是通用的客户端啊。
2 TCP协议和UDP协议
我们的木马客户端和服务端一定会进行通信,在两者之间不断发送信息。 信息的传递当然需要制定确保信息真实性、正确性的规则。 为此,人们制定了一系列通用协议来规范通信标准。 这有TCP和UDP。 当然,不仅仅是这两个。 关于协议的更详细内容,如果有兴趣的话请自己调查。 )协议规定,每个终端将各自字符集的字符转换为标准字符集的字符,然后传输到网络,到达目的地终端后再转换为该终端字符集的字符。 也就是说,我们的小马在收集服务端信息后,也会遵循该准则,将信息统一转换为标准字符集进行传递,客户端进行解析转换。
基本知识准备完毕,开始行动。 在完成代码时,将一点一点地了解具体使用的函数和库。
首先,最核心的功能——获取主机的计算机名称和用户名。 1 .获取计算机名称的函数:
boolwinapigetcomputername (_ out _ lptstr lpbuffer,_Inout_ LPDWORD lpnSize );
参数说明:
lpBuffer是输出参数,是指向接受计算机名称的缓冲区的指针,大小必须足够大才能存储max _ computer name _ length1characters
lpnSize是输入输出参数,输入限定lpBuffer的size,输出和返回的计算机名的大小不包含末尾的空白字符
MSDN地址: http://msdn.Microsoft.com/zh-cn/ms 724295
2 .获取用户名的函数:
boolwinapigetusername (_ out _ lptstr lpbuffer,_Inout_ LPDWORD lpnSize );
与GetComputerName参数基本相同的详细信息: msdn:http://msdn.Microsoft.com/zh-cn/subscriptions/ms 724432.aspx
接下来,我们来看看基本实现的完整代码。 暂时不进行通信。 请不要着急,慢慢来。
# include stdio.h # include windows.h # definemax _ size 20 int main (int argc,char* argv[] ) charszcomputername [ max ] 无符号长整型=max byte; 获取计算机名称(SZ计算机名称,nSize ); printf (计算机名称is % sn ),SZ计算机名称); nSize=MAXBYTE; Getusername(SZusername,nSize ); printf(usernameis%s(n ),szUserName ); 返回0; }
哈,最核心的代码是我们完成的。 很简单吗?
然后,实现完整的服务端代码。 预备知识:
1 WinSock界面:
是Windows套接字的简称,也是Windows套接字,是微软基于BSD UNIX操作系统中流行的Berkeley套接字规范实现的Windows网络编程接口的我们的小木马网络通信是基于WinSock实现的。 当然,还有其他类似的库,这里不介绍。
使用时部署#includewinsock2.h和#pragmacomment(lib,' ws2_32 ' )。
2 WinSock服务端开发流程:
支持WinSock初始化(函数WSAStartupup ) ) ——套接字套接字(套接字)套接字) ——绑定IP和端口(函数bind ) ) ) ——监听端口)
( ) / recv( ) )——> 关闭套接字 (对应函数closesocket( ) )——> 结束动态链接库(对应函数( WSACleanup( ) )
int WSAStartup{ WORD wVersionRequested, LPWSADATA lpWSAData};该函数的第一个参数指明程序请求使用的Socket版本,其中高位字节 指明副版本、低位字节指明主版本;
操作系统利用第二个参数返回请求的Socket的版本信息。
af 指定通信协议簇,对于TCP/IP协议,该参数为PF_INET
type 指定要创建的套接字类型
protocol 指定使用的通信协议,具体和第二个参数有关,第二个参数为SOCK_STREAM则该参数为IPPROTO_TCP ,
若第二个参数为SOCK_DGRAM,则该参数为IPPROTO_UDP
int bind( SOCKET s, const struct sockaddr* name, int namlen );
s 服务器端套接字
name 制定一个sockaddr结构
namelen 指定缓冲区的长度
这里有必要介绍一下sockaddr结构——
struct sockaddr_in {short int sin_family; /* Address family */unsigned short int sin_port; /* Port number */struct in_addr sin_addr; /* Internet address */unsigned char sin_zero[8]; /* Same size as struct sockaddr */};
sin_family 指代协议族
sin_port 存储端口号(使用网络字节顺序)
sin_addr 存储IP地址,使用in_addr这个数据结构
sin_zero 是为了让sockaddr与sockaddr_in两个数据结构保持大小相同而保留的空字节。
第一个参数很明显就是处于监听状态的套接字
backlog 客户连接请求队列
SOCKET accept( SOCKET s, struct sockaddr FAR* addr, int FAR* addrlen);s:套接口描述字,该套接口在listen()后监听连接。
addr:(可选)指针,指向一缓冲区,其中接收为通讯层所知的连接实体的地址。Addr参数的实际格式由套接口创建时所产生的地址族确定。
addrlen:(可选)指针,指向存有addr地址长度的整形数。
buf是个指向发送的缓冲区的指针,也就是个地址
len是要发送的数据大小,一般是和buf的大小有关
flag 一般设置为0
所需要的函数基本讲完了,接下来真正的动手写代码吧,上代码
/*服务器端代码*/#include<winsock2.h>#include<windows.h>#pragma comment (lib,"ws2_32")#define MAX_SIZE 20typedef struct _SYS_INFO{char szComputerName[MAX_SIZE];//保存计算机名char szUserName[MAX_SIZE];//保存当前用户登录名}SYS_INFO,*PSYS_INFO;void GetSysInfo(PSYS_INFO sysinfo){unsigned long nSize = MAXBYTE;GetComputerName(sysinfo->szComputerName,&nSize);nSize = MAXBYTE;GetUserName(sysinfo->szUserName,&nSize);};int main(int argc,char* argv[]){//winsock的初始化WSADATA wsaData;WSAStartup(MAKEWORD(2,2),&wsaData);//创建套接字SOCKET s = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);//进行IP和端口的绑定sockaddr_in sockaddr;sockaddr.sin_family = PF_INET;sockaddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");sockaddr.sin_port = htons(827);bind(s,(SOCKADDR*)&sockaddr,sizeof(SOCKADDR));//监听端口listen(s,1);//接收请求SOCKADDR clientAddr;int Size = sizeof(SOCKADDR);SOCKET clientSock;clientSock = accept(s,(SOCKADDR*)&clientAddr,&Size);//注意,accept函数返回一个新的套接字while(true){//向客户端发送的信息,用于模拟一个命令行界面send(clientSock,"Hacker@Shell>",strlen("Hacker@Shell>")+sizeof(char),NULL);char buff[MAXBYTE] = {0};//保存接受的信息//接收信息recv(clientSock,buff,MAXBYTE,NULL);//根据从客户端接收到的指令进行相应的操作if(!strcmp(buff,"getpcname")||(!strcmp(buff,"getusername"))){SYS_INFO SysInfo = {0};GetSysInfo(&SysInfo);send(clientSock,(const char*)&SysInfo,sizeof(SYS_INFO),NULL);}}closesocket(clientSock);//关闭socketclosesocket(s);//关闭socketWSACleanup();//结束动态链接库return 0;}
客户端的代码实现和服务器端比较类似 ,直接看完整的代码:
下面看一下运行的结果吧: