• 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 两个地方查找。

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


     

  • 相关阅读:
    阻止事件传播的常用方法
    原生JS获取元素的位置与尺寸
    FileReader 与canvas结合使用显示图片
    dot.js使用心得
    时间格式转换
    JS对象操作
    vue-awesome-swipe 基于vue使用的轮播组件 使用(改)
    vscode 插件推荐
    chrome 发送请求出现:Provisional headers are shown 提示
    手机端
  • 原文地址:https://www.cnblogs.com/welcomesay/p/1797764.html
Copyright © 2020-2023  润新知