大家有兴趣可以加我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例子网上一抄一大把,原理就不细说了,废话都被说完了,看代码吧。
首先导入一些头文件和库文件,后面的代码要用
#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最好了,没有的话需要加入一点点定义,后面需要用到
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_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);
变量定义起来:
{
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 "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 两个地方查找。
此代码可以扩展用来在浏览器底层去做到网络方面很细节的控制。