相信有很多朋友在遇到應用程式各種奇葩問題後,拿下來一個dump檔案,辛辛苦苦分析了大半天,終于在某一個線程的調用棧上找到了一個可疑的方法,但 windbg 常常是以 <code>彙編</code> 的方式顯示方法代碼的,可惜的是,現如今的彙編,有多少像我們這些速成系碼農還看的懂呢? 😂😂😂
接下來尖銳的問題就來了,如何将這些彙編代碼轉成 C# 源代碼,如果轉不成源代碼轉成 IL代碼也好呀,起碼我努努力還是能試着看的懂的。。。
本篇我就來分享下如何把 dump 中的方法源碼提取出來。
為了能夠示範友善,我用 .netcore 3.1 寫了一個簡單的demo,代碼如下:
将程式跑起來後,使用 <code>任務管理器</code>, <code>adplus</code>, <code>procdump</code> 随便哪一個抓取 dump 都可以。
如果你的程式足夠簡單,可以直接用 lm 擷取程式中所有的子產品,然後使用 savemodule 将子產品導出為 <code>exe/dll</code> 實體檔案,如下所示:
使用 lm 提取出所有子產品
可以隐約的看到,我有一個名為 <code>ConsoleApp6_2c2264b0000</code> 的子產品,這就是我要提取的 <code>ConsoleApp6.exe</code>,順便提一下,那個很礙眼的 <code>ConsoleApp6 (deferred)</code> 是 PE 檔案,要問我怎麼知道的? 試一下就好啦😁
使用 savemodule 提取
從上面第一行 start 列中可以看到 ConsoleApp6_2c2264b0000 的開始位址為 <code>000002c2264b0000</code>,接下來用 savemodule 導出到 <code>E:\dump</code>。
然後就可以看到 <code>E:\dump</code> 裡面多了一個 ConsoleApp6.exe 🐂,有了這玩意看源碼就簡單多了,直接用 ILSpy 對其進行反編譯即可。
實際開發中有可能你的程式非常複雜,使用 lm 直接提取子產品是找不到的,最好的辦法就是 <code>按圖索骥</code> 的方式尋找你要的 module,還記得 <code>CLR Via C#</code> 上說過的 AppDomain,Assembly,Module 之間的關系嗎?如果要詳細了解,建議翻看一下,這裡我大概簡述一下, Assembly 一般包含若幹個 <code>Module + 資源檔案</code>, Assembly 就是一個 dll/exe 檔案,程式跑起來後,Assembly是被妥善安置在 AppDomain 中的。
有了上面這個思想,是不是就可以通過這個流程 <code>AppDomain -> Assembly -> Module</code> 找到 module 啦? 接下來看看如何去實作。
使用 !dumpdomain 找到 ConsoleApp6 所在的程式域
尴尬,記得不錯的話,在 .NET Framework 中預設會有三個應用程式域。
System Domain
Shared Domain
Domain 1
咋到 .NET Core 上就丢了一個 <code>Shard Domain</code> 呢 😄😄😄,先不管啦,從圖中可以清楚的看到 Domian 1 上有我的dll <code>E:\net5\ConsoleApp3\ConsoleApp6\bin\Debug\netcoreapp3.1\ConsoleApp6.dll</code>,同時還有一個 module 的位址 <code>00007ffa45b5f7d0</code>。
使用 !dumpmodule 擷取 module 詳細資訊
從上面的 <code>BaseAddress: 000002C2264B0000</code> 可以看出,module 的start 位址為 000002C2264B0000,是不是和剛才我用 lm 提取出來的位址一緻哈,最後用 savemodule 導出一下就可以啦,為了做區分,我取名為 ConsoleApp7.exe, 如下所示:
哈哈,剩下來的就是用 ILSpy 反編譯 CosoleApp7 啦。
更多高品質幹貨:參見我的 GitHub: dotnetfly