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++宏定义
这个特性真的是让人又爱又恨,写得过于复杂阅读性就差了,简单使用提供了方便,至于那个可以省去函数入栈出栈的开销我可没有那么关心
-
字符串化
#
将宏定义中传参数名转化成用
""
包起来。#define LOGW(str) printf("W: %s\n", #str)
它会忽略传入参数前面和后面的空格;当传入参数中间存在空格时,预处理器会自动连接各个子字符串,用一个空格连接子字符串。
LOGW( 1 324 a bc ); // 将预处理为 printf("W: %s\n", "1 324 a bc");
-
符号连接
##
连接各个子部分,
##
前后的空格可有可无,如:a##b
与a ## b
是一样的意义。另外,如果##
后的部分本身也是一个宏的话,##
将会阻止后面这个宏的展开。 -
字符化
#@
将传入的单字符转化成用
''
包起来。#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
-
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)
-
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(); }
-
入口函数文件
#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; }
-
输出结果,不是
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...