首页 > 其他分享 >code patch hook

code patch hook

时间:2023-06-18 23:55:29浏览次数:39  
标签:code 字节 reinterpret patch hook 原函数 patchedMemory originFunPtr

code patch hook

今天在逆向分析一个程序的时候接触到了code patch hook,其实这个hook技术我在接触逆向之初就已经知道了,但是今天遇到的有点特殊

code patch hook

原理是通过修改api的前5个字节,jmp到自己的函数

当用户调用api时,会跳转到自己的函数

  1. 脱钩
  2. 调用原始api
  3. 脱钩

为正常调用原API,需要先1. 脱钩(若不脱钩2. 调用原始Api就会陷入无限循环)。然后再钩取函数,在退出函数之前再次3.挂钩,使之进入钩取状态。也就是在每次调用原api时都必须反复进行脱钩/挂钩操作,不仅会造成整体性能低下,更严重的是在多线程环境运行下产生错误,这是由脱钩/挂钩操作要对原API的前5个字节进行修改(覆写)引起的。

一种特殊的code patch hook

如何避免呢,其实只要避免反复进行脱钩/挂钩操作就行了

  1. 获取原函数前面几个指令的总长度,一直到字节数>5为止
  2. 创建总长度+5的内存pMem
  3. 将原函数前面总长度的指令复制到内存中pMem的前总长度字节中
  4. 计算pMem+总长度+ 5 到原函数 + 总长度的偏移,并将 E9 XXXXXXXX(偏移)复制到pMem+总长度的位置
  5. 计算原函数 + 5 到自己的函数的偏移,并将E9 XXXXXXXX(偏移)复制到原函数的前面5个字节
  6. pMem返回并保存起来,这个就是调用原函数正常功能的函数地址
    这样用户调用API时,会转到我们的函数,而我们调用原函数时只需调用pMem即可,避免了反复进行脱钩/挂钩操作。

具体实现

下面是我的实现代码,其实还不完善,第一点我并没有计算原函数前面几个字节的长度,而是默认为5,因为Windows API的前面几个指令的字节长度刚好是5,所以下面的代码只能用于x86 Windows api

#include <Windows.h>
#include <iostream>

using namespace std;

typedef DWORD(__stdcall *MyGetFileAttributes)(LPCWSTR lpFileName);
MyGetFileAttributes originMyGetFileAttributes;
DWORD __stdcall __GetFileAttributes(LPCWSTR lpFileName) {
    cout << "__GetFileAttributes" << endl;
    return originMyGetFileAttributes(lpFileName);;
}


int main() {

    originMyGetFileAttributes =  hookCodePatch<MyGetFileAttributes>(::GetFileAttributes, __GetFileAttributes);

    ::GetFileAttributes(LR"(C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Accessories\Notepad.lnk)");

}



template<typename T>
 T hookCodePatch(T originFun, T hookFuntion)
{
    const int patchSize = 10; // 假设需要 patch 的字节数
    const int pageSize = 5;
    unsigned char* patchedMemory = new unsigned char[patchSize];
    unsigned char* originFunPtr = reinterpret_cast<unsigned char*>(originFun);
    
   // 如有必要, 将原函数转到实际的函数地址
    DWORD oldProtect;
    VirtualProtect(patchedMemory, patchSize, PAGE_EXECUTE_READWRITE, &oldProtect);

    if (originFunPtr[0] == 0xFF &&originFunPtr[1] == 0x25) {
        originFunPtr = reinterpret_cast<unsigned char*>(**(int **)(originFunPtr + 2));
    }
    if (originFunPtr[0] == 0xEB ) {
        originFunPtr = originFunPtr + originFunPtr[1] + 2;
        if (originFunPtr[0] == 0xFF && originFunPtr[1] == 0x25) {
            originFunPtr = reinterpret_cast<unsigned char*>(* (int*)(originFunPtr + 2));
        }
        if (originFunPtr[0] == 0xE9) {
            originFunPtr = originFunPtr +*(int*)(originFunPtr + 1);
        }
    }
    
    // 复制 originFun 的前五个字节到 patchedMemory
    memcpy(patchedMemory, originFunPtr, 5);

    intptr_t hookOffset = (reinterpret_cast<intptr_t>(originFunPtr) + 5) - reinterpret_cast<intptr_t>(patchedMemory + 0xA);

    // 修改 patchedMemory 的后五个字节为跳转到 originFun + 5 的指令
    patchedMemory[5] = 0xE9; // x86 跳转指令的操作码
    memcpy(patchedMemory + 6, &hookOffset, sizeof(hookOffset));
    // 计算跳转偏移量
    hookOffset = reinterpret_cast<intptr_t>(hookFuntion) - (reinterpret_cast<intptr_t>(originFunPtr) + 5);
    
    
    // 修改 originFun 的前五个字节为跳转到 hookFunction 的指令
   
    VirtualProtect(originFunPtr, pageSize, PAGE_EXECUTE_READWRITE, &oldProtect);
    originFunPtr[0] = 0xE9; // x86 跳转指令的操作码
    memcpy(originFunPtr + 1, &hookOffset, sizeof(hookOffset));
    VirtualProtect(originFunPtr, pageSize, oldProtect, &oldProtect);
    return (T)patchedMemory;
}

