MinHook 如何對 .NET 母體 CoreCLR 進行攔截

一:背景

1. 講故事

這篇文章起源于和一家 .NET公司 開線上會議時,提出的一個場景問題,程序出現了非托管內存暴漲,這些非托管內存關聯的對象都囤積在 終結器隊列 中,很顯然這是代碼中沒用 using 及時釋放引發的,而這塊代碼又是第三方組件,你想加也加不了,所以提出了一個設想:能不能設法干預 終結器隊列的 freachable 節段,讓里面的對象提前釋放,而不是等待不穩定的終結器線程來兜底。。。

這個問題我最近也在考慮,畢竟我寫過如何用 harmony 攔截 .net sdk ,用 minhook 攔截 win32api,唯獨這一塊沒有跟大家聊,雖然 eventpipe 給 coreclr 開了很多的日志口子,但怎么說呢? eventpipe 是一種君子之法,和黑客性質的minhook無法相提并論,所以這一篇就詳細的和大家聊一聊。

二:如何攔截 coreclr

1. 一個小案例

為了方便演示,就以攔截 GC.Collect() 方法為例吧,參考代碼如下:

static void Main(){for (int i = 0; i < 3; i++){Console.WriteLine($"Triggering GC #{i}...");GC.Collect();Thread.Sleep(1000);}}

熟悉GC的朋友應該知道 GC.Collect() 下游方法是coreclr!WKS::GCHeap::GarbageCollect(),我想在命中這個方法的時候執行一點我的自定義邏輯,這里有一點注意的是,鉤子的回調不要回調到 C#,最好采用 SlideCar 的方式,這里使用靜態鏈接,C代碼參考如下:


#include <windows.h>
#include <stdio.h>
#include <MinHook.h>// 1. 使用 extern "C" 防止名稱修飾
#ifdef __cplusplus
extern "C" {
#endif// 2. 定義原始函數類型typedef int(__fastcall* Real_GarbageCollect)(void* pThis, int generation, bool lowMemory, int mode);// 3. 導出函數聲明__declspec(dllexport) BOOL WINAPI InstallGCHook();__declspec(dllexport) void WINAPI UninstallGCHook();#ifdef __cplusplus
}
#endif// 4. 全局變量
static Real_GarbageCollect fpOriginalGarbageCollect = NULL;
static void* pTargetFunction = NULL;// 5. 獲取 coreclr.dll 中的函數地址(關鍵修改點)
static void* GetGCDunctionAddress() {HMODULE hCoreCLR = GetModuleHandleW(L"coreclr.dll");if (!hCoreCLR) {printf("[ERROR] coreclr.dll not loaded\n");return NULL;}// 計算目標地址return (BYTE*)hCoreCLR + 0x30E670; // 替換為你的實際偏移量
}// 6. Detour 函數(保持不變)
int __fastcall Hook_GarbageCollect(void* pThis, int generation, bool lowMemory, int mode) {printf("[GC Hook] this=0x%p, gen=%d, lowMem=%d, mode=%d\n",pThis, generation, lowMemory, mode);if (fpOriginalGarbageCollect) {MH_DisableHook(pTargetFunction);int result = fpOriginalGarbageCollect(pThis, generation, lowMemory, mode);MH_EnableHook(pTargetFunction);return result;}return 0;
}// 7. 安裝Hook(改為自動計算地址)
__declspec(dllexport) BOOL WINAPI InstallGCHook() {pTargetFunction = GetGCDunctionAddress();if (!pTargetFunction) return FALSE;if (MH_Initialize() != MH_OK) {printf("[ERROR] MinHook init failed\n");return FALSE;}MH_STATUS status = MH_CreateHook(pTargetFunction,&Hook_GarbageCollect,(void**)&fpOriginalGarbageCollect);if (status != MH_OK) {printf("[ERROR] CreateHook failed (status=0x%X)\n", status);MH_Uninitialize();return FALSE;}if (MH_EnableHook(pTargetFunction) != MH_OK) {printf("[ERROR] EnableHook failed\n");MH_Uninitialize();return FALSE;}printf("[SUCCESS] Hook installed at 0x%p\n", pTargetFunction);return TRUE;
}// 8. 卸載Hook(保持不變)
__declspec(dllexport) void WINAPI UninstallGCHook() {if (pTargetFunction) {MH_DisableHook(pTargetFunction);MH_RemoveHook(pTargetFunction);}MH_Uninitialize();printf("[INFO] Hook uninstalled\n");
}

