-
-
[原创]C++非常简单的HOOK修改信息框信息
-
2022-1-25 15:50
22901
-
起因
朋友们好啊我是编程形意太极门掌门人阿星。刚才有个朋友问我星老师发生什么事了,我说怎么回事,给我发了一几个程序
我一看!嗷!原来是刚刚,有一几个程序,一个体重,六百七十六k,另一个烫烫烫烫烫烫烫烫,他们说,唉…有一个说是我在OD练HOOK OD练坏了,星老师你能不能表演一下HOOK,哎……帮助治疗一下,我说
准备工具
1.反汇编软件(本篇使用OD) 2.一个被HOOK的程序 3.一点点C++知识 4.一个转的过来的脑子 5.百度 (www.baidu.com)
感谢这位同学提供的HOOKME!点我进他看雪主页~
分析程序
诶…我一说的啪就站起来了,很快嗷!直接打开OD 定位到信息框所在call
我们通过字符串即可知道:
push 0x47E6A8是压入标题
push 0x47E6B5是压入提示信息
那么我们该如何HOOK呢?
既然上面两个push压入了信息的地址
那么我们只需要在push标题之前跳转到我们的代码区
在我们的代码区进行压栈最后跳回push提示信息之后不就好了吗?
理论可行,开始实践
编写代码
首先我们创建一个dll项目
在DLL_PROCESS_ATTACH事件(初次映射事件)添加处理函数HOOK
现在我们定义出跳转到我们的函数的跳转命令
1 2 | BYTE JmpCode[ 5 ];
JmpCode[ 0 ] = 0xE9 ; / / E9就是汇编jmp命令
|
因为这是一个长跳转,所以跳转指令需要五个字节
现在问题来了:
后面的地址怎么表示呢?
我们回到OD 找一找其他的跳转指令
观察短跳指令
我们发现从je指令开始(0x4010CC)到跳转的位置(0x4010EA)相差
然而跳转指令后面是1C
1C与1E差2,正好是跳转指令的长度
一个可能有偶然性,我们再找一个跳转
观察长跳指令
我们发现从jnz指令开始(0x4010D3)到跳转的位置(0x40115F)相差
然而跳转指令后面是86
8C与86差6,正好是跳转指令的长度
可以确定:
jmp 某地址
E9 [从跳转指令的字节到欲跳转的地址的相差字节数]
了解了跳转命令之后就好办多了
先创建一个函数用来压栈与跳回:
1 2 3 4 5 | void __declspec(naked) Push() {
__asm {
}
}
|
__declspec(naked)就是用来告诉编译器这个函数代码的汇编代码是我们自己写的,不要自动添加任何汇编指令
现在我们定义修改jmp指令的位置,我们需要覆盖掉0x401014位置的代码
那么偏移为:该命令所在地址 - 该函数所在模块基址
即 0x401014 - 0x400000 = 0x1014
所以修改地址为:
1 | DWORD Address = (DWORD)GetModuleHandle( "HookMePlease.exe" ) + 0x1014 ;
|
(GetModuleHandle这个函数可以获取本程序某个模块的基地址)
那么跳转指令就应该:
1 2 | DWORD cha = (DWORD)&Push - Address - 5 ; / / 计算Push函数到修改地址的长度
* (DWORD * )&JmpCode[ 1 ] = cha; / / 将差值写入跳转指令的后面四个字节
|
现在我们就把jmp指令构建好了,现在我们写入程序
1 | WriteProcessMemory(GetCurrentProcess(), (LPVOID)Address, &JmpCode, sizeof(JmpCode), NULL);
|
因为此dll稍后会注入HookMePlease.exe所以可以使用GetCurrentProcess()来写自身内存
这样程序再运行到0x401014时就会跳入我们的Push函数
现在编写Push函数代码
我们现在修改的跳转位置直接覆盖掉了push 0x47E6A8(压入标题)
所以我们第一条push指令需要压入标题地址
先定义一个字符串用来储存标题(必须在Push函数外定义变量)
1 | char TitleText[] = "OK~" ;
|
然后创建一个遍历用于储存标题地址(楼主本来想直接push [TitleText],但是并不能这样,如果哪位大佬知道如何直接push而不用创建变量麻烦告知一下谢谢:) )
1 | DWORD TitleTextAddress = (DWORD)&TitleText;
|
然后进行压栈
1 2 3 4 5 | void __declspec(naked) Push() {
__asm {
push TitleTextAddress
}
}
|
然后压入跳过的值
1 2 3 4 5 6 7 8 9 10 | void __declspec(naked) Push() {
__asm {
push TitleTextAddress
push 80000301h
push 0h
push 40h
push 80000004h
push 0h
}
}
|
提示信息和标题一样
1 | char Text[] = "Yes,I can~ ,I have changed your information!" ;
|
1 | DWORD TextAddress = (DWORD)&Text;
|
1 2 3 4 5 6 7 8 9 10 11 | void __declspec(naked) Push() {
__asm {
push TitleTextAddress
push 80000301h
push 0h
push 40h
push 80000004h
push 0h
push TextAddress
}
}
|
最后我们跳回原程序的call
在我们的函数里
内容已经压入了,那么我们就跳到压提示信息的下一行即可
计算本行代码偏移地址即可得出
1 | DWORD RetAddress = (DWORD)GetModuleHandle( "HookMePlease.exe" ) + 0x1031 ;
|
最后跳回该位置
1 2 3 4 5 6 7 8 9 10 11 12 | void __declspec(naked) Push() {
__asm {
push TitleTextAddress
push 80000301h
push 0h
push 40h
push 80000004h
push 0h
push TextAddress
jmp RetAddress
}
}
|
现在HOOKdll就写好了
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | char TitleText[] = "OK~" ;
char Text[] = "Yes,I can~ ,I have changed your information!" ;
DWORD TitleTextAddress = (DWORD)&TitleText;
DWORD TextAddress = (DWORD)&Text;
DWORD RetAddress = (DWORD)GetModuleHandle( "HookMePlease.exe" ) + 0x1031 ;
void __declspec(naked) Push() {
__asm {
push TitleTextAddress
push 80000301h
push 0h
push 40h
push 80000004h
push 0h
push TextAddress
jmp RetAddress
}
}
DWORD Address = (DWORD)GetModuleHandle( "HookMePlease.exe" ) + 0x1014 ;
void HOOK() {
BYTE JmpCode[ 5 ];
JmpCode[ 0 ] = 0xE9 ; / / E9就是汇编jmp命令
DWORD cha = (DWORD)&Push - Address - 5 ;
* (DWORD * )&JmpCode[ 1 ] = cha;
WriteProcessMemory(GetCurrentProcess(), (LPVOID)Address, &JmpCode, sizeof(JmpCode), NULL);
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call) {
case DLL_PROCESS_ATTACH:
{
HOOK();
}
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break ;
}
return TRUE;
}
|
注入
编译注入试一试(楼主采用ProcessHack自带的dll注入)
现在看一看OD里代码变成了什么样
看!我们修改的地方已被OD标红
检查修改位置没有问题
回车红色指令看看
和我们写的真的是一模一样呢 (为什么标识符名称都有呢...)
调试
大家在第一次写这种HOOK时不一定会完全写对 (我第一次写的乱七八糟)
所以调试也是非常有必要的
(楼主在写这篇文章的时候就出了错...所以调试很有必要)
在段头下断点,回到窗口按下按钮
使用单步步过调试(F8)
现在我们向下压
栈中已经出现了字符串~
现在删除所有断点试一试有没有修改
~完美
总结
HOOK文化博大精深,楼主讲的只是非常普通非常简单的一种钩子~
1.写程序要细心 (不然我也不至于让程序崩溃了两次)
2.要善于思考 (jmp后面的字节不思考神能知道是什么鬼)
3.楼主是C++小白 欢迎大家积极提意见~
4.要多学习混元功法,要讲武德
0.感谢这位同学给我提供了灵感和HOOKME~
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
最后于 2022-1-25 15:58
被Axinger编辑
,原因: 还有图片没有成功上传