一、前言
通常對於加殼的程序,第一步的操作通常是脫殼,而現在脫殼一般都選擇利用frida
來進行hook
進行脫殼,不談其他脫殼方式,利用frida
脫殼原理大致分爲兩種:
1、找到DexFile對象(art虛擬機下是DexFile對象,dalvik虛擬機下是DexFile結構體),獲取到DEX文件的起始地址和大小,然後dump
下來。常見能夠找到DexFile對象
的函數有LoadMethod
、ResolveMethod
函數等,能直接獲取到DEX起始地址和大小
的常見函數有openMemory
、dexparse
、dexFileParse
、dvmDexFileOpenPartial
等函數。frida_unpack
便是其中的代表作。
2、利用frida的搜索內存,通過匹配DEX
文件的特徵,例如DEX
文件的文件頭
中的magic
---dex.035
這個特徵。frida-Dexdump
便是這種脫殼方法的代表作。
然而不管是上述哪一種原理,在我這個有點強迫症
的看來,都有一點小缺陷,這兩種方法從原理上決定了經過某個函數的DEX
(或者存在於內存中的DEX
)都會被dump
下來,所以出現了dump
下來很多個DEX文件
,但是隻有其中一個或者幾個是我們的目標DEX
,爲了尋找到目標DEX
,只有全部反編譯出後來能知道,這就比較浪費時間和精力了,對此,本人對脫殼腳本做了一些改進,通過對dump
下來的DEX
進行解析,從而識別出那個是我們的目標DEX
!!!
二、通過類名識別出DEX
PS:通過類名識別是本人發現識別率最準確、實現代價最小的方法,所以本篇重點主要在這,後面的其他識別方法在某些特殊情況下更好用!!!
DEX
文件的格式可以大致分爲文件頭
、索引區
、數據區
,文件頭
這個區域無法找到一個DEX
文件的一個唯一特徵
(ps:sha-1
和校驗碼
這兩個能作爲一個DEX文件
唯一特徵的前提是我們已經知道這個dex
文件所有字節了,所以放在這裏並不成立),索引區
包括了很多數據的索引,其中便包括字符串
的索引,通過這我們可以解析出整個DEX
文件使用到的字符串。而我們已知的DEX
文件的一些信息便包括包名
。
通過解析一個DEX
文件,我們可以發現在DEX
中一個類被表示出如下形式--L包名/類名;
,例如Lcom/example/test/ManActivity;
這種形式,例如下面爲使用腳本解析DEX
的字符串,獲取到的類名的截圖:
包名是唯一的,所以我們只需要構造/com/example/test
這種形式的特徵,便可以很輕易的鎖定到目標DEX
,但是,在殼程序
中,也可能含有這種類型的字符串,我們的特徵便不再是唯一的,這個時候,我們便需要一個新的唯一特徵。
在一個APP中,我們通常所寫的類不止一個,而是很多個,那麼便含有很多個上述所說的特徵
;而寫過加殼程序都應該知道,我們在加殼程序中,最多也就拉起那麼一個或幾個類。那麼,通過這種數量上的差異同樣也可以作爲唯一特徵,以下是脫殼改進腳本腳本
運行截圖:
三、其他識別方法
1、其他字符串,通過將app安裝運行手動觀察到的,但是這種方式有點碰運氣,只有直接寫入到java
源碼中的才能作爲特徵,寫入到strings.xml
便不得行。如下截圖(ps:爲直接寫入到java中的,可以在字符串池中解析出來的),解析字符串池:
2、佈局xml文件名、控件名(ps:這種可行性太低,在這裏籌字數的,基本不能作爲特徵)
3、佈局、控件資源ID,這些16進制搜索整個DEX文件也可以作爲特徵,但是有很其他DEX文件裝車的可能。
4、方法原型,例如一個方法返回值是Double,參數也是Double,那個這個方法原型便是FF
,而這個方法原型一定存在於字符串池中,但是也不是很靠譜這個特徵,原因如下截圖所示(而且還需要知道一個方法纔行):
5、對DEX做更深入解析,解析出更多特徵,而不僅僅止於解析出字符串池,感興趣的研究一下,但第一個依靠類名便夠用了。