http://www.cnblogs.com/zhangdongsheng/archive/2013/04/08/3007154.html
学习这部分,不要被复杂的Windows编程类型所困扰
首先说明大概原理,我们既然要hook某一个函数P,让其首先执行我们的函数Q就是达到这样一个过程的话,本来是P,现在我们让它先P->Q->P那么只要修改P的前几行指令,让其跳转到我们的Q函数地址上,一般采用的是JMP指令,也看到有人说可以用push ret 和call的。
那么我们为什么一般会修改进程的前5个字节呢,这是根据需求得到的,就是我们要jmp的时候,一般是jmp(0xe9)加上一个四字节偏移,正好是5个字节的内容。所以要修改前5个字节。
那么下一个问题,加入P的地址是&P,Q的地址是&Q,好像直接jmp &Q-&P就好了但是要注意jmp的时候是使得EIP的值增加,跳转到增加后的EIP指针的位置执行,而EIP指向的并不是我们正在执行的jmp的地址,或者说不是已经被修改了的P的人口处的地址,而是它的下一条指令。下一条指令显然距离入口5个字节。所以jmp的是&Q-&P-5。所以我们修改被覆盖的函数的地址的时候,要修改它的前5个字节为jmp &Q-&P-5,数值要提前计算出来再写进去。
需要注意的是,在执行完我们自己的函数以后,要加上已经被覆盖的原来的函数的5个字节的指令,使得他们能够继续执行,好像什么都没有发生一样。然后至于我们的函数想要做什么,那就全凭自己控制了!
最后一个,也是困扰了我好久的一个难题,就是,如何修改人家函数的指令。。。我总不能直接把内存条打开手写进去吧。。。
在大神的源码里发现了这个神奇地函数:
BOOL WriteProcessMemory(
HANDLE hProcess,
LPVOID lpBaseAddress,
LPVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesWritten
);
所以windows的API真是功能强大啊,了解了一下几个参数的作用,以后备用:
hProcess,就是打开的进程句柄,要写入某个进程的内存
IpBaseAddress,指向要写入的地址开始处的指针,要hook某函数,就填写函数运行时.text段的地址,要hook其他进程的什么地方就随便填写啦!
lpBuffer,要写入内存地址空间的内容的缓冲区的指针。
nSize就是要写入函数地址的内容的大小。类型是整型。
lpNumberOfBytesWritten最后一个是一个整型指针,看意思是指向的是写入的字节数,,好像就是前一个参数的指针,大神的源码里把这个设为了NULL。
附上大神链接和源码,以备后面的学习:http://www.cnblogs.com/zhangdongsheng/archive/2013/04/08/3007154.html
// hook_blog_writer.cpp : 定义控制台应用程序的入口点。
//
#include <stdafx.h>
#include <windows.h>
#include <stdio.h>
typedef int (WINAPI
*MessageBox_type) (
__in_opt HWND hWnd,
__in_opt LPCSTR lpText,
__in_opt LPCSTR lpCaption,
__in UINT uType);
MessageBox_type RealMessageBox = MessageBoxA;
//我们自己的MessageBox,每调用MessageBox都要跳到myMessageBox来处理
_declspec(naked) void WINAPI
myMessageBox(
__in_opt HWND hWnd,
__in_opt LPCSTR lpText,
__in_opt LPCSTR lpCaption,
__in UINT uType)
{
__asm
{
PUSH ebp
mov ebp, esp
/*
vs2010 debug 编译后的代码由于要cmp esi esp来比较堆栈。
所以这里在调用非__asm函数前push一下esi
*/
push esi
}
//下面打印MessageBox参数
printf("hwnd:%8X lpText:%s lpCaption:%s,uType:%8X", hWnd, lpText, lpCaption, uType);
__asm
{
/*
vs2010 debug 编译后的代码由于要cmp esi esp来比较堆栈。
所以这里在调用非__asm函数前push一下esi
*/
pop esi
mov ebx, RealMessageBox
add ebx, 5
jmp ebx
}
}
#pragma pack(1)
typedef struct _JMPCODE
{
BYTE jmp;
DWORD addr;
}JMPCODE, *PJMPCODE;
VOID HookMessageBoxA()
{
JMPCODE jcode;
jcode.jmp = 0xe9;//jmp
jcode.addr = (DWORD)myMessageBox - (DWORD)RealMessageBox - 5;
RealMessageBox = MessageBoxA;
::WriteProcessMemory(GetCurrentProcess(), MessageBoxA, &jcode, sizeof(JMPCODE), NULL);
}
int _tmain(int argc, TCHAR* argv[])
{
HookMessageBoxA(); //hook操作
::MessageBoxA(NULL, "hook test", "tip", MB_OK); //执行api MessageBox
return 0;
}