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

大家有兴趣可以加我QQ群交流:14792063 广州软件开发团队

开发中经常使用到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中的 LdrLoadDll 和 LdrGetProcedureAddress 。这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 两个地方查找。

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

 


 

posted on 2010-08-12 06:49  welcomesay  阅读(3069)  评论(0编辑  收藏  举报

导航