- 注册时间
- 2010-11-3
- 最后登录
- 2024-2-22
- 在线时间
- 510 小时
终身VIP会员
- 魔鬼币
- 58088
|
发表于 2012-4-18 22:42:26
|
显示全部楼层
其实 DNF QQ三国 等SX HS 非法扩展名文件提示检测 完全可以用API_HOOK技术来搞定的
截获API是个很有用的东西,比如你想分析一下别人的程序是怎样工作的。这里我介绍一下一种我自己试验通过
的方法。 首先,我们必须设法把自己的代码放到目标程序的进程空间里去。WindowsHook可以帮我们实现这一点。
SetWindowsHookEx的声明如下:
HHOOKSetWindowsHookEx(
intidHook,hooktype
HOOKPROClpfn,hookprocedure
HINSTANCEhMod,handletoapplicationinstance
DWORDdwThreadIdthreadidentifier
);
具体的参数含义可以翻阅msdn,没有msdn可谓寸步难行。
这里Hook本身的功能并不重要,我们使用它的目的仅仅只是为了能够让Windows把我们的代码植入别的进程里去。
hookType我们任选一种即可,只要保证是目标程序肯定会调用到就行,这里我用的是WH_CALLWNDPROC。lpfn和
hMod分别指向我们的钩子代码及其所在的dll,dwThreadId设为0,表示对所有系统内的线程都挂上这样一个hook,
这样我们才能把代码放到别的进程里去。
之后,我们的代码就已经进入了系统内的所有进程空间了。必须注意的是,我们只需要截获我们所关心的目标程
序的调用,因此还必须区分一下进程号。我们自己的钩子函数中,第一次运行将进行最重要的API重定向的工作。
也就是通过将所需要截获的API的开头几个字节改为一个跳转指令,使其跳转到我们的API中来。这是最关键的部
分。这里我想截三个调用,ws2_32.dll中的send和recv、user32.dll中的GetMessageA。
DWORDdwCurrentPID=0;
HHOOKhOldHook=NULL;
DWORDpSend=0;
DWORDpRecv=0;
GETMESSAGEpGetMessage=NULL;
BYTEbtNewBytes[8]={0x0B8,0x0,0x0,0x40,0x0,0x0FF,0x0E0,0};
DWORDdwOldBytes[3][2];
HANDLEhDebug=INVALID_HANDLE_value;
LRESULTCALLBACKCallWndProc(intnCode,WPARAMwParam,LPARAMlParam)
{
DWORDdwSize;
DWORDdwPIDWatched;
HMODULEhLib;
if(dwCurrentPID==0)
{
dwCurrentPID=GetCurrentProcessId();
HWNDhwndMainHook;
hwndMainHook=FindWindow(0,MainHook);
dwPIDWatched=SendMessage(hwndMainHook,(WM_USER+100),0,0);
hOldHook=(HHOOK)SendMessage(hwndMainHook,(WM_USER+101),0,0);
if(dwCurrentPID==dwPIDWatched)
{
hLib=LoadLibrary(ws2_32.dll);
pSend=(DWORD)GetProcAddress(hLib,send);
pRecv=(DWORD)GetProcAddress(hLib,recv);
ReadProcessMemory(INVALID_HANDLE_value,(void)pSend,(void)dwOldBytes[0],sizeof(DWORD)2,
&dwSize);
(DWORD)(btNewBytes+1)=(DWORD)new_send;
WriteProcessMemory(INVALID_HANDLE_value,(void)pSend,(void)btNewBytes,sizeof(DWORD)2,
&dwSize);
ReadProcessMemory(INVALID_HANDLE_value,(void)pRecv,(void)dwOldBytes[1],sizeof(DWORD)2,
&dwSize);
(DWORD)(btNewBytes+1)=(DWORD)new_recv;
WriteProcessMemory(INVALID_HANDLE_value,(void)pRecv,(void)btNewBytes,sizeof(DWORD)2,
&dwSize);
hLib=LoadLibrary(user32.dll);
pGetMessage=(GETMESSAGE)GetProcAddress(hLib,GetMessageA);
ReadProcessMemory(INVALID_HANDLE_value,(void)pGetMessage,(void)dwOldBytes[2],sizeof(DWORD)2,
&dwSize);
(DWORD)(btNewBytes+1)=(DWORD)new_GetMessage;
WriteProcessMemory(INVALID_HANDLE_value,(void)pGetMessage,(void)btNewBytes,sizeof(DWORD)2,
&dwSize);
hDebug=CreateFile(CTrace.log,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0);
}
}
if(hOldHook!=NULL)if(hOldHook!=NULL)
{
returnCallNextHookEx(hOldHook,nCode,wParam,lParam);
}
return0;
}
上面的钩子函数,只有第一次运行时有用,就是把三个函数的首8字节修改一下(实际上只需要7个)。
btNewBytes中的指令实际就是
moveax,0x400000
jmpeax
这里的0x400000就是新的函数的地址,比如new_recvnew_sendnew_GetMessage,此时,偷梁换柱已经完成。
再看看我们的函数中都干了些什么。以GetMessageA为例:
BOOL_stdcallnew_GetMessage(LPMSGlpMsg,HWNDhWnd,UINTwMsgFilterMin,UINTwMsgFilterMax)
{
DWORDdwSize;
charszTemp[256];
BOOLr=false;
Watchherebeforeit’sexecuted.
sprintf(szTemp,BeforeGetMessageHWND0x%8.8X,msgMin0x%8.8X,msgMax0x%8.8xrn,hWnd,
wMsgFilterMin,wMsgFilterMax);
WriteFile(hDebug,szTemp,strlen(szTemp),&dwSize,0);
Watchover
restoreitatfirst
WriteProcessMemory(INVALID_HANDLE_value,(void)pGetMessage,(void)dwOldBytes[2],sizeof(DWORD)2,
&dwSize);
executeit
r=pGetMessage(lpMsg,hWnd,wMsgFilterMin,wMsgFilterMax);
hookitagain
(DWORD)(btNewBytes+1)=(DWORD)new_GetMessage;
WriteProcessMemory(INVALID_HANDLE_value,(void)pGetMessage,(void)btNewBytes,sizeof(DWORD)2,
&dwSize);
Watchhereafterit’sexecuted
sprintf(szTemp,ResultofGetMessageis%d.rn,r);
WriteFile(hDebug,szTemp,strlen(szTemp),&dwSize,0);
if(r)
{
sprintf(szTemp,MsgHWND0x%8.8X,MSG0x%8.8x,wParam0x%8.8X,lParam0x%8.8XrnTime0x%8.8X,
X%d,Y%drn,
lpMsg-hwnd,lpMsg-message,
lpMsg-wParam,lpMsg-lParam,lpMsg-time,
lpMsg-pt.x,lpMsg-pt.y);
WriteFile(hDebug,szTemp,strlen(szTemp),&dwSize,0);
}
strcpy(szTemp,rn);
WriteFile(hDebug,szTemp,strlen(szTemp),&dwSize,0);
Watchover
returnr;
}
先将截获下来的参数,写入到一个log文件中,以便分析。然后恢复原先保留下来的GetMessageA的首8字节,
然后执行真正的GetMessageA调用,完毕后再将执行结果也写入log文件,然后将GetMessageA的执行结果返回
给调用者。
整个截获的过程就是这样。你可以把其中的写log部分改成你自己想要的操作。这里有个不足的地方是,截获动
作是不能够并发进行的,如果目标进程是多线程的,就会有问题。解决办法是,可以在每次new_GetMessage中
加入一个CriticalSection的锁和解锁,以使调用变为串行进行,但这个我没有试验过。 |
|