一、 什么是 inline hook
inline hook 就是在运行的流程中插入跳转指令(call/jmp)来抢夺程序运行流程的一个方法。
好了那么问题就来了:
1. 插入怎么样的跳转指令
一般为 相对JMP(0xE9) + 4字节地址,方便计算
公式:源地址 + 相对偏移 = 目的地址
公式:目的地址 - 源地址 = 相对偏移
2. 被跳转指令覆盖的原始指令应该被保存起来,找适当的时机再执行
3. 需要对应的 jmpIn 和 jmpOut 跳转。
4. inline hook 的一般流程:
源程序流 -> jmpIn -> 保存寄存器 -> 具体处理 -> 恢复寄存器 -> jmpOut -> 源程序流
被跳转指令覆盖的代码可以在 jmpIn之后 或者 jmpOut之前
二、 被 inline hook 的位置
1. 指令或者指令之和大于等于5,因为我们要塞进去5个字节(0xE9 + Address)。只要你处理跳转指令覆盖的指令,理论上可以 inline hook 函数中的任意位置。
2. 判断被 inline hook 位置的指令可以使用反汇编引擎判断指令长度。
3. 很多系统调用的开头都是,能很方便的 inline hook
mov edi, edi
push ebp
mov ebp, esp
三、 可以写 hookProxy 函数,保存和恢复寄存器,统一调用界面。
例子:
// inline_hook.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
__declspec(naked) int add(int a, int b)
{
__asm
{
mov edi, edi
push ebp
mov ebp, esp
sub esp, 8
mov eax, [ebp + 0x08]
mov [ebp - 4], eax
mov eax, [ebp + 0x0C]
mov [ebp - 8], eax
mov eax, [ebp - 4]
add eax, [ebp - 8]
mov esp, ebp
pop ebp
ret
}
}
__declspec(naked) void hookProxy()
{
// moved bytes
__asm
{
nop
nop
nop
nop
nop
}
// save regs
// __asm
// {
// pushad
// pushfd
// }
// do something (or call specific function.)
__asm
{
add [esp + 0x08], 1
add [esp + 0x0C], 1
}
// store old regs
// __asm
// {
// popfd
// popad
// }
// jump back code
__asm
{
nop
nop
nop
nop
nop
}
}
void inlineHook()
{
char* pMovedBytes = &((char*)hookProxy)[0];
char* pJmpBackCode = &((char*)hookProxy)[0xF];
// move old bytes
memcpy((char*)hookProxy, (char*)add, 5);
// fill jump in code
char jmpInBuffer[5];
jmpInBuffer[0] = 0xE9;
int* pJmpInOffset = (int*)&jmpInBuffer[1];
*pJmpInOffset = (char*)hookProxy - ((char*)add + 5);
memcpy((char*)add, jmpInBuffer, 5);
// fill jump out code
char jmpOutBuffer[5];
jmpOutBuffer[0] = 0xE9;
int* pJmpOutOffset = (int*)&jmpOutBuffer[1];
*pJmpOutOffset = ((char*)add + 5) - ((char*)pJmpBackCode + 5);
memcpy(pJmpBackCode, jmpOutBuffer, 5);
}
int _tmain(int argc, _TCHAR* argv[])
{
_asm int 3;
DWORD oldProtect;
if( VirtualProtect((LPVOID)add, 4096, PAGE_EXECUTE_READWRITE, &oldProtect) )
{
inlineHook();
}
printf("result = %d \n", add(1, 2));
system("pause");
return 0;
}
四、解析例子
1. 把Add函数的前5个字节搬到了 hookProxy的前5个字节。
2. 然后再 Add函数的前5个字节填充跳转到 hookProxy 的跳转指令
3. 在hookProxy的末尾5个字节填充跳转回 Add函数 + 5 的跳转指令
4. 原本 Add 函数的结构是3,被 hook 之后会变成 5
五、调试过程
在main函数中的,printf F11进去就能看到被 inline hook 改写的程序流程
0:000> t
inline_hook!add:
01001000 e91b000000 jmp inline_hook!hookProxy (01001020)
0:000> p
inline_hook!hookProxy:
01001020 8bff mov edi,edi
0:000> p
inline_hook!hookProxy+0x2:
01001022 55 push ebp
0:000> p
inline_hook!hookProxy+0x3:
01001023 8bec mov ebp,esp
0:000> p
inline_hook!hookProxy+0x5:
01001025 8044240801 add byte ptr [esp+8],1 ss:0023:002ef794=01
0:000> p
inline_hook!hookProxy+0xa:
0100102a 8044240c01 add byte ptr [esp+0Ch],1 ss:0023:002ef798=02
0:000> p
inline_hook!hookProxy+0xf:
0100102f e9d1ffffff jmp inline_hook!add+0x5 (01001005)
六、工程附件(VS2010 - Release)
inline_hook.rar
[课程]Android-CTF解题方法汇总!