Android APP加固與脫殼基礎----加固與脫殼簡介

先從DEX文件格式開始分析,因爲dex是安卓應用程序編譯後的結果,直接與Android虛擬機進行交互的文件。在這裏插入圖片描述
有關DEX文件的介紹可以參照我之前寫的這篇文章

看這個圖片很複雜,其實對於初學者來說,只要瞭解到這一點就行了:

Android應用的Java代碼,所有的數據格式、數據、算法都是經過轉化,變成了以上的格式存儲,儲存的是具體內容的偏移地址。

比如索引區的string_ids,描述了所有程序中的字符串,格式也很簡單,只有一個偏移量地址,用文件偏移地址來記錄、描述字符串的內容。文件偏移地址和編程經常會用到的內存地址區別,我們瞭解內存地址,因爲是在程序運行的時候,會用到,但是此時的android應用是保存在dex文件中的,所以繼續我們成爲文件偏移地址,並用來記錄描述的。

type_ids,描述了所有的數據類型,包括class類型,數組類型和基本類型。

言而總之,程序被分區分塊的進行轉換和保存了。

dex文件和加固有什麼關係?

如果dex文件未加密,未混淆等安全加固,我們可以通過apktool或者jeb拿到彙編源代碼或源代碼,之前也介紹過。

dex文件的混淆加密

混淆和加密主要是爲了隱藏dex文件中關鍵的代碼,力度從輕到重:靜態變量的隱藏、函數的重複定義、函數的隱藏、以及整個類的隱藏。混淆後的dex文件依舊可以通過dex2jar jeb等工具反編譯成Java源碼,但是裏面的關鍵代碼已經看不見了。

四種混淆加密的實現方式都是通過修改class_def結構體字段實現的。
在這裏插入圖片描述

1、靜態變量隱藏

static_values_off保存了每個類中靜態變量值的偏移量,指向data區的一個列表,格式爲encode_array_item,如果沒有此項內容,此值爲0,所以要實現靜態變量賦值隱藏只需要將static_cales_off值修改爲0即可。

2、函數重複定義

class_def -> class_data -> virtual_methods -> code_ff表示的是某個類中某個函數的代碼偏移地址。

這裏提一點,Java中所有函數實現都是虛函數,這一點和C++是不一樣的,所以所有這裏修改的都是virtual_methods中的code_off。

大概的原理和實現方式就是,讀取第一個函數的代碼偏移地址,將接下來的函數偏移地址都修改爲第一的值。

根據文件偏移量確定函數的,這樣就實現了函數重複定義。

在這裏插入圖片描述

3、函數隱藏

class_def -> class_data -> virtual_methods_size和class_def -> class_data -> direct_methods_size記錄了類定義中函數的個數,如果沒有定義函數則該值爲0.所以只要將該值改爲0,函數定義就會被隱藏。

老規矩,代碼先不管。
在這裏插入圖片描述

4、類定義隱藏

手段比較重的隱藏是直接隱藏了類的所有東西,包括成員變量,成員函數,靜態變量,靜態函數。

在class_def -> class_data_off保存了具體類定義的偏移地址,也就是class_def -> class_data的地址,把該值爲0即可實現隱藏。

APK加固

在這裏插入圖片描述
需要:

  • 需要加密的APK
  • 殼程序APK
  • 加密工具(將Dex合併成新的Dex)

源APK經過加密,然後用殼APK(沒錯,殼也是APK)的dex和源APK的dex文件進行融合,得到一個全新的dex,然後再打包成新的APK,這個新的APK已經不是傳統意義的APK了,他的主要工作是:負責解密源Apk,然後加載Apk,讓它正常運行起來。

源APK和殼Dex合併成新的Dex

我們主要看head頭,因爲head頭可以用來校驗整個包的完整性和安全性。
在這裏插入圖片描述

  • checksum

    文件校驗碼,使用alder32算法校驗文件除去magic, checksum外餘下的所有文件區域,用於檢查文件錯誤。破解後如果提示"文件已損壞",就是這個地方數據出了問題。

  • signature

    使用SHA-1算法hash除去magic, checksum和signature外餘下的所有文件區域,用於唯一識別本文件。

  • File_size

    Dex文件的大小。

    因爲將一個文件(加密之後的源Apk)寫入到Dex中,那麼肯定需要修改文件校驗碼(checksum)、signature,因爲他是檢查文件和簽名是否有錯誤,還有就是需要修改dex文件的大小。

    還需要一個操作,就是標註一下加密的APK的大小,因爲在脫殼的時候,需要知道Apk的大小,才能正確的得到Apk。這個值放到哪裏呢,直接放到文件末尾就可以了。

    所以修改之後得到新的Dex文件樣式如下:
    在這裏插入圖片描述

(1)源程序項目(需要加密的Apk)

(2)脫殼項目(解密源Apk和加載Apk,其實就是殼APK)

(3)對源Apk進行加密和脫殼項目的Dex的合併

加密代碼:

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述

APK脫殼

在這裏插入圖片描述
1、從脫殼Apk獲取到Dex文件

2、從脫殼Dex中得到源Apk文件

3、解密源程序Apk

4、加載解密之後的源程序Apk

5、找到源程序的Application程序,讓其運行。

兩種思路:

一、替換LoadedApk中的mClassLoader

加載一個Activity肯定不像加載一般的類那樣,因爲activity作爲系統的組件有自己的聲明週期,所以不能像其他類一樣自定義一個DexClassLoader類加載器來加載插件中的Activity。它有專門的啓動流程這裏不做過多描述,只需要知道加載Activity的時候,有一個很重要的類:LoadedApk.Java
在這裏插入圖片描述
這個類是負責加載一個Apk程序的,其內部有一個mClassLoader變量,是負責加載一個Apk程序的,只要獲取到這個類加載器就可以獲取到APK內容了,所以還得獲取一個LoadedApk對象。再去看一下另外一個類ActivityThread.java的源碼
在這裏插入圖片描述
ActivityThread類中有一個自己的static對象,然後還有一個ArrayMap存放Apk包名和LoadedApk映射關係的數據結構,那麼分析清楚了,下面通過反射來獲取mClassLoader對象就可以拿到想要的Apk包了。
在這裏插入圖片描述

合併PathClassLoader和DexClassLoader中的dexElements數組

PathClassLoader和DexClassLoader類的父加載器是BootClassLoader,他們的父類是BaseDexClassLoader。裏面有一個DexPathList對象,在來看一下DexPathList.java源碼:
在這裏插入圖片描述
首先看一下這個類的描述,還有一個Elements數組,這個變量是專門存放加載的dex文件的路徑的,系統默認的類加載器是PathClassLoader,一個程序加載之後會釋放一個dex出來,這時候會將dex路徑放到裏面,

當然DexClassLoader也是一樣的,可以將DexClassLoader中的dexElements和PathClassLoader中的dexElements進行合併,然後在設置給PathClassLoader中。
在這裏插入圖片描述
在這裏插入圖片描述

refer:

https://www.jianshu.com/p/6a504c7928da

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章