本文假設您熟悉 .Net 與 C#
摘要
.NET 體系結構的優勢之一在於,利用該體系結構構建的程序集包含很多有用的信息,使用中間語言反匯編程序 ILDASM 即可恢復這些信息。但是這樣會帶來另一個問題,就是可以訪問您的二進制代碼的人能夠以非常近似的手段恢復原始源代碼。作者將在文中介紹程序模糊處理,該處 理可作為一種阻止反相工程的手段。此外,他們還將討論可用的不同類型的模糊處理技術,並示范 Visual Studio .Net 2003 中包含的新模糊處理工具。
本頁內容
反匯編
反編譯
深入了解模糊處理
重命名元數據
刪除非基本元數據
其他技術
使用 Dotfuscator Community Edition
檢查映射文件
模糊處理程序的缺陷
小結
迄 今為止,從減輕部署和版本控制的負擔,到自描述二進制數據所實現的豐富 IDE 功能,您可能已經熟悉了這些元數據豐富的 Microsoft® .NET Framework 體系結構帶來的所有好處。您可能不知道元數據的這種易用性帶來的一個目前對於大多數開發人員來說還沒有注意到的問題。為公共語言運行庫 (CLR) 編寫的程序更易於進行反相工程。不管怎麼說,這並不是 .NET Framework 設計中的缺陷;它只是一種現代的、中間編譯語言(Java 語言應用程序具有同樣的特征)的現實狀況。Java 和 .NET Framework 都使用內嵌在可執行代碼中的豐富元數據:在 Java 中是字節碼,在 .Net 中是 Microsoft 中間語言 (MSIL)。由於比二進制機器碼要高級很多,可執行文件充滿了可以輕松破解的信息。
借助於諸如 ILDASM 這樣的工具(隨同 .NET Framework SDK 一同發布的 MSIL 反匯編程序)或者類似於 Anakrino 和 Reflector for .Net 這樣的反匯編程序,任何人都可以輕松地查看您的程序集並將其反相工程為可讀的源代碼。黑客可以搜索安全缺陷,以探究、竊取獨特的創意並破譯程序。這足以使您猶豫不決。
盡 管如此,請不必擔心。有一種模糊處理解決方案可幫助您防止反相工程。模糊處理是為程序集中的符號提供無縫重命名的一項技術,它還提供了其他技巧以阻止反匯 編程序。如果運用適當,模糊處理可以大幅度提升應用程序防止反相工程的能力,同時保持應用程序的完整無缺。模糊處理技術通常用於 Java 環境中,多年來已幫助了眾多公司保護他們的基於 Java 技術產品的知識產權。
現在已有多家第三方通過創建 .NET代碼的模糊處理程序來予以響應。通過與我們公司 PreEmptive Solutions 合作,Microsoft 在 Visual Studio?.Net 2003 中包含了 Dotfuscator Community Edition,而 PreEmptive Solutions 也推出了多種模糊處理程序軟件包。
通過使用 Dotfuscator Community Edition,本文將向您講授與模糊處理有關的所有內容(同時簡要介紹一下反匯編)、通常可用的模糊處理的類型以及利用模糊處理程序工作時需要解決的一些問題。
為演示反編譯和模糊處理,我們將使用經典的 Vexed 游戲的一個開放源代碼實現。Vexed.NET 由 Roey Ben-amotz 編寫,可從 http://vexeddotnet.benamotz.com 獲得。這是一個益智類游戲,您的目標就是將相似的塊移到一起,從而使它們消失。下面是Vexed.Net 源代碼中的一個簡單方法:
public void undo() { if (numOfMoves>0) { numOfMoves--; if (_UserMoves.Length>=2) _UserMoves = _UserMoves.Substring(0, _UserMoves.Length02); this.loadBoard(this.moveHistory[numOfMmoves - (numOfMoves/50) * 50]); this.drawBoard(this.gr); }
得到不斷的重新使用。通常,一個重載歸納項目將有高達 35% 的方法被重命名為“a”。
要了解重命名對反編譯代碼的影響,請查看重命名處理後的 undo 方法:
public void c() { if (this.p > 0) { this.p = this.p - 1; if (this.r.Length >= 2) this.r = this.r.Substring(0, this.r.Length - 2); this.a(this.q[this.p - this.p / 50 * 50]); this.a(this.e); }}
您可以看出來,在沒有經過任何模糊處理,這個方法就已經比較難於理解了。
返回頁首
刪除非基本元數據
在 編譯過的、基於 .Net 的應用程序中,並非所有的元數據在運行時都會得到使用。其中的一些數據將由其他工具使用(例如,設計器、IDE和調試器)。例如,如果您在 C# 中的類型上定義了一個名為“Size”的屬性,則編譯器將省略屬性名“Size”的元數據,並將該名稱與實現 get 和 set 操作的那些方法關聯起來(它們被分別命名為“get_Size”和“set_Size”)。當您開始編寫設置 Size 屬性的代碼時,編譯器將始終生成一個對方法“size-Size”本身的調用,並且決不會通過其名稱引用該屬性。事實上,屬性的名稱供 IDE 和使用您的代碼的開發人員使用;CLR 從不訪問它。
如果只是由運行庫而不是其他工具使用您的應用程序,那麼模糊處理程序刪除這種類型的元數據就是安全的。除了屬性名,事件名和方法參數名也在這個范疇之列。Dotfuscator Community Edition 在它認為這樣做安全時會刪除所有這些類型的元數據。
返回頁首
其他技術
Dotfuscator Community Edition 使用我們剛剛介紹的技術來提供良好的模糊處理,但是您應該知道模糊處理技術在提供更為強大的保護的同時,可能還會阻止反相工程的進行。 Dotfuscator Professional Edition 實現了很多其他技術,其中包括控制流模糊處理、字符串加密、增量模糊處理和規模降低。
控制流是一種強大的模糊處理技術,它的目的是隱藏一系列指令的意圖而又不會更改邏輯。更為重要的是,它可用來刪除反編譯程序為了忠實重現高級源代碼語句(比如 if-then-else 語句和循環)而尋找的那些線索。事實上,這項技術試圖破壞反匯編程序的工作。
要查看運行效果,在運用重命名和控制流模糊處理後,再次研究反編譯後的undo方法(請參見圖 3)。您可以看到反匯編程序並沒有生成原始的嵌套 if 語句,而是生成了一個 if 語句、兩個嵌套 while 循環和一些將其捆綁在一起的 goto。標簽 i1 被引用了,但它不是由反編譯程序生成的(我們假定它是一個反編譯程序錯誤)。
字 符串加密是一種將簡單加密算法應用到嵌入您的應用程序中的字符串的技術。如上所述,在運行時執行的任何加密(或特殊情況下的解密)從根本上講都是不安全 的。也就是說,技術高超的黑客事實上是可以破解它的,但對於應用程序代碼中的字符串而言,這樣做是值得的。我們所面對的事實是,如果黑客希望進入您的代 碼,那麼他們不會盲目地開始搜索已重命名的類型。他們可能確實會搜索“無效許可證密鑰”,這會將他們直接引導到執行許可證處理的代碼。對字符串進行搜索非 常簡單;字符串加密設置有保護,這是因為在編譯的密碼中只存在加密的版本。
增量模糊處理有助於發布修補程序來解決客戶在面對模糊處理時碰到 的問題。修復代碼中的錯誤時經常會創建或刪除類、方法或字段。更改代碼(例如,添加或刪除某個方法)可能會導致隨後的模糊處理運行,從而使事物的重命名稍 有不同。先前稱為“a”的名稱現在可能稱為“b”。遺憾的是,如何不同地進行重命名和不同地重命名哪些內容卻不容易弄清楚。
增量模糊處理可 以解決這一問題。Dotfuscator 將創建一個映射文件以告知您它是如何執行重命名的。但是,這個映射文件在隨後的運行中同樣可用作對 Dotfuscator 的輸入,以指示先前使用的重命名應在任何可能的地方再次使用。如果發布您的產品,然後修補一些類,Dotfuscator 就會以一種模仿其先前重命名方案的方式運行。這樣,您就可以只將修補過的類發布給您的客戶。
減小規模不會嚴格地阻止反相工程,但這裡仍值得 提一提,因為模糊處理程序幾乎始終必須要在輸入程序集上執行依賴性分析。因此,模糊處理程序不僅可以很好地進行模糊處理,更好的是,它還可以利用對您的應 用程序的了解來刪除您的程序沒有使用的代碼。看起來有點奇怪,實際上,刪除未使用的代碼非常容易,那麼,是誰編寫了這些不使用的代碼呢?答案是,我們所有 的人。此外,我們都使用其他人編寫的、可重用的庫和類型。
可重用代碼意味著存在一些可處理許多用例的隨附代碼;但在任何給定的應用程序中, 您通常只使用這些眾多用例中的一種或兩種。高級模糊處理程序可以確定這一點並刪除所有未使用的代碼(而且,是從已編譯的程序集而非源文件中刪除)。結果 是,輸出中所包含的正是您的應用程序不再需要的類型和方法。較小的應用程序具有節省計算資源和縮短加載時間等好處。這些好處對於在 .Net Compact Framework 上運行的應用程序或分布式應用程序尤為重要。
返回頁首
使用 Dotfuscator Community Edition
現 在讓我們使用 Dotfuscator Community Edition 來模糊處理 Vexed 應用程序。Dotfuscator Community Edition 使用一個配置文件來指定特定應用程序的模糊處理設置。它讓一個 GUI 來幫助您輕松創建和維護配置文件,以及運行模糊處理程序並檢查輸出。此外,Dotfuscator Community Edition 的命令行界面允許您將模糊處理輕松集成到您自動生成過程中。您可以從 Visual Studio .Net 2003 的工具菜單直接啟動 GUI。
要 配置 Vexed 以進行模糊處理,您需要在 Dotfuscator Community Edition GUI 中指定 3 項:輸入程序集、映射文件位置和輸出目錄。輸入程序集(Dotfuscator 稱之為“觸發器程序集”)在 Trigger 選項卡上指定。您可以在這裡根據所需添加任意多的程序集,但對 Vexed 應用程序來說只需要一個。
在“Rename | Options”選項卡上指定映射文件的位置(請參見圖 4)。 映射文件中含有原始名稱和被模糊處理名稱之間的明確名稱映射,這些信息至關重要。重要的一點是,對應用程序進行模糊處理後,要保存該文件;如果沒有它,您 就不能輕松地對模糊處理過的應用程序進行查錯。由於其重要性,Dotfuscator 在默認情況下不會改寫現有映射文件,除非您顯式地選中 "Overwrite Map file" 框。
最後,“Build”選項卡允許您指定放置經過模糊處理的應用程序的目錄。完成上述工作 後,就可以對應用程序進行模糊處理了。您可以保存配置文件以備後用,然後可以在“Build”選項卡上按“Build”按鈕,或在工具欄上使用 “Play”按鈕。在構建時,Dotfuscator 會在 GUI 的輸出窗格中顯示進度信息。在“Options”選項卡上選擇 QuIEt 或者 Verbose,可以控制在這裡顯示的信息量。
一旦完成生成,您就可以在 Output 選項卡上浏覽結果,如圖 5 所示。如您所見,Dotfuscator 顯示了一個與對象浏覽器類似的應用程序圖形視圖。新名稱位於視圖中原始名稱的正下方。在此圖中,您會看到名為“board”的類被重命名為“h”,具有不同簽名的兩個方法(init 和 ToImage)都被重命名為“a”。
返回頁首
檢查映射文件
Dotfuscator 生成的映射文件是一種 XML 格式的文件,這種文件除包含上述名稱映射外,還包含一些統計數據,這些數據指出重命名過程的有效性。圖 6 匯總了對 Vexed 應用程序進行模糊處理後類型和方法的統計。
映 射文件還被用於執行增量模糊處理。此過程允許您從以前的運行中導入名稱,這樣會通知模糊處理程序采用與以前同樣的方式來執行重命名。如果為一個經模糊處理 的應用程序發布修補程序(或新插件),您可以使用與原始版本相同的名稱集對更新程序進行模糊處理。這對維護多個相互依賴的應用程序的企業開發小組特別有 用。
返回頁首
模糊處理程序的缺陷
有關復雜應用程序的模糊處理(特別是重命名)比較棘手,它對正確配置高度敏感。如果不慎,模糊處理程序就會中斷您的應用程序。在本部分中,我們將討論一些使用模糊處理程序時可能出現的常見問題。
首 先,如果您的應用程序包含強名稱程序集,則您需要多做一些工作。強名稱程序集是經過數字簽名的,允許運行庫確定是否已在簽名後改變了程序集。簽名是一個利 用 RSA 公鑰/私鑰對的私鑰簽名的 SHA1 哈希值。此簽名和公鑰都被嵌入到程序集的元數據中。因為模糊處理程序將修改程序,所以在模糊處理後進行簽名非常重要。在開發過程中和進行模糊處理之前,您 應該對程序集延遲簽名,然後完成簽名過程。有關延遲簽名程序集的詳細信息,請參閱 .Net Framework 文檔。請記住,在測試延遲簽名的程序集時,關閉強名稱驗證。
使用 Reflection API 和動態類加載還將增加模糊過程的復雜性。由於這些實用程序是動態的,所以它們優於大多數模糊處理程序使用的靜態分析。請考慮下列 C# 代碼片段,該代碼片段按名稱獲取類型並動態地將其實例化,然後將類型轉換返回給接口:
public MyInterface GetNewType() { Type type = Type.GetType( GetUserInputString(), true ); object newInstance = Activator.CreateInstance( type ); return newInstance as MyInterface;}
類型的名稱來自另一個方法。GetUserInputString 可能要求用戶輸入一個字符串,也可能從數據庫中檢索一個字符串。不論采用哪種方式,代碼中都不顯示靜態分析可恢復的類型名稱,因此,無法了解輸入程序集中 的哪些類型可能會采用此方式來進行實例化。在此情況下采用的解決方案是防止對實現 MyInterface 的所有潛在的可加載類型進行重命名(請注意,仍可以執行方法和字段重命名)。因此,手動配置和掌握一些有關要進行模糊處理的應用程序的知識在這裡非常重 要。Dotfuscator Community Edition 為您提供了多種工具來防止對所選類型、方法或字段進行重命名。您可以挑選和選擇獨特的名稱;或者,您可以使用正則表達式和其他標准(例如作用域的可見性) 來編寫排除規則。例如,您可以將所有的公共方法排除在重命名之外。
在您已部署了一個經模糊處理的應用程序並嘗試支持它時,使用模糊處理程序會產生另一個問題。假定應用程序將拋出一個異常(對大多數人而言,都會發生該情形)並且客戶向您發送如下的堆棧轉儲:
System.Exception: A serious error has occurred at cv.a() at cv..ctor(Hashtable A_0) at ar.a(di A_0) at ae.a(String[] A_0)
顯然,上述堆棧轉儲所含的信息少於來自未模糊處理的程序所含的信息。好的方面是,您可以使用模糊處理期間生成的映射文件將堆棧跟蹤解碼 回原始代碼。壞的方面是,堆棧跟蹤中的消息有時不足以明確地從映射文件中檢索出原始符號。例如,請注意在轉儲中省略了方法返回類型。在用增強的重載歸納重 命名算法模糊處理的應用程序中,或許只有返回類型不同的方法才會被重命名為相同的名稱。因此,堆棧跟蹤可能是任意的。在大多數情況下,您可以縮小檢索范 圍,以便更有把握找到原始名稱。要獲得幫助,Dotfuscator Professional 為您提供了一個工具以自動將堆棧跟蹤轉換回不招人喜歡的原始方法。
返回頁首
小結
您 可以防止黑客使用隨處可得的 ILDASM 實用程序對您的應用程序進行惡意處理。您可以用模糊處理程序來保護代碼。模糊處理可以有效阻止反相工程。使用 Visual Studio .Net 2003 產品中提供的 Dotfuscator Community Edition,只需點擊幾下鼠標即可進行良好的模糊處理。
有關文章,請參閱
Inside Microsoft .Net IL Assembler by Serge Lidin (Microsoft Press, 2002)
Dotfuscator FAQ
有關背景信息,請參閱
Ildasm.exe Tutorial
Anakrino
http://vexeddotnet.benamotz.com
http://www.preemptive.com
GabrIEl Torok 是 PreEmptive Solutions 的總裁。他與別人合著有 Javascript Primer Plus 和 Java Primer Plus,這兩本書均由 Macmillan 出版。GabrIEl 在世界各地的開發會議上發表演講並講授課程。
Bill Leach 是 PreEmptive Solutions 的首席技術官。他是 Dotfuscator 產品線的架構師和技術主管。Bill 還擔任了軟件開發書籍和文章的技術評論。
轉到原英文頁面
返回頁首
Trackback: http://tb.blog.csdn.Net/TrackBack.ASPx?PostId=1180520
Trackback: http://tb.blog.csdn.Net/TrackBack.ASPx?PostId=1487566