1. 程式人生 > >Android中實現「類方法指令抽取方式」加固方案原理解析

Android中實現「類方法指令抽取方式」加固方案原理解析

一、前言

Android中加固方案一直在進步,因為新的加固方案出來就會被人無情的破解脫殼了,從第一代加固方案落地加密dex檔案,第二代加固方案不落地加密dex檔案,在到第三代加固方案類方法抽取,以後後面的更多加固方案來說都是安全的進步,關於脫殼方案網上有很多資料,但是加固方案卻沒多少資料,因為有些加固方案是一些加固公司的商業機密不可洩露的,所以我們現在看到的網上加固方案還是以前的加固方案,不瞭解以前的加固方案同學,可以看我寫的逆向大黃書,而本文就來介紹如何實現類方法抽取方案來實現應用加固。

二、指令抽取方案

首先不多說,這種方案依賴的技術就是攔截系統的載入類函式,然後進行類方法指令還原。所以這個技術必須瞭解,好在我們在之前一篇文章中已經詳細介紹瞭如何在native層攔截系統函式實現應用方法指令篡改,不瞭解的同學可以看這篇文章:

Android中Hook系統函式實現執行時態篡改方法執行邏輯;本文的技術是依賴於這篇文章,如果這篇文章沒看明白,那麼本文將很難看懂。一定要先看這篇文章。不多說了,我們在介紹加固方案主要從兩方面入手,一方面是如何進行指令抽取,一方面是如何進行指令還原,所以下面先來介紹如何進行類方法的指令抽取功能。

我們還是先用之前的工程作為案例:


在這個類中,我們定義了一個獲取密碼的方法:


現在為了安全,我們將這個方法資訊置空,可以先用010Editor工具檢視這個方法的指令資訊:

看到這個方法包含了3個指令,那麼我們如何將其設定成0呢?這裡就需要自己寫個工具了,因為我們不能依賴於這個工具手動去置空,那就太不智慧了。這個就需要藉助之前介紹dex檔案格式解析的時候那個原始碼了。我們需要做一下改動就可以實現這個功能。dex檔案格式解析原始碼下載地址:

https://github.com/fourbrother/parse_androiddex;是個java工程,下載之後直接匯入Eclipse即可。程式碼邏輯不做分析了,不瞭解的同學看之前的一篇文章:Android中Dex檔案格式解析;我們的目的就是想置空指定方法的的指令資料,那麼直接去解析方法指令的那塊邏輯即可:


這裡在解析程式碼結構的時候,對類方法和物件方法的程式碼結構體資訊,進行儲存,用到的是map結構,而key值就必須用方法的唯一簽名資訊,這樣後面會通過具體的方法簽名信息獲取到該方法對應的程式碼結構體資訊,然後進行操作:


這裡通過解析完dex檔案格式之後:在通過指定類的指定方法檢索到其程式碼結構體資訊,然後拿到指令個數和指令的偏移地址,構造一個空指令集,覆蓋原始指令。最後重新計算檔案的checksum和signature值,回寫回去。這裡最後一步非常重要,如果dex檔案的checksum和signature值不正確,dex檔案就是失效的。沒任何意義了載入也是失敗。

下面在來詳細看一下這兩個值的計算方法:


這兩個值的計算方法很簡單,我們可以從系統原始碼檢視[Android原始碼目錄/dalvik/libdex/DexFile.cpp]中,首先看看checksum的計算方法:


整個dex檔案去除頭部中的magic和checksum共12個位元組,餘下的內容計算crc即可。而signature的計算方法:


對整個dex檔案,去除頭部資訊中的magic,checksum,signature共32個位元組,餘下的內容做sha1計算即可。最終都要回寫到檔案中的頭部資訊,我們可以利用010Editor檢視:


