首页
社区
课程
招聘
[原创]HOOK的原理分析与easy_hook逆向题分析
2023-5-26 14:23 18300

[原创]HOOK的原理分析与easy_hook逆向题分析

2023-5-26 14:23
18300

分析文件在附件

内容

(1)API函数分析:选取特定的API函数,通过逆向工程技术分析其二进制代码结构和执行流程,了解其参数传递方式和返回值处理方法。
(2)HOOK技术实现:介绍HOOK技术的基本原理和实现方法
(3)OD的动态分析、IDA的静态分析工具的使用
(4)基于攻防世界逆向题easy hook的静态分析

简单介绍以下hook

HOOK是一种截取信息、更改程序执行流向、添加新功能的强大技术。通过在执行真正的目标函数之前执行实现插入的代码,获取程序执行过程的决定权。
二次开发或补丁 信息截获 安全防护 HOOK使用最多的战场,各类安全软件都会在应用层和内核中安装hook、系统回调、过滤驱动等。从而对系统中所有的进/线程、窗口、文件、网络操作等进行检查、过滤和拦截,在x86系统中,流行在KiFastCallEntry中进行HOOK,以达到间接hook所有系统调用的目的,同时在应用层中通常也会有一些安全模块,通过安装一些应用层HOOK来配合操作

API HOOK

API HOOK是一种HOOK技术,它的原理是通过修改目标程序中的API调用来实现对程序的拦截和修改。在Windows操作系统中,每个API都有一个唯一的标识符,称为函数地址或入口地址。通过修改目标程序中API调用的入口地址,可以将程序的流程控制转移到HOOK函数中,从而实现对程序的拦截和修改。
具体来说,API HOOK的实现分为以下几个步骤:
(1)获取目标程序中API的入口地址;
(2)保存原始的API入口地址,以便在HOOK函数中调用;
(3)修改目标程序中API的入口地址,将其指向HOOK函数;
(4)在HOOK函数中实现自定义的功能或修改;
如果需要,可以在HOOK函数中调用原始的API函数。
通过API HOOK技术,可以实现对目标程序中的API进行拦截和修改,比如监控系统调用、实现自定义的功能、加强安全性等。但是,使用API HOOK技术也有一定的风险和副作用,如果使用不当可能会导致系统不稳定或者安全漏洞。因此,在使用API HOOK技术时需要注意安全性和稳定性问题。

HOOK 流程

图片描述

