Hook浏览器控件WebBrowser对WININET.dll的调用

此文章的代码可以从此处下载:http://www.codeproject.com/KB/shell/RetrieveHttponlyCookies.aspx

 

开发中经常使用到WebBrowser。WebBrowser控件编程控制起来很方面,好处不用说了。

 

但日前遇到一个问题,如何获取HTTP服务器页面返回的HTTP HEADER(不是DOM的head)?

比如说ASP.Net页面返回的SessionID,尝试通过DOM的 IHTMLDocument2::get_cookie 获取不到

浏览器控件并没有提供此类接口。那就HOOK吧。

 

HOOK winsock? HTTP协议不想去分析啊

 

通过Depends.exe查看mshtml.dll, 发现HTTP的时候使用了 WinInet.dll,WinInet.dll的升级版WinHttp.dll早出来了,不知M$怎么还在用WinInet.dll. 不过没关系,只要能够HOOK到 mshtml.dll 对 WinInet.dll 的调用,什么问题都解决了。HOOK WinInet.dll 还不需要去处理HTTP协议底层,多简单啊。

 

进程内HOOK是很简单的,不用考虑内存空间问题。HOOK一般分2种:inline hook和dispatch hook.

inline hook具有普适性,但dispatch hook具有robust性, (呃,这个词常被翻译成鲁棒性,健壮性就健壮性吧)

可爱的 SSDT GDT IDT HOOK都属于此类。那还是用后者吧。

 

扯远了,扯远了。在这里是HOOK IAT,IAT是导入函数表(Import Address Table)的缩写,对它的HOOK例子网上一抄一大把,原理就不细说了,废话都被说完了,看代码吧。

 

首先导入一些头文件和库文件,后面的代码要用

#include <WinInet.h> #pragma comment( lib, "WinInet.lib") #include <Dbghelp.h> #include <DelayImp.h> #pragma comment( lib, "Dbghelp.lib") #include <Psapi.h> #pragma comment( lib, "Psapi.lib")

 

如果你有DDK/WDK最好了,没有的话需要加入一点点定义,后面需要用到

typedef struct _STRING { USHORT Length; USHORT MaximumLength; PCHAR Buffer; } ANSI_STRING, *PANSI_STRING; typedef struct _LSA_UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; }LSA_UNICODE_STRING, *PLSA_UNICODE_STRING, UNICODE_STRING, *PUNICODE_STRING; typedef LONG NTSTATUS; #define STATUS_SUCCESS ((NTSTATUS)0x00000000L)

 

呃,为什么我要使用到一些内核中的结构?

一般的HOOK方式是HOOK Kernel32.dll 中的 LoadLibrar(Ex)  GetProcAddress 来检测动态加载的DLL以及通过函数指针方式的调用。

不过这里是HOOK NTDLL.DLL中的 LdrLoadDllLdrGetProcedureAddress 。这2个API更彻底,LoadLibrar(Ex)GetProcAddress 最终都是通过它们实现。NTDLL.DLL是Win32 SubSystem调用 Ring3 通往 Ring0 的最后一道门户,HOOK它更加彻底和保险。

所以这里要用到一点点内核中的结构。

 

现在最主要的问题是HOOK WinInet的调用,函数定义直接查MSDN就可以了。这里只HOOK的一部分的函数,根据需要你可以增加更多的函数。

 

首先定义函数指针

