Android 加殼技術原理以及經常使用的保護手段(上)

Android 應用程序加殼技術已經逐步趨於成熟,應用程序加殼成爲一種常態。市場上比較多的企業提供安全加固服務,如梆梆安全、愛加密、360、百度、阿里、騰訊、幾維安全、通付盾、網易等等,還有一些其餘的加殼技術,如APKProtect。咱們有時也會發現有些惡意程序也利用了加殼技術,以達到逃避安全軟件的檢測,增長逆向難度的效果,本篇文章主要是分享Android 加殼技術原理的簡單過程,以及加殼代碼經常使用的保護手段,讓你們對從概念上有個簡單的認識,以便在平常工做中遇到這樣的問題,知道該如何應對,因爲篇幅緣由,分上下兩部分進行分享。java


殼的簡單模型:編程

圖1 加殼程序的簡單模型安全

如圖1所示,這個是最初的加殼模型,將原程序的dex文件進行加密保存,而後修改應用程序的配置文件Manifest.xml,讓程序的入口爲殼的類,保證應用程序運行時,優先執行殼的代碼,以便在殼的代碼中實現對應用程序的加密數據進行還原與修復。微信

其中,在這個過程當中,主要涉及三個部分:app

(1)加殼程序:加密原應用程序核心代碼,有的是單獨存儲,如:assets/路徑下,有的是添加在殼代碼的後面,而後修改指定的參數,修改應用程序的配置文件Manifest.xml替換原程序的Manifest.xml文件;函數

(2)解密程序:解密加密的原代碼數據,運行時,經過DexClassLoader函數動態加載,解密完成後,再修復指定參數;工具

(3)原程序:待保護的代碼。測試


加殼技術出現後,與之對應的脫殼技術也隨之出現,各類大會分論壇都在介紹本身研究的通用脫殼方法,最先公開的是基於xposed的ZjDroid,以及基於源代碼的DexHunter,還有各類五花八門的脫殼方法,如:drizzleDumper,inotifywait、dumpDex、dex2oat等等,固然加殼技術也在不斷提升,對抗脫殼技術,下面咱們瞭解一下這些年加固技術的演進過程,也算是加固技術的發展史。flex


加固技術的演進


第一代:第一代加固技術主要是代碼混淆技術,經過對源代碼進行壓縮、優化、混淆等操做,提升代碼閱讀的難度,簡單運行原理如圖2所示:優化

圖2 第一代加固技術的原理簡圖

典型的內容是採用混淆技術,使用a、b、c、d這樣簡短而無心義的名稱,對類、字段和方法進行重命名。


第二代:第二代加固技術主要是對原始應用程序中的dex文件加密,並外包一層殼,將核心代碼進行隱藏,以達到保護應用程序的目的,簡單運行原理如圖3所示:

圖3 第二代加固技術的原理簡圖

典型的內容是dex文件被加密後隱藏了dex文件中的類和方法函數,攻擊者只能看到安全假裝的入口類和方法函數,看不到被保護的原始應用程序文件裏的類、方法函數以及方法內容。


第三代:第三代加固技術主要是基於類和方法的代碼抽取技術,旨在解決第二代加固技術沒法抵禦攻擊者經過動態分析方式進行攻擊的問題,簡單運行原理如圖4所示:

圖4 第三代加固技術的原理簡圖

典型內容:第三代加固技術對dex文件中全部的類及方法函數內容進行抽取、加密和隱藏,單獨加密後存放在應用程序中的特定文件內。攻擊者進行靜態逆向分析時沒法查看被保護的類內代碼,當Android虛擬機要執行應用程序的某個方法時,加殼引擎纔讀取該方法被保護的代碼進行解密,並將解密後的方法代碼以不連續的碎片化代碼形式存放在內存中。


前三代加固保護技術涉及的dex文件總體加密、dex類運行時保護和dex運行時方法保護等都屬於程序加殼的範疇,從本質上來講都是代碼隱藏技術,最終仍是須要經過Android虛擬機執行「解殼後」的原始代碼。攻擊者能夠對原生Android虛擬機進行修改,構建一個以「脫殼」爲目標的定製化虛擬機。當加固後的App在定製化虛擬機中運行時,虛擬機中的「脫殼」程序實時捕獲App實際運行時在內存中釋放的原始執行代碼,還原出App的原始dex文件,達到脫殼的目的。


