Detours学习5 - 进程内使用Detours

在进程内使用Detours来拦截用户函数

前面写4篇关于Detours的文章,主要是来自官方ReadMe的翻译和少量自己的理解

C++包管理器

用于 Windows、Linux 和 macOS 的 C++ 包管理器

写了比较长时间的C#,已经离不开Nuget这种包管理利器了,当再次使用C/C++时,那种下载源代码、看ReadMe、找依赖包、编译...一阵心乱如麻,在Google胡乱搜索了一通,发现C++也有了一些包管理的方案,后面就留意到VcPkg这个由微软以MIT协议开源的C++包管理。

下面就用VcPkg先安装Detours并集成到VS2019中

./VcPkg.exe install detours:x86-windows
./VcPkg.exe install detours:x64-windows
./VcPkg.exe integrate install

查看项目属性页可以看到vcpkg的选项

关于VcPkg的更多信息请查看微软官方文档


顺便提一下C/C++宏定义

这个特性真的是让人又爱又恨,写得过于复杂阅读性就差了,简单使用提供了方便,至于那个可以省去函数入栈出栈的开销我可没有那么关心

  1. 字符串化 #

    将宏定义中传参数名转化成用""包起来。

    #define LOGW(str) printf("W: %s\n", #str)
    

    它会忽略传入参数前面和后面的空格;当传入参数中间存在空格时,预处理器会自动连接各个子字符串,用一个空格连接子字符串。

    LOGW(   1     324    a   bc    );
    // 将预处理为
    printf("W: %s\n", "1 324 a bc");
    
  2. 符号连接 ##

    连接各个子部分,## 前后的空格可有可无,如:a##ba ## b是一样的意义。另外,如果##后的部分本身也是一个宏的话,##将会阻止后面这个宏的展开。

  3. 字符化 #@

    将传入的单字符转化成用''包起来。

    #define MAKECHAR(c) #@c
    // 将c赋值为'A'
    char c = MAKECHAR(A);
    

有时间遇到一些费解的宏定义时的确会比较头大,遇到那种情况可以将宏定义展开后再阅读一下,vs的加上/EP选项,不使用 #line 指令预处理到 stdout。关于/EP选项和更多编译/连接选项请查看微软官方文档


建立工程编写代码

│  Detour.cpp
│  Detour.h
│  DetourProcessInside.cpp
│  DetourProcessInside.vcxproj
│  DetourProcessInside.vcxproj.filters
│  DetourProcessInside.vcxproj.user
  1. Detour.h

    #pragma once
    class Detour
    {
    	void* targetPtr;
    	void* detourFunc;
    public:
    	Detour(void* src, void* dest);
    	~Detour();
    };
    
    #define DETOURS(src, dest) Detour instance(src, dest)
    
  2. Detour.cpp

    #include "Detour.h"
    #include <Windows.h>
    #include <detours/detours.h>
    
    Detour::Detour(void* src, void* dest):
    	targetPtr(src), detourFunc(dest)
    {
    	DetourRestoreAfterWith();
    	DetourTransactionBegin();
    	DetourUpdateThread(GetCurrentThread());
    	DetourAttach(&targetPtr, detourFunc);
    	DetourTransactionCommit();
    }
    
    Detour::~Detour()
    {
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
        DetourDetach(&targetPtr, detourFunc);
        DetourTransactionCommit();
    }
    
  3. 入口函数文件

    #include <iostream>
    #include <Windows.h>
    #include "Detour.h"
    
    double Add(double a, double b);
    double(__cdecl* targetPtr)(double, double) = Add;
    
    double Add(double a, double b)
    {
        return a + b;
    }
    
    double hkAdd(double a, double b)
    {
        std::cout << "The source function has been detoured" << std::endl;
    
        return 9527;
    }
    
    int main()
    {
        //DETOURS(targetPtr, hkAdd);
        auto pd = new Detour(targetPtr, hkAdd);
        std::cout << "1 + 1 = " << Add(1, 1) << std::endl;
        std::cout << "...Now Restore" << std::endl;
        delete pd;
        std::cout << "1 + 1 = " << Add(1, 1) << std::endl;
    
        std::cout << "Press Escape To Exit..." << std::endl;
        while (true)
        {
            if (GetAsyncKeyState(VK_ESCAPE))
            {
                break;
            }
        }
    
        return 0;
    }
    
  4. 输出结果,不是1 + 1 = 2而是1 + 1 = 9527,调用函数Add(1, 1)时跳转到hkAdd(1, 1)

    The source function has been detoured
    1 + 1 = 9527
    ...Now Restore
    1 + 1 = 2
    Press Escape To Exit...
    
posted @ 2020-12-21 16:49  非法关键字  阅读(683)  评论(0编辑  收藏  举报