typedef NTSTATUS (WINAPI* PFN_LdrGetProcedureAddress)(IN HMODULE ModuleHandle, IN PANSI_STRING FunctionName OPTIONAL, IN WORD Oridinal OPTIONAL, OUT PVOID *FunctionAddress ); typedef NTSTATUS (WINAPI* PFN_LdrLoadDll)(IN PWCHAR PathToFile OPTIONAL, IN ULONG Flags OPTIONAL, IN PUNICODE_STRING ModuleFileName, OUT PHANDLE ModuleHandle); typedef BOOL (WINAPI* PFN_HttpSendRequestA)(HINTERNET hRequest, LPCSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength ); typedef BOOL (WINAPI* PFN_HttpSendRequestW)(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength ); typedef BOOL (WINAPI* PFN_HttpSendRequestExA)( __in HINTERNET hRequest, __in_opt LPINTERNET_BUFFERSA lpBuffersIn, __out_opt LPINTERNET_BUFFERSA lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); typedef BOOL (WINAPI* PFN_HttpSendRequestExW)( __in HINTERNET hRequest, __in_opt LPINTERNET_BUFFERSW lpBuffersIn, __out_opt LPINTERNET_BUFFERSW lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); typedef BOOL (WINAPI* PFN_HttpEndRequestA)( __in HINTERNET hRequest, __out_opt LPINTERNET_BUFFERSA lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); typedef BOOL (WINAPI* PFN_HttpEndRequestW)( __in HINTERNET hRequest, __out_opt LPINTERNET_BUFFERSW lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); typedef HINTERNET (WINAPI* PFN_HttpOpenRequestA)(__in HINTERNET hConnect,__in_opt LPCSTR lpszVerb, __in_opt LPCSTR lpszObjectName, __in_opt LPCSTR lpszVersion, __in_opt LPCSTR lpszReferrer, __in_z_opt LPCSTR FAR * lplpszAcceptTypes, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); typedef HINTERNET (WINAPI* PFN_HttpOpenRequestW)(__in HINTERNET hConnect,__in_opt LPCWSTR lpszVerb,__in_opt LPCWSTR lpszObjectName,__in_opt LPCWSTR lpszVersion,__in_opt LPCWSTR lpszReferrer,__in_z_opt LPCWSTR FAR * lplpszAcceptTypes,__in DWORD dwFlags, __in_opt DWORD_PTR dwContext); typedef HINTERNET (WINAPI* PFN_InternetConnectA)(__in HINTERNET hInternet,__in LPCSTR lpszServerName,__in INTERNET_PORT nServerPort,__in_opt LPCSTR lpszUserName,__in_opt LPCSTR lpszPassword,__in DWORD dwService,__in DWORD dwFlags,__in_opt DWORD_PTR dwContext); typedef HINTERNET (WINAPI* PFN_InternetConnectW)(__in HINTERNET hInternet,__in LPCWSTR lpszServerName,__in INTERNET_PORT nServerPort,__in_opt LPCWSTR lpszUserName,__in_opt LPCWSTR lpszPassword,__in DWORD dwService,__in DWORD dwFlags,__in_opt DWORD_PTR dwContext); typedef BOOL (WINAPI* PFN_HttpAddRequestHeadersA)(__in HINTERNET hRequest,__in_ecount(dwHeadersLength) LPCSTR lpszHeaders,__in DWORD dwHeadersLength,__in DWORD dwModifiers); typedef BOOL (WINAPI* PFN_HttpAddRequestHeadersW)(__in HINTERNET hRequest,__in_ecount(dwHeadersLength) LPCWSTR lpszHeaders,__in DWORD dwHeadersLength,__in DWORD dwModifiers);

 

变量定义起来:

class CHookWinHttp { public: CHookWinHttp(void); ~CHookWinHttp(void); private: // 保存真实的函数地址 static PFN_LdrLoadDll s_pfnLdrLoadDll; static PFN_LdrGetProcedureAddress s_pfnLdrGetProcedureAddress; static PFN_HttpSendRequestA s_pfnHttpSendRequestA; static PFN_HttpSendRequestW s_pfnHttpSendRequestW; static PFN_HttpSendRequestExA s_pfnHttpSendRequestExA; static PFN_HttpSendRequestExW s_pfnHttpSendRequestExW; static PFN_HttpEndRequestA s_pfnHttpEndRequestA; static PFN_HttpEndRequestW s_pfnHttpEndRequestW; static PFN_HttpOpenRequestA s_pfnHttpOpenRequestA; static PFN_HttpOpenRequestW s_pfnHttpOpenRequestW; static PFN_InternetConnectA s_pfnInternetConnectA; static PFN_InternetConnectW s_pfnInternetConnectW; static PFN_HttpAddRequestHeadersA s_pfnHttpAddRequestHeadersA; static PFN_HttpAddRequestHeadersW s_pfnHttpAddRequestHeadersW; // 加入的替换函数 static NTSTATUS WINAPI _LdrLoadDll(IN PWCHAR PathToFile OPTIONAL, IN ULONG Flags OPTIONAL, IN PUNICODE_STRING ModuleFileName, OUT PHANDLE ModuleHandle); static NTSTATUS WINAPI _LdrGetProcedureAddress(IN HMODULE ModuleHandle, IN PANSI_STRING FunctionName OPTIONAL, IN WORD Oridinal OPTIONAL, OUT PVOID *FunctionAddress ); static BOOL WINAPI _HttpSendRequestA(HINTERNET hRequest, LPCSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength ); static BOOL WINAPI _HttpSendRequestW(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength ); static BOOL WINAPI _HttpSendRequestExA( __in HINTERNET hRequest, __in_opt LPINTERNET_BUFFERSA lpBuffersIn, __out_opt LPINTERNET_BUFFERSA lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); static BOOL WINAPI _HttpSendRequestExW( __in HINTERNET hRequest, __in_opt LPINTERNET_BUFFERSW lpBuffersIn, __out_opt LPINTERNET_BUFFERSW lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); static BOOL WINAPI _HttpEndRequestA( __in HINTERNET hRequest, __out_opt LPINTERNET_BUFFERSA lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); static BOOL WINAPI _HttpEndRequestW( __in HINTERNET hRequest, __out_opt LPINTERNET_BUFFERSW lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); static HINTERNET WINAPI _HttpOpenRequestA(__in HINTERNET hConnect,__in_opt LPCSTR lpszVerb, __in_opt LPCSTR lpszObjectName, __in_opt LPCSTR lpszVersion, __in_opt LPCSTR lpszReferrer, __in_z_opt LPCSTR FAR * lplpszAcceptTypes, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext); static HINTERNET WINAPI _HttpOpenRequestW(__in HINTERNET hConnect,__in_opt LPCWSTR lpszVerb,__in_opt LPCWSTR lpszObjectName,__in_opt LPCWSTR lpszVersion,__in_opt LPCWSTR lpszReferrer,__in_z_opt LPCWSTR FAR * lplpszAcceptTypes,__in DWORD dwFlags, __in_opt DWORD_PTR dwContext); static HINTERNET WINAPI _InternetConnectA(__in HINTERNET hInternet,__in LPCSTR lpszServerName,__in INTERNET_PORT nServerPort,__in_opt LPCSTR lpszUserName,__in_opt LPCSTR lpszPassword,__in DWORD dwService,__in DWORD dwFlags,__in_opt DWORD_PTR dwContext); static HINTERNET WINAPI _InternetConnectW(__in HINTERNET hInternet,__in LPCWSTR lpszServerName,__in INTERNET_PORT nServerPort,__in_opt LPCWSTR lpszUserName,__in_opt LPCWSTR lpszPassword,__in DWORD dwService,__in DWORD dwFlags,__in_opt DWORD_PTR dwContext); static BOOL WINAPI _HttpAddRequestHeadersA(__in HINTERNET hRequest,__in_ecount(dwHeadersLength) LPCSTR lpszHeaders,__in DWORD dwHeadersLength,__in DWORD dwModifiers); static BOOL WINAPI _HttpAddRequestHeadersW(__in HINTERNET hRequest,__in_ecount(dwHeadersLength) LPCWSTR lpszHeaders,__in DWORD dwHeadersLength,__in DWORD dwModifiers); };

 

初始化以及转接函数如下:

#include "StdAfx.h" #include "HookWinHttp.h" // 静态变量初始化 PFN_LdrLoadDll CHookWinHttp::s_pfnLdrLoadDll = NULL; PFN_LdrGetProcedureAddress CHookWinHttp::s_pfnLdrGetProcedureAddress = NULL; // 保存函数真实地址 PFN_HttpSendRequestA CHookWinHttp::s_pfnHttpSendRequestA = HttpSendRequestA; PFN_HttpSendRequestW CHookWinHttp::s_pfnHttpSendRequestW = HttpSendRequestW; PFN_HttpAddRequestHeadersA CHookWinHttp::s_pfnHttpAddRequestHeadersA = HttpAddRequestHeadersA; PFN_HttpAddRequestHeadersW CHookWinHttp::s_pfnHttpAddRequestHeadersW = HttpAddRequestHeadersW; PFN_HttpSendRequestExA CHookWinHttp::s_pfnHttpSendRequestExA = HttpSendRequestExA; PFN_HttpSendRequestExW CHookWinHttp::s_pfnHttpSendRequestExW = HttpSendRequestExW; PFN_HttpEndRequestA CHookWinHttp::s_pfnHttpEndRequestA = HttpEndRequestA; PFN_HttpEndRequestW CHookWinHttp::s_pfnHttpEndRequestW = HttpEndRequestW; PFN_HttpOpenRequestA CHookWinHttp::s_pfnHttpOpenRequestA = HttpOpenRequestA; PFN_HttpOpenRequestW CHookWinHttp::s_pfnHttpOpenRequestW = HttpOpenRequestW; PFN_InternetConnectA CHookWinHttp::s_pfnInternetConnectA = InternetConnectA; PFN_InternetConnectW CHookWinHttp::s_pfnInternetConnectW = InternetConnectW; CHookWinHttp::CHookWinHttp(void) { s_pfnLdrLoadDll = (PFN_LdrLoadDll)::GetProcAddress( ::GetModuleHandle(_T("NTDLL.DLL")), "LdrLoadDll"); s_pfnLdrGetProcedureAddress = (PFN_LdrGetProcedureAddress)::GetProcAddress( ::GetModuleHandle(_T("NTDLL.DLL")), "LdrGetProcedureAddress"); if( !s_pfnLdrLoadDll || !s_pfnLdrGetProcedureAddress ) return; // ReplaceIATEntryForAll 的定义在后面 ReplaceIATEntryForAll( "NTDLL.DLL", s_pfnLdrLoadDll, &CHookWinHttp::_LdrLoadDll); ReplaceIATEntryForAll( "NTDLL.DLL", s_pfnLdrGetProcedureAddress, &CHookWinHttp::_LdrGetProcedureAddress); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpSendRequestA, &CHookWinHttp::_HttpSendRequestA); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpSendRequestW, &CHookWinHttp::_HttpSendRequestW); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpAddRequestHeadersA, &CHookWinHttp::_HttpAddRequestHeadersA); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpAddRequestHeadersW, &CHookWinHttp::_HttpAddRequestHeadersW); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpSendRequestExA, &CHookWinHttp::_HttpSendRequestExA); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpSendRequestExW, &CHookWinHttp::_HttpSendRequestExW); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpEndRequestA, &CHookWinHttp::_HttpEndRequestA); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpSendRequestExW, &CHookWinHttp::_HttpSendRequestExW); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpEndRequestA, &CHookWinHttp::_HttpEndRequestA); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpEndRequestW, &CHookWinHttp::_HttpEndRequestW); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpOpenRequestA, &CHookWinHttp::_HttpOpenRequestA); ReplaceIATEntryForAll( "WININET.DLL", s_pfnHttpOpenRequestW, &CHookWinHttp::_HttpOpenRequestW); ReplaceIATEntryForAll( "WININET.DLL", s_pfnInternetConnectA, &CHookWinHttp::_InternetConnectA); ReplaceIATEntryForAll( "WININET.DLL", s_pfnInternetConnectW, &CHookWinHttp::_InternetConnectW); } CHookWinHttp::~CHookWinHttp(void) { } static CHookWinHttp g_oHook; // // 下面都是转接函数,这里什么都不做。 // BOOL WINAPI CHookWinHttp::_HttpSendRequestA(HINTERNET hRequest, LPCSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength ) { return s_pfnHttpSendRequestA( hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength); } BOOL WINAPI CHookWinHttp::_HttpSendRequestW(HINTERNET hRequest, LPCWSTR lpszHeaders, DWORD dwHeadersLength, LPVOID lpOptional, DWORD dwOptionalLength ) { return s_pfnHttpSendRequestW( hRequest, lpszHeaders, dwHeadersLength, lpOptional, dwOptionalLength); } BOOL WINAPI CHookWinHttp::_HttpAddRequestHeadersA(__in HINTERNET hRequest,__in_ecount(dwHeadersLength) LPCSTR lpszHeaders,__in DWORD dwHeadersLength,__in DWORD dwModifiers) { return s_pfnHttpAddRequestHeadersA( hRequest, lpszHeaders, dwHeadersLength, dwModifiers); } BOOL WINAPI CHookWinHttp::_HttpAddRequestHeadersW(__in HINTERNET hRequest,__in_ecount(dwHeadersLength) LPCWSTR lpszHeaders,__in DWORD dwHeadersLength,__in DWORD dwModifiers) { return s_pfnHttpAddRequestHeadersW( hRequest, lpszHeaders, dwHeadersLength, dwModifiers); } BOOL WINAPI CHookWinHttp::_HttpSendRequestExA( __in HINTERNET hRequest, __in_opt LPINTERNET_BUFFERSA lpBuffersIn, __out_opt LPINTERNET_BUFFERSA lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext) { return s_pfnHttpSendRequestExA( hRequest, lpBuffersIn, lpBuffersOut, dwFlags, dwContext); } BOOL WINAPI CHookWinHttp::_HttpSendRequestExW( __in HINTERNET hRequest, __in_opt LPINTERNET_BUFFERSW lpBuffersIn, __out_opt LPINTERNET_BUFFERSW lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext) { return s_pfnHttpSendRequestExW( hRequest, lpBuffersIn, lpBuffersOut, dwFlags, dwContext); } BOOL WINAPI CHookWinHttp::_HttpEndRequestA( __in HINTERNET hRequest, __out_opt LPINTERNET_BUFFERSA lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext) { return s_pfnHttpEndRequestA( hRequest, lpBuffersOut, dwFlags, dwContext); } BOOL WINAPI CHookWinHttp::_HttpEndRequestW( __in HINTERNET hRequest, __out_opt LPINTERNET_BUFFERSW lpBuffersOut, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext) { return s_pfnHttpEndRequestW( hRequest, lpBuffersOut, dwFlags, dwContext); } HINTERNET WINAPI CHookWinHttp::_HttpOpenRequestA(__in HINTERNET hConnect,__in_opt LPCSTR lpszVerb, __in_opt LPCSTR lpszObjectName, __in_opt LPCSTR lpszVersion, __in_opt LPCSTR lpszReferrer, __in_z_opt LPCSTR FAR * lplpszAcceptTypes, __in DWORD dwFlags, __in_opt DWORD_PTR dwContext) { return s_pfnHttpOpenRequestA( hConnect, lpszVerb, lpszObjectName, lpszVersion, lpszReferrer, lplpszAcceptTypes, dwFlags, dwContext); } HINTERNET WINAPI CHookWinHttp::_HttpOpenRequestW(__in HINTERNET hConnect,__in_opt LPCWSTR lpszVerb,__in_opt LPCWSTR lpszObjectName,__in_opt LPCWSTR lpszVersion,__in_opt LPCWSTR lpszReferrer,__in_z_opt LPCWSTR FAR * lplpszAcceptTypes,__in DWORD dwFlags, __in_opt DWORD_PTR dwContext) { return s_pfnHttpOpenRequestW( hConnect, lpszVerb, lpszObjectName, lpszVersion, lpszReferrer, lplpszAcceptTypes, dwFlags, dwContext); } HINTERNET WINAPI CHookWinHttp::_InternetConnectA(__in HINTERNET hInternet,__in LPCSTR lpszServerName,__in INTERNET_PORT nServerPort,__in_opt LPCSTR lpszUserName,__in_opt LPCSTR lpszPassword,__in DWORD dwService,__in DWORD dwFlags,__in_opt DWORD_PTR dwContext) { return s_pfnInternetConnectA( hInternet, lpszServerName, nServerPort, lpszUserName, lpszPassword, dwService, dwFlags, dwContext); } HINTERNET WINAPI CHookWinHttp::_InternetConnectW(__in HINTERNET hInternet,__in LPCWSTR lpszServerName,__in INTERNET_PORT nServerPort,__in_opt LPCWSTR lpszUserName,__in_opt LPCWSTR lpszPassword,__in DWORD dwService,__in DWORD dwFlags,__in_opt DWORD_PTR dwContext) { return s_pfnInternetConnectW( hInternet, lpszServerName, nServerPort, lpszUserName, lpszPassword, dwService, dwFlags, dwContext); }

 

终于到了最核心的部分了。

// 遍历进程所有模块,并依次查找相应模块的函数 void CHookWinHttp::ReplaceIATEntryForAll(LPCSTR lpszDllName, LPVOID pfnCurrent, LPVOID pfnNew) { HMODULE hMods[1024] = {0}; DWORD cbNeeded; HANDLE hProcess = ::GetCurrentProcess(); if( ::EnumProcessModules( hProcess, hMods, sizeof(hMods), &cbNeeded)) { for ( UINT i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ ) { /* TCHAR szModName[MAX_PATH] = {0}; GetModuleFileNameEx( hProcess , hMods[i] , szModName , sizeof(szModName)/sizeof(TCHAR)) );*/ ReplaceIATEntryInImageImportTable( hMods[i] , lpszDllName , pfnCurrent , pfnNew ); } } } // 查找 IMAGE_IMPORT_DESCRIPTOR 中需要挂接的函数然后挂件 BOOL CHookWinHttp::ReplaceIATEntryInImageImportTable( HANDLE hBaseAddress , LPCSTR lpszDllName , LPVOID pfnCurrent , LPVOID pfnNew ) { ASSERT(hBaseAddress && lpszDllName && pfnCurrent && pfnNew ); // 获取 IMAGE_IMPORT_DESCRIPTOR DWORD dwSize = 0; PIMAGE_SECTION_HEADER pFoundHeader = NULL; PIMAGE_IMPORT_DESCRIPTOR pImgImportDescriptor = (PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToDataEx( hBaseAddress , TRUE , IMAGE_DIRECTORY_ENTRY_IMPORT , &dwSize , &pFoundHeader ); if( pImgImportDescriptor == NULL ){ return FALSE; } while (pImgImportDescriptor->Name) { if ( _strcmpi((CHAR*)((PBYTE)hBaseAddress+pImgImportDescriptor->Name), lpszDllName) == 0 ) { break; // 找到 } ++pImgImportDescriptor; } // 这里需要特别注意!!!! // 如果在IMAGE_DIRECTORY_ENTRY_IMPORT找不到,这尝试在IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT中找 // mshtml.dll就是使用了延迟加载的。如果不这样会挂钩不上。 if( !pImgImportDescriptor->Name ) return ReplaceIATEntryInDelayImageImportTable( hBaseAddress, lpszDllName, pfnCurrent, pfnNew); // 获取 IAT PIMAGE_THUNK_DATA pThunk = (PIMAGE_THUNK_DATA)(((LPBYTE)hBaseAddress) + pImgImportDescriptor->FirstThunk); // 循环IAT查找 while(pThunk->u1.Function) { PDWORD lpAddr = (PDWORD)&(pThunk->u1.Function); if(*lpAddr == (DWORD)pfnCurrent) { // 找到并修改地址为转接函数 ::WriteProcessMemory(::GetCurrentProcess() , lpAddr , &pfnNew , sizeof(DWORD) , NULL ); return TRUE; } pThunk++; } return FALSE; } // 此函数 在延迟加载DLL节中查找 目标 BOOL CHookWinHttp::ReplaceIATEntryInDelayImageImportTable( HANDLE hBaseAddress , LPCSTR lpszDllName , LPVOID pfnCurrent , LPVOID pfnNew ) { ASSERT(hBaseAddress && lpszDllName && pfnCurrent && pfnNew ); // 获取 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT DWORD dwSize = 0; PIMAGE_SECTION_HEADER pFoundHeader = NULL; PImgDelayDescr pImgDelayDescr = (PImgDelayDescr)ImageDirectoryEntryToDataEx( hBaseAddress , TRUE , IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT , &dwSize , &pFoundHeader ); if( pImgDelayDescr == NULL ){ return FALSE; } while (pImgDelayDescr->rvaDLLName) { if ( _strcmpi((CHAR*)((PBYTE)hBaseAddress+pImgDelayDescr->rvaDLLName), lpszDllName) == 0 ) { break; } ++pImgDelayDescr; } // 找不到此模块 if( !pImgDelayDescr->rvaDLLName ) return FALSE; // 获取 IAT PIMAGE_THUNK_DATA pThunk = NULL; if( (pImgDelayDescr->grAttrs & dlattrRva) == 0 ) return FALSE; pThunk = (PIMAGE_THUNK_DATA)(((LPBYTE)hBaseAddress) + pImgDelayDescr->rvaIAT); // 循环IAT查找 while(pThunk->u1.Function) { PDWORD lpAddr = (PDWORD)&(pThunk->u1.Function); if(*lpAddr == (DWORD)pfnCurrent) { // 替换 ::WriteProcessMemory(::GetCurrentProcess() , lpAddr , &pfnNew , sizeof(DWORD) , NULL ); return TRUE; } pThunk++; } return FALSE; } // 所有动态加载的DLL,都需要对IAT处理一次 NTSTATUS WINAPI CHookWinHttp::_LdrLoadDll(IN PWCHAR PathToFile OPTIONAL, IN ULONG Flags OPTIONAL, IN PUNICODE_STRING ModuleFileName, OUT PHANDLE ModuleHandle) { NTSTATUS ntStatus = s_pfnLdrLoadDll( PathToFile, Flags, ModuleFileName, ModuleHandle); if( ntStatus == STATUS_SUCCESS && (Flags & LOAD_LIBRARY_AS_DATAFILE) == 0 ) { HANDLE hDll = *ModuleHandle; ReplaceIATEntryInImageImportTable( hDll, "NTDLL.DLL", s_pfnLdrLoadDll, &CHookWinHttp::_LdrLoadDll); ReplaceIATEntryInImageImportTable( hDll, "NTDLL.DLL", s_pfnLdrGetProcedureAddress, &CHookWinHttp::_LdrGetProcedureAddress); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpSendRequestA, &CHookWinHttp::_HttpSendRequestA); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpSendRequestW, &CHookWinHttp::_HttpSendRequestW); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpAddRequestHeadersA, &CHookWinHttp::_HttpAddRequestHeadersA); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpAddRequestHeadersW, &CHookWinHttp::_HttpAddRequestHeadersW); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpSendRequestExA, &CHookWinHttp::_HttpSendRequestExA); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpSendRequestExW, &CHookWinHttp::_HttpSendRequestExW); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpEndRequestA, &CHookWinHttp::_HttpEndRequestA); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpSendRequestExW, &CHookWinHttp::_HttpSendRequestExW); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpEndRequestA, &CHookWinHttp::_HttpEndRequestA); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpEndRequestW, &CHookWinHttp::_HttpEndRequestW); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpOpenRequestA, &CHookWinHttp::_HttpOpenRequestA); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnHttpOpenRequestW, &CHookWinHttp::_HttpOpenRequestW); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnInternetConnectA, &CHookWinHttp::_InternetConnectA); ReplaceIATEntryInImageImportTable( hDll, "WININET.DLL", s_pfnInternetConnectW, &CHookWinHttp::_InternetConnectW); } return ntStatus; } // 如果是动态获取地址,则返回转接函数地址 NTSTATUS WINAPI CHookWinHttp::_LdrGetProcedureAddress(IN HMODULE ModuleHandle, IN PANSI_STRING FunctionName OPTIONAL, IN WORD Oridinal OPTIONAL, OUT PVOID *FunctionAddress ) { NTSTATUS ntStatus = s_pfnLdrGetProcedureAddress( ModuleHandle, FunctionName, Oridinal, FunctionAddress); if( ntStatus == STATUS_SUCCESS ) { TCHAR tszPath[MAX_PATH] = {0}; if( GetModuleFileName( ModuleHandle, tszPath, MAX_PATH) ) { CString strFile(tszPath); int nFind = strFile.ReverseFind('//'); if( nFind > 0 ) strFile = strFile.Mid(nFind+1); if( strFile.CompareNoCase(_T("WININET.dll")) == 0 ) { CHAR szFunName[1024] = {0}; memcpy( szFunName, FunctionName->Buffer, FunctionName->Length ); if( strcmp( szFunName, "HttpSendRequestA") == 0 ) { if( !s_pfnHttpSendRequestA ) { s_pfnHttpSendRequestA = (PFN_HttpSendRequestA)(*FunctionAddress); } *FunctionAddress = s_pfnHttpSendRequestA; } else if( strcmp( szFunName, "HttpSendRequestW") == 0 ) { if( !s_pfnHttpSendRequestW ) { s_pfnHttpSendRequestW = (PFN_HttpSendRequestW)(*FunctionAddress); } *FunctionAddress = s_pfnHttpSendRequestW; } else if( strcmp( szFunName, "HttpAddRequestHeadersA") == 0 ) { if( !s_pfnHttpAddRequestHeadersA ) { s_pfnHttpAddRequestHeadersA = (PFN_HttpAddRequestHeadersA)(*FunctionAddress); } *FunctionAddress = s_pfnHttpAddRequestHeadersA; } else if( strcmp( szFunName, "HttpAddRequestHeadersW") == 0 ) { if( !s_pfnHttpAddRequestHeadersW ) { s_pfnHttpAddRequestHeadersW = (PFN_HttpAddRequestHeadersW)(*FunctionAddress); } *FunctionAddress = s_pfnHttpAddRequestHeadersW; } else if // 后面的好长啊, 应该用点设计把这段简化下, 后面就省略吧, } } } return ntStatus; }

 

唯一需要注意的事:挂接IAT需要到 IMAGE_IMPORT_DESCRIPTOR 和 IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 两个地方查找。

 

此代码可以扩展用来在浏览器底层去做到网络方面很细节的控制。

 

你可能感兴趣的:(浏览器,import,hook,Descriptor,WebBrowser,winapi)