防止對 Visual Basic .NET 或 C# 代碼進行反相工程

來源:互聯網
上載者:User
發布日期: 12/28/2004 | 更新日期: 12/28/2004

Gabriel Torok和 Bill Leach

本文假設您熟悉 .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);  }}


反組譯碼

.NET Framework SDK 附帶有一個名為 ILDASM 的反組譯碼工具 + 生產力,該工具允許您將 .NET Framework 程式集反編譯為 IL 組合語言語句。為了啟動 ILDASM,您必須確保安裝了 .NET Framework SDK,並在命令列中輸入 ILDASM,然後是您希望進行反組譯碼的程式名。在當前例子中,我們將輸入“ILDASM vexed.net.exe”。這樣將啟動 ILDASM UI,它可用於瀏覽任何基於 .NET Framework 的應用程式的結構。圖 1 顯示了經過反組譯碼的 undo 方法。

返回頁首


反編譯

如果您認為只有少數真正瞭解 IL 組合語言的人才會看到並理解您的原始碼,請牢記反編譯並不會到此為止。我們可以使用反編譯器來建立實際的原始碼。這些工具 + 生產力可以直接將 .NET 程式集反編譯為如 C#、 Visual Basic .NET 或 C++ 這樣的進階語言。讓我們看一下由 Anakrino 反組譯工具產生的 undo 方法:

public void undo() {  if (this.numOfMoves > 0) {    this.numOfMoves =       this.numOfMoves - 1;    if (this._UserMoves.Length >= 2)      this._UserMoves =            this._UserMoves.Substring(0, this._UserMoves.Length - 2);      this.loadBoard(           this.moveHistory[this.numOfMoves -               this.numOfMoves / 50 * 50]);      this.drawBoard(this.gr);    }}

您可以看到,結果幾乎與原始代碼完全相同。稍後,我們將回到這裡來查看經過模糊處理後的結果。

返回頁首


深入瞭解模糊處理

模糊處理是使用一組相關技術來實現的。模糊處理的目的是隱藏程式的意圖而又不改變其運行時行為。它不是加密,但對於 .NET 代碼而言,它比加密可能更勝一籌。您可以加密 .NET 程式集,使它們完全不可讀。但是,該方法會造成一個典型的進退兩難的局面,這是因為運行庫必須執行未加密代碼,解密密鑰必須與已加密程式儲存在一起。因此,可建立一個自動化的工具 + 生產力來修復金鑰、解密代碼,然後以 IL 的原始形式將其寫到磁碟上。一旦發生這種情況,程式就完全暴露在反編譯之下了。

我們可以將加密比作是將包含六道菜的套餐鎖到箱子裡。只有預定的用餐者(在本例中為 CLR)才有鑰匙,而且我們不想讓任何其他人知道他或她將要吃什麼。遺憾的是,到了用餐時間所有食物將完全處於眾目睽睽之下。模糊處理工作更像將包含六道菜的套餐放到一個攪拌機中,然後將它放到一個塑料袋中送給用餐者。當然,每個人都可以看到正在遞送的食物,但是除了碰巧可以看到一顆完整的豌豆或一些牛肉色的粘糊東西之外,他們並不知道原來的食物是什麼。用餐者仍然獲得了他想要的東西,而且這次用餐仍然提供了與以前一樣的營養價值(幸運的是,CLR 對口味並不挑剔)。模糊處理常式的竅門就是把窺探者搞糊塗,同時該程式仍然能向 CLR 提交同樣的產品。

當然,模糊處理(或加密)並不是百分之百地堅不可摧。即使編譯後的 C++ 也可能被反組譯碼。如果駭客堅持不懈,他就可以重新產生您的代碼。

圖 2 模糊處理過程

模糊處理是一個應用於編譯後的 .NET 程式集而不是原始碼的過程。模糊處理常式決不會讀取或更改您的原始碼。圖 2 顯示了模糊處理過程的流程。模糊處理常式的輸出是另一組程式集,功能上與輸入程式集等同,但是該程式以一種阻礙反相工程的方式進行了轉換。現在我們將討論 Dotfuscator Community Edition 用來實現該目標所使用的兩項基本技術:重新命名和刪除非基本中繼資料。

返回頁首


重新命名中繼資料

模糊處理的第一道防線就是將有意義的名稱重新命名為一個無意義的名稱。如您所知,從精心選擇的名稱中可得出許多有價值的線索。它們有助於使您的代碼自我文檔化,並充當了揭示它們所表示的項目的有價值的線索。CLR 不關心一個名稱的描述性如何,因此模糊處理常式可以自由地修改這些名稱,通常是修改為類似於“a”這樣的單字元名稱。

顯然,模糊處理常式對一個特定程式所能執行的重新命名次數是有限制的。通常來說,有三種常見的重新命名方案。

