分享
分享赚钱 收藏 举报 版权申诉 / 14

类型利用HOOK拦截封包原理.doc

  • 上传人:kpmy5893
  • 文档编号:9310482
  • 上传时间:2019-08-01
  • 格式:DOC
  • 页数:14
  • 大小:41KB
  • 配套讲稿:

    如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。

    特殊限制:

    部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。

    关 键  词:
    利用HOOK拦截封包原理.doc
    资源描述:

    1、利用 HOOK 拦截封包原理利用 HOOK 拦截封包原理 截获 API 是个很有用的东西,比如你想分析一下别人的程序是怎样工作的。这里我介绍一下一种我自己试验通过的方法。 首先,我们必须设法把自己的代码放到目标程序的进程空间里去。Windows Hook 可以帮我们实现这一点。SetWindowsHookEx 的声明如下: HHOOK SetWindowsHookEx( int idHook, / hook type HOOKPROC lpfn, / hook procedure HINSTANCE hMod, / handle to application instance DWORD dw

    2、ThreadId / thread identifier ); 具体的参数含义可以翻阅 msdn,没有 msdn 可谓寸步难行。 这里 Hook 本身的功能并不重要,我们使用它的目的仅仅只是为了能够让 Windows 把我们的代码植入别的进程里去。hook Type 我们任选一种即可,只要保证是目标程序肯定会调用到就行,这里我用的是 WH_CALLWNDPROC。lpfn 和 hMod 分别指向我们的钩子代码及其所在的 dll,dwThreadId 设为 0,表示对所有系统内的线程都挂上这样一个 hook,这样我们才能把代码放到别的进程里去。 之后,我们的代码就已经进入了系统内的所有进程空间了

    3、。必须注意的是,我们只需要截获我们所关心的目标程序的调用,因此还必须区分一下进程号。我们自己的钩子函数中,第一次运行将进行最重要的 API 重定向的工作。也就是通过将所需要截获的 API 的开头几个字节改为一个跳转指令,使其跳转到我们的 API 中来。这是最关键的部分。这里我想截三个调用,ws2_32.dll 中的 send 和recv、user32.dll 中的 GetMessageA。 DWORD dwCurrentPID = 0; HHOOK hOldHook = NULL; DWORD pSend = 0; DWORD pRecv = 0; GETMESSAGE pGetMessage

    4、 = NULL; BYTE btNewBytes8 = 0x0B8, 0x0, 0x0, 0x40, 0x0, 0x0FF, 0x0E0, 0 ; DWORD dwOldBytes32; HANDLE hDebug = INVALID_HANDLE_value; LRESULT CALLBACK CallWndProc( int nCode, WPARAM wParam, LPARAM lParam ) DWORD dwSize; DWORD dwPIDWatched; HMODULE hLib; if( dwCurrentPID = 0 ) dwCurrentPID = GetCurrent

    5、ProcessId(); HWND hwndMainHook; hwndMainHook = :FindWindow( 0, “MainHook“ ); dwPIDWatched = :SendMessage( hwndMainHook, (WM_USER+100), 0, 0 ); hOldHook = (HHOOK):SendMessage( hwndMainHook, (WM_USER+101), 0, 0 ); if( dwCurrentPID = dwPIDWatched ) hLib = LoadLibrary( “ws2_32.dll“ ); pSend = (DWORD)Get

    6、ProcAddress( hLib, “send“ ); pRecv = (DWORD)GetProcAddress( hLib, “recv“ ); :ReadProcessMemory( INVALID_HANDLE_value, (void *)pSend, (void *)dwOldBytes0, sizeof(DWORD)*2, *(DWORD *)( btNewBytes + 1 ) = (DWORD)new_send; :WriteProcessMemory( INVALID_HANDLE_value, (void *)pSend, (void *)btNewBytes, siz

    7、eof(DWORD)*2, :ReadProcessMemory( INVALID_HANDLE_value, (void *)pRecv, (void *)dwOldBytes1, sizeof(DWORD)*2, *(DWORD *)( btNewBytes + 1 ) = (DWORD)new_recv; :WriteProcessMemory( INVALID_HANDLE_value, (void *)pRecv, (void *)btNewBytes, sizeof(DWORD)*2, hLib = LoadLibrary( “user32.dll“ ); pGetMessage

    8、= (GETMESSAGE)GetProcAddress( hLib, “GetMessageA“ ); :ReadProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)dwOldBytes2, sizeof(DWORD)*2, *(DWORD *)( btNewBytes + 1 ) = (DWORD)new_GetMessage; :WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)btNewBytes, sizeof(D

    9、WORD)*2, hDebug = :CreateFile( “C:Trace.log“, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 ); if( hOldHook != NULL ) return CallNextHookEx( hOldHook, nCode, wParam, lParam ); return 0; 上面的钩子函数,只有第一次运行时有用,就是把三个函数的首 8字节修改一下(实际上只需要 7 个) 。btNewBytes 中的指令实际就是 mov eax, 0x400000 jmp eax 这里的

    10、 0x400000 就是新的函数的地址,比如new_recv/new_send/new_GetMessage,此时,偷梁换柱已经完成。再看看我们的函数中都干了些什么。以 GetMessageA 为例: BOOL _stdcall new_GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax ) DWORD dwSize; char szTemp256; BOOL r = false; /Watch here before its executed. sprintf( szTemp, “Before

    11、GetMessage : HWND 0x%8.8X, msgMin 0x%8.8X, msgMax 0x%8.8x rn“, hWnd, wMsgFilterMin, wMsgFilterMax ); :WriteFile( hDebug, szTemp, strlen(szTemp), /Watch over / restore it at first :WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)dwOldBytes2, sizeof(DWORD)*2, / execute it r = pG

    12、etMessage( lpMsg, hWnd, wMsgFilterMin, wMsgFilterMax ); / hook it again *(DWORD *)( btNewBytes + 1 ) = (DWORD)new_GetMessage; :WriteProcessMemory( INVALID_HANDLE_value, (void *)pGetMessage, (void *)btNewBytes, sizeof(DWORD)*2, /Watch here after its executed sprintf( szTemp, “Result of GetMessage is

    13、%d.rn“, r ); :WriteFile( hDebug, szTemp, strlen( szTemp ), if( r ) sprintf( szTemp, “Msg : HWND 0x%8.8X, MSG 0x%8.8x, wParam 0x%8.8X, lParam 0x%8.8XrnTime 0x%8.8X, X %d, Y %drn“, lpMsg-hwnd, lpMsg-message, lpMsg-wParam, lpMsg-lParam, lpMsg-time, lpMsg-pt.x, lpMsg-pt.y ); :WriteFile( hDebug, szTemp,

    14、strlen( szTemp ), strcpy( szTemp, “rn“ ); :WriteFile( hDebug, szTemp, strlen( szTemp ), /Watch over return r; 先将截获下来的参数,写入到一个 log 文件中,以便分析。然后恢复原先保留下来的 GetMessageA 的首 8 字节,然后执行真正的GetMessageA 调用,完毕后再将执行结果也写入 log 文件,然后将GetMessageA 的执行结果返回给调用者。 整个截获的过程就是这样。你可以把其中的写 log 部分改成你自己想要的操作。这里有个不足的地方是,截获动作是不能够并发

    15、进行的,如果目标进程是多线程的,就会有问题。解决办法是,可以在每次 new_GetMessage 中加入一个 CriticalSection 的锁和解锁,以使调用变为串行进行,以原始套接字的方式 截获流经本机网卡的IP 数据包 从事网络安全的技术人员和相当一部分准黑客(指那些使用现成的黑客软件进行攻击而不是根据需要去自己编写代码的人)都一定不会对网络嗅探器(sniffer)感到陌生,网络嗅探器无论是在网络安全还是在黑客攻击方面均扮演了很重要的角色。通过使用网络嗅探器可以把网卡设置于混杂模式,并可实现对网络上传输的数据包的捕获与分析。此分析结果可供网络安全分析之用,但如为黑客所利用也可以为其发动

    16、进一步的攻击提供有价值的信息。可见,嗅探器实际是一把双刃剑。 虽然网络嗅探器技术被黑客利用后会对网络安全构成一定的威胁,但嗅探器本身的危害并不是很大,主要是用来为其他黑客软件提供网络情报,真正的攻击主要是由其他黑软来完成的。而在网络安全方面,网络嗅探手段可以有效地探测在网络上传输的数据包信息,通过对这些信息的分析利用是有助于网络安全维护的。权衡利弊,有必要对网络嗅探器的实现原理进行介绍。 文章正文 嗅探器设计原理 嗅探器作为一种网络通讯程序,也是通过对网卡的编程来实现网络通讯的,对网卡的编程也是使用通常的套接字(socket)方式来进行。但是,通常的套接字程序只能响应与自己硬件地址相匹配的或是

    17、以广播形式发出的数据帧,对于其他形式的数据帧比如已到达网络接口但却不是发给此地址的数据帧,网络接口在验证投递地址并非自身地址之后将不引起响应,也就是说应用程序无法收取到达的数据包。而网络嗅探器的目的恰恰在于从网卡接收所有经过它的数据包,这些数据包即可以是发给它的也可以是发往别处的。显然,要达到此目的就不能再让网卡按通常的正常模式工作,而必须将其设置为混杂模式。具体到编程实现上,这种对网卡混杂模式的设置是通过原始套接字(raw socket)来实现的,这也有别于通常经常使用的数据流套接字和数据报套接字。在创建了原始套接字后,需要通过setsockopt()函数来设置 IP 头操作选项,然后再通过

    18、 bind()函数将原始套接字绑定到本地网卡。为了让原始套接字能接受所有的数据,还需要通过 ioctlsocket()来进行设置,而且还可以指定是否亲自处理 IP 头。至此,实际就可以开始对网络数据包进行嗅探了,对数据包的获取仍象流式套接字或数据报套接字那样通过 recv()函数来完成。但是与其他两种套接字不同的是,原始套接字此时捕获到的数据包并不仅仅是单纯的数据信息,而是包含有 IP 头、 TCP头等信息头的最原始的数据信息,这些信息保留了它在网络传输时的原貌。通过对这些在低层传输的原始信息的分析可以得到有关网络的一些信息。由于这些数据经过了网络层和传输层的打包,因此需要根据其附加的帧头对数

    19、据包进行分析。下面先给出结构.数据包的总体结构:数据包 IP 头 TCP 头(或其他信息头) 数据 数据在从应用层到达传输层时,将添加 TCP 数据段头,或是UDP 数据段头。其中 UDP 数据段头比较简单,由一个 8 字节的头和数据部分组成,具体格式如下:16 位 16 位 源端口 目的端口 UDP 长度 UDP 校验和 而 TCP 数据头则比较复杂,以 20 个固定字节开始,在固定头后面还可以有一些长度不固定的可选项,下面给出 TCP 数据段头的格式组成:16 位 16 位 源端口 目的端口 顺序号 确认号 TCP 头长 (保留)7 位 URG ACK PSH RST SYN FIN 窗口

    20、大小 校验和 紧急指针 可选项(0 或更多的 32 位字) 数据(可选项) 对于此 TCP 数据段头的分析在编程实现中可通过数据结构_TCP来定义:typedef struct _TCP WORD SrcPort; / 源端口WORD DstPort; / 目的端口DWORD SeqNum; / 顺序号DWORD AckNum; / 确认号BYTE DataOff; / TCP 头长BYTE Flags; / 标志(URG、ACK 等)WORD Window; / 窗口大小WORD Chksum; / 校验和WORD UrgPtr; / 紧急指针 TCP;typedef TCP *LPTCP;

    21、typedef TCP UNALIGNED * ULPTCP; 在网络层,还要给 TCP 数据包添加一个 IP 数据段头以组成 IP数据报。IP 数据头以大端点机次序传送,从左到右,版本字段的高位字节先传输(SPARC 是大端点机;Pentium 是小端点机) 。如果是小端点机,就要在发送和接收时先行转换然后才能进行传输。IP 数据段头格式如下:16 位 16 位 版本 IHL 服务类型 总长 标识 标志 分段偏移 生命期 协议 头校验和 源地址 目的地址 选项(0 或更多) 同样,在实际编程中也需要通过一个数据结构来表示此 IP 数据段头,下面给出此数据结构的定义:typedef struc

    22、t _IPunion BYTE Version; / 版本BYTE HdrLen; / IHL;BYTE ServiceType; / 服务类型WORD TotalLen; / 总长WORD ID; / 标识union WORD Flags; / 标志WORD FragOff; / 分段偏移;BYTE TimeToLive; / 生命期BYTE Protocol; / 协议WORD HdrChksum; / 头校验和DWORD SrcAddr; / 源地址DWORD DstAddr; / 目的地址BYTE Options; / 选项 IP; typedef IP * LPIP;typedef

    23、IP UNALIGNED * ULPIP;在明确了以上几个数据段头的组成结构后,就可以对捕获到的数据包进行分析了。嗅探器的具体实现根据前面的设计思路,不难写出网络嗅探器的实现代码,下面就给出一个简单的示例,该示例可以捕获到所有经过本地网卡的数据包,并可从中分析出协议、IP 源地址、IP 目标地址、TCP 源端口号、TCP 目标端口号以及数据包长度等信息。由于前面已经将程序的设计流程讲述的比较清楚了,因此这里就不在赘述了,下面就结合注释对程序的具体是实现进行讲解,同时为程序流程的清晰起见,去掉了错误检查等保护性代码。主要代码实现清单为:/ 检查 Winsock 版本号,WSAData 为 WSA

    24、DATA 结构对象WSAStartup(MAKEWORD(2, 2), / 创建原始套接字sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);/ 设置 IP 头操作选项,其中 flag 设置为 ture,亲自对 IP 头进行处理setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char*)/ 获取本机名gethostname(char*)LocalName, sizeof(LocalName)-1);/ 获取本地 IP 地址pHost = gethostbyname(char*)LocalName);/ 填充 SOCKA

    25、DDR_IN 结构addr_in.sin_addr = *(in_addr *)pHost-h_addr_list0; /IPaddr_in.sin_family = AF_INET;addr_in.sin_port = htons(57274);/ 把原始套接字 sock 绑定到本地网卡地址上bind(sock, (PSOCKADDR)/ dwValue 为输入输出参数,为 1 时执行,0 时取消DWORD dwValue = 1; / 设置 SOCK_RAW 为 SIO_RCVALL,以便接收所有的 IP 包。其中SIO_RCVALL/ 的定义为: #define SIO_RCVALL _

    26、WSAIOW(IOC_VENDOR,1)ioctlsocket(sock, SIO_RCVALL, 前面的工作基本上都是对原始套接字进行设置,在将原始套接字设置完毕,使其能按预期目的工作时,就可以通过 recv()函数从网卡接收数据了,接收到的原始数据包存放在缓存 RecvBuf中,缓冲区长度 BUFFER_SIZE 定义为 65535。然后就可以根据前面对 IP数据段头、TCP 数据段头的结构描述而对捕获的数据包进行分析:while (true)/ 接收原始数据包信息int ret = recv(sock, RecvBuf, BUFFER_SIZE, 0);if (ret 0)/ 对数据包进

    27、行分析,并输出分析结果ip = *(IP*)RecvBuf;tcp = *(TCP*)(RecvBuf + ip.HdrLen);TRACE(“协议: %srn“,GetProtocolTxt(ip.Protocol);TRACE(“IP 源地址: %srn“,inet_ntoa(*(in_addr*)TRACE(“IP 目标地址: %srn“,inet_ntoa(*(in_addr*)TRACE(“TCP 源端口号: %drn“,tcp.SrcPort);TRACE(“TCP 目标端口号:%drn“,tcp.DstPort);TRACE(“数据包长度: %drnrnrn“,ntohs(ip.

    28、TotalLen); 其中,在进行协议分析时,使用了 GetProtocolTxt()函数,该函数负责将 IP 包中的协议(数字标识的)转化为文字输出,该函数实现如下:#define PROTOCOL_STRING_ICMP_TXT “ICMP“#define PROTOCOL_STRING_TCP_TXT “TCP“#define PROTOCOL_STRING_UDP_TXT “UDP“#define PROTOCOL_STRING_SPX_TXT “SPX“#define PROTOCOL_STRING_NCP_TXT “NCP“#define PROTOCOL_STRING_UNKNO

    29、W_TXT “UNKNOW“CString CSnifferDlg:GetProtocolTxt(int Protocol)switch (Protocol)case IPPROTO_ICMP : /1 /* control message protocol */return PROTOCOL_STRING_ICMP_TXT;case IPPROTO_TCP : /6 /* tcp */return PROTOCOL_STRING_TCP_TXT;case IPPROTO_UDP : /17 /* user datagram protocol */return PROTOCOL_STRING_

    30、UDP_TXT;default:return PROTOCOL_STRING_UNKNOW_TXT; 最后,为了使程序能成功编译,需要包含头文件 winsock2.h和 ws2tcpip.h。在本示例中将分析结果用 TRACE()宏进行输出,在调试状态下运行,得到的一个分析结果如下:协议: UDPIP 源地址: 172.168.1.5IP 目标地址: 172.168.1.255TCP 源端口号: 16707TCP 目标端口号:19522数据包长度: 78协议: TCPIP 源地址: 172.168.1.17IP 目标地址: 172.168.1.1TCP 源端口号: 19714TCP 目标端口号:10数据包长度: 200从分析结果可以看出,此程序完全具备了嗅探器的数据捕获以及对数据包的分析等基本功能。小结本文介绍的以原始套接字方式对网络数据进行捕获的方法实现起来比较简单,尤其是不需要编写 VxD 虚拟设备驱动程序就可以实现抓包,使得其编写过程变的非常简便,但由于捕获到的数据包头不包含有帧信息,因此不能接收到与 IP 同属网络层的其它数据包, 如 ARP 数据包、RARP 数据包等。在前面给出的示例程序中考虑到安全因素,没有对数据包做进一步的分析,而是仅仅给出了对一般信息的分析方法。通过本文的介绍,可对原始套接字的使用方法以及TCP/IP 协议结构原理等知识有一个基本的认识。

    展开阅读全文
    提示  道客多多所有资源均是用户自行上传分享,仅供网友学习交流,未经上传用户书面授权,请勿作他用。
    关于本文
    本文标题:利用HOOK拦截封包原理.doc
    链接地址:https://www.docduoduo.com/p-9310482.html
    关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

    道客多多用户QQ群:832276834  微博官方号:道客多多官方   知乎号:道客多多

    Copyright© 2025 道客多多 docduoduo.com 网站版权所有世界地图

    经营许可证编号:粤ICP备2021046453号    营业执照商标

    1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png 10.png



    收起
    展开