在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
标 题: 【原创】另类挂钩-RING3数据包监视
闲着无聊,在看雪上看到这个帖子。Hook NtDeviceIoControlFile 果然够另类,于是迅速翻成Delphi的代码,效果还不错: ]
关键代码如下:
unit uNtDeviceIoControl;
{ 原理:Hook ntdll!NtDeviceIoControlFile 拦截 AFD_RECV 和 AFD_SEND 对TCP包进行监视, 通过比较 send 函数的 Buffer 是否为 GET/POST recv 函数的 Buffer 是否为 HTTP,来判断HTTP包 代码思路相当清晰,又有注释(原来就有),我就不多说了。 } interface uses SysUtils, Windows; const AFD_RECV = $12017; AFD_SEND = $1201f; HTTP_GET: AnsiString = 'GET '; HTTP_POST: AnsiString = 'POST '; HTTP_RESPONSE: AnsiString = 'HTTP'; type NTSTATUS = DWORD; PVOID = Pointer; _AFD_WSABUF = record len: DWORD; buf: PAnsiChar; end; TAFD_WSABUF = _AFD_WSABUF; PAFD_WSABUF = ^TAFD_WSABUF; _AFD_INFO = record BufferArray: PAFD_WSABUF; BufferCount: DWORD; AfdFlags: DWORD; TdiFlags: DWORD; end; TAFD_INFO = _AFD_INFO; PAFD_INFO = ^TAFD_INFO; _IO_STATUS_BLOCK = record //union { Status: NTSTATUS; // PVOID Pointer; //} Information: ULONG_PTR; end; IO_STATUS_BLOCK = _IO_STATUS_BLOCK; PIO_STATUS_BLOCK = ^IO_STATUS_BLOCK; TIoStatusBlock = IO_STATUS_BLOCK; PIoStatusBlock = ^TIoStatusBlock; PIO_APC_ROUTINE = procedure(ApcContext: PVOID; IoStatusBlock: PIO_STATUS_BLOCK; Reserved: ULONG); stdcall; PIMAGE_IMPORT_DESCRIPTOR = ^_IMAGE_IMPORT_DESCRIPTOR; PImageImportDescriptor = PIMAGE_IMPORT_DESCRIPTOR; _IMAGE_IMPORT_DESCRIPTOR = packed record CharacteristicsOrOriginalFirstThunk: DWord; TimeDateStamp: DWord; ForwarderChain: DWord; Name: DWord; FirstThunk: DWord; end; PIMAGE_THUNK_DATA = ^_IMAGE_THUNK_DATA; PImageThunkData = PIMAGE_THUNK_DATA; _IMAGE_THUNK_DATA = packed record case Integer of 0 : (ForwarderString: DWord); 1 : (Function_: DWord); 2 : (Ordinal: DWord); 3 : (AddressOfData: DWord); end; function NT_SUCCESS(Status: NTSTATUS): BOOL; {$EXTERNALSYM NT_SUCCESS} var OldNtDeviceIoControl: DWORD; procedure SuperHookDeviceIoControl(); implementation function NT_SUCCESS(Status: NTSTATUS): BOOL; begin //Result := Status >= 0; Result := Status < $80000000; end; ////////////////////////////////////////////////////////////////////////// /// /// LookupSendPacket /// 检查Send包 /// 目前实现了过滤HTTP请求(GET AND POST) /// ////////////////////////////////////////////////////////////////////////// function LookupSendPacket(Buffer: Pointer; Len: DWORD): Boolean; begin Result := False; // 过滤长度太小的包 if (Len < 10) then Exit; // 检查是不是GET或POST if ( CompareMem(Buffer, @HTTP_GET[1], 4) or CompareMem(Buffer, @HTTP_POST[1], 4) ) then begin Result := True; end; end; ////////////////////////////////////////////////////////////////////////// /// /// LookupRecvPacket /// /// 检查Recv包 /// 在这里可以实现Recv包查字典功能 /// 目前实现了过滤HTTP返回数据包的功能 /// /// /////////////////////////////////////////////////////////////////////////// function LookupRecvPacket(Buffer: Pointer; Len: DWORD): Boolean; begin Result := False; if (Len < 10) then Exit; if ( CompareMem(Buffer, @HTTP_RESPONSE[1], 4) ) then begin Result := True; end; end; { HOOK 函数 } ////////////////////////////////////////////////////////////////////////// /// /// NtDeviceIoControlFile的HOOK函数 /// ws2_32.dll的send , recv最终会调用到mswsock.dll内的数据发送函数 /// mswsock.dll会调用NtDeviceIoControl向TDI Client驱动发送Send Recv指令 /// 我们在这里做拦截,可以过滤所有的TCP 收发包(UDP之类亦可,不过要更改指令) /// ////////////////////////////////////////////////////////////////////////// /// Compatibility: NT3, NT4, W2K, WXP, 2K3 function NewNtDeviceIoControlFile( FileHandle : THANDLE; Event : THANDLE; ApcRoutine : PIO_APC_ROUTINE; ApcContext : PVOID; IoStatusBlock : PIO_STATUS_BLOCK; IoControlCode : ULONG; InputBuffer : PVOID; InputBufferLength : ULONG; OutputBuffer : PVOID; OutputBufferLength : ULONG ): NTSTATUS; stdcall; var AfdInfo: PAFD_INFO; Buffer: PAnsiChar; Len: DWORD; begin // 先调用原始函数 asm push OutputBufferLength push OutputBuffer push InputBufferLength push InputBuffer push IoControlCode push IoStatusBlock push ApcContext push ApcRoutine push Event push FileHandle call OldNtDeviceIoControl mov Result, eax end; // 如果原始函数失败了(例如RECV无数据) if (Not NT_SUCCESS(Result)) then begin Exit; end; // 检查是否为TCP收发指令 if (IoControlCode <> AFD_SEND) and (IoControlCode <> AFD_RECV) then begin Exit; end; // 访问AFD INFO结构,获得SEND或RECV的BUFFER信息 // 这里可能是有问题的BUFFER,因此我们要加TRY EXCEPT try // 从 InputBuffer 得到 Buffer 和 Len AfdInfo := PAFD_INFO(InputBuffer); Buffer := AfdInfo.BufferArray.buf; Len := AfdInfo.BufferArray.len; case IoControlCode of AFD_SEND: if ( LookupSendPacket(Buffer, Len) ) then begin // 输出包内容 OutputDebugString(PChar(Format('[HTTP Send] Length = %d', [Len]))); OutputDebugString(PChar(Format('%s', [StrPas(Buffer)]))); end; AFD_RECV: if ( LookupRecvPacket(Buffer, Len) ) then begin // 输出包内容 OutputDebugString(PChar(Format('[HTTP Recv] Length = %d', [Len]))); OutputDebugString(PChar(Format('%s', [StrPas(Buffer)]))); end; end; except end; end; ////////////////////////////////////////////////////////////////////////// /// /// Hook mswsock.dll导出表的Ntdll!NtDeviceIoControlFile /// 并过滤其对TDI Cilent的请求来过滤封包 /// 稳定,隐蔽,RING3下最底层的包过滤~ /// ////////////////////////////////////////////////////////////////////////// procedure SuperHookDeviceIoControl(); var hMod: HMODULE; pDosHeader: PImageDosHeader; pNtHeaders: PImageNtHeaders; ImportDescriptor: PImageImportDescriptor; ThunkData: PImageThunkData; dll_name, func_name: PAnsiChar; iNum: Integer; lpAddr: Pointer; myaddr, btw: DWORD; begin //得到ws2_32.dll的模块基址 hMod := LoadLibrary('mswsock.dll'); if (hMod = 0) then begin OutputDebugString(PChar(Format('LoadLibrary(%s)失败!', ['mswsock.dll']))); Exit; end; //得到DOS头 pDosHeader := PImageDosHeader(hMod); //如果DOS头无效 if ( pDosHeader^.e_magic <> IMAGE_DOS_SIGNATURE ) then begin Exit; end; //得到NT头 pNtHeaders := PImageNtHeaders(hMod + DWORD(pDosHeader^._lfanew)); //如果NT头无效 if ( pNtHeaders^.Signature <> IMAGE_NT_SIGNATURE ) then begin Exit; end; //检查输入表数据目录是否存在 if (pNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = 0) or (pNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = 0) then begin Exit; end; //OutputDebugString(PChar(Format('[HOOK] lock mswsock.dll, waiting', []))); //得到输入表描述指针 ImportDescriptor := PImageImportDescriptor(hMod + pNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); //检查每个输入项 while (ImportDescriptor^.FirstThunk <> 0) do begin // 检查输入表项是否为ntdll.dll dll_name := PAnsiChar(hMod + ImportDescriptor^.Name); // 如果不是,则跳到下一个处理 if (StrIComp(dll_name, 'ntdll.dll') <> 0) then begin ImportDescriptor := PImageImportDescriptor(DWORD(ImportDescriptor) + SizeOf(_IMAGE_IMPORT_DESCRIPTOR)); Continue; end; ThunkData := PImageThunkData(hMod + ImportDescriptor^.CharacteristicsOrOriginalFirstThunk); iNum := 1; while (ThunkData^.Function_ <> 0) do begin // 检查函数是否为NtDeviceIoControlFile func_name := PAnsiChar(hMod + ThunkData^.AddressOfData + 2); //OutputDebugString(PChar(Format('[HOOK] find API: %s', [StrPas(func_name)]))); if (StrIComp(func_name , 'NtDeviceIoControlFile') = 0) then begin OutputDebugString(PChar(Format('[HOOK] Lock "%s" for HOOK.', [StrPas(func_name)]))); // // 如果是,那么记录原始函数地址 // HOOK我们的函数地址 // // 序号 RVA 偏移 Name // 9A D8E3 CCE3 NtDeviceIoControlFile myaddr := DWORD(@NewNtDeviceIoControlFile); lpAddr := Pointer(hMod + ImportDescriptor^.FirstThunk + DWORD(iNum-1)*4); OldNtDeviceIoControl := PDWORD(lpAddr)^; OutputDebugString(PChar(Format('[HOOK] Base=%0.8X, Thunk=%0.8X, ID=%X', [hMod, ImportDescriptor^.FirstThunk, iNum-1]))); OutputDebugString(PChar(Format('[HOOK] Orign[0x%0.8X]=0x%0.8X, new Addr=0x%0.8X', [DWORD(lpAddr), PDWORD(lpAddr)^, myaddr]))); WriteProcessMemory(GetCurrentProcess(), lpAddr, @myaddr, 4, btw); Exit; end; Inc(iNum); ThunkData := PImageThunkData(DWORD(ThunkData) + SizeOf(_IMAGE_THUNK_DATA)); end; Inc(ImportDescriptor); end; end; end.
这里是源码 r3_Hook_NtDeviceIoControl_src.rar,Delphi 2007/2009编译通过。 使用方法:用附带的 DLL_Inject.exe 插入 NDIC_Hook.dll 到浏览器中,可以使用DebugView看到HTTP的信息。
补充:从ReactOS的AFD中导出的完整定义,对应NtDeviceIoControlFile中的IoControlCode,可以把之前的这个替换掉了:) IOCTL_AFD_BIND = $00012003; IOCTL_AFD_CONNECT = $00012007; IOCTL_AFD_START_LISTEN = $0001200B; IOCTL_AFD_WAIT_FOR_LISTEN = $0001200C; IOCTL_AFD_ACCEPT = $00012010; IOCTL_AFD_RECV = $00012017; IOCTL_AFD_RECV_DATAGRAM = $0001201B; IOCTL_AFD_SEND = $0001201F; IOCTL_AFD_SEND_DATAGRAM = $00012023; IOCTL_AFD_SELECT = $00012024; IOCTL_AFD_DISCONNECT = $0001202B; IOCTL_AFD_GET_SOCK_NAME = $0001202F; IOCTL_AFD_GET_PEER_NAME = $00012033; IOCTL_AFD_GET_TDI_HANDLES = $00012037; IOCTL_AFD_SET_INFO = $0001203B; IOCTL_AFD_GET_CONTEXT = $0001203F; IOCTL_AFD_SET_CONTEXT = $00012043; IOCTL_AFD_SET_CONNECT_DATA = $00012047; IOCTL_AFD_SET_CONNECT_OPTIONS = $0001204B; IOCTL_AFD_SET_DISCONNECT_DATA = $0001204F; IOCTL_AFD_SET_DISCONNECT_OPTIONS = $00012053; IOCTL_AFD_GET_CONNECT_DATA = $00012057; IOCTL_AFD_GET_CONNECT_OPTIONS = $0001205B; IOCTL_AFD_GET_DISCONNECT_DATA = $0001205F; IOCTL_AFD_GET_DISCONNECT_OPTIONS = $00012063; IOCTL_AFD_SET_CONNECT_DATA_SIZE = $0001206B; IOCTL_AFD_SET_CONNECT_OPTIONS_SIZE = $0001206F; IOCTL_AFD_SET_DISCONNECT_DATA_SIZE = $00012073; IOCTL_AFD_SET_DISCONNECT_OPTIONS_SIZE = $00012077; IOCTL_AFD_GET_INFO = $0001207B; IOCTL_AFD_EVENT_SELECT = $00012087; IOCTL_AFD_DEFER_ACCEPT = $0001208F; IOCTL_AFD_GET_PENDING_CONNECT_DATA = $000120A7; IOCTL_AFD_ENUM_NETWORK_EVENTS = $0001208B; |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论