如果您的應用程式由一個或多個獨立的程式集組成(即未模糊處理的代碼不依賴於任何程式集),那麼模糊處理常式可以自由地對程式集進行重新命名,而無論名稱的可見度如何,只要名稱和對名稱的引用在程式集組中是一致的。Windows 表單應用程式就是一個很好的例子。作為一個反面的極端例子,如果您的應用程式設計目的就是供未經過模糊處理的代碼使用,那麼模糊處理常式將無法更改那些對客戶可見的類型或成員的名稱。這種類型的應用程式的例子,包括共用類庫、可重用組件等諸如此類的東西。位於二者之間的是那些打算插到現有的未做模糊處理的架構中的應用程式。在這種情況下,模糊處理常式可以對它運行時所在的環境不訪問的任何東西進行重新命名,不管可見度如何。ASP.NET 應用程式是這種類型應用程式的很好的例子。

Dotfuscator Community Edition 使用一種稱為為“重載歸納”的專利重新命名技術,這項技術可以向重新命名添加扭曲。在詳盡分析範圍之後,方法標識符得到了最大限度的重載。重載歸納技術並不是將舊名稱替換為一個新名稱,而是儘可能地將很多方法重新命名為相同的名稱,從而迷惑那些試圖理解反編譯代碼的人。

此外,作為一個好的副作用,由於程式集中所包含的字串堆變小,應用程式的大小也隨之而變小了。例如,如果您有一個長度為 20 個字元的名稱,將其重新命名為“a”將節省 19 個字元。此外,通過節約字串堆項以不斷地重新使用重新命名來節省空間的。將每一項都重新命名為“a”意味著“a”只儲存了一次,每個被重新命名為“a”的方法或欄位都可以指向它。重載歸納增強了這種效果,原因是最短的標識符會得到不斷的重新使用。通常,一個重載歸納項目將有高達 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 被引用了,但它不是由反編譯器產生的(我們假定它是一個反編譯器錯誤)。

字串加密是一種將簡單密碼編譯演算法應用到嵌入您的應用程式中的字串的技術。如上所述,在運行時執行的任何加密(或特殊情況下的解密)從根本上講都是不安全的。也就是說,技術高超的駭客事實上是可以破解它的,但對於應用程式代碼中的字串而言,這樣做是值得的。我們所面對的事實是,如果駭客希望進入您的代碼,那麼他們不會盲目地開始搜尋已重新命名的類型。他們可能確實會搜尋“無效許可證密鑰”,這會將他們直接引導到執行許可證處理的代碼。對字串進行搜尋非常簡單;字串加密設定有保護,這是因為在編譯的密碼中只存在加密的版本。

增量模糊處理有助於發布Hotfix來解決客戶在面對模糊處理時碰到的問題。修複代碼中的錯誤時經常會建立或刪除類、方法或欄位。更改代碼(例如,添加或刪除某個方法)可能會導致隨後的模糊處理運行,從而使事物的重新命名稍有不同。先前稱為“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 應用程式進行模糊處理後類型和方法的統計。

對應檔還被用於執行增量模糊處理。此過程允許您從以前的運行中匯入名稱,這樣會通知模糊處理常式採用與以前同樣的方式來執行重新命名。如果為一個經模糊處理的應用程式發布Hotfix(或新外掛程式),您可以使用與原始版本相同的名稱集對更新程式進行模糊處理。這對維護多個相互依賴的應用程式的企業開發小組特別有用。

返回頁首


模糊處理常式的缺陷

有關複雜應用程式的模糊處理(特別是重新命名)比較棘手,它對正確配置高度敏感。如果不慎,模糊處理常式就會中斷您的應用程式。在本部分中,我們將討論一些使用模糊處理常式時可能出現的常見問題。

首先,如果您的應用程式套件組合含強式名稱程式集,則您需要多做一些工作。強式名稱程式集是經過數位簽章的,允許運行庫確定是否已在簽名後改變了程式集。簽名是一個利用 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 為您提供了多種工具來防止對所選類型、方法或欄位進行重新命名。您可以挑選和選擇獨特的名稱;或者,您可以使用Regex和其他標準(例如範圍的可見度)來編寫排除規則。例如,您可以將所有的公用方法排除在重新命名之外。

在您已部署了一個經模糊處理的應用程式並嘗試支援它時,使用模糊處理常式會產生另一個問題。假定應用程式將拋出一個異常(對大多數人而言,都會發生該情形)並且客戶向您發送如下的堆棧轉儲:

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 PlusJava Primer Plus,這兩本書均由 Macmillan 出版。Gabriel 在世界各地的開發會議上發表演講並講授課程。

Bill Leach 是 PreEmptive Solutions 的首席技術官。他是 Dotfuscator 產品線的架構師和技術主管。Bill 還擔任了軟體開發書籍和文章的技術評論。

轉到原英文頁面

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.