2

[原创]C++非常简单的HOOK修改信息框信息

 2 years ago
source link: https://bbs.pediy.com/thread-271281.htm
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

朋友们好啊我是编程形意太极门掌门人阿星。刚才有个朋友问我星老师发生什么事了,我说怎么回事,给我发了一几个程序

我一看!嗷!原来是刚刚,有一几个程序,一个体重,六百七十六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
现在我们定义出跳转到我们的函数的跳转命令

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 [从跳转指令的字节到欲跳转的地址的相差字节数]
了解了跳转命令之后就好办多了
先创建一个函数用来压栈与跳回:

void __declspec(naked) Push() {
__asm {
}
}

__declspec(naked)就是用来告诉编译器这个函数代码的汇编代码是我们自己写的,不要自动添加任何汇编指令
现在我们定义修改jmp指令的位置,我们需要覆盖掉0x401014位置的代码
那么偏移为:该命令所在地址 - 该函数所在模块基址
即 0x401014 - 0x400000 = 0x1014
所以修改地址为:

DWORD Address = (DWORD)GetModuleHandle("HookMePlease.exe") + 0x1014;

(GetModuleHandle这个函数可以获取本程序某个模块的基地址)
那么跳转指令就应该:

DWORD cha = (DWORD)&Push - Address - 5;//计算Push函数到修改地址的长度
*(DWORD*)&JmpCode[1] = cha;//将差值写入跳转指令的后面四个字节

现在我们就把jmp指令构建好了,现在我们写入程序

WriteProcessMemory(GetCurrentProcess(), (LPVOID)Address, &JmpCode, sizeof(JmpCode), NULL);

因为此dll稍后会注入HookMePlease.exe所以可以使用GetCurrentProcess()来写自身内存
这样程序再运行到0x401014时就会跳入我们的Push函数
现在编写Push函数代码
我们现在修改的跳转位置直接覆盖掉了push 0x47E6A8(压入标题)
所以我们第一条push指令需要压入标题地址
先定义一个字符串用来储存标题(必须在Push函数外定义变量)

char TitleText[] = "OK~";

然后创建一个遍历用于储存标题地址(楼主本来想直接push [TitleText],但是并不能这样,如果哪位大佬知道如何直接push而不用创建变量麻烦告知一下谢谢:) )

DWORD TitleTextAddress = (DWORD)&TitleText;

然后进行压栈

void __declspec(naked) Push() {
__asm {
push TitleTextAddress
}
}

然后压入跳过的值

void __declspec(naked) Push() {
__asm {
push TitleTextAddress
push 80000301h
push 0h
push 40h
push 80000004h
push 0h
}
}

提示信息和标题一样

char Text[] = "Yes,I can~ ,I have changed your information!";
DWORD TextAddress = (DWORD)&Text;
void __declspec(naked) Push() {
__asm {
push TitleTextAddress
push 80000301h
push 0h
push 40h
push 80000004h
push 0h
push TextAddress
}
}

最后我们跳回原程序的call

在我们的函数里
内容已经压入了,那么我们就跳到压提示信息的下一行即可
计算本行代码偏移地址即可得出

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
}
}

现在HOOKdll就写好了

#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~

【公告】看雪团队招聘安全工程师,将兴趣和工作融合在一起!看雪20年安全圈的口碑,助你快速成长!

最后于 2022-1-25 15:58 被Axinger编辑 ,原因: 还有图片没有成功上传

上传的附件:


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK