GSS資安電子報0217期 【九招應用程式強化之道:解析進階程式碼混淆技術】

訂閱電子報
2023年十二月10日(日) AM 09:00
翻譯及整理:叡揚資訊 資訊安全事業處

  BP TN CT 2023 7 100 test automation 2

   

程式碼混淆技術(Obfuscations)

  

  應用程式安全(Application Security)現在是眾所周知的重要議題。每個人都知道應用程式安全的必要性,而攻擊者也知道如何突破基本的防護措施。換言之,毫無防護的應用程式絕非可行選項。

  一個強大的防護具備兩個部分:靜態分析預防以及動態攻擊偵測。靜態分析是一個強大的工具,它可以讓攻擊者以獨特的方式觀察應用程式中的實作方法。它暴露了應用程式的弱點,並且加速攻擊者竊取有價值的商業智慧財產。對於原始碼以及資料而言,混淆是任何靜態分析防護中重要的一環。

  以下是幾種混淆程式碼和數據以拖延惡意攻擊者速度的方法。(他們越費力,我們的應用程式就越安全)

   

1. 防護私有化(Privatize Your Protection)

   

  雖然應用程式在發布時應該加入某種形式的混淆,但並非所有的混淆方式都一樣有效。強大的程式碼混淆技術需皆具備兩大要素:私有化(專屬防護)以及隨機化。

  程式開發者可直接使用與查閱“開源的程碼混淆工具”,攻擊者也是如此。因此,這些開源程式碼混淆工具並不足以強大到能夠可靠地保護企業級應用程式。真正具保護力的程式碼混淆需要將原始碼轉成人類難以理解,且自動化攻擊工具無法對程式碼做反混淆。

  目前公開的“開源程式碼混淆技術”,在允許任何人取用工具的同時,也將混淆技術公開給了駭客。而使用私有化(專屬防護)且不公開的程式混淆技術,則可阻止駭客對應用程式的程式碼混淆進行逆向工程。

  換言之,如果要確保程式碼混淆不會遭人類或大型語言模型(LLM)破解,就必須使用私有的演算法及良好的隨機性互相搭配。

  

2. 偽隨機數生成器(PRNG)的逆襲

   

  攻擊者可比較同一應用程式的不同版本,去獲取許多資訊。因此,讓程式碼混淆結果隨著應用程式不同版本改變是絕對有其必要的。

  大多數偽隨機化引擎(包含程式碼混淆技術)使用亂數種子(seed 值)並透過演算法來決定邏輯的序列與隨機性。因此修改亂數種子(seed 值)將會顯著影響混淆結果。這不但在需要時可確保復現性(reproducibility),也迫使攻擊者於新版本釋出後,必須重新對應用程式進行逆向工程分析。

  程式碼混淆安全其中一個目的在於浪費逆向工程的時間,使其攻擊變得非常艱難與耗時。而打造一個不斷變化的環境,就是耗費他們時間的最佳方法之一。

  

3. 多重程式碼混淆(Obfuscations)

   

  概念上,混淆是優化的反義詞。就像編譯器通常會有多道最佳化過程一樣,我們也可以進行多重程式碼混淆。這代表我們將程式碼混淆的結果再次應用於新增的混淆,以產生艱深難懂的結果。

ghidra obfuscation blog

圖示1:多重程式碼混淆可顯著降低Ghidra等工具在解析程式邏輯流上的效率

  以簡單的「add」 或「mov」 指令為例,它們可以迅速變成五十甚至數百條指令。對「adrp add」配對適時進行程式碼混淆,可降低自動化工具(例如 Ghidra 或 IDA)解析程式控制流的能力。即使是看似微小的程式碼混淆,也能讓攻擊者幾乎無法找到「acceptUserCredentials」函數呼叫的起始、結束或中間部分。在數百種不同的混淆方式複合之下,攻擊者光是理解程式碼究竟如何成功運作就得煞費苦心。

  

4. 客製化防護設定(自訂防護混淆等級)

   

  在一個應用程式中,並非所有程式片段都是重要並具機敏性,另外有的程式片段則會經常性被呼叫因此特別影響性能。對整個應用程式進行全面的程式碼混淆,比什麼都不做要好得多,但這種防護策略則會對執行性能造成可觀影響。

  因此一個世界級防護工具重要的一個要件,是要能讓資安工程師決定對敏感呼叫的程式碼進行高強度混淆,同時對不具重要與機敏性的密集型呼叫的程式片段進行低混淆程度調整。

  另外任何注入到應用程式中的動態防護程式(Guards)與應用程式程式碼一樣,都需要進行相當程度的程式碼混淆。將相同的安全性混淆技術應用在持續運作的動態防護(Guards)機制上,不但有助於保護在應用程式執行期間進行的偵測,還可拖慢攻擊者識別和移除它們的速度。

  對於任何以安全為本的企業組織而言,可客製化防護設定與等級是至關重要的。因此防護工具必須依公司取向能快速變換。

  