這樣我們就一氣呵成,利用自己寫的工具對指定方法進行指令置空:先解析原始dex檔案格式,儲存所有類的所有方法的程式碼結構體資訊,然後通過傳入的方法簽名信息檢索到其程式碼結構體資訊,在獲取其指令個數和指令偏移地址,構造出同數量的空指令集,覆蓋原始指令實現置空。最後一步非常關鍵,就是需要重新計算dex檔案的checksum和signature資訊回寫到頭部資訊中。

下面我們就用上面的CoreDex工程編譯出來的dex檔案作為案例,藉助這個工具,將CoreUtils.getPwd方法指令置空,然後用IDA工具進行檢視:


不相信的話,我們在繼續用Jadx工具進行檢視:


這個方法就是個空方法了,到這裡我們抽空方法指令的功能就完成了,下面繼續來看如何進行還原指令。

三、指令還原

還原指令就簡單了,直接藉助之前那個篡改記憶體指令的程式碼即可,在native層hook系統函式dexFindClass,然後進行類的方法名過濾,獲取指定方法的程式碼結構體,修改指令記憶體塊為可讀屬性,然後把指令還原即可:


這裡為了簡單,就把原始指令儲存在native中,然後直接還原了。到這裡我們還原指令的邏輯也完成了,下面就執行專案看看日誌和效果,先把之前抽取指令的dex檔案拷貝到SD卡中,然後用這個工程進行動態載入執行看看效果:


這裡看到了,dex中的指令的確被抽取置空了,然後我們也還原成功了,方法執行也有結果了:


四、流程總結

到這裡我們就介紹完了本文內容,下面來總結一下流程:

第一、抽取指令流程

  • 1、解析原始dex檔案格式,儲存所有方法的程式碼結構體資訊。
  • 2、通過傳入需要置空指令的方法和類名,檢索到其程式碼結構體資訊。
  • 3、通過方法的程式碼結構體資訊獲取指令個數和偏移地址,構造空指令集,然後覆蓋原始指令。
  • 4、重新計算dex檔案的checksum和signature資訊,回寫到頭部資訊中。

第二、指令還原流程

  • 1、native層hook系統函式dexFindClass,獲取類結構體資訊。
  • 2、獲取類中所有的方法資訊,通過指定方法名進行過濾,獲取該方法的程式碼結構體資訊。
  • 3、獲取該方法被抽取的指令集,修改方法對應的記憶體地址為可讀屬性,直接進行指令還原。

在這個過程中,抽取指令需要藉助編寫的工具,當然工具可以進行深入優化。可以留給你們進行完善。對於還原指令中,如何儲存抽取指令並沒有介紹,這部分內容可以後續完善優化,比如我們可以將抽取的指令再做一次加密儲存到程式中的某個地方,在指令還原的時候去這個檔案進行讀取解密即可。下面來看看整個流程圖:


本文涉及到的程式碼專案可以去編碼美麗小密圈自取,歡迎加入小密圈一起學習探討技術

五、總結

在之前的兩代加固方案中,我們都可以攔截系統解析dex的函式或者IDA動態除錯來dump出解密後的dex檔案,那個依賴的核心就是不管dex檔案怎麼加密,最終都是需要解密載入到記憶體中執行的。但是這種類方法資訊抽取加固方案就可以解決dump出記憶體的dex檔案的問題。因為我們是在方法程式執行的時候進行指令還原,所以在此之前dump出的dex檔案都是被抽取指令的,其實沒什麼意義了。所以後面結合native層對抽取指令加密等更強的安全防護,這種加固方案還是可取的。

不過遺憾的是,這種加固方案並不是完美的,畢竟沒有絕對的安全可言,我們可以看到在還原指令的時候是攔截系統函式做到的,那麼破解的人也可以攔截這個系統函式,他在你已經還原成功之後在獲取類資訊,然後重組dex檔案,這樣就可以完美的還原原始dex檔案了。不過這個破解難度就會增大了。

《Android應用安全防護和逆向分析》

點選立即購買:京東  天貓 

更多內容:點選這裡

關注微信公眾號,最新技術乾貨實時推送