然后指定 頭文件,鏈接文件,截圖如下:


上面的 Hook_GarbageCollect 函數就是回調的地方,我用 printf 輸出當前 GarbageCollect 參數信息, 接下來就是 C# 側了,把生成好的 ConsoleApplication2.dll 丟到 C# 的 bin 目錄下,參考代碼如下:


using System;
using System.Runtime.InteropServices;class Program
{[DllImport("ConsoleApplication2.dll", CallingConvention = CallingConvention.StdCall)]public static extern bool InstallGCHook();[DllImport("ConsoleApplication2.dll", CallingConvention = CallingConvention.StdCall)]public static extern void UninstallGCHook();static void Main(){try{if (InstallGCHook()){Console.WriteLine("Hook installed. Press any key to exit...");for (int i = 0; i < 3; i++){Console.WriteLine($"Triggering GC #{i}...");GC.Collect();Thread.Sleep(1000);}}}finally{UninstallGCHook();}}
}

最后運行程序,可以清楚的看到每次 GC.Collect() 都被成功攔截,截圖如下:

如果你很想知道匯編層到底發生了什么變化,可以用 windbg 觀察便知,截圖如下,真的太完美了,經典的 jmp 跳轉。

2. 相對偏移 0x30E670 的疑問

相信有不少人閱讀代碼之后,會對 return (BYTE*)hCoreCLR + 0x30E670; 中的 0x30E670 感興趣,其實這條語句表示函數coreclr!WKS::GCHeap::GarbageCollect 的入口地址,其中的 0x30E670 偏移是怎么知道的呢? 我是用 windbg 觀測的,計算如下:


0:000> lmvm coreclr
Browse full module list
start             end                 module name
00007ff8`508c0000 00007ff8`50d9d000   coreclr    (private pdb symbols)  
...0:000> x coreclr!WKS::GCHeap::GarbageCollect
00007ff8`50bce670 coreclr!WKS::GCHeap::GarbageCollect (int, bool, int)0:000> ? 00007ff8`50bce670 - 00007ff8`508c0000
Evaluate expression: 3204720 = 00000000`0030e670

卦中的 000000000030e670 便是,相信此時又會有人提一個疑問,不同版本不同環境下的 coreclr 都可以用這個 0x30e670 嗎?很顯然這是不對的, 0x30e670 本質上是相對 模塊 的偏移地址,同版本的coreclr是沒有問題的,不同版本因為代碼結構不一樣,自然相對地址就不一樣,所以大家需要根據生產環境的coreclr版本提前計算一下偏移值即可。

三:總結

借助 harmony,minhook 兩大工具可以黑進三大代碼領域 .netsdk,win32,coreclr,這在.NET高級調試體系下是一枚核武的存在,相信這篇文章也給這家 .NET公司 解決場景問題提供了一個思考點。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/87392.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/87392.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/87392.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DPI深度檢索原理和架構

大家讀完覺得有幫助記得關注和點贊&#xff01;&#xff01;&#xff01; DPI&#xff08;深度包檢測&#xff09;技術通過**透視網絡載荷內容**實現精細化流量管控與威脅檢測&#xff0c;其核心在于突破傳統防火墻僅檢查IP/端口等表層信息的局限&#xff0c;對**應用層數據**進…

QT Creator的返回到上一步、下一步的快捷鍵是什么?

