Detours學習5
阿新 • • 發佈:2020-12-21
在程序內使用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(&src, dest); DetourTransactionCommit(); } Detour::~Detour() { DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourDetach(&targetPtr, detourFunc); DetourTransactionCommit(); }
-
入口函式檔案
#include <iostream> #include "Detour.h" 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() { void* targetPtr = (void*)Add; DETOURS(targetPtr, hkAdd); std::cout << "1 + 1 = " << Add(1, 1) << std::endl; return 0; }
-
輸出結果,不是
1 + 1 = 2
而是1 + 1 = 9527
,呼叫函式Add(1, 1)
時跳轉到hkAdd(1, 1)
The source function has been detoured 1 + 1 = 9527 請按任意鍵繼續. . .