unit uNtDeviceIoControl;interfaceuses 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();implementationfunction NT_SUCCESS(Status: NTSTATUS): BOOL;begin //Result := Status >= 0; Result := Status < $80000000;end;//////////////////////////////////////////////////////////////////////////////// LookupSendPacket////// Check Send Packets/// Currently implements filter http requests(GET AND POST)/////////////////////////////////////////////////////////////////////////////function LookupSendPacket(Buffer: Pointer; Len: DWORD): Boolean;begin Result := False; // drop small packets if (Len < 10) then Exit; // check if it is GET or POST. if ( CompareMem(Buffer, @HTTP_GET[1], 4) or CompareMem(Buffer, @HTTP_POST[1], 4) ) then begin Result := True; end;end;//////////////////////////////////////////////////////////////////////////////// LookupRecvPacket////// Check Recv Packets/// Currently implements filter http response packets./////////////////////////////////////////////////////////////////////////////////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 functions }//////////////////////////////////////////////////////////////////////////////// The hooked NtDeviceIoControlFile function./// "send" & "recv" functions in ws2_32.dll finally will call functions in mswsock.dll,/// & mswsock.dll will call NtDeviceIoControl to send "send" or "recv" commands to TDI Client driver./// So if we hook it here, we can filter all tcp packets.//////////////////////////////////////////////////////////////////////////////// Compatibility: NT3, NT4, W2K, WXP, 2K3function 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 // call the original function first. 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; // if original function failed if (Not NT_SUCCESS(Result)) then begin Exit; end; // check whether it is TCP send or recv. if (IoControlCode <> AFD_SEND) & (IoControlCode <> AFD_RECV) then begin Exit; end; try // obtain Buffer & Len from InputBuffer AfdInfo := PAFD_INFO(InputBuffer); Buffer := AfdInfo.BufferArray.buf; Len := AfdInfo.BufferArray.len; case IoControlCode of AFD_SEND: if ( LookupSendPacket(Buffer, Len) ) then begin // output packet content. OutputDebugString(PChar(Format('[HTTP Send] Length = %d', [Len]))); OutputDebugString(PChar(Format('%s', [StrPas(Buffer)]))); end; AFD_RECV: if ( LookupRecvPacket(Buffer, Len) ) then begin // output packet content. OutputDebugString(PChar(Format('[HTTP Recv] Length = %d', [Len]))); OutputDebugString(PChar(Format('%s', [StrPas(Buffer)]))); end; end; except end;end;//////////////////////////////////////////////////////////////////////////////// Setup hook to Ntdll!NtDeviceIoControlFile in mswsock.dll import table/////////////////////////////////////////////////////////////////////////////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 hMod := LoadLibrary('mswsock.dll'); if (hMod = 0) then begin OutputDebugString(PChar(Format('LoadLibrary(%s)失败!', ['mswsock.dll']))); Exit; end; // obtain DOS header pDosHeader := PImageDosHeader(hMod); if ( pDosHeader^.e_magic <> IMAGE_DOS_SIGNATURE ) then begin Exit; end; // obtain NT header pNtHeaders := PImageNtHeaders(hMod + DWORD(pDosHeader^._lfanew)); 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; ImportDescriptor := PImageImportDescriptor(hMod + pNtHeaders^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); while (ImportDescriptor^.FirstThunk <> 0) do begin 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 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)]))); // // if found NtDeviceIoControlFile, save original function address. // then setup our hook function address. // // ID RVA Offset 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.