黑客爱用的 HOOK 技术大揭秘!
什么是 HOOK 技术?
病毒木马为何惨遭杀软拦截?
商业软件为何频遭免费破解?
系统漏洞为何能被补丁修复?
这一切的背后到底是人性的扭曲,还是道德的沦丧,敬请收看今天的专题文章:《什么是 HOOK 技术?》
上面是开个玩笑,言归正传,今天来聊的话题就是安全领域一个非常重要的技术:HOOK 技术。
HOOK,英文意思是“钩子”。
在计算机编程中,HOOK 是一种「劫持」程序原有执行流程,添加额外处理逻辑的技术。
按照这个定义,其实我们 Python 中的装饰器和 Java 中的注解,这种面向切面编程的手法在某种程度上来说,也算是 HOOK。
不同的是,本文要探讨的 HOOK 并非属于程序原有的逻辑,而是在程序已经编译成可执行文件甚至已经在运行中的时候,如何劫持和修改程序的流程。
按照劫持的目标不同,常见的 HOOK 有以下这些类型:
- Inline HOOK
- IAT HOOK
- C++ virtable HOOK
- SEH HOOK
- IDT HOOK
- SSDT HOOK
- IRP HOOK
- TDI HOOK && NDIS HOOK
- Windows Message HOOK
接下来,咱们挨个来看一下。
Inline HOOK
程序和代码是给程序员们看的,计算机要运行,最终是要编译成 CPU 的机器指令才能执行。
Inline HOOK 的目标就是直接修改程序编译后的指令,属于最基础也最常见的 HOOK 技术。
下面我们以一个实例来感受一下 Inline HOOK 的效果:
void functionA() {
cout << "this is function A" << endl;
}
void hookFunction() {
cout << "this is hookFunction" << endl;
}
int main() {
cout << "before hook" << endl;
functionA();
// prepare hook
unsigned char code[5] = { 0xe9, 0x00, 0x00, 0x00, 0x00 };
unsigned int offset = (unsigned int)hookFunction - ((unsigned int)functionA + 5);
*(unsigned int*)&code[1] = offset;
// install hook
unsigned long old = 0;
VirtualProtect(functionA, 0x1000, PAGE_EXECUTE_READWRITE, &old);
memcpy(functionA, code, 5);
cout << "after hook" << endl;
functionA();
return 0;
}
输出:
代码中定义了目标函数 functionA 和 hook 函数 hookFunction。
第一次调用,输出显示调用了原函数。
然后安装一个 HOOK,准备了一条 jmp 指令,覆盖函数入口处的指令。此时观察覆盖前后的函数指令变化对比:
再次调用该函数,则一进入就发生跳转,我们安装的 HOOK 函数得到了执行。
所以第二次输出显示 HOOK 函数得到了调用。
大部分情况下,我们习惯于在函数入口处执行 HOOK,但这并不是绝对的,还需要具体问题具体分析。比如如果我们需要等待函数执行完毕时拿到返回值才能介入处理,这个时候就需要在函数 return 的地方进行 HOOK。甚至有可能需要在函数中途某个地方介入,这个时候就需要更进一步地对函数的反编译指令进行分析,确定 HOOK 的点位和处理逻辑。
执行 Inline HOOK 非常关键的几点:
- 指令所在的内存页是否允许写入操作,若只读,须先添加写入权限。
- 需要动态解析目标位置处的指令,不能像上面那样暴力覆盖,否则会影响原来函数的执行逻辑。
- 如果在 HOOK 处理函