吾愛破解 - LCG - LSG |安卓破解|病毒分析|破解軟件|www.dypczhxn.cn

 找回密碼
 注冊[Register]

QQ登錄

只需一步,快速開始

搜索
查看: 8751|回復: 116
上一主題 下一主題

[.NET逆向] .NET JIT脫殼指南與工具源碼

  [復制鏈接]
跳轉到指定樓層
樓主
wwh1004 發表于 2019-8-8 15:54 回帖獎勵

脫殼指南與工具源碼">.NET JIT脫殼指南與工具源碼

前言

JIT脫殼可能對很多人來說是很難的,因為網上沒有特別多的介紹,有的工具源碼也僅限于yck1509(ConfuserEx作者)的jitDumper3和基于這個工具的CodeCracker修改的ManagedJiter和DNGuard_HVM_Unpacker,然后還有CodeCracker自己寫的Simple_MSIL_Decryptor(很不穩定)。

要研究JIT脫殼需要先了解clr源碼。對于.NET 2.0~3.5可以看IDA反編譯mscorwks.dll和mscorjit.dll或者是看SSCLI的源碼,對于.NET 4.0+可以看coreclr的源碼。如果我沒記錯,coreclr是.NET 4.6分支出來的。

.NET可以說有3個大版本,分別是.NET 2.0 .NET 4.0 .NET 4.5,這3個版本的clr有很大變化。.NET 2.0的clr名稱是mscorwks.dll,jit名稱是mscorjit.dll。.NET 4.0的clr名稱變成了clr.dll,jit名稱變成了clrjit.dll,還有少量的clr和jit內部結構體的變化。.NET 4.5的clr名稱和jit名稱與.NET 4.0的相同,但是內部結構體有巨大變化,最明顯的是clr提供給jit編譯所需信息的接口ICorJitInfo的虛表結構和函數的定義,與.NET 4.0的完全不一樣。所以CodeCracker發布的幾個工具要用NetBox或者虛擬機安裝.NET 4.0來運行,CodeCracker的那幾個工具不支持.NET 4.5+。

本文要介紹的內容在.NET 2.0~4.72都是正確的,最新出的.NET 4.8有些變化,但是我沒去看有什么變化,所以本文不討論.NET 4.8。我的工具運行不了,我也懶得去修改我的工具了。源碼在文章后半部分會貼出,好早之前就上傳到github了,一直沒寫使用說明。

CLR與JIT簡介

這個部分我推薦看coreclr的文檔 Book of the Runtime ,非常不錯的資料,對CLR任何版本都是適用的,我就沒必要重復啰嗦一遍了。

JIT編譯流程

這個東西應該是非常重要的,必須要了解的,不然文章很多地方會看不懂,那些脫殼機的源碼也會看不懂。這里依然推薦看coreclr的文檔,RyuJIT Ooverview 雖然RyuJIT是.NET 4.5還是.NET 4.6才有的,但是老版本的JIT的編譯流程還是幾乎相同的。

Phases of RyuJIT 看不懂可以直接機翻,雖然有好多流程,但是實際上要了解的只有 Pre-import 和 Importation 這2個階段,這2個階段還會調用ICorJitInfo接口,我們要研究的就是這個接口。

從DoPrestub到compileMethod

現在我們可以打開coreclr源碼,找到 MethodDesc::DoPrestub 。CLR會為每個方法生成一個stub,stub最終都會跳轉到MethodDesc::DoPrestub,由MethodDesc::DoPrestub調用JIT編譯器。在編譯之前,MethodDesc::DoPrestub會進行參數檢查,并且判斷方法類型,其中包括泛型方法的泛型參數檢測。

Alt text

最終,DoPrestub會轉到jit的導出函數compileMethod,在coreclr里面也找得到對應的代碼 CILJit::compileMethod

Alt text

可以說所有的殼,都是通過Hook ICorJitCompiler虛表來進行jit解密的,沒有例外。

可能有人會問為什么不Hook更底層的函數,比如jitNativeCode,Compiler::compCompile等等,原因還是很簡單,Inline Hook這些函數很麻煩。尋找這些函數的地址還要通過特征匹配,如果JIT有點變動,特征就變了,就會出現匹配失敗,這也是CodeCracker的脫殼機不能在.NET 4.5+運行的原因之一。

可能還有人會問Hook這么淺層的導出函數,會不會出現不安全的情況,答案是不會的,因為有些殼同時自己實現了ICorJitInfo接口,在ICorJitInfo接口內進行解密操作。直接dump到的IL是對的,但是IL中的token會是加密的。所以脫殼機Hook更底層的Compiler::compCompile和網上說的Hook更底層的函數來解密是沒有什么依據的,Hook哪一層函數都是一樣的,dump到的IL不會變,token永遠是加密的,解密操作還在更底層進行,并且解密之后不會還原到IL里面!!!

CILJit::compileMethod不會執行實際的編譯,它會調用jitNativeCode,由jitNativeCode實例化Compiler類。實際上jitNativeCode也是一個包裝,負責調用Compiler::compCompile。

Alt text

JIT內部

先貼張JIT流程圖,看不懂的可以對著這個看看。

Alt text

Compiler::compCompile有2個重載方法,我們從最表層的說起。

Alt text

這個是jitNativeCode會調用的。CodeCracker的那個脫殼機通過hook jitNativeCode中call Compiler::compCompile來達到hook Compiler::compCompile的效果,在這里進行dump IL。

這個Compiler::compCompile依然是個包裝,沒有實際執行的部分。

Alt text

接下來是這個函數調用的Compiler::compCompileHelper,這個函數會初始化一些信息,EHcount是異常處理子句數量,maxStack是棧元素最大數量。

Alt text

接下來是局部變量表初始化。

Alt text

Alt text

這個locals是局部變量信息,對應的結構體是CORINFO_SIG_INFO。

Alt text

其中的字段pSig指向了#Blob堆中的LocalSig。脫殼機可以通過這個來dump局部變量簽名。當然,殼也可以直接抹掉這個LocalSig,通過ICorJitInfo這個接口來給jit提供局部變量信息,因為jit也是使用ICorJitInfo這個接口來獲取局部變量信息,而不是直接解析CORINFO_SIG_INFO.pSig。所以一些情況下dump pSig得到的局部變量簽名是無效的,要如何解密或者dump,這個大家自己研究了,我就不透露那么多了。

現在我們回到Compiler::compCompileHelper,繼續探究編譯流程。我們可以看到調用了fgFindBasicBlocks這個函數

Alt text

Alt text

fgFindBasicBlocks是生成基本塊的入口函數,和我那個控制流分析類庫一樣,要生成基本塊才能繼續分析。這個函數會調用ICorJitInfo::getEHinfo來獲取異常處理子句的信息。

Alt text

這個CORINFO_EH_CLAUSE結構體也是我們脫殼需要的。

Alt text

現在,我們獲取了解密方法體需要的3大信息,IL代碼,局部變量,異常處理子句。但是還記得我在前面說過IL指令中如果操作數是token,token是加密的嗎?是的,所以我們要繼續深入JIT。

我們應該來到importer.cpp,這里JIT會通過ICorJitInfo把IL指令轉化為GenTree,其中token需要轉化為JIT內部定義,所以token是不會被還原到IL代碼里的,需要自寫代碼解密并還原。

Alt text

這個是.NET 4.5+的token相關函數,.NET 4.5+引入了CORINFO_RESOLVED_TOKEN這個結構體,coreclr也用的這個結構體,里面的token就是IL指令中操作數的token,在.NET 2.0~3.5 .NET 4.0的時候還有個embedGenericHandle用來獲取token。這個函數是CodeCracker的脫殼機用來解密token的。

Alt text

整個JIT編譯流程,我們就算了解完畢了。

JitUnpacker

這個是我和畫眉一起寫的一個脫殼機,去年9月份左右開寫的,現在已經開源了整個框架,去掉了脫DNG和其它一些殼的代碼,只留下了通用的脫殼部分。所以叫JitUnpacker-Framework更合適,GitHub:JitUnpacker-Framework 一次性開源后我不會繼續維護這個倉庫,僅供研究使用,注意!!!

如果要研究JIT脫殼,我還是非常推薦先看我的這個開源版本JitUnpacker的代碼,這個JitUnpacker支持.NET 2.0~3.5 .NET 4.0~4.72(不支持.NET 4.8,我沒安裝.NET 4.8,所以沒做支持)。而且結構體定義全部是正確的,關鍵地方的注釋都有。CodeCracker的那個脫殼機代碼太亂了,而且對泛型支持,值類型支持不太好,最關鍵的是結構體定義是錯的,部分代碼也是錯的,會誤導人。

簡介

整個脫殼機有2大部分。

Alt text

第一個是文件夾Runtime里面的內容,第二個是Unpackers文件夾里面的內容。

Runtime提供了運行時相關信息,比如DoPrestub的包裝,JitHook的接口之類的。

Unpackers是脫殼邏輯的代碼,實現IMethodDumper IUnpacker IUnpackerDetector這三個接口就可以了。Unknown文件夾是和de4dot參數-p un類似的東西,可以處理沒反脫殼的殼。

Runtime

這個是CORINFO_METHOD_INFO的包裝,因為CORINFO_METHOD_INFO結構體在.NET 2.0和.NET 4.0+有區別,所以有個包裝。

Alt text

這個是JitHook的接口,實現這個接口,為IMethodDumper提供所需信息即可。目前已經內置了CodeCracker脫殼機的hook方式(準確的說式yck1509的,CodeCracker只是做了些修改)和compileMethod虛表hook方式。

Alt text

Alt text

由于值類型的存在,所以有了UnboxingStub,對比方法句柄的時候,我們不能直接對比,需要這樣。

Alt text

接下來是RuntimePatcher,首先要patch的是canInline,如果不patch這里,讓一些方法被內聯編譯,脫殼會出錯。然后還有類靜態構造器的檢測,編譯方法的時候DoPrestub會檢查類靜態構造器有沒有運行過,如果沒運行,CLR會先運行類靜態構造器,導致運行我們脫殼機之外的代碼。最后一個patch的地方是泛型檢測,DoPrestub會檢測泛型參數,如果沒有泛型參數,會禁止編譯。

Alt text

類靜態構造器運行檢測的代碼沒在coreclr里面找到,就不貼了。下面是泛型參數檢測。

Alt text

其它

這里就是些雜七雜八的東西了。首先要提一下的是LoadMethodHandles,CodeCracker的代碼里面會特別處理泛型,但是那個是錯的。

我直接調用ResolveMethodHandle。

Alt text

CodeCracker打算實例化泛型方法,但是其實這是沒用的,我特意去看了coreclr源碼,也做過測試,這樣得到的方法句柄是和直接調用ResolveMethodHandle得到的一樣的。

Alt text

第二個要提的是CLR內部的UnboxingStub,在處理值類型的方法的時候,CLR會生成這個,如果直接DoPrestub,CLR是不會讓JIT編譯這個方法的,要調用GetWrappedMethodDesc,用這個返回值給DoPrestub才能觸發JIT。

Alt text

CodeCracker的處理方法是直接Invoke,然后在hook到的compCompile里面直接寫入0xC3,也就是ret指令。

Alt text

Alt text

這樣JIT脫殼就大體介紹完成了。

使用方法

https://github.com/wwh1004/JitUnpacker-Framework clone我的代碼到本地,注意把子模塊一起clone。然后編譯,生成文件。你會看到一個.bat文件

Alt text

然后下載我的ToolLoader https://github.com/wwh1004/ToolLoader 這個里面有編譯好的,下載之后只需要把這5個文件復制出來。

Alt text

現在,你需要下載好mscorwks.dll mscorjit.dll clr.dll clrjit.dll的符號文件,怎么下載別問我了,x64dbg windbg都可以下載,然后修改這里的YOUR_SYMBOLS_PATH

Alt text

比如我的是E:\Symbols,那就改成這樣,然后保存。

Alt text

運行RuntimeFunctionConfigGenerator.bat,會生成"JitUnpacker.RuntimeFunctions.CLR20.x86.config"和"JitUnpacker.RuntimeFunctions.CLR40.x86.config"這2個配置文件。

Alt text

把要脫殼的文件,包括相關的dll一起復制到JitUnpacker.dll所在目錄,shift+右鍵點擊文件夾,選擇在此處打開命令行窗口。

可以先看看JitUnpacker參數

Alt text

-f 指定要脫殼的文件的路徑

-hook-type 指定jithook的類型,這個翻源碼找得到有什么類型,默認用inlinehook

其它的參數自己看得懂了。

找個CodeCracker的工具做示范,比如SimpleByteArrayInit.exe,用dnSpy可以知道這個是.NET 2.0 x86的

Alt text

然后命令行里面輸入"Tool.Loader.CLR20.x86.exe JitUnpacker.dll -f SimpleByteArrayInit.exe",回車即可。

Alt text

寫在最后

我不接單,不要私信找我,也不要通過各種聊天方式加我好友!!!

DNG等殼脫殼代碼不會出現在開源版本的JitUnpacker-Framework中,也不要問我私有版本的JitUnpacker的代碼,這些不會放出的!!!

如果看不懂文章,或者不會使用文章給出的工具,可以自己多研究研究,這個我不會回復。當初一點資料都沒,CodeCracker的源碼還一堆錯誤的時候,還是和畫眉一點一點研究,寫出了這個脫殼機。

如果脫殼機有BUG,或者不能在某個.NET版本上工作,嘗試其它.NET版本,我不會繼續更新這個開源版本的JitUnpacker-Framework,這個倉庫僅供研究使用!!!

免費評分

