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

本文介绍了一种通过HOOK技术控制WebBrowser控件网络请求的方法,利用HOOK WinInet.dll实现对HTTP请求和响应头的拦截及修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

此文章的代码可以从此处下载: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 两个地方查找。

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

.h文件里面的代码放出来一下,CPP就不放了,自己下载哦。 #ifndef Download_h__ #define Download_h__ #include <wininet.h> #pragma comment(lib,"wininet.lib") class CHttpGet { public: //测试网络是否连接成功。 BOOL TestNetworkIsConnected(); //动态获取URL的文件名。 //LPCTSTR szURL URL地址 //LPSTR pFileName 文件名缓冲区,获取到文件名后,会文件名放入到该buffer //DWORD dwBufferOfLenght pFileName缓冲区大小。 //pResult 是否成功。 BOOL HttpGetFileName(LPCTSTR szURL,LPSTR pFileName,DWORD dwBufferOfLenght,BOOL * pResult); //将文件下载到缓冲区,而不是保存到文件 //szURL URL地址 //szBuffer 缓冲区。 //dwSize 缓冲区大小 //lpdwSizeOfRet实际下载到的数据大小。 DWORD URLDownloadToBuffer(LPCTSTR szURL,LPBYTE szBuffer,DWORD dwSize,DWORD *lpdwSizeOfRet); //下载文件 //szURL URL地址 //szFileSavePath 文件完整保存路径 // CheckFileTypeIsPe 是否需要检测文件是不是PE文件。 DWORD URLDownloadToFile(LPCTSTR szURL,LPCTSTR szFileSavePath,BOOL CheckFileTypeIsPe); }; #endif // Download_h__ CPP部分代码,详细自己下载。 完全原创。代码注释详细。 使用及其方便... DWORD CHttpGet::URLDownloadToFile(LPCTSTR szURL,LPCTSTR szFileSavePath,BOOL CheckFileTypeIsPe) { if(!CheckUrl(szURL)) return FALSE; HINTERNET hInternetOpen = InternetOpen( "User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)", INTERNET_OPEN_TYPE_PRECONFIG,/*返回注册表中代理或直接的配置*/ NULL,//不使用代理 所以不要设置用户名 NULL,//不使用代理 所以不用设置密码 NULL ); if(hInternetOpen == NULL) return FALSE; HINTERNET hInternetUrl = InternetOpenUrl( hInternetOpen, szURL, "Accept: */*",//支持左所有文件 -1, INTERNET_FLAG_RELOAD|INTERNET_FLAG_PRAGMA_NOCACHE,/*不要从缓冲里面获取数据 */ NULL); if(hInternetUrl == NULL) return FALSE; CHAR szStatus[1024]={NULL}; DWORD dwBufferLen = sizeof(szStatus); //查询状态 HttpQueryInfo(hInternetUrl,HTTP_QUERY_STATUS_CODE,szStatus,&dwBufferLen;,NULL); //4xx(请求错误) DWORD dwCode = atoi(szStatus); if( dwCode > 400 && dwCode < 500) return FALSE; //5xx(服务器错误) if( dwCode >500 && dwCode < 600) return FALSE; //开始下载文件 HANDLE hFile = CreateFile(szFileSavePath,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if(hFile == INVALID_HANDLE_VALUE) { InternetCloseHandle(hInternetUrl); InternetCloseHandle(hInternetOpen); return FALSE; } CHAR szReadBuffer[4096]={NULL}; DWORD dwInternetReadOfByte = 0; DWORD dwWriteByte = 0; BOOL bFirst = FALSE; BOOL bResult = TRUE; do { BOOL bRet = InternetReadFile(hInternetUrl,szReadBuffer,sizeof(szReadBuffer),&dwInternetReadOfByte;); //说明文件传送完了。 if(bRet == TRUE && dwInternetReadOfByte == 0) break; if(bFirst == FALSE && CheckFileTypeIsPe==TRUE) { bFirst = TRUE; if(((PIMAGE_DOS_HEADER)szReadBuffer)->e_magic!= IMAGE_DOS_SIGNATURE) { bResult = FALSE; break; } } WriteFile(hFile,szReadBuffer,dwInternetReadOfByte,&dwWriteByte;,NULL); } while (TRUE); CloseHandle(hFile); InternetCloseHandle(hInternetUrl); InternetCloseHandle(hInternetOpen); return bResult; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值