📄 hookapi.cpp
字号:
/*
//////////////////////////////////////////////////////////////////////////
HookApi 0.5
thanks to xIkUg ,sucsor
by 海风月影[RCT] , eIcn#live.cn
2008.04.15
//////////////////////////////////////////////////////////////////////////
//更新内容
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 有BUG,678b803412 会算错
换了一个LDX32,代码更少,更容易理解
2,修复了VirtualProtect的一个小BUG
0.4以前
改动太大了,前面的就不写了
*/
#include <windows.h>
#include <stdio.h>
#include "HookApi.h"
#pragma comment(linker, "/SECTION:HookStub,RW")
#define ALLOCATE_HookStub ALLOCATE(HookStub)
#pragma code_seg("HookStub")
#pragma optimize("",off)
ALLOCATE_HookStub HOOKENVIRONMENT pEnv={0};
NAKED DWORD GetDelta()
{
__asm
{
call next
next:
pop eax
sub eax,offset next
ret
}
}
NAKED void NewStub()
{
__asm
{
jmp next
back:
_emit 0xE9
NOP
NOP
NOP
NOP
next:
push [esp]
push [esp]
push eax //保存一下Stub中唯一使用到的EAX
call GetDelta
lea eax,[eax+pEnv]
mov dword ptr [esp+0xC],eax
pop eax //恢复EAX
jmp back
}
}
NAKED DWORD GetEndAddr()
{
__asm
{
call next
next:
pop eax
sub eax,5
ret
}
}
#pragma optimize("",off)
#pragma code_seg()
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;
}
PHOOKENVIRONMENT __stdcall InstallHookApi(PCHAR DllName,PCHAR ApiName,PVOID HookProc)
{
HMODULE DllHandle;
PVOID ApiEntry;
int ReplaceCodeSize;
DWORD oldpro;
DWORD SizeOfStub;
DWORD delta;
DWORD RetSize =0;
PHOOKENVIRONMENT pHookEnv;
if (HookProc == NULL)
{
return NULL;
}
DllHandle = GetModuleHandle(DllName);
if (DllHandle == NULL)
DllHandle = LoadLibrary(DllName);
if (DllHandle == NULL)
return NULL;
ApiEntry = GetProcAddress(DllHandle,ApiName);
if (ApiEntry == NULL) return NULL;
ReplaceCodeSize = GetOpCodeSize((BYTE*)ApiEntry);
while (ReplaceCodeSize < 5)
ReplaceCodeSize += GetOpCodeSize((BYTE*)((DWORD)ApiEntry + (DWORD)ReplaceCodeSize));
if (ReplaceCodeSize > 16) return NULL;
SizeOfStub = GetEndAddr()-(DWORD)&pEnv;
pHookEnv = (PHOOKENVIRONMENT)VirtualAlloc(NULL,SizeOfStub,MEM_COMMIT,PAGE_READWRITE);
memset((void*)&pEnv,0x90,sizeof(pEnv));
CopyMemory(pHookEnv,(PVOID)&pEnv,SizeOfStub);
CopyMemory((void*)pHookEnv,(void*)&pEnv,sizeof(pEnv.savebytes));
CopyMemory(pHookEnv->savebytes,ApiEntry,ReplaceCodeSize);
pHookEnv->OrgApiAddr = ApiEntry;
pHookEnv->SizeOfReplaceCode = ReplaceCodeSize;
pHookEnv->jmptoapi[0]=0xE9;
*(DWORD*)(&pHookEnv->jmptoapi[1]) = (DWORD)ApiEntry + ReplaceCodeSize - ((DWORD)pHookEnv->jmptoapi + 5);
//patch api
if (!VirtualProtect(ApiEntry,ReplaceCodeSize,PAGE_EXECUTE_READWRITE,&oldpro))
return FALSE;
delta = (DWORD)pHookEnv - (DWORD)&pEnv;
*(DWORD*)(&JMPGate[1]) = ((DWORD)NewStub + delta) - ((DWORD)ApiEntry + 5);
WriteProcessMemory(GetCurrentProcess(), ApiEntry, JMPGate, sizeof(JMPGate),&RetSize);
if (!VirtualProtect(ApiEntry,ReplaceCodeSize,oldpro,&oldpro))
return FALSE;
//写入变量
*(DWORD*)((DWORD)NewStub + delta + 3) = (DWORD)HookProc - ((DWORD)NewStub + delta + 3 + 4);
return pHookEnv;
}
BOOL __stdcall UnInstallHookApi(PHOOKENVIRONMENT pHookEnv)
{
DWORD oldpro;
DWORD RetSize;
//如果内存不存在了,则退出
if(IsBadReadPtr((const void*)pHookEnv,sizeof(HOOKENVIRONMENT)))
return FALSE;
if(!VirtualProtect(pHookEnv->OrgApiAddr,pHookEnv->SizeOfReplaceCode,PAGE_EXECUTE_READWRITE,&oldpro))
return FALSE;
WriteProcessMemory(GetCurrentProcess(),pHookEnv->OrgApiAddr,pHookEnv->savebytes,pHookEnv->SizeOfReplaceCode,&RetSize);
if(!VirtualProtect(pHookEnv->OrgApiAddr,pHookEnv->SizeOfReplaceCode,oldpro,&oldpro))
return FALSE;
VirtualFree((LPVOID)pHookEnv,0,MEM_RELEASE);
}
//定义下面这行可以作为演示使用
//#define TEST_MAIN
#ifdef TEST_MAIN
BOOL IsMe = FALSE;
//先定义一下要hook的WINAPI
typedef HMODULE (WINAPI __pfnLoadLibraryA)(LPCTSTR 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,
LPCTSTR lpFileName
)
{
HMODULE hLib;
//需要自己处理重入和线程安全问题
if (!IsMe)
{
IsMe = TRUE;
MessageBoxA(NULL,lpFileName,"test",MB_ICONINFORMATION);
hLib = LoadLibrary(lpFileName);//这里调用的是系统的,已经被hook过的
IsMe = FALSE;
//这里是卸载Hook,这里卸载完就不能用pfnLoadLibraryA来调用了
UnInstallHookApi((PHOOKENVIRONMENT)pfnLoadLibraryA);
return hLib;
}
return pfnLoadLibraryA(lpFileName);//这里调用非hook的
}
int main()
{
DWORD RetSize =0;
DWORD dwThreadId;
HANDLE hThread;
PHOOKENVIRONMENT pHookEnv;
pHookEnv = InstallHookApi("Kernel32.dll", "LoadLibraryA", My_LoadLibraryA);
LoadLibrary("InjectDll.dll");
MessageBoxA(NULL,"Safe Here!!!","Very Good!!",MB_ICONINFORMATION);
UnInstallHookApi(pHookEnv);//由于HookProc中卸载过了,所以这里的卸载就无效了
MessageBoxA(NULL,"UnInstall Success!!!","Good!!",MB_ICONINFORMATION);
return 0;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -