使用32位64位交叉編碼混淆來打敗靜態和動態分析工具
Ke Sun([email protected])
原文:http://en.wooyun.io/2015/12/08/33.html
0x00 摘要
混淆是一種能增加二進位制分析和逆向工程難度與成本的常用技術。主流的混淆技術都是著眼於使用與目標CPU相同的機器程式碼,在相同的處理器模式下,隱藏程式碼並進行控制。本文中引入了一種新的混淆方法,這一方法利用了64Windows系統中的32位/64位交叉模式編碼。針對靜態和動態分析工具的案例研究證明了這種混淆技術雖然簡單,但是十分有效。
0x01 64位Windows中的模式轉換
所有的64位Windows作業系統都能向下相容未修改過的 32位應用,這是透過WoW64(64位Windows上的32位Windows)子系統實現的。WoW64使用了3個動態連結庫(Wow64.dll,Wow64win.dll 和 Wow64cpu.dll),提供了一個相容層,用作64位核心與32位應用{1}之間的介面,藉此,處理器模式就可以在32位和64位之間動態地切換。
在任何時間中,處理器模式都是由當前程式碼段(CS)描述符中的控制位決定的。圖1就是一個段描述符的示意圖。L位(21位)是“64位程式碼段”控制標記:“值為1則說明這個程式碼段中的指令會在64位模式下執行,值為0則說明在這個程式碼段中的指令會在相容(32位)模式下執行。” {2}
圖1-段描述符的示意圖 {2}
64位Windows下的任何應用,無論是32位還是64位,在載入到記憶體中時,都至少有兩個程式碼段。這兩個程式碼段的32位地址空間對映是完全重合的,但是段選擇器是不同的:其中一個的選擇器是0x23,L標記為0(32位程式碼段);另一個的選擇器是0x33,L標記為1(64位程式碼段)。 在一個應用的PE(可移植可執行)標頭中,“Machine”欄位的標籤是32位還是64位PE決定了這個應用的預設程式碼段。
當遠分支指令把控制流從一個程式碼段上轉移到另一個有著不同L標記的程式碼段上時,處理器模式交換就會被觸發。例如,如果一個32位應用在64位Windows中執行,預設的CS選擇器就會是0x23,處理器會是32位模式。如果,使用了遠轉移來跳轉到一個選擇器是0x33的程式碼段上,那麼在執行完這條指令後,處理器模式就會切換到64位,在從32位向64位切換時也是一樣的。
有很多遠分支指令都可以用於觸發模式轉換,包括(1)遠轉移(2)遠呼叫(3)遠返回和(4)中斷返回。這些指令就像是不同維度的平行世界之間的傳送門,在需要時可以透過這些門穿梭於不同的世界。因為這種方便的可控模式交換,混淆技術才有了機會來使用交叉模式編碼,這種方法既可以用在32位應用中,也可以用在64位應用上。
唯一需要注意的是64位應用,在64位模式中使用的記憶體地址需要限制在低於2G的記憶體空間中,否則,在切換到32位模式時,會出現記憶體地址衝突。
0x02 交叉模式混淆的概念
所有的IA指令都可以分為兩類:相容交叉模式的指令和不相容交叉模式的指令。相容交叉模式指的是指令的機器程式碼在32位和64位模式下都是有效的,並且含義也都是完全相同的,否則指令就會被視作不相容交叉模式。
英特爾的軟體開發人員手冊中列出了每條指令及其可應用模式的詳細資訊。在這個指令表中,“64-bit Mode”欄位和“Compat/Leg Mode”(32位)欄位都顯示是“有效的”(類似於圖2中的“MOV r32, imm32”),這就是一條相容指令。如果其中任何一個欄位不是“有效的”,那麼這就是一條不相容指令。這兩類指令都可以用於交叉模式混淆。
圖2-相容與不相容指令示例
2.1相容指令
雖然相容指令的執行在32位和64位模式下都是相同的,但是,考慮到兩種模式的差異,得到的結果也有可能是不同的。圖3中就是一個簡單的例子。從圖中可以看到,無論是在32位還是64位模式下,在執行時反彙編同一組指令會得到完全相同的結果。
圖3-相容指令在不同模式下的執行示例
“call”只是簡單地呼叫了下一條指令“mov ebx, esp”,並且這個程式碼塊僅僅會檢查棧指標在“call”指令的執行前後,修改了多少位元組。由於棧框架大小的區別,在32位模式下,eax中的結果是4;在64位模式下,eax中的結果是8。這就證明了,同一組指令的結果要取決於模式,也就是說可以利用混淆資料或控制流來對抗某種單一模式的分析工具。
2.2不相容指令
利用不相容指令進行混淆更加直接,因為,這類指令只在一種模式下是有效的。一條64位的不相容指令要麼會被視作有效指令,要麼就在32位模式下解釋成完全不同的指令,反之亦然(如圖4),不支援處理動態模式轉換的分析工具在這時就會遇到問題。
圖4-不相容指令在不同模式下的執行示例
0x03 案例研究交叉模式混淆
一個很簡單的例子就能證明交叉模式混淆的有效性。圖5是交叉模式程式碼的示意圖,這些程式碼首先會作為32位原生指令來執行。然後,透過使用遠轉移,跳轉到CS 0x33,把處理器轉換成64位模式,並繼續執行64位原生指令(在32位模式中不相容)。64位程式碼在執行後會解碼另一組32位原生指令,在透過遠返回把處理器切換回32位模式後,接著這些32位指令就會執行。最終,這一部分的32位程式碼會解密出秘鑰。
圖5-使用了交叉模式編碼的示例程式示意圖
圖6中是這個交叉模式程式碼在命令列中執行的結果。在十六進位制中列印出的程式碼段選擇器證實了,處理器確實從32位轉換到了64位,又從64位轉換成了32位。
圖6-交叉模式程式碼示例在命令列中的執行
3.1靜態分析工具
當使用32位的IDA Pro來分析上面的交叉模式程式碼時,很明顯,在透過遠轉移進行模式交換後,IDA仍然會把64位的原生程式碼反彙編成32位的指令,導致反彙編結果與實際的64位指令出現偏差。(圖7)
圖7-對比IDA Pro的執行時反彙編與靜態反彙編
如果使用64位版本的IDA Pro,IDA仍然會在32位模式下分析這一交叉模式程式碼,因為IDA會自動把這些程式碼識別成一個32位應用。此時,再透過遠轉移來轉換模式,反彙編就會出錯,並把控制流帶到錯誤的地址(圖8)。
圖8-64位IDA Pro的靜態反彙編顯示了錯誤的遠轉移地址
除了廣泛使用的IDA,我們還使用了另一個靜態分析工具-Radare2來測試我們的交叉模式程式碼。Radare2是一個開源的命令列框架,支援多個平臺上的逆向工程。類似於IDA,Radare2在32位模式下無法正確地反彙編64位原生程式碼,而在64位下,無法正確地除了32位原生程式碼。
3.2動態分析工具
在執行時程式碼分析中,動態二進位制插樁(DBI)是一種廣泛應用的技術。在這次研究中,我們選擇了兩個常用的二進位制翻譯工具- DynamoRio 和 Pin來執行測試程式。
這兩個工具都無法處理從32位到64位的執行時模式轉換,並且在透過遠轉移進行模式轉換時會崩潰。圖9顯示,DynamoRio 和 Pin都無法在64位模式下,列印出程式碼段選擇器的值。
(a)
(b)
(c)
圖9-(a)命令列(b)DynamoRio(c)Pin執行交叉模式程式碼的情況
由於需要切換到32位模式,DynamoRio在執行64位應用時也遇到了類似的崩潰問題,而Pin直接停止執行,顯示錯誤資訊“不支援透過遠返回來轉換不同的程式碼段”。
有趣的是,在僅僅使用相容指令時,有時候DBI工具可能會在執行了用於切換模式的遠轉移後,繼續執行,但是,實際上模式並沒有切換。圖10中顯示,DynamoRio使用相容指令執行了程式碼,與2.1中討論的例子一樣。可以看到,程式執行到了模式交換點之後,但是,沒能真正的轉換到程式碼段 0x33,而是停留在了CS 0x23。eax中的返回值是4而不是8,這與直接執行時的結果不同,從而為DBI環境監測創造了機會。
(a)
(b)
圖9-(a)命令列(b)DynamoRio執行相容交叉模式的程式碼
3.3除錯工具
我們還發現,在除錯包含執行時模式切換的程式碼時,交叉模式程式碼還會給OllyDbg和WinDbg這樣的常用除錯工具造成問題。32位的OllyDbg(目前64位不可用)在從32位切換到6位模式後,無法繼續除錯。而64位的WinDbg可以正確的執行交叉模式程式碼,但是在交叉模式條件下,修改過的程式碼會出現單步執行問題。
0x04 總結
利用64位Windows系統向下相容32位程式的優勢,交叉模式編碼可以作為一種非常有效的混淆技術。目前,大多數靜態分析工具、DBI工具和除錯工具都是基於單一的處理器模式,這些工具在處理包含執行時模式交換的程式碼時就會遇到問題。而且,只要在設計時稍加註意,交叉模式程式碼還可以用於檢測DBI環境。
從理論上說,只要讓這些分析工具能適應動態模式交換,那麼交叉模式問題就會迎刃而解,只不過需要大量的工程努力。
0x05 致謝
感謝李曉寧,亞歐對此次研究和審閱做出的貢獻。
0x06 參考
- {1}https://en.wikipedia.org/wiki/WoW64
- {2}Intel® 64 and IA-32 Architectures Software Developer’s Manual
- {3}The Performance Cost of Shadow Stacks and Stack Canaries. Thurston H.Y. Dang, Petros Maniatis, David Wagner. ASIACCS 2015
- {4}Counterfeit Object-oriented Programming: On the Difficulty of Preventing Code Reuse Attacks in C++ Applications. Felix Schuster, Thomas Tendyck, Christopher Liebchen, Lucas Davi, Ahmad-Reza Sadeghi, Thorsten Holz. 36th IEEE Symposium on Security and Privacy (Oakland), May 2015
- {5}Exploring Control Flow Guard in Windows 10. Jack Tang. Trend Micro Threat Solution Team, 2015
- {6}ROP is Still Dangerous: Breaking Modern Defenses. Nicholas Carlini and David Wagner. 23rd USENIX Security Symposium, Berkeley 2014
- {7}Windows 10 Control Flow Guard Internals. MJ0011, POC 2014
- {8}Write Once, Pwn Anywhere. Yu Yang. Blackhat 2014
- {9}Hardware-Assisted Fine-Grained Control-Flow Integrity: Towards Efficient Protection of
- {10}Embedded Systems Against Software Exploitation. Lucas Davi, Patrick Koeberl, and Ahmad-Reza Sadeghi. DAC 2014
- {11}Transparent ROP Exploit Mitigation Using Indirect Branch Tracing. Vasilis Pappas, Michalis Polychronakis, and Angelos D. Keromytis. Columbia University, 22nd USENIX Security Symposium 2013
- {12}kBouncer: Efficient and Transparent ROP Mitigation. Vasilis Pappas. Columbia University 2012 Security Breaches as PMU Deviation: Detecting and Identifying Security Attacks Using
- {13}Performance Counters. Liwei Yuan, Weichao Xing, Haibo Chen, Binyu Zang. APSYS 2011
- {14}Transparent Runtime Shadow Stack: Protection against malicious return address modifications. Saravanan Sinnadurai, Qin Zhao, and Weng-Fai Wong. 2008
- {15}Control-Flow Integrity Principles, Implementations, and Applications. Martín Abadi, Mihai Budiu, Úlfar Erlingsson, Jay Ligatti. CCS2005
- {16}IROP – interesting ROP gadgets, Xiaoning Li/Nicholas Carlini, Source Boston 2015
相關文章
- 原始碼靜態分析工具:Infer2016-05-24原始碼
- Android:JNI與NDK(二)交叉編譯與動態庫,靜態庫2019-07-31Android編譯
- 關於MNN工程框架編譯出來的靜態庫和動態庫的使用2024-08-19框架編譯
- 偽靜態、靜態和動態的區別2020-12-18
- 為了簡寫這行程式碼,我竟使用靜態和動態編譯技術2023-10-31行程編譯
- Windows靜態庫和動態庫的建立和使用2013-05-06Windows
- apache動態編譯/靜態編譯區別2009-05-18Apache編譯
- 靜態代理和動態代理2019-05-15
- 靜態路由和動態路由2020-10-15路由
- C++中的靜態聯編和動態聯編介紹(轉)2007-08-15C++
- 動態圖和靜態圖的程式碼區別2020-10-03
- ios靜態庫和動態庫2018-04-22iOS
- java靜態代理和動態代理2016-04-15Java
- ABAP程式碼靜態分析工具SQF - Support Query Framework2020-07-08Framework
- PHP工具箱:PHPStan —— PHP 靜態程式碼分析工具2018-11-14PHP
- Linux下快速靜態編譯Qt以及Qt動態/靜態版本共存2018-03-11Linux編譯QT
- 常用Java靜態程式碼分析工具的分析與比較2012-09-09Java
- 機器學習的靜態特徵和動態特徵2022-11-13機器學習特徵
- cmake:生成靜態庫和動態庫2020-12-26
- 動態註冊和靜態註冊2018-05-21
- 靜態註冊和動態註冊2013-11-27
- 動態監聽和靜態監聽2014-04-27
- oracle listener 靜態和動態註冊2012-12-12Oracle
- oracle動態和靜態監聽listener2009-03-10Oracle
- 靜態合批和動態合批2024-10-01
- jdk的動態代理和靜態代理你還寫不出來嘛???2020-11-16JDK
- 藉助 Webpack 靜態分析能力實現程式碼動態載入2019-03-04Web
- AbsInt — 確保程式碼安全的靜態效能分析工具2022-03-10
- 什麼情況下需要進行靜態程式分析?常用Java靜態程式碼分析工具的優勢2020-08-06Java
- Xcode新增Shell指令碼打包靜態庫和動態庫2017-08-04XCode指令碼
- Java 靜態代理和動態代理的使用及原理解析2018-12-24Java
- HTML+CSS編寫靜態網站-42 使用開發者工具2017-07-21HTMLCSS網站
- 靜態SDRAM和動態SDRAM的區別2020-06-24
- Java中的靜態代理和動態代理2020-08-31Java
- 靜態路由和動態路由的比較2017-09-27路由
- 動態庫和靜態庫的區別2017-05-02
- oracle靜態監聽和動態監聽2015-12-18Oracle
- 英語的靜態句和動態句2006-09-24