欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[原创]inline hook 入门教程

[原创]inline hook 入门教程

一、 什么是 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

上传的附件 inline_hook.rar

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功