HOOK 本函数MessageBoxA的源代码(能运行)

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
#include <stdio.h>
#include<Windows.h>
typedef int (WINAPI* lpMessageBoxA)(HWND, LPCSTR, LPCSTR, UINT);
BYTE olddata32[5] = { 0 };
void hook();
void Unhook();
//回调函数 当调用hook时,hook执行完成后调用该函数后再进入main函数
int WINAPI MyMessageboxA(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)
{
    Unhook();
    lpMessageBoxA messagebox = (lpMessageBoxA)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
    int ret = messagebox(0, "inlinehook", "tip3", 0);
    hook();//函数释放前再次HOOK,为了拦截下次调用
    return ret;
}
void hook()
{
    //获取messagebox的基地址
    DWORD messagebox = (DWORD)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
    BYTE data[5] = { 0xe9, };
    DWORD offset = (DWORD)MyMessageboxA - messagebox - 5; //计算jmp跳转的偏移量
    //保存前五个字节的数据
    memcpy(olddata32, (const void *)messagebox, 5);
    //把偏移量与JMP指令拼接
    memcpy(&data[1], &offset, 4);
    DWORD oldProtect = 0;
    //更改页面属性 将内存改为可读可写可执行
    VirtualProtect((LPVOID)messagebox, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
    memcpy((void*)messagebox, data, 5);
    //还原属性
    VirtualProtect((LPVOID)messagebox, 5, oldProtect, &oldProtect);
}
void Unhook()
{
 
    DWORD messagebox = (DWORD)GetProcAddress(GetModuleHandleA("user32.dll"), "MessageBoxA");
    DWORD oldProtect = 0;
    VirtualProtect((LPVOID)messagebox, 5, PAGE_EXECUTE_READWRITE, &oldProtect);
    memcpy((void*)messagebox, olddata32, sizeof(olddata32));
    VirtualProtect((LPVOID)messagebox, 5, oldProtect, &oldProtect);
 
}
void main()
{
    MessageBoxA(0, "hello", "tip1", 0);
    hook();
    MessageBoxA(0, "hello", "tip2", 0);
}

结果分析

Hook前
图片描述
Hook后,我们的弹窗本该是hello的但是hook后,程序流程被我们修改了。
图片描述

过程分析

(1)首先我们先给MessageBoxA API下软件断点
这里我提供三种方法:
方法一: Ctrl + F 快捷键输入MessageBoxA,跳到一个地址,下软件断点
图片描述
方法二:在Command后面红色标注的命令框里输入:BP MessageBoxA
图片描述
方法三:利用吾爱破解里面的OD插件给MessageBoxA下断点
图片描述
(2)下好断点后程序运行后跳到了760D34B0地址
图片描述
我们可以看到760D34B0就是我们BP MessageBoxA下断点后的地址,我们可以记住这个地址,因为我们HOOK主要修改的就是该地址,下面我们从汇编代码分析该函数流程
760D34B0 > 8BFF mov edi,edi
它只是一个占位符,方便在调试和优化代码时进行修改。
760D34B2 55 push ebp
760D34B3 8BEC mov ebp,esp
通过这两条指令,函数就可以在堆栈中为局部变量分配存储空间,并在函数执行过程中保存和恢复现场。这样做的好处是可以避免局部变量和其他函数之间的冲突,同时也可以提高函数的可读性和可维护性。
760D34B5 6A FF push -0x1
760D34B7 6A 00 push 0x0
通常被用于函数的参数传递,将参数压入堆栈中,以便被调用函数在堆栈中获取。
760D34B9 FF75 14 push dword ptr ss:[ebp+0x14]
760D34BC FF75 10 push dword ptr ss:[ebp+0x10] ;
760D34BF FF75 0C push dword ptr ss:[ebp+0xC] ;
760D34C2 FF75 08 push dword ptr ss:[ebp+0x8]
这四个push是将MessageBoxA的四个参数压入堆栈中去
760D34C5 E8 D6010000 call user32.MessageBoxTimeoutA
该函数是显示MessageBoxA的弹窗函数
(3)执行函数后我们继续运行,执行该函数后OD显示如图所示
图片描述
00C4295C 6A 00 push 0x0
00C4295E 68 187CC400 push hookmess.00C47C18 ; ASCII "tip2"
00C42963 68 107CC400 push hookmess.00C47C10 ; ASCII "hello"
00C42968 6A 00 push 0x0
这四个push是hook前的函数流程,将该四个push压入堆栈后,在运行到光标的call中跳入到前面的MessageBoxA函数流程
(4)hook后我们F7进入该函数
图片描述
我们可以看到760D34B0-760D34B7地址的汇编指令被我们修改了
Hook前的执行指令:
760D34B0 > 8BFF mov edi,edi
760D34B2 55 push ebp
760D34B3 8BEC mov ebp,esp
Hook后执行过程的指令被我们修改成了jmp 00C4110E
00C4110E地址就是我们修改MessageBoxA函数的地址
(5)HOOK函数的逆向分析如下:
这个跳转是VC编译器的特性可以不用管
图片描述
00C41730是HOOK函数的起始地址
图片描述
这下面的四个push就是将我们修改MessageBoxA也就是MyMessageBoxA的参数压入堆栈,然后通过下面的call调用
图片描述
最后执行以前的函数流程,将修改后的MessageBoxA函数的弹窗显示出来
图片描述

攻防世界逆向题Easy Hook分析过程

查壳

如下图所示,我们可以知道该程序是32位的PE文件
图片描述

IDA静态分析

步骤一,拉进IDA中按下f5得到main函数的反汇编代码
图片描述
步骤二:分析伪代码,如下图是我整理的伪代码注释,我们分析完毕后可以知道flag的长度为19,sub_401220()函数就是hook函数,hook的是WriteFile函数。加密过程也在该函数里面。
图片描述
步骤三:我们运行程序输入1234567890123456789,可以在程序运行目录下找到一个文件,我们用文本的形式打开该文件可以得到下面的结果,并不是我们的输入。
图片描述
步骤四:进入sub_401220()函数分析,这个函数逻辑清晰地找到了库函数 WriteFile 的地址,向 byte_40C9BC 中载入了 JUMP 指令的字节码 E9,计算了 sub_401080 距离 WriteFile 的第五个字节的距离。我们分析先sub_4010D0()函数
图片描述
步骤五:进入sub_4010D0()函数分析,我们分析该函数就可以确定是hook了,我们回到 sub_401220()函数,可以知道sub_401080就是整个程序的关键了。
图片描述
步骤六:进入sub_401080()函数分析,该函数就是我们HOOK的返回值,通过sub_401080()函数重新定义了一个WriteFile函数,修改了参数里面的值。我们先分析sub_401140()函数有什么用
图片描述
步骤七:进入sub_401140()函数分析,在 sub_401000() 函数加密完 lpBuffer 后,sub_401140又把 WriteFile 函数还原,继续写操作。
图片描述
步骤八:进入sub_401000()函数分析,该函数就是我们加密的函数,flag由此解密,简单的异或,第一个判断i=18时,flag[i] = a1[i] ^ 0x13; i 不等于18时,第二个判断,if (i % 2),满足条件flag[i] = (a1[i] ^ i) + i,不满足条件flag[i+2] = (res[i] ^ i)。至此IDA的分析就完成了,接下来就是写解密脚本了。
图片描述
最后写解密脚本,得到flag
图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
unsigned char res[] = {
    0x61, 0x6A, 0x79, 0x67, 0x6B, 0x46, 0x6D, 0x2E,
    0x7F, 0x5F, 0x7E, 0x2D, 0x53, 0x56, 0x7B, 0x38,
    0x6D, 0x4C, 0x6E, 0x00};
char flag[19];
int main()
{for (int i = 18; i >= 0; i--){
        if (i == 18)
            flag[i] = res[i] ^ 0x13;
        else{
            if (i % 2){
                flag[i] = (res[i] ^ i) + i;
            }else{
                flag[i+2] = (res[i] ^ i);
            } } }
    for (int i = 1; i < 19; i++)
        printf("%c", flag[i]);}

自此


[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

上传的附件:
收藏
点赞8
打赏
分享
最新回复 (6)
雪    币: 0
活跃值: (76)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zzy2023 2023-5-26 16:32
2
0

请问,为什么运行代码出错了。

上传的附件:
雪    币: 699
活跃值: (466)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
孤岛林潭 2023-5-26 21:38
3
0

这是32位程序,你把运行环境改成32位的,64位的jmp后面不止5个字节

最后于 2023-5-26 21:40 被孤岛林潭编辑 ,原因:
雪    币: 699
活跃值: (466)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
孤岛林潭 2023-5-26 21:39
4
0
zzy2023 请问,为什么运行代码出错了。
这是32位程序,你把运行环境改成32位的,64位的jmp后面不止5个字节
雪    币: 19270
活跃值: (28900)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-6-1 09:05
5
1
感谢分享
雪    币: 0
活跃值: (76)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
zzy2023 2023-6-5 11:42
6
0
感谢分享。
雪    币: 166
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
mb_pmxzjzqc 2023-11-15 14:47
7
0
感谢分享
游客
登录 | 注册 方可回帖
返回