第四代:爲了應對攻擊者經過動態分析實施攻擊行爲,第四代加固技術-dex虛擬機保護(dexvirtual machine protect,DVMP)技術應運而生。DVMP技術具備自定義虛擬機、指令集和解釋器。當應用程序運行時,在自定義的虛擬機中,經過自定義的指令解釋器對被保護的代碼進行解釋執行,攻擊者經過內存轉儲只能還原出自定義的指令集,沒法還原被保護的原始指令,簡單運行原理如圖5所示:

圖5 第四代加固技術的原理簡圖

總體來看,從代碼混淆,到文件保護,再到類保護、方法保護,最後到指令保護,從靜態保護到動態保護,對應用程序的安全防禦由淺入深演變。更通俗一點的比方:若是把應用程序看做咱們的家,把應用程序的核心資產看做家中的財物,那麼四代加固技術就至關於家的四道安全防禦。第一道防禦,即代碼混淆技術,能夠看做咱們的小區大門,強度不夠,只可以增長攻擊者尋找地址的難度;第二道防禦,即文件總體加密技術,能夠看做家所在大樓的樓門,起到保護整棟樓的做用,可是強度有限,攻擊面是整棟樓,找到突破點並不是難事;第三道防禦,即代碼抽取保護技術,能夠看做家門,保護家裏全部的財產,保護粒度更細,進一步增長了攻擊者的成本;第四道防禦,即虛擬機保護技術,能夠看做家裏的保險箱,保護家庭最核心的資產,強度最高。

更多詳細的內容,請閱讀《Android應用安全測試與防禦》



加殼技術經常使用的保護手段



常見的保護手段有Manifest.xml文件反編譯失敗,僞加密、花指令、反調試、CRC校驗、調試器檢測、ELF Header修改,SMC技術等。


Manifest.xml文件反編譯失敗

一般使用apktool反編譯,會報異常錯誤:java.io.IOException:Expected: 0x00080003, got: 0x000800XXX ,這種問題是AndroidManifest.xml的頭部幾個字節被修改了,致使apktool工具沒法識別。

使用十六進制工具,如:010Editor,查看頭是否是被修改了,【03 00 08 00】是正常的。

圖6 修改前和修改後對比圖

還有一種狀況是,StringBlock中並不包含styleString,styleCount的值爲0,若是是其餘值也會報錯。


僞加密

僞加密,這是早期的加密手段,實際上是壓縮包某些字節被修改了,使用rar壓縮軟件打開須要密碼,使用apktool反編譯會失敗。僞加密的APK壓縮包打開後如圖7所示,文件後面多了*號,須要解密密碼,如圖7所示。

圖7 僞加密打開文件的界面

其修改原理很簡單,是使用十六進制工具,打開壓縮包文件,經過十六進制的方式查找連續4位字節 」50 4B 01 02」,找到後,順延到第5位字節,奇數表示不加密,偶數表示加密,修改成00便可,如圖8所示。

可是,僞加密在Android4.2.x系統發佈之後,這樣僞加密的應用程序將沒法安裝,所以,這種方式就再也不適用了,你們知道有這個問題便可,沒必要深究。


花指令

花指令是對抗靜態反彙編分析的一種手段,在PC端使用很是普遍,目前移動端也存在,它是向正常代碼中插入花指令,可以使靜態反彙編工具對指令的分析失效,從而使分析結果出現混亂、錯誤,同時花指令能夠增長逆向分析人員的工做量,以達到防禦靜態分析的效果。

花指令的去除方法,一般是用反彙編軟件(一般指IDA Pro)載入ELF文件,分析代碼指令的規律(一般的花指令都會存在必定的規律),而後編寫IDC腳本或者IDAPython腳本將垃圾指令批量NOP掉,保留真實的代碼,達到去除花指令的效果。


下面以某惡意軟件爲例,分析花指令的去除方法,如圖9所示,該動態庫文件使用IDA加載後存在大量的花指令代碼:

圖9 存在花指令的代碼

通過分析發現,該樣本的花指令模式是這樣的:

LDMFD SP!, {R0}真正的指令 STMFD   SP!, {R0}ADRL    R0, loc_value SUB     R0, R0, #4BX      R0

也就是說,上圖中MOV R0,#1爲真實指令,若是不處理花指令,分析起來很是麻煩,幸虧IDA提供了一個腳本引擎,讓用戶從編程的角度對IDA的操做進行全面的控制,編寫IDA腳本的語言簡稱IDC,IDC是IDA內置的類C語言的腳本語言,總共提供了100多個內建函數下面咱們利用IDC腳本撰寫去除花指令的代碼,再編寫代碼以前,咱們先簡單瞭解一下IDC腳本經常使用的函數。

IDC腳本經常使用的函數

#工具函數ScreenEA()  //得到當前IDA代碼視圖中的光標所在的地址。這個函數的做用一般能夠做爲腳本的起始地址。GetInputFileMD5() //得到當前載入文件的MD5值。這個函數的做用一般做爲校驗文件的修改變化。
# 區段函數Firstseg() //獲取首個區段的起始地址。在脫殼解密區段時常用。NextSeg(long  Address) //根據指定的Address返回下一個區段的起始地址。SegByName(long  SegmentName) //根據指定的區段名,返回區段的起始地址。SegEnd(long  Address) // 根據指定的Address,返回當前區段的結束地址。Segments() //返回各個區段首地址列表。
# 功能函數:Functions(long StartAddress, long EndAddress)  //返回起始地址StartAddress與結束地址EndAddress之間的全部函數。LocByName(long FunctionName)  //根據指定的函數名稱返回相應的函數地址。GetFunctionName(long Address) //根據指定的地址Address,返回該地址所在的函數名稱。
# 交叉引用:CodeRefsTo(long Address, bool Flow) //根據指定的目標地址Address,返回一個指向此處的代碼引用列表。CodeRefsFrom(long Address, bool Flow) //根據指定的源地址Address,返回一個由此地址發出的代碼引用列表。DataRefsTo(long Address) //根據指定的目標地址Address,返回一個指向此處的數據引用列表。DataRefsFrom(long Address) //根據制定的源地址Address,返回一個由此地址發出的數據應用列表。
# Patch函數PatchByte(long ea, long value) //Patch一個字節。PatchWord(long ea, long value) //Patch一個字。PatchDword(long ea, long value) //Patch一個雙字。FindBinary(long EA, bool downorup, long value)  //查找二進制數據,並返回查找到的二進制數據的起始地址。

編寫IDC腳本代碼 ,去除花指令:

#include <idc.idc>static main(void){ auto EA,Counter; auto Address; auto name; EA = ScreenEA(); Counter = 0; while(EA != BADADDR) { Address = FindBinary(EA, SEARCH_DOWN, "E2 04 00 80 E2 04 00 40 E2 10 FF 2F E1"); name = GetFunctionName(Address); Message("Address=%lx name=%s\n", Address, name); if(Address == BADADDR)        break; PatchDword(Address - 15, 0xE1A00000); PatchDword(Address - 7, 0xE1A00000); PatchDword(Address - 3, 0xE1A00000); PatchDword(Address + 1, 0xE1A00000); PatchDword(Address + 5, 0xE1A00000); PatchDword(Address + 9, 0xE1A00000); Counter++; EA = Address + 1; EA++; }      Message("這是 %d 花指令代碼塊.\n", Counter);      Message("完成.\n");}

編寫完成後,使用IDA->File->Script file加載執行便可,如圖10所示:

圖10 IDA加載IDC腳本方法

執行完後,花指令就NOP掉了,再看上面代碼如圖11所示,真實的指令並無幾條:

圖11 去除花指令的代碼



本篇暫時分享到此,未完,待續……


---------------------------------------------
本節部份內容節選自《Android 應用安全測試與防禦》
若是您對App安全有任何問題
可在本公衆號進行留言
咱們會進行回覆~
---------------------------------------------
本書由中國工信出版集團人民郵電出版社(2020年5月)出版,可到各大電商平臺(京東、天貓、噹噹等)購買,搜索書名《Android 應用安全測試與防禦》便可。

歡迎關注本書公衆號
獲取更多App安全知識

       

本文分享自微信公衆號 - App安全紅寶書(apphongbaoshu)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索