在 Qt Creator 中&#xff0c;用于導航的 返回上一步 (Back) 和 前進下一步 (Forward) 的快捷鍵如下&#xff1a; 默認快捷鍵&#xff1a; 功能Windows/LinuxmacOS返回上一步Alt ←Command [前進下一步Alt →Command ]

UI前端大數據處理策略優化:基于云計算的數據存儲與計算

hello寶子們...我們是艾斯視覺擅長ui設計、前端開發、數字孿生、大數據、三維建模、三維動畫10年經驗!希望我的分享能幫助到您!如需幫助可以評論關注私信我們一起探討!致敬感謝感恩! 一、引言&#xff1a;大數據時代前端處理的挑戰與云計算破局 在數字化轉型的浪潮中&#xff…

機器學習基礎 多層感知機

機器學習基礎 多層感知機 文章目錄 機器學習基礎 多層感知機1. 多層感知機1.1 線性模型的失效1.2 感知機1.3 感知機的收斂定理1.4 從線性到非線性1.5 多層感知機的定義和實現 參考 1. 多層感知機 1.1 線性模型的失效 ? 在李沐《動手學深度學習》中有這樣的描述&#xff1a; …

關于安裝Ollama大語言模型本地部署工具

一、Ollama 安裝方法概述 Ollama 是一個開源的大型語言模型(LLM)本地部署工具&#xff0c;支持在 Windows、macOS 和 Linux 系統上運行。它簡化了在本地計算機上運行和管理大語言模型的流程&#xff0c;讓開發者能夠輕松部署各種開源模型。 Windows 系統安裝步驟 訪問 Ollam…

html配置rem實現頁面自適應

1.在js文件使用&#xff0c;建議放到全局js中 // 全局js文件 $(function () {// 設置根目錄字體大小var baseSize 16; // 設計稿的基準字體大小&#xff0c;通常是16pxvar baseWidth 750; // 設計稿的基準寬度&#xff0c;通常是750pxfunction adjustFontSize() {const widt…

POI實現文檔的圖片的提取和替換

1. 簡介 在日常辦公自動化開發中&#xff0c;常常需要對 Word 文檔中的圖片進行批量提取、保存&#xff0c;甚至將圖片替換為自定義的文本或鏈接。Apache POI 是一款強大的 Java 開源庫&#xff0c;支持對 Microsoft Office 文檔&#xff08;包括 Word、Excel、PowerPoint 等&…

毫米波雷達 – 深度學習

目錄 數據表示 公開數據庫 未來發展方向 稀疏點云 + 深度學習 直接處理點云 (1/2) 候選生成+特征提取+候選分類(DL* ) 候選生成+特征提取+候選分類(DL) 直接處理點云 (2/2) 候選生成+特征提取(DL)+候選分類(DL) 網格數據+端對端檢測(DL) 稠密數據塊 + 深度學習 直接…

Redis——常用指令匯總指南(一)

目錄 1.set & get ①set指令 ②get指令 2.keys 3.del 4.expire & setex & psetex 5.ttl 6.exists 7.setnx 8.flushall 9.object encoding 10. type 1.set & get set & get指令中key和value都是字符串&#xff0c;但是不需要加單引號或雙引號。 …

PDF處理控件Aspose.PDF教程:在 Java 中刪除 PDF 頁面

您是否需要使用 Java 從PDF文檔中刪除特定頁面&#xff1f;無論您是要清理空白頁、刪除機密部分&#xff0c;還是僅僅在分發前調整內容&#xff0c;以編程方式操作 PDF 頁面的能力都將大有裨益。本指南將向您展示如何借助Aspose.PDF僅用幾行代碼刪除不需要的頁面。讓我們深入了…

RediSearch 字段類型與配置選項

1. 數值字段&#xff08;NUMERIC&#xff09; 用途&#xff1a;存儲整數或浮點數&#xff0c;可進行范圍查詢與排序。 選項&#xff1a; SORTABLE&#xff1a;允許用 SORTBY 排序NOINDEX&#xff1a;不參與索引&#xff0c;僅供返回 定義語法 FT.CREATE idx ON HASH PREFIX…