5. 程式化控制邏輯流(Computed Control Flow)

   

  攻擊者可透過觀察應用程式中的函數呼叫流程,就能對該應用程式取得相當程度的認識。

  簡單使用反編譯工具進行分析二進位檔案時,可輕易觀察一個函數如何呼叫另一個函數並非難事。透過了解虛擬記憶體位址存放的資料內容。以「b.eq 0x10055bc42」 和 「bl 0x100abcdef」等指令為例,它可能是函數內的標籤,或者是函數呼叫本身。

  任何一款反編譯工具,都能完整呈現函數呼叫的架構,清楚的顯示應用程式中的執行流程。只要結合這點與其他基本技巧,例如查看組合語言(assembly)中「登入成功」訊息的呼叫位置,攻擊者即可輕鬆識別可利用的程式碼。

  為了對抗這一點,我們的混淆技術使用了一種稱為「計算控制流」(Computed Control Flow)的方法。Computed Control Flow技術會阻止反編譯工具將函數呼叫和標籤參照連接到應用程式的主進入點。(這是任何世界級防護的關鍵環節之一。)

  Computed Control Flow 是將原本清楚可見的程式邏輯流呼叫流程,額外再去加入數學邏輯判斷式。它可以阻止反編譯工具得知程式跳轉的確切虛擬位址(Relative Virtual Address),並破壞反組譯工具生成控制流程圖的能力。

 

1 768x768

圖示 2:程式化控制邏輯流(Computed Control Flow)(右)可阻止反編譯工具知道要跳轉的確切相對虛擬位址,破壞其生成控制流程圖的能力(左)。

  

6. 控制邏輯流扁平化(Control Flow Flattening)

   

  對於反編譯工具來說,程式化控制邏輯流(Computed Control Flow)已經是一種可怕的存在。然而還有另一種擾亂程式邏輯流的策略,那就是「控制邏輯流扁平化」(Control Flow Flattening,CFF)。

  我們擁有各種形式的 CFF,尤其是新加入的生力軍(Nexus)則為此類關鍵的程式混淆技術帶來了新氣象。我們都曾在「main」 中寫過西洋棋遊戲,那麼在一個單獨、自我參照的 switch 敘述中撰寫一整個已經能夠發布給大眾使用的應用程式呢?Nexus 混淆技術就是使用此方法,並且還能優先考慮執行期間的性能。

  坊間關於 CFF 的重要性以及運作方式的資訊不計其數,它的重要性以及工作原理等方面的資訊,很難言之過甚其詳。這種程式碼混淆技術令攻擊者的執行逆向工程困難度加倍,其重要性自然不言可喻。也因此,任何應用程式在離開測試階段前(staging)階段之前,程式碼都應先經過混淆。

  

7. Chopup(碎片化)

   

  對於不鏽鋼刀具組來說,少了一把不鏽鋼剪刀就不完整,而 Chopup 就是控制流程式碼混淆技術的那把剪刀。

  二進位檔案格式通常緊密封存以節省磁碟空間。這代表大多數相關的函數呼叫彼此都非常接近。因此,當二進位檔案被反組譯時,相關函數通常會被聚在一起,並且幾乎總是將函數作為二進位制中的一個連續區塊,以致於太容易讀取,非常讓人困擾。

  Chopup 改變了這一點。在二進位檔案中,沒有限制在記憶體中函式呼叫必須連續,而 Chopup 這把好剪刀在讓二進位檔案按預期運作的同時,但能迫使攻擊者需要在尋找邏輯控制流的過程中,跳躍在二進位制的每個角落。

 

2 768x768

圖示 3: Chopup 迫使攻擊者在尋找邏輯控制流的過程中,跳躍到二進位制的每個角落。

  

  

8. Damage(破壞)及 Repair(還原)

   

  雖然對程式碼流程進行混淆是保護的關鍵層面,但對底層應用程式資料進行混淆同樣重要。

  Damage 和 Repair 代表著靜態分析防護中的邪惡和良善這兩股力量,幾乎總是密不可分。破壞一段資料或是程式碼片段,然後在它被讀取或執行前修復完畢,可讓攻擊者幾乎無法對其進行靜態分析。

  Damage 可將特定資料,轉變成垃圾數值的形式。當毀壞過後的資料被 Repair 呼叫時,他會被還原為原始形式,並且該資料之後可在呼叫完畢之後再次被破壞,直到下次呼叫之前。在二進位檔案中,這 API 金鑰可能一開始以「1#&at0d$*nd@@z」被毀損的樣子為起始,但不用擔心,它會在使用之前還原成原始的樣子。

  

9. 符號重新命名(Symbol Renaming)

   

  即便對原始碼和資料進行混淆,在編譯後的二進位檔案中原始符號名稱依然會存留。例如,一個為「acceptContinuousPayment」這樣的函數名稱符號遺留可以輕易地直接關聯到該函數的實現。

  一旦找到該關聯,修改程式碼及分析重要功能的方法就變得非常簡單。全面的符號重新命名隱藏了剩餘的符號遺留,讓攻擊者無從下手。在受保護的二進位檔案中移除敏感功能的任何提示或線索,可使攻擊者徹底放棄靜態分析。

 

3 768x768

圖示 4 :全面的符號重新命名隱藏了剩餘的符號遺留,對攻擊者來說無從下手。

   

結語

   

  以上幾個例子只是帶領您了解高強度混淆的實作與方法理論,並非相關技術的完整說明。若讓應用程式的程式碼暴露在一個毫無防護的狀態,不但任由大眾直接看到企業獨有的智慧財產,也會讓駭客在攻擊過程中毫無阻礙的觀察到應用程式中的商業邏輯。

  隨著生成式 AI 與原始碼協作工具迅速躍上主流,不論撰寫程式碼或進行逆向工程相較以往都變得輕鬆許多。在這樣一個步調明快的環境中,企業上下一心致力使用強大的資訊安全解決方案,才是持續進步的不二法門。

  在此提醒您採取必要的安全防護措施,別讓開發者努力工作的成果一問世就暴露在危險中。