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...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)