用VC编程阻止全局钩子的加载[组图](3)
static HMODULE WINAPI newLoadLibraryExW(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags)
{
//get the return address
DWORD dwCaller;
__asm push dword ptr [ebp+4]
__asm pop dword ptr [dwCaller]
if(dwCaller > m_dwUser32Low && dwCaller < m_dwUser32Hi)
{
#ifdef _DEBUG
UINT uLenWide = lstrlenW(lpLibFileName);
char* pNewChar = new char[uLenWide + 1];
memset(pNewChar,0,uLenWide+1);
WideCharToMultiByte(CP_ACP,0,lpLibFileName,-1,pNewChar,uLenWide,NULL,NULL);
TRACE2(".......................LoadLibrary:return addr 0x%x,%s ",dwCaller,pNewChar);
TRACE("Blocked....................... ");
delete []pNewChar;
#endif
return 0;
}
return rawLoadLibraryExW(lpLibFileName,hFile,dwFlags);
}
private:
static DWORD m_dwUser32Low; //user32.dll 的加载基址
static DWORD m_dwUser32Hi; //user32.dll 的加载基址+ImageSize
static BYTE fakeLoadLibraryExW[12]; //save first bytes of the raw function,and jmp back to that function
//保存LoadLibraryExW的指针,然后修改为fakeLoadLibraryExW
static HMODULE (WINAPI *rawLoadLibraryExW)( LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags );
};
DWORD GBlockHookDll::m_dwUser32Low = 0;
DWORD GBlockHookDll::m_dwUser32Hi = 0;
BYTE GBlockHookDll::fakeLoadLibraryExW[12] = {0};
HMODULE (WINAPI *GBlockHookDll::rawLoadLibraryExW)(LPCWSTR lpLibFileName,HANDLE hFile,DWORD dwFlags) = LoadLibraryExW;
注1:怎么知道函数的返回地址呢?我们都知道,函数调用的时候,先要把参数入栈,然后把返回地址入栈,这样,在我们的函数里,esp指向的应该就是函数的返回地址了。但是为了返回函数时恢复原来的栈和在函数中方便引用传递的参数,编译器一般都会产生两条指令:
push ebp
mov ebp,esp
先把ebp入栈,把原来的esp保存在ebp寄存器中,这样,我们的返回地址就是[ebp+4],第一个参数是[ebp+8],第二个是[ebp+0xC]
注2:如果想写一个通用一点儿的API Hook,就不能简单的patch前5个或者前7字节了,需要根据不同的指令分析需要patch多少字节。可以参考微软的 Detours 的实现。