Inline_hook
LkaiInlineHook
原理介绍
上次打考核赛的时候遇到的一道题,不过当时是全凭做题经验写出来的,现在正好实现一下(都是在32位下的,64位下的没有去实现)
inline hook (内联钩子) 是一种在程序运行时修改函数执行流程的技术。他通过修改函数的原始代码,将目标函数的执行路径重定向到自定义的代码段,从而实现对目标函数的拦截与修改(也就是hook)
那该如何去实现跳转呢
这里有两种方式
第一种就是用jmp,也就是相对地址的方式,
1 2 3
| __NewCode[0] = 0xE9; DWORD relativeAddr = (DWORD)fun1 - (DWORD)fun2 - 5; memcpy(&__NewCode[1], &relativeAddr, 4);
|
也就是相当于
这种的话,就需要找合适的地方有5个字节的,如果长了,就会使后面的机器码,去形成指令去配对,从而就会导致后面的内容都会乱掉,所以我们通常使用绝对寻址的方式去实现
1 2 3 4
| __NewCode[0] = 0xB8; memcpy(&__NewCode[1], &JmpAddress, 4); __NewCode[5] = 0xFF; __NewCode[6] = 0xE0;
|
也就相当于
代码实现
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
| #include <iostream> #include <windows.h> #include <cstdio> using namespace std;
typedef VOID(*PFUNMSG)(LPCWSTR szMsg, LPCWSTR Title); HMODULE hModule; PFUNMSG Crypto; BYTE _NewCode[7] = { 0xe9,0x0,0x0,0x0,0x0,0x0 }; BYTE _OldCode[7] = { 0 }; int fun2(); int fun1(); void InlineHook(); void InlineHook() { memcpy(_OldCode, fun2, 7); DWORD JmpAddress = (DWORD)fun1; _NewCode[0] = 0xB8; memcpy(&_NewCode[1], &JmpAddress, 4); _NewCode[5] = 0xff; _NewCode[6] = 0xE0; DWORD dwOldProtect; VirtualProtect(fun2, 7, PAGE_EXECUTE_READWRITE, &dwOldProtect); memcpy(fun2, _NewCode, 7); VirtualProtect(fun2, 7, dwOldProtect, &dwOldProtect); } int main() { InlineHook(); fun2(); } int fun2() { puts("Hello world"); return 0; } int fun1() { puts("Obaby girl 别叫我达芬奇"); return 0; }
|
也正好写一下当时考核赛那道题的wp
写一道类似的wp
打开主函数

在sub_4112B2 函数中

其实我们也已经可以看见我们要自定义的代码段了,总感觉要出题的话得加点混淆
但是我们先按正常的分析,因为知道是被hook了所以我们得启用动态调试了

下好断点

当步入到tea这个函数时f7步入

发现我们说的mov eax fun1 了(绝对寻址),然后再步入

发现jmp eax ,所以下一个步入就是我们的自定义的代码段

解开之后

得到真正的加密的地方,然后写出代码
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
| #include <iostream> using namespace std; #include <bits/stdc++.h> void decrypt (uint32_t *v ,int *key){ uint32_t v0=v[0]^3; uint32_t v1=v[1]^4; uint32_t delta = 0x61C88647; uint32_t sum= -(delta * 32) ; for(int i=0;i<32;i++){ v1 -=(key[3] + (v0 >> 5)) ^ (sum + v0) ^ (key[2] + 16 * v0); v0 -= (key[1] + (v1 >> 5)) ^ (sum + v1) ^ (*key + 16 * v1); sum += delta; } v[0]=v0^1; v[1]=v1^2; } int main (){ uint32_t enc[14]={0xBDF30C56,0x86C9E780,0xCD2D53F2,0x47FDE322,0x1F8B1C9F,0x159683FF,0x21816944,0x36850959, 0xB8F837D1,0xFAB82602,0x471CF06D,0x4287B2DA};
int key[4]={0x114514,0x1919810,0x5201314,0x7355608 }; for(int i=0;i<=10;i+=2){ decrypt(&enc[i],key); }
cout<<(char *)enc<<endl; return 0; }
|