9月12日,烏云安全峰會今日召開。來自LBE安全大師創始人兼CEO張勇帶來了《軟件加固技術淺析》演講!以下是他的演講全文:
非常感謝利用這樣的機會能夠在這樣的會場跟大家來分享一些在移動應用安全相關的議題。我自我介紹一下,我是張勇,我是LBE安全大師的早期開發者,也是創始人之一,可能我現在掛著CEO名頭,但是我還是一個純粹的工程師,也是一個技術愛好者。
關于這個主題其實也是有些小的故事的,在一個月以前,烏云當時找到我們,希望我們能夠做一個相關的演講。我們就很快的想到這樣一個話題,是因為我們對這個很感興趣。半個月前我完成了大綱,大家看后覺得太水了,所以說在一周以前我就推倒重寫了,我寫的主題是單子上面的主題,前天晚上討論之后覺得還是太水了,所以覺得干脆再推倒一次,就是再重寫一份,熬了兩夜,給大家帶來這樣的主題,就是主流移動應用加固產品攻防分析。
這個議題包含兩部分:第一,我們跟大家簡單介紹一下移動應用加固用戶的需求,以及主流移動應用加固的方案和實現的核心細節。第二部分,我會列舉市面上五款非常流行的應用加固的產品,來分析它加固的原理和它實現的方法。
同時我也會給出這五款產品如何對其進行破解和脫殼的核心的要點。我希望通過這樣的PPT一方面讓大家對移動應用加固有些更深的了解,另一方面,我也希望能夠幫助一些,或者能夠為一些在這個領域內進行研究的安全工作者帶來一些資訊和一些信息。
為什么需要應用加固?這個問題很簡單,在PC上就有,從發展了很多代,在安卓上面從2013年被大家提及,2014年成為非常熱的熱點。應用加固如此火熱的原因有如下幾點:首先,安全平臺的應用核心代碼都是以JAVA書寫的,我們知道它很容易被反匯編的。
即便大部分開發者都對原碼進行混淆,但是核心邏輯是可以通過一些函用關系看出來的。無論是登錄也好,驗證也好,有經驗的工程師還是可以根據調用的關系來找到你的程序里面的核心的點,然后對它進行破解和修改。
第二,安卓是一個開放的系統,如果我沒記錯的話,安卓平臺逆向工具應該是1.5時代,也就是三四年前已經發展,到現在非常非常成熟。
第三,為什么需要用加固?因為安卓平臺淡化了進程的概念,應用是基于消息和事件來運行的,基于這樣的情況,惡意代碼的植入變得非常容易,想在PC時代植入代碼,要對原有的代碼進行反匯編,然后插入你的入口點。
在安卓根本不用動到原碼,只需要在清單文件,增加一些事件的響應,像開機自啟動,然后你在你的惡意代碼中去接收這些事件響應就可以實現基本的注入。
最后,安卓平臺,我相信特別是在國內,安卓平臺大約有30%的安卓手續已經獲得入權限,在這個情況下無論通過APPI或者修改值,都很容易實現注入。實現這樣注入話,這樣的功能也就在一方面惡化了安卓軟件的生態的安全。
正是有這樣的原因,市場上包括開發者都對于應用加固,都希望能有這樣的一些產品來保證自己的軟件不會被輕易地重打包,不會被輕易地注入,也不會被輕易地破解,正是有了這樣的原因,才有了現在非常火熱的應用加固市場。
我在國內選了五個比較主流的應用加固供應商。基本上目前國內主流的加固供應上有以下功能:防止惡意篡改,防止內存竊取,防止調試。而且目前的做法通常是用戶上傳一份已經修改好的APK,然后重打包,反饋給用戶的是已經加固過的APK,這套流程背后技術的原理和技術的要點主要有哪些呢?
最主要的就是所謂的加殼技術,可PC不太相同的地方是,安卓應用的核心部分代碼是JAVA語言書寫的,針對很多DX這樣的加殼技術應運而生了,在目前三種比較主流的加殼技術:
第一,對DX完整的加密。這種加密技術會在加固的時候將DX文件給完整做一次加密,然后保存在APK中,同時用加固方案商動態聲明來代替掉原始的。在應用啟動的時候,加固的脫殼代碼就會自動運行起來,它會對已經加密的進行脫殼并且加載到系統中,同時它還會修改一些東西來運行組件。
隨著攻防的增加,第二種方案也開始出現,我稱為自節碼變形方案。它的原理其實也非常顯而易見,它在運行時修改文件,使得你從記憶 Dump中盜取的文件是不合法或者不完整,你無法對它進行重新分析和重打包。目前我們看到的像騰訊、360的加固主要采用這樣的方案。
還有一種就是綜合了加密和變形的兩種的方案,就是百度應用加固方案,這些加固方案它的具體的實踐原理和細節我會在后面的PPT中詳細介紹。
除了DX加密之外,我們知道APX還有很多東西,像我們寫的動態庫,還有像資源文件,包括像很多加密方案商提供的防止動態調試,防止侏儒的功能,這些功能把很多加密方案也都有(卡爾)。
資源文件的防護通常針對APK中兩個比較特殊的目錄,一個是RES目錄,還有ACS目錄,進行保護,像音頻、視頻,還有圖片及其他資源進行加密保存,然后殼代碼通常會去確保這些資源在應用讀取之前被解密,這個過程是透明的,所以對應用不需要做額外的工作。
但是這樣的做法可能會有一些問題。首先,跨應用間跨進程可能會失敗,影響性能,還有反二次打包,加固時記錄APK內容Hash,運行時由殼進行檢驗。還有反Ptrace,防止注入,多進程相互Ptrace,還有一些廠商采用另外一個方法,就是在運行時不斷地輪巡。
安卓是多進程系統,你無法保護所有的線程,即便保護了一些線程,其他線程也會被傳上去,這樣的話都不會很完全。所有安卓的進程都是通過一個叫做Zygote進程報出來的,對于注入者而言或者調試者而言,他根本不需要在你進程運行的時候才Tress,像很多安全軟件,像360、騰訊,所謂的超強模式,主動防御其實都是基于這樣的技術。
換句話說,安全軟件可以這么做,惡意軟件也好,修改器它們也是可以采用同樣的做法。所以說反Tress基本上沒有任何功能,從現實中來講。
其實在剛才我列舉的這些功能中,最為核心的一點就是Classes Dex加密方案的實現。首先,我想跟大家先介紹一下最標準的Classes Dex整包加密的思路,這個思路也是目前最為成熟和眾多產品都應用的方式。
這樣的方式其實會分兩步運行,首先在加固的時候,當把APK傳到服務器時會解析APK,它會動態地生成一個新的Classes Dex,來代替原先的,原始的會放在其他目錄下面。
當程序運行的時候,因為在加固過程中殼已經替換掉了程序入口點,當運行的時候,殼代碼首先運行起來,在幾個函數中它會調起脫殼代碼,通常是用C來寫的,來進行脫殼操作。
在脫殼操作中會做這樣的事情,首先它會把DEX文件加入到內存中,通過一些手段在MAX中看不見,這樣可以避免一些非常簡單的方法來定位到你脫殼后的Classes Dex下的DEX的內存中的地址。
第二,我們知道安卓平臺有四大組件,這些組件它和PC是不一樣的,安卓平臺做應用你是無法真正控制你的代碼是什么時候運行的,是系統認為你需要你運行的時候,系統會把你啟動起來。
換句話說,系統負責來啟動你的代碼,但是在通常情況下,系統會假設所有代碼都存在標準的Classes Dex文件中,但是在加固中你的代碼已經挪到了另外一個包中,已經不在原始的里,如果試圖構建你這些組件的時候不能實現,所以為了避免這個問題,所有的加固方案會去修改Classes Older,來確保系統構造組件的時候成功找到組件。
第二,它還會確保標準正常運作,在執行完這些操作的話,最后一步會做簽名驗證,然后才會真正調起目標進程的對象,并且對它進行初始化,最后完成脫殼操作話就會重新交給操作系統。對這樣的方案有沒有可殼的可能性呢?當然是肯定的。
因為我們知道安卓肯定不會支持任何的加密,或者任何變字節解碼的,它只能接受也只能運行標準的解碼。換句話說,任何基于Classes Dex整包加密的方案在程序運行之前必然會在內存中對字解碼進行解碼,然后才輸入虛擬機中運行。
另外一個事實,因為Classes Dex非常的大,所以虛擬機會通常傾向采用記憶Dump方法來加載速度。并且Classes Dex也類似ERS,也類似PE,所以基于這樣的一些方案,就以下的一些脫殼的方案,最基礎的方法就是去查看MAX文件,從中找到Classes Dex的地址。
去年的年底的時候,當時的加入方案還非常的初級,我記得有好幾家,名勝比較響亮的加密應用,可以直接看到解密后的Dex的地址,你可以把它CAP出來,就可以解密了,所以當時等于形同虛設。
隨著技術的發展,現在的加固方案商都會采取一些手段來保護,比如從內存中直接加內存解碼,或者在加載之后通過MAX調用,把文件映射給轉化為文件共供血量的過程,在MAX中看不見文件映射的信息,很難找到MAX。
即使做到這樣還是有機可乘的,第一,通常MAX文件比較大,需要連續的文件,所以在MAX中是能夠找到一些蛛絲馬跡的。其次,因為在加載DEX文件的時候會采取MAX方法,這決定了它是是和頁對齊的,所以我們可以變異MAX的表象,讀取它的每一個表象開頭的四字節,判斷它是否是MAX字位,如果是那它就是MAX,現在在網上也有類似的代碼做這個事情。
今年五月份的時候,應該是百度的安全實驗室的一個工程師,他做了一個項目,他可以實現包括對于不少通用加固方案的脫殼工作,這也是一種方案,以及我今天跟大家介紹的,如何通過反射的方法來獲取DEX的方案。
下面我介紹一下五款常用加固產品的原理和脫殼的方法。
首先是這個行業的創始人在國內,就是梆梆加固,它應該是這個行業最早的倡導者,我相信它也有最多的用戶量。針對梆梆的加固我準備了兩個案例,第一個,就是梆梆的企業級用戶,就是國美在線,第二個,就是我自己的一個上傳的產品進行了加密。
梆梆實際上對企業用戶和免費用戶的提供的防護級別不同的,我稍候會向大家解釋。目前,梆梆的代碼是支持X86平臺。對梆梆的分析過程中我發現一些問題,首先就是stub classes并非必須。
第二,梆梆為了支持Art,在內部裝了一個東西,這個文件是來自于安卓4.4的。對于梆梆這樣的產品,對它如何能夠實現脫殼包括解密操作呢?我們知道企業版本和免費用戶版本是有區別的。
對于企業版本梆梆使用了內存加DEX方法。被梆梆加固的應用沒有做所謂的DEX OPX操作的,這樣的話會導致一些程序加固后的行為有差異,或者性能變差。
這時企業版本,做了更多的防護,對于公開版本而言的話,梆梆使用了標準的開放方式,從文件中下載的方式,同時也沒有將DEX下載地址往后,就是繞可四字節的方式,使用公開版本加固過后的產品,是可以通過MAX的方式找到加固后的代碼。
另外,對梆梆分析過程中我們發現對應用的修改比較多,比如它會同時啟動三個進程,相互之間tress,其實這是一個偽命題,所以我個人建議這個功能可以砍掉。
同時梆梆會在運行過程中會發送一些特殊的kust,這樣會降低代碼的可靠性。同時脫殼后的話,梆梆在加殼時在原始的文件中也插入了相應的代碼,這個在脫殼中都要移除。
第二,基于Classes Dex加固方案是來自于愛加密。它的做法和梆梆大同小異,原始的Classes Dex會被加密后放在assets下。它的方案相對而言可能更加成熟一些,但是跟梆梆比也有劣勢,它是不支持安卓L的,只支持ARM平臺。
愛加密相對于梆梆在自我調控方面做了比較多的工作,在公開的版本,它在下載Dex時用了四個方法,在MAX中看不到任何痕跡的,一些關鍵的指針被它替換成錯誤的指針,這樣的話使用標準的脫殼工具是很難對其直接進行脫殼的。如何來解決脫殼問題呢?
其實有一個辦法,首先目標用戶中選擇隨意的MAX方法,將其傳遞給GNI,獲得內部的一個MAS對象,MAS有一個指針的地址,這個文件就在它所在的區域中,然后在PROMAX中尋找這個地址的頁表象,然后真正的DEX就藏在這個地址中,然后用這個地址尋找起始,就能找到DEX,我們測試結果也是跟梆梆一樣,使用了將DEX地址從4K對齊位向后偏移8個字節,這樣就很好地避開那個。
第三個產品就是360。現在360應用中心推出了一款加固寶產品,它也是和梆梆、愛加密一樣,是基于Classes Dex加固的這樣一款產品,實驗原理都是非常接近的。
我們在對比的時候,發現我們將360加固解包后和原始的APK有些須的差異,我們認為這是360對APK做了一些所謂的性能優化,包括像構造函數優化等等,這些都是在標準的ODS做的優化。360目前是支持X86,也能在安卓上運行。
上面就是最傳統的Classes Dex加密方法的案例和分析,下面我想跟大家介紹的是基于字節碼變形的實現,會更加有趣一些,這些方案的出現,其實它們為了解決一個問題,就是我剛才跟大家介紹的,對于任何Classes Dex加密的產品,一旦找到了地址之后,所有的加密都無所遁形,你可以輕易地下載出來,對它為所欲為。這就有了字節碼變形加密方案,它本身是一個執行機密的腳本。
換句話說,虛擬機只要完成了對這個文件的加載,文件中很多部分的格式也好,數據也好,所以它只需要將這些格式破壞掉,記憶中下載不出來的Classes文件是非法文件,失效文件。為了實現這樣的目的目前有兩種方案:第一,在加固的時候,首先去蘊藏一些DEX中一些關鍵的代碼,然后在加載的時候再由程序修復。
因為修復的過程不是發生在文件本身,即便我們輕易找到了DEX的加載地址,下載后還是不可執行的文件。我們有兩個方法,一個,是加密的時候把JAVA的方法改成Lunix方法,將字節碼進行隱藏,在運行的時候再將字節碼恢復,這個是騰訊采用的方法。
第二,在加固的時候把DEX的BAD COAD改了,放在其他地方,這個方法是360的方法。第二種方案,在DEX加載后破壞內存中DEX鏡像關鍵結構體,使得你下載出來的結構無法被靜態分析工具或者其他工具來分析,包括像DEX,這個方法是目前百度采用的方法。
如何對其進行脫殼呢?首先單純的記憶DUMP是無效的,單純的對其脫殼的話,是對破壞的一方進行修復,對DEX TEDER在運行的時候將其破壞值在稍候計算出來的。對于像某些支持ARK的方案,還有比較獨特的方案,就是劫持系統的DEX的 OAT,這樣把原始的偷出來。
第二種,像騰訊和360對MAX進行處理,來隱藏其字節碼方案,也有對應的方法,就是修復MAX。
下面我想跟大家分享一下我們對市面幾款使用變形技術的加固產品的技術細節的分析。首先,就是騰訊,騰訊的加固產品應該說是,我個人認為是最別出心裁的,對于其他家的加固產品,通常是對應一個PK上去,加固一個回傳過來,但是在騰訊中需要填寫需要加固的函數名,為什么會有這樣的情況,這跟它的做法是直接相關的。
因為騰訊的應用加固方案在加固的時候會將真正的函數的類型從JAVA函數改為linux函數,將關鍵的結構體給清空,讓靜態分析工具認為這個函數是沒有任何字節碼的,就可以跳過,對于未加固的函數沒有任何變化。
我們注意到騰訊的加固其實并沒有真正把字節碼藏起來,給放到其他地方,字節碼其實還在這個DEX文件中,只不過它修改了函數到字節碼的指針,讓靜態分析工具和虛擬機認為這個函數是不需要字節碼的,解密的時候也是同樣的做法,找到函數和字節碼的對應,恢復就好了。
這個是打開了一個騰訊應用加固方案后的,一個被加密的偽函數,這個函數里設置了AK了,它的代碼屬性被設成NO,就是沒有代碼。我們打開DEX文件本身,我們發現字節碼還保存著,只是你們不知道如何將它和函數利用起來。
這個方案其實非常的有開創性,我個人覺得非常贊,但是最大的問題在于,由于ART原理,這個不可能支持ART的,因為在ART運行中,因為ART運行環境首先將DEX文件編譯成本地代碼,然后在這個過程中它生成的并非是DEX,而是ELF格式的一個本級代碼,騰訊這種做法不可能在ART環境下,在運行時重新將這個函數指向另外一個地方,所以目前騰訊的方案仍然是完全不支持ART的,我覺得未來這個方案可能也無法支持ART。
解密其實非常簡單,使用DVL的函數蓋到MASCOAD的地址,計算出這個偏移量,然后就可以修復這個函數的類型。所以我個人認為這個方案是非常巧妙的。當然就像我PPT中寫的,這個字節碼是無法保存的,安全感會比較差一些。
最后一個方案,也就是最近剛剛百度發布的一個混合的方案。百度的方案是混合了Classes Dex加固以及Classes Dex字節碼變形的兩種方式的一個方案,應該說在目前是最為完善的。
百度的方案對于DEX加固這塊,它和360,和梆梆和愛加密是完全相同的,也并無太多新意。但是另外一邊,它是如何來隱藏DEX的內容呢?
當使用百度加固方案后,它會將很重要的DEX的頭的重要的位置給清空,包括DEX TIDER,當你下載不出來的時候,這個文件實際上是無法識別,也無法做靜態分析的。地可以看到DEX頭全是零,包括后面的OPT信息全是零了。怎么樣來實現脫殼?
脫殼方法相對而言也比較簡單,既然百度將信息清空了,我們將其還原就是了。基于DEX的一些特性,它是連續的,并且不允許有空隙的,我們是可以根據Aseent的格式是固定的,而且百度沒有將每個字段的長度給清零,所以我們只要算出來第一個Aseent的位置,然后Aseent加,把每個數字填起來就可以了。
后面后這個DEX可以成功地被其他的靜態工具分析了。相對而言百度的加固我個人認為比較完善的,因為它結合了現在的兩種方式,同時也有比較高的Dop難度,還支持X86和安卓平臺。
但是百度加固會在原始DEX文件中插入很多百度代碼,我個人比較不喜歡這樣的行為,這是從我們自己工具里摘取出來的代碼,它是來重構DEX TIDER。
最后我想提一下360早期版本,實際上360最新版本中已經使用了類似梆梆和愛加密的方法,在它早期的方法也是有創意的,這種方法破解難度很大,但是它在目前的版本上為什么沒有延續,我覺得還是跟兼容性相關。因為目前來看的話,所有DEX字節碼變形的方案和ART都存在著或多或少接入性問題。
最后,我最近做的一些研究的總結。首先,我們認為應用加固的產品本身技術也好,包括攻防也好,是高速發展,去年搜集這個關鍵詞應該看不到太多的信息,今年搜加固可以搜到大量的信息,我們也看到隨著早期的DEX文件加密的方式的成熟,現在其實也有更多更新的方式在重現,加殼的強度也會越來越高,據傳言國內已經有一些廠商實現了類似PC上面的技術,能夠進一步提升加固強度,但是目前沒有看到在公開市場上有這樣的案例。
第二,ART是安卓的未來,從安卓L開始。ART本質是在運行前將字節碼編譯為本地指令,任何試圖將這個解碼隱藏,都會導致使本地指令無法執行,這也是目前360和騰訊無法解決的。未來可能有其他的方式,像安卓MASS上面,有的人做的方案,能夠未來對EOT進行PACH,我們認為ART在加固方面還有很多空間,目前還不是很成熟。
最后,應用加固它其實還是有很多兼容性問題的,在實際測試過程中我們也注意到,像不同的硬件平臺,像不同版本的系統,甚至像不同廠商的手機,為什么會有這樣的問題呢?
因為作加固中很多操作是需要通過反射來做的,還有很多操作是許多對結構體進行修改,我們知道安卓是開放系統,任何廠家都可以修改這些結構體,這就導致了在某些手機上面這個結構體的偏移量,或者位置、地址是不同的,這會影響它同其他設備兼容性的問題。
在最近一段時間我的很多朋友問我,對堅固問題怎么看?從目前來看,我認為加固并不是萬能藥,而且有很多脫殼工具。對開發者而言,一個完整的體系才是他所需要的,他需要多管齊下,才能真正解決APK安全問題,單純加固肯定是不足夠的。