參與人數 34吾愛幣 +31 熱心值 +33 收起 理由
Lucifer_BW + 1 + 1 熱心回復!
tchivs + 1 + 1 用心討論,共獲提升!
dns2018 + 1 [email protected]
柊痕 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
N0LL + 1 + 1 [email protected]
我是一個小白 + 1 + 1 [email protected]
簡單單單 + 1 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
gsyifan + 1 + 1 [email protected]
spll6 + 1 + 1 這個厲害了,DNG怎么脫
yaoyao7 + 1 + 1 [email protected]
zz0147 + 1 + 1 我很贊同!
5omggx + 1 + 1 膜拜大佬
3yu3 + 2 + 1 用心討論,共獲提升!
非凡公子 + 1 + 1 感謝大佬分享
psx1lin + 1 用心討論,共獲提升!
zx575645128 + 1 + 1 我很贊同!
情話布墨 + 1 + 1 頂一下wwh老哥。
笙若 + 1 + 1 [email protected]
Ouyang520 + 1 + 1 熱心回復!
limao2630 + 1 + 1 我很贊同!
哈哈呵 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
yao564100 + 1 很是辛苦!
nj001 + 1 + 1 我很贊同!
despy + 1 + 1 [email protected]
CLRSCR + 1 + 1 用心討論,共獲提升!
evea + 1 + 1 給力
testunpack + 1 + 1 你這個一流高手 年薪百萬不是夢!
阿呆哥 + 1 感謝發布原創作品,吾愛破解論壇因你更精彩!
Ravey + 1 + 1 [email protected]
hszt + 1 + 1 寫這么多,辛苦了
平淡最真 + 1 + 1 熱心回復!
拿破輪胎 + 2 + 1 用心討論,共獲提升!
201 + 1 歡迎分析討論交流,吾愛破解論壇有你更精彩!
asd2940155 + 1 + 1 熱心回復!

查看全部評分

本帖被以下淘專輯推薦:

發帖前要善用論壇搜索功能,那里可能會有你要找的答案或者已經有人發布過相同內容了,請勿重復發帖。

來自 2#
 樓主| wwh1004 發表于 2019-8-8 15:57 <
文章里面沒有太多的代碼,具體的代碼我完全開源了,注釋也有的,應該算詳細,在github上, https://github.com/wwh1004/JitUnpacker-Framework
這個項目代碼比較多,因為目的是支持x86全版本.NET,目前不支持.NET 4.8,有條件的可以自己修復一下
推薦
 樓主| wwh1004 發表于 2019-8-8 16:06 <
本帖最后由 wwh1004 于 2019-8-11 18:34 編輯

順帶一提VMP 3.4,VMP 3.4加入了對.NET的支持,默認帶壓縮輸出文件,但是也可以使用我的脫殼機加參數--preserve-all搞定

之前說錯了,不是JIT保護,具體的可以看 http://www.dypczhxn.cn/forum.php ... 16&pid=27376490



當然,這個只是反混淆VMP .NET的第一步,VMP不可能那么簡單,還有mutation和virtualization需要處理

免費評分

參與人數 3吾愛幣 +6 熱心值 +3 收起 理由
liphily + 3 + 1 用心討論,共獲提升!
軟妹幣玩家 + 1 + 1 用心討論,共獲提升!
拿破輪胎 + 2 + 1 [email protected]

查看全部評分

推薦
31818350 發表于 2019-8-10 16:20
@wwh1004 請問你是怎么把一個工程中的某個項目設置為子模塊的?是手動在.gitmodules下添加的嗎?
[submodule "Libraries/dnlib"]
        path = Libraries/dnlib
        url = https://github.com/0xd4d/dnlib.git
[submodule "Libraries/MetadataLocator"]
        path = Libraries/MetadataLocator
        url = https://github.com/wwh1004/MetadataLocator.git

你是不是先把dnlib克隆到你解決方案的子目錄下,然后用記事本打開.gitmodules,手動添加了上述內容,然后提交到github?
5#
zxzt 發表于 2019-8-8 16:07
占樓,火鉗留名
6#
拿破輪胎 發表于 2019-8-8 16:41
樓主牛B,
7#
軟妹幣玩家 發表于 2019-8-8 16:49


真的是很高深了,感謝開源給了學習機會
8#
digitalhouse 發表于 2019-8-8 16:53
完全看不懂...
9#
羔羊 發表于 2019-8-8 16:55
感謝開源 ~~~~~~
10#
w108808888 發表于 2019-8-8 17:01
蟹蟹樓主的經驗分享
11#
it1024 發表于 2019-8-8 17:02
占樓,樓層招租
您需要登錄后才可以回帖 登錄 | 注冊[Register]

本版積分規則 警告:禁止回復與主題無關內容,違者重罰!

快速回復 收藏帖子 返回列表 搜索

RSS訂閱|小黑屋|聯系我們|吾愛破解 - LCG - LSG ( 京ICP備16042023號 | 京公網安備 11010502030087號 )

GMT+8, 2019-10-17 16:09

Powered by Discuz!

© 2001-2017 Comsenz Inc.

快速回復 返回頂部 返回列表
现在靠网络挣钱的方法