标签:code,字节,reinterpret,patch,hook,原函数,patchedMemory,originFunPtr
From: https://www.cnblogs.com/czlnb/p/17490050.html

相关文章

  • AtCoder Beginner Contest 220 H Security Camera
    洛谷传送门AtCoder传送门看到数据范围猜复杂度是\(O(\text{poly}(n)2^{\frac{n}{2}})\),所以考虑折半。至少有一个端点被选不好算,考虑转成两个端点都被选,但是边数奇偶性与\(m\)相同。称编号\(<\frac{n}{2}\)的点为左点,编号\(\ge\frac{n}{2}\)的点为右点(点编号从\(0......
  • AtCoder Beginner Contest 306 题解 A - E
    A-Echo题目大意给定一个字符串,需要把它每个字符重复输出。解题思路可以读完整个字符串,也可以按照字符读一个输出两个。ACCode#include<iostream>#include<algorithm>#include<cstring>#include<numeric>#defineendl'\n'#defineiosios::sync_with_stdio(fals......
  • 一款代码辅助工具——Amazon CodeWhisperer
    一款代码辅助工具——AmazonCodeWhisperer官方链接: https://aws.amazon.com/cn/codewhisperer/?trk=a2076b82-2c5d-475a-8b78-f22f4bb4f9a1&sc_channel=display+ads 特点免费供个人使用无限的代码建议参考跟踪50次安全扫描(每位用户每月)支持IDE工具 VS插件搜索aws插......
  • Leetcode Hot 100 & 239. Sliding Window Maximum
    参考资料:Python文档heapq部分考点:子串&[题干]1Input:nums=[1,3,-1,-3,5,3,6,7],k=32Output:[3,3,5,5,6,7]3Explanation:4WindowpositionMax5--------------------6[13-1]-353673......
  • VSCode输出"Hello, World!"(编写C语言) 脑残版本一看就懂
    第一步,官网下载VSCode1.官网下载好我全部勾选了2.下载这些扩展第一个,第四个是必需的第二步,MinGW-w64官网下载gcc的资源1.下载64位的2.下载好之后解压到设置的特定文件中3.配置环境变量,点击Path添加这行环境,路径是你下载配置环境的路径配置完毕,一路点击确定3.测......
  • AtCoder ABC306 DEF
    D-PoisonousFull-Course(DP)题意现在有\(N\)道菜,高桥需要依次享用。第\(i\)道菜有两个属性\((X_i,Y_i)\),其意义是:若\(X_i=0\),则第\(i\)道菜是解毒的,其美味度为\(Y_i\);若\(X_i=1\),则第\(i\)道菜是有毒的,其美味度为\(Y_i\)。当高桥享用一道菜,他的状态变化如下:......
  • AtCoder Beginner Contest 306 G Return to 1
    洛谷传送门AtCoder传送门考虑若干个能被\(1\)到达且能到达\(1\)的环,设它们的环长分别为\(a_1,a_2,...,a_k\)。那么我们现在要每个环走若干遍,使得步数不含除\(2\)或\(5\)以外的质因子。设第\(i\)个环走\(x_i\)遍,那么其实就是要求\(\sum\limits_{i=1}^ka_i......
  • 【React工作记录一百一十二】React(Hook)+TS+axios+ant design+json server实现todoli
    前言大家好我是歌谣最近开始在做关于前端扫盲的一些只是处理花了一周左右录制了了一个hook写法的关于todoList的视频主要用于基础知识的一个使用和处理目录#前端巅峰人才交流群私信我#第一节创建项目todolist项目技术选型React(Hook)+TS+axios+antdesign+jsonserve......
  • vscode快捷键
    1.vscode打开设置快捷键使用快捷键对齐凌乱的代码,在编写程序时,有时只考虑了程序的算法,而忘记了代码的缩进格式。导致写出来的一段代码非常零乱。此时,可以按Alt+F8组合键来对齐代码。在实例中经常使用快捷键将多行不规则的代码对齐,如果不使用该快捷键而是一行一行对齐是很浪费时......
  • 【题解】Atcoder ABC300 F.More Holidays(线性做法)
    F.MoreHolidays题目描述:给你一个由o和x组成的长度为\(N\)的字符串\(S\),以及整数\(M\)和\(K\)。保证\(S\)至少包含一个x。假设\(T\)是由\(S\)复制\(M\)次而成的长度为\(NM\)的字符串。考虑将\(T\)中的\(K\)个x恰好替换为o。你的目标是在替换后的......