首页
社区
课程
招聘
[原创]C++非常简单的HOOK修改信息框信息
2022-1-25 15:50 22901

[原创]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
#include <windows.h>
 
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编辑 ,原因: 还有图片没有成功上传
上传的附件:
收藏
点赞3
打赏
分享
最新回复 (3)
雪    币: 3686
活跃值: (3703)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
Mxixihaha 2022-2-8 13:59
2
0
就是 Hook API函数搞定啊   直接HOOK  User32.dll 中的 MessageBoxA 为什么搞这么复杂... 
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
一笑倾国倾城 2022-3-4 07:30
3
0
这么快就不能下载了?
雪    币: 11236
活跃值: (3993)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xie风腾 2022-3-4 13:33
4
0

多谢楼主分享,学习了
游客
登录 | 注册 方可回帖
返回