BlockTheSpot/src/HookApi.cpp
2019-08-22 07:10:10 +07:00

472 lines
No EOL
11 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
//////////////////////////////////////////////////////////////////////////
HookApi 0.6
thanks to xIkUg ,sucsor
by 海风月影[RCT] , StrongOD@Safengine.com
2011.06.08
//////////////////////////////////////////////////////////////////////////
//更新内容
2011.06.08 0.6
1增加cdecl的hook
2使用malloc申请内存节约空间
3新接口InstallHookStub支持直接传函数地址去hook
4hook还没完成的时候不会发生调用hookproc的情况(主要是VirtualProtect函数)
2008.04.15 0.5
1重新写了Stub换了一种模式使hook更加自由将hookbefore和hookafter合并
HookProc的定义方式与以前有所不同
HookProc的函数类型和原来的api一样只是参数比原API多2个
DWORD WINAPI HookProc(DWORD RetAddr ,__pfnXXXX pfnXXXX, ...);
//参数比原始的API多2个参数
RetAddr //调用api的返回地址
pfnXXX //类型为__pfnXXXX待hook的api的声明类型用于调用未被hook的api
详见My_LoadLibraryA
原始的LoadLibraryA的声明是
HMODULE WINAPI LoadLibraryA( LPCSTR lpLibFileName );
那么首先定义一下hook的WINAPI的类型
typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR lpFileName);
然后hookproc的函数声明如下
HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr,
__pfnLoadLibraryA pfnLoadLibraryA,
LPCTSTR lpFileName
);
比原来的多了2个参数参数位置不能颠倒在My_LoadLibraryA中可以自由的调用未被hook的pfnLoadLibraryA
也可以调用系统的LoadLibraryA不过要自己在hookproc中处理好重入问题
另外也可以在My_LoadLibraryA中使用UnInstallHookApi()函数来卸载hook用法如下
将第二个参数__pfnLoadLibraryA pfnLoadLibraryA强制转换成PHOOKENVIRONMENT类型使用UnInstallHookApi来卸载
例如:
UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA);
至于以前版本的HookBefore和HookAfter完全可以在自己的HookProc里面灵活使用了
2支持卸载hook
InstallHookApi()调用后会返回一个PHOOKENVIRONMENT类型的指针
需要卸载的时候可以使用UnInstallHookApi(PHOOKENVIRONMENT pHookEnv)来卸载
在HookProc中也可以使用UnInstallHookApi来卸载参数传入HookProc中的第二个参数
注意当HookProc中使用UnInstallHookApi卸载完后就不能用第二个参数来调用API了~~,切记!
2008.04.15 0.41
1前面的deroko的LdeX86 有BUG678b803412 会算错
换了一个LDX32代码更少更容易理解
2修复了VirtualProtect的一个小BUG
0.4以前
改动太大了,前面的就不写了
*/
#include "stdafx.h"
#include "HookApi.h"
//#pragma comment(linker, "/SECTION:HookStub,R")
//#define ALLOCATE_HookStub ALLOCATE(HookStub)
//#pragma code_seg("HookStub")
#pragma optimize("gsy",on)
/*ALLOCATE_HookStub*/ HOOKENVIRONMENT pEnv={0};
NAKED void StubShell_stdcall()
{
__asm
{
push dword ptr [esp];
push dword ptr [esp];
call _next;
_next:
xchg dword ptr [esp], eax;
lea eax, [eax - 0x20];
mov dword ptr [esp + 0xC], eax;
pop eax;
_emit 0xE9;
_emit 'g';
_emit 'o';
_emit 'o';
_emit 'd';
}
}
NAKED void StubShell_cdecl()
{
__asm
{
push dword ptr [esp];
call _next;
_next:
xchg dword ptr [esp], eax;
lea eax, [eax - 0x1D];
mov dword ptr [esp + 0x8], eax;
pop eax;
_emit 0x68;
_emit 'b';
_emit 'a';
_emit 'd';
_emit 'd';
_emit 0xE9;
_emit 'g';
_emit 'o';
_emit 'o';
_emit 'd';
}
}
#pragma optimize("",off)
//#pragma code_seg()
NAKED void cdeclret_stub()
{
__asm retn 4;
}
DWORD MyInterlockedExchange32(PDWORD Target, DWORD Value)
{
DWORD retvalue;
__asm
{
mov ecx, Target;
mov eax, Value;
xchg dword ptr[ecx], eax;
mov retvalue, eax;
}
return retvalue;
}
WORD MyInterlockedExchange16(PWORD Target, WORD Value)
{
WORD retvalue;
__asm
{
mov ecx, Target;
mov ax, Value;
xchg word ptr[ecx], ax;
mov retvalue, ax;
}
return retvalue;
}
void MyCopyBytes(void * pTarget, BYTE *pBuf, int size)
{
/*
优化 memcpy 字节
先把stub的前2个字节改成 EB FE构造一个死循环然后memcpy剩下字节再把前2个字节改回去
*/
WORD w1;
w1 = *(WORD*)pBuf;
MyInterlockedExchange16((PWORD)pTarget, 0xFEEB);
memcpy((char*)pTarget + 2, (char*)pBuf + 2, size - 2);
MyInterlockedExchange16((PWORD)pTarget, w1);
}
DWORD __stdcall GetOpCodeSize(BYTE* iptr0)
{
BYTE* iptr = iptr0;
DWORD f = 0;
prefix:
BYTE b = *iptr++;
f |= table_1[b];
if (f&C_FUCKINGTEST)
if (((*iptr)&0x38)==0x00) // ttt
f=C_MODRM+C_DATAW0; // TEST
else
f=C_MODRM; // NOT,NEG,MUL,IMUL,DIV,IDIV
if (f&C_TABLE_0F)
{
b = *iptr++;
f = table_0F[b];
}
if (f==C_ERROR)
{
//printf("error in %02X\n",b);
return C_ERROR;
}
if (f&C_PREFIX)
{
f&=~C_PREFIX;
goto prefix;
}
if (f&C_DATAW0) if (b&0x01) f|=C_DATA66; else f|=C_DATA1;
if (f&C_MODRM)
{
b = *iptr++;
BYTE mod = b & 0xC0;
BYTE rm = b & 0x07;
if (mod!=0xC0)
{
if (f&C_67) // modrm16
{
if ((mod==0x00)&&(rm==0x06)) f|=C_MEM2;
if (mod==0x40) f|=C_MEM1;
if (mod==0x80) f|=C_MEM2;
}
else // modrm32
{
if (mod==0x40) f|=C_MEM1;
if (mod==0x80) f|=C_MEM4;
if (rm==0x04) rm = (*iptr++) & 0x07; // rm<-sib.base
if ((rm==0x05)&&(mod==0x00)) f|=C_MEM4;
}
}
} // C_MODRM
if (f&C_MEM67) if (f&C_67) f|=C_MEM2; else f|=C_MEM4;
if (f&C_DATA66) if (f&C_66) f|=C_DATA2; else f|=C_DATA4;
if (f&C_MEM1) iptr++;
if (f&C_MEM2) iptr+=2;
if (f&C_MEM4) iptr+=4;
if (f&C_DATA1) iptr++;
if (f&C_DATA2) iptr+=2;
if (f&C_DATA4) iptr+=4;
return iptr - iptr0;
}
HANDLE g_hStupHeap = NULL;
PHOOKENVIRONMENT __stdcall InstallHookStub(PVOID StubAddress, PVOID HookProc, int type)
{
int ReplaceCodeSize;
DWORD oldpro;
DWORD SizeOfStub;
DWORD SizeOfStubShell = 0;
DWORD AddrOfStubShell = 0;
DWORD dwHookStubAddress;
DWORD RetSize =0;
PHOOKENVIRONMENT pHookEnv;
BYTE JMPGate[5] = {0xE9, 0x00, 0x00, 0x00, 0x00};
if (HookProc == NULL)
{
return NULL;
}
if (StubAddress == NULL) return NULL;
if (*(BYTE*)StubAddress == 0xE9 || *(BYTE*)StubAddress == 0xE8) return NULL;
if(type == e_stdcall)
{
SizeOfStubShell = 0x1B;
AddrOfStubShell = (DWORD)StubShell_stdcall;
}
else if (type == e_cdecl)
{
SizeOfStubShell = 0x1D;
AddrOfStubShell = (DWORD)StubShell_cdecl;
}
#ifdef _DEBUG
AddrOfStubShell = AddrOfStubShell + 5 + *(DWORD*)(AddrOfStubShell + 1);
#endif
ReplaceCodeSize = GetOpCodeSize((BYTE*)StubAddress);
while (ReplaceCodeSize < 5)
{
ReplaceCodeSize += GetOpCodeSize((BYTE*)((DWORD)StubAddress + (DWORD)ReplaceCodeSize));
}
if (ReplaceCodeSize > 16) return NULL;
SizeOfStub = SizeOfStubShell + sizeof(HOOKENVIRONMENT);
if(g_hStupHeap == NULL)
{
g_hStupHeap = HeapCreate(HEAP_CREATE_ENABLE_EXECUTE, 0, 0);
if(g_hStupHeap == NULL)
{
return NULL;
}
}
pHookEnv = (PHOOKENVIRONMENT)HeapAlloc(g_hStupHeap, 0, sizeof(HOOKENVIRONMENT));
memcpy(pHookEnv, (PVOID)&pEnv, sizeof(HOOKENVIRONMENT));
memset((void*)pHookEnv->savebytes, 0x90, sizeof(pHookEnv->savebytes));
memcpy((void*)pHookEnv->hookstub, (PVOID)AddrOfStubShell, SizeOfStubShell);
memcpy(pHookEnv->savebytes, StubAddress, ReplaceCodeSize);
pHookEnv->OrgApiAddr = StubAddress;
pHookEnv->SizeOfReplaceCode = ReplaceCodeSize;
pHookEnv->jmptoapi[0] = 0xE9;
*(DWORD*)(&pHookEnv->jmptoapi[1]) = (DWORD)StubAddress + ReplaceCodeSize - ((DWORD)pHookEnv->jmptoapi + 5);
dwHookStubAddress = (DWORD)pHookEnv->hookstub;
pHookEnv->jmptostub[0] = 0xE9;
*(DWORD*)(&pHookEnv->jmptostub[1]) = (DWORD)pHookEnv->savebytes - ((DWORD)pHookEnv->jmptostub + 5);
//*(DWORD*)(&pHookEnv->jmptostub[1]) = (DWORD)(dwHookStubAddress) - ((DWORD)pHookEnv->jmptostub + 5);
*(DWORD*)(&JMPGate[1]) = ((DWORD)pHookEnv->jmptostub) - ((DWORD)StubAddress + 5);
//写入变量这里要先写变量否则如果hook VirtualProtect下面的api调用会出问题
if(type == e_stdcall)
{
*(DWORD*)(dwHookStubAddress + SizeOfStubShell - 4) = (DWORD)HookProc - (dwHookStubAddress + SizeOfStubShell);
}
else if(type == e_cdecl)
{
*(DWORD*)(dwHookStubAddress + SizeOfStubShell - 4) = (DWORD)HookProc - (dwHookStubAddress + SizeOfStubShell);
*(DWORD*)(dwHookStubAddress + SizeOfStubShell - 9) = (DWORD)cdeclret_stub;
}
//patch api
if (VirtualProtect(StubAddress, ReplaceCodeSize, PAGE_EXECUTE_READWRITE, &oldpro))
{
//memcpy(StubAddress, JMPGate, sizeof(JMPGate));
MyCopyBytes((void*)StubAddress, (BYTE*)JMPGate, sizeof(JMPGate));
VirtualProtect(StubAddress, ReplaceCodeSize, oldpro, &oldpro);
MyInterlockedExchange32((PDWORD)(&pHookEnv->jmptostub[1]), (DWORD)(dwHookStubAddress) - ((DWORD)pHookEnv->jmptostub + 5));
}
else
{
//失败了无法hook
HeapFree(g_hStupHeap, 0, (void*)pHookEnv);
return NULL;
}
return pHookEnv;
}
PHOOKENVIRONMENT __stdcall InstallHookApi(PCHAR DllName, PCHAR ApiName, PVOID HookProc, int type)
{
return InstallHookStub((PVOID)GetProcAddress(LoadLibraryA(DllName), ApiName), HookProc, type);
}
BOOL __stdcall UnInstallHookApi(PHOOKENVIRONMENT pHookEnv)
{
DWORD oldpro;
//如果内存不存在了,则退出
if(HeapSize(g_hStupHeap, 0, (void*)pHookEnv) <= 0)
return FALSE;
if(IsBadReadPtr((const void*)pHookEnv, sizeof(HOOKENVIRONMENT)))
return FALSE;
if(!VirtualProtect(pHookEnv->OrgApiAddr, pHookEnv->SizeOfReplaceCode, PAGE_EXECUTE_READWRITE, &oldpro))
return FALSE;
//memcpy(pHookEnv->OrgApiAddr, pHookEnv->savebytes, pHookEnv->SizeOfReplaceCode);
MyCopyBytes((void*)pHookEnv->OrgApiAddr, (BYTE*)pHookEnv->savebytes, pHookEnv->SizeOfReplaceCode);
VirtualProtect(pHookEnv->OrgApiAddr, pHookEnv->SizeOfReplaceCode, oldpro, &oldpro);
HeapFree(g_hStupHeap, 0, (void*)pHookEnv);
return TRUE;
}
//定义下面这行可以作为演示使用
//#define TEST_MAIN
#ifdef TEST_MAIN
BOOL IsMe = FALSE;
//先定义一下要hook的WINAPI
typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCSTR lpFileName);
/*
HookProc的参数声明方式类型等和原来的api一样只是参数比原API多2个
DWORD WINAPI HookProc(DWORD RetAddr ,__pfnXXXX pfnXXXX, ...);
//参数比原始的API多2个参数
RetAddr //调用api的返回地址
pfnXXX //类型为__pfnXXXX待hook的api的声明类型用于调用未被hook的api
详见My_LoadLibraryA
原始的LoadLibraryA的声明是
HMODULE WINAPI LoadLibraryA( LPCSTR lpLibFileName );
那么首先定义一下hook的WINAPI的类型
typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR lpFileName);
然后hookproc的函数声明如下
HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr,
__pfnLoadLibraryA pfnLoadLibraryA,
LPCTSTR lpFileName
);
比原来的多了2个参数参数位置不能颠倒在My_LoadLibraryA中可以自由的调用未被hook的pfnLoadLibraryA
也可以调用系统的LoadLibraryA不过要自己在hookproc中处理好重入问题
另外也可以在My_LoadLibraryA中使用UnInstallHookApi()函数来卸载hook用法如下
将第二个参数__pfnLoadLibraryA pfnLoadLibraryA强制转换成PHOOKENVIRONMENT类型使用UnInstallHookApi来卸载
例如:
UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA);
至于以前版本的HookBefore和HookAfter完全可以在自己的HookProc里面灵活使用了
*/
HMODULE WINAPI My_LoadLibraryA(DWORD RetAddr,
__pfnLoadLibraryA pfnLoadLibraryA,
LPCSTR lpFileName
)
{
HMODULE hLib;
//需要自己处理重入和线程安全问题
if (!IsMe)
{
IsMe = TRUE;
MessageBoxA(NULL, lpFileName, "test", MB_ICONINFORMATION);
hLib = LoadLibraryA(lpFileName);//这里调用的是系统的已经被hook过的
IsMe = FALSE;
//这里是卸载Hook这里卸载完就不能用pfnLoadLibraryA来调用了
UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA);
return hLib;
}
return pfnLoadLibraryA(lpFileName);//这里调用非hook的
}
int main()
{
PHOOKENVIRONMENT pHookEnv;
pHookEnv = InstallHookApi("Kernel32.dll", "LoadLibraryA", My_LoadLibraryA);
//pHookEnv = InstallHookApi("Kernel32.dll", "Beep", My_LoadLibraryA);
LoadLibraryA("InjectDll.dll");
MessageBoxA(NULL,"Safe Here!!!","Very Good!!",MB_ICONINFORMATION);
UnInstallHookApi(pHookEnv);//由于HookProc中卸载过了所以这里的卸载就无效了
MessageBoxA(NULL,"UnInstall Success!!!","Good!!",MB_ICONINFORMATION);
return 0;
}
#endif