PHP Yii2 安裝SQL Server擴展-MAC M4 Pro芯片

MAC M4 Pro芯片版本&#xff0c;千錘百煉編譯十幾次終于成功 # 設置基礎鏡像并強制使用 x86_64 架構&#xff08;適配 M4 芯片&#xff09; FROM --platformlinux/amd64 php:8.1-fpm-alpine3.18WORKDIR /var/www/html# 可選&#xff1a;設置時區 ARG TZAsia/Shanghai ENV TZ${…

HTML初學者第二天

<1>HTML的語法規范 1.1標簽 -雙標簽&#xff1a;如 <html></html> 前面的叫開始標簽&#xff0c;后面的叫結束標簽。 -單標簽&#xff1a;如 <br /> 1.2基本語法概述 -HTML標簽是由尖括號包圍的關鍵詞&#xff0c;例如<html>。 -HTML標…

【加解密與C】HASH系列(二) SHA

SHA&#xff08;安全散列算法&#xff09;簡介 SHA&#xff08;Secure Hash Algorithm&#xff09;是由美國國家安全局&#xff08;NSA&#xff09;設計的一系列密碼散列函數&#xff0c;用于將任意長度的數據轉換為固定長度的散列值。SHA家族包括SHA-1、SHA-2&#xff08;含S…

【Python】進階 - 數據結構與算法

系列篇章&#x1f389; No.文章1【Python】基礎知識&#xff08;詳細&#xff09;&#x1f680;2【Python】基礎 - 循環、容器類型&#x1f680;3【Python】基礎 - 推導式、函數&#x1f680;4【Python】基礎 - 文件、異常、模塊&#x1f680;5【Python】進階 - 面向對象&…

【如何實現分布式壓測中間件】

分布式壓測中間件的原理及其實現 原理全鏈路追蹤框架&#xff08;Trace&#xff09;MQ中間件數據庫分布式緩存中間件&#xff08;Redis&#xff09;分庫分表中間件 原理 通過大量閱讀中間件源碼&#xff0c;開源社區調研&#xff0c;得到設計原理&#xff1a; &#xff08;1&a…

Qt進程間保活方案:詳解如何實現進程間通信與自動保活機制

目錄 摘要 一、進程間保活的基本原理 二、具體步驟及代碼示例 三、常見問題與優化 四、總體方案 摘要 在一些需要長時間運行的應用程序中&#xff0c;確保進程在意外退出時能夠自動重啟是一項非常重要的任務。尤其是在嵌入式開發、后臺服務以及需要高可用性的場景下&#x…

Python-內置數據結構-list-tuple-bubble-字符串-bytes-bytesarray-切片-學習筆記

欠4年前自己的一份筆記&#xff0c;獻給今后的自己。 分類 數值型 int、float、complex、bool 序列對象 字符串 str 列表 list tuple 鍵值對 集合set 字典dict 數值型 int、float、complex、bool都是class&#x…

利用事務鉤子函數解決業務異步發送問題

利用事務鉤子函數解決業務異步發送問題 一、問題背景二、實現方案1、生產者代碼2、消費者代碼 三、測試與驗證1、未開啟事務場景2、開啟事務場景 四、項目結構及源碼 一、問題背景 在某項業務中&#xff0c;需要在事務完成后&#xff0c;寫入日志到某數據庫中。需要要么都成功&…

uniapp選擇相冊

概述 一款針對Android平臺下的圖片選擇器&#xff0c;支持從相冊獲取圖片、視頻、音頻&拍照&#xff0c;支持裁剪(單圖or多圖裁剪)、壓縮、主題自定義配置等功能&#xff0c;支持動態獲取權限&適配Android 5.0系統的開源圖片選擇框架。 支持Uniapp和Uniapp X下的Vue2、…