欢迎来到 嗅灵易学

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

[原创]hook函数返回1

[原创]hook函数返回1

作者签名


应用场景

有些时候,我们需要hook一些函数,达到我们预想的一些效果。
普通的windows api就不说了,hook的资料还是很多的。
但是普通的call和function相关资料还是很少的。
最近反编译一个项目是,需要这样的功能,这里整理了一下资料,做了个小DEMO演示一下。

模拟效果

某个call调用一个function,原本返回的0,这里修改返回1

忽略

代码中有些细节有更好的解决方案,请忽略,不同的项目中有不同的适合解决方案,这里只做一个演示。

划重点,要考的,呵呵

  • hook模版
  • 查找call/function
  • 计算修改call/jmp的偏移值

流程、逻辑

  • 查找function的内存地址,例如:0x00413CC0
  • 搜索代码相关代码段,查找调用function的call,例如:0x00418125 call 0x00413CC0
  • 申请一个小内存,将hook模版写入。
      // hook模版
    
      // ... 这里可以增加一些预处理代码,例如修改参数的数据
    
      call 0x00000000 // call function
    
      // ... 这里可以增加一些后置代码,例如修改某些数据
    
      mov eax, 1      // 将返回值改为1
    
      jmp 0x00000000  // 返回代码写一个code
    
    
  • 写入正确的function和call的偏移地址。
      call 0x00413CC0
    
      mov eax, 1
    
      jmp 0x0041812A // 0x00418125+0x5
    
    
  • 修改code内存页权限,修改原call代码为jmp,改回内存页权限
      VirtualProtect                // PAGE_EXECUTE_READWRITE
    
      *(BYTE*)fromAddr = 0xE9;      // JMP
    
      *(int*)(fromAddr + 1) = fix3; // JMP x
    
      VirtualProtect                // 恢复
    
    
  • 恢复执行,完美搞定

完整DEMO代码

#include <string>

#include <windows.h>

using namespace std;

// 一个正常的普通函数,最后返回0/1,这里模拟返回0

static __declspec(naked) bool dosomething() {

    __asm {

        // ... code ...

        mov eax, 1; // B8 01 00 00 00

        // ... code ...

        mov eax, 2; // B8 02 00 00 00

        // ... code ...

        mov eax, 3; // B8 03 00 00 00

        // ... code ...

        mov eax, 4; // B8 04 00 00 00

        // return false

        xor eax, eax; // 33 C0

        ret;

    }

}

// hook 代码

static __declspec(naked) void return1() {

    __asm {

        // call x // 5bit

        _emit 0xE8;

        _emit 0;

        _emit 0;

        _emit 0;

        _emit 0;

        mov eax, 1; // 5bit

        // jmp far:x

        __emit 0xE9; // 5bit

        _emit 0;

        _emit 0;

        _emit 0;

        _emit 0;

    }

}

// 设置hook

void* setReturn1(int toAddr, int fromAddr) {

    int isize = 5 + 5 + 5;

    char *p1 = (char*)VirtualAlloc(0, isize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    memset(p1, 0, isize);

    char *p = (char*)&return1;

    // 改用汇编,不然Release编译时会出错

    // memcpy(p1, p, isize);

    __asm {

        pushad;

        mov esi, p;

        mov edi, p1;

        mov ecx, isize;

        rep movsb;

        popad;

    }

    // 目标地址 - (当前地址 + 指令长度)

    int fix1 = toAddr - ((int)p1 + 5);

    int fix2 = (fromAddr + 5) - ((int)p1 + 0xA + 5); // ret addr

    int fix3 = (int)p1 - (fromAddr + 5);

    *(int*)((int)p1 + 1) = fix1;

    *(int*)((int)p1 + 0xB) = fix2;

    // hook

    DWORD flOldProtect;

    VirtualProtect((LPVOID)fromAddr, 5, PAGE_EXECUTE_READWRITE, &flOldProtect);

    *(BYTE*)fromAddr = 0xE9; // JMP x

    *(int*)(fromAddr + 1) = fix3; // JMP x

    VirtualProtect((LPVOID)fromAddr, 5, flOldProtect, &flOldProtect);

    return p1;

}

// 查找方法地址

int findCallAddr(char *code, int codeSize, char *bin, int binSize) {

    string s(code, codeSize);

    int p = s.find(bin, 0, binSize);

    if (p < 0) return 0;

    return (int)code + p;

}

// 查找调用方法的call

int findCall(char *start, char *end, int callAddr) {

    for (int p = (int)start; p < (int)end; p++) {

        if (p < 0x417E00) continue;

        if (*(BYTE*)p != 0xE8) continue; // 不是call,继续找

        int addr = *(int*)(p + 1); // 操作数

        if (callAddr - p - 0x5 != addr) continue; // 不是call addr

        return p;

    }

    return 0;

}

int main()

{

    // 要查找代码的起始地址

    char *base = (char*)GetModuleHandle(NULL) + 0x10000;

    // 搜索代码的总长度

    int codeSize = 0x10000;

    // 查找call的特征sig

    char codeSig[] = { 0xB8,0x01,0x00,0x00,0x00,0xB8,0x02,0x00,0x00,0x00 };

    // 查找call地址

    int call = findCallAddr(base, codeSize, codeSig, sizeof(codeSig));

    if (call == 0) {

        printf("not found call\n");

        return 1;

    }

    printf("call address: 0x%08X\n", call);

    // 查找调用call的地址

    int p = findCall(base, base + codeSize, call);

    if (p != 0) {

        printf("address: 0x%08X\n", p);

        // hook

        setReturn1(call, p);

    }

    // 由原来的返回0,改为返回1

    printf("return: 0 => %d\n", dosomething());

    getchar();

    return 0;

}

DEMO输出

output:

call address: 0x00413CC0

address: 0x00418125

return: 0 => 1


@2019-04-05 11:14:53 +0800

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

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

0 0 0 举报
复制成功