Apk脫殼聖戰之---脫掉 愛加密 的殼
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
一、前言
今天是端午節,然而小編不能吃粽子了,只能繼續破解之路,今天我們來看一下在瞭解了破解三部曲之後,如何開始脫掉各個市場中的apk殼,關於破解三部曲在之前已經介紹了:
第一篇:Android中使用Eclipse動態除錯smali原始碼
第三篇:Android中破解加固的apk
在看完這三篇文章之後,我們開始操作如何破解市場中的加殼方案,現在市場中比較流行的加殼平臺就那麼幾個:愛加密,梆梆加固,360加固,騰訊加固等,所以後面會一一介紹如何脫掉這些平臺的殼。之前也說過現在加固的方案大體思路都是:把源apk進行加密拆分處理,然後在套一個外部的殼Application做一些初始化操作:比如解密apk,動態載入執行即可。但是我們已經知道了如何去破解那些加固的apk了,就是使用IDA給dvmDexFileOpenPartial函式下斷點,然後dump出記憶體中的dex資料即可。因為記憶體中的dex肯定是解密之後的,所以大體思路知道了,但是這些加固平臺也有對策,他們會把做一些反除錯操作,對so檔案進行混淆加密等,讓我們的除錯變得比較困難。這才是我們脫殼的阻礙地方。
二、案例分析
好了,說了這麼多,下面我們就開始脫殼第一站:愛加密家的殼
為了脫掉他家的殼,我們得首先有一個案例程式,這個比較簡單,我們自己弄一個demo程式,然後去他家的網站上加固一下,得到加固之後的apk,然後這時候我們開始破解了,按照慣例:
第一步:解壓apk,看看大體的目錄,得到classes.dex檔案,然後用dex2jar+jd-gui得到Java原始碼
看到,這裡只有Application的殼,而且這個是愛加密加固之後的特點,都是這兩個Application的。
第二步:使用apktool來反編譯apk,獲取資原始檔資訊
分析一下愛加密的加密流程
也是國際慣例,愛加密把我們的源程式進行加密操作然後隱藏到了一個地方,在之前破解加固apk的那篇文章中也說過了,隱藏的地方就那麼幾個:assets目錄、libs目錄、自己的dex檔案中
這裡我們直接看assets目錄:
多了這個東東,猜想這個可能就是處理之後的源apk了。我們在AndroidManifest.xml中看到了入口的Application類,先來看這個類
下面我們來分析一下這個SuperApplication類:
這裡一般都是在attachBaseContext這個方法中進行操作的,這裡的時機比較早,我們看到首先會呼叫loadLibs方法進行載入libs:
這裡區分不同的平臺,然後進行拷貝不同的so檔案,繼續看copyLib方法:
這裡我們可以看到了,從assets目錄下把愛加密增加的兩個so檔案:libexec.so和libexecmain.so拷貝到應用程式的files目錄下,我們可以去看看assets/ijm_lib目錄下的so檔案:
到這裡loadLibs方法就執行完了,下面就開始呼叫NativeApplication的load方法進行載入資料,繼續看NativeApplication類:
這裡會開始從應用程式的files目錄中載入這兩個so檔案,而且load方法也是一個native方法,我們繼續看看這兩個so檔案內容:
我們首先用IDA開啟libexecmain.so檔案,但是發現,他裡面並沒有什麼重要資訊,連JNI_OnLoad函式都沒有東東
我們繼續在檢視libexec.so檔案:
擦,可惜的是,開啟提示so檔案格式錯誤,到這裡,我們就猜到了,這個so可能被加密處理了,elf格式改了,關於so如何進行加密操作的,不瞭解的同學可以看這裡:Android中如何對so檔案進行加密 那麼這裡我們點選Yes繼續強制開啟之後,在使用Ctrl+S檢視so的各個段資訊:
現在可以百分百的確定,這個so檔案被處理了,段格式被修改了。我們沒辦法分析so檔案了,當然這裡我們可以在dump出記憶體中的so檔案,然後在分析的,但是這個不是今天講解的重點。我們先分析到這裡,也知道了愛加密的大體加密流程。
好了,到這裡,我們差不多分析完了愛加密的加密流程了:
1、按照國際慣例把源apk進行加密處理存放在一個地方,通過分析猜想是assets目錄下的ijiami.dat檔案
2、新增殼Application:SuperApplication類,在這個殼的attachContext方法中,主要做了兩件事:
1》第一件事是把assets/ijm_lib目錄下的兩個so檔案copy到程式的files目錄中;
2》第二件事是呼叫NativeApplication的load方法,在這個類中同時也把上面的兩個so檔案載入到記憶體中
3、對apk的加密操作都是放在底層的兩個so檔案中操作的,我們通過IDA去分析這兩個so檔案之後,發現核心功能的so檔案被加密了,IDA開啟是看不到具體資訊了
到這裡,我們知道愛加密加固之後的特點是:在程式的assets目錄下多了一個ijiami.dat檔案和兩個so檔案,同時這兩個so檔案被加密處理了,增加破解難度。
三、破解脫殼
上面就簡單分析了愛加密的原理和流程,但是我們沒有繼續往下面分析了,因為這個不是我們今天講解的重點,我們今天的重點是如何脫掉愛加密的殼,那麼還是開始說到的,脫殼的核心就一個:給dvmDexFileOpenPartial函式下斷點,dump出記憶體的dex檔案即可,那麼下面我們就是用IDA開始脫殼操作了:
第一步:啟動裝置中的android_server,然後進行埠轉發
adb forward tcp:23946 tcp:23946
第二步:用debug模式啟動程式
adb shell am start -D -n com.droider.crackme0201/.MainActivity
這裡的包名和入口Activity都可以在上面反編譯之後的AndroidManifest.xml中找到
第三步:雙開IDA,一個用於靜態分析libdvm.so,一個用於動態除錯
記錄dvmDexFileOpenPartial函式的相對地址:4777C
再次開啟一個IDA,進行attach除錯程序
第四步:使用jdb命令attach上偵錯程式
jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8700
第五步:對dvmDexFileOpenPartial函式下斷點
進入除錯頁面之後,Ctrl+S查詢libdvm.so的記憶體基地址:415BB000
在第三步得到相對地址:4777C+415BB000=4160277C 得到了dvmDexFileOpenPartial在記憶體中的絕對地址
注意:
當然這裡還有一個更方便的辦法:
就是直接開啟Modules View:
在這裡查詢libdvm.so檔案:
然後雙擊libdvm.so檔案:
查詢需要下斷點的函式名稱,看到這裡的絕地地址也是:4160277C
這裡有兩種方式可以得到一個函式在記憶體中的絕對地址。
然後我們使用G鍵,直接跳轉到函式處,下斷點:
第六步:設定Debugger Options選項
能夠讓程式斷在dvmDexFileOpenPartial函式處
注意:
上面的第四步,第五步,第六步,沒有順序的,只要在執行之前設定到就可以了。
第七步:執行程式
出現這個對話方塊,不要在意,一路點選Cancel即可
jdb也attach上了除錯程式:
我們一路點選執行按鈕,知道執行到dvmDexFileOpenPartial處的斷點,但是可惜的是,這裡我們遇到了錯誤:
我們點選OK之後,出現了下面對話方塊:
再次點選任何一個按鈕,都會退出了除錯頁面:
我們在重新嘗試一次上面的流程,開始除錯,但是錯誤是一樣的,好了,到這裡我們就立馬想到了,之前說的IDA除錯so的那篇文章遇到的那個問題:反除錯檢測
當時我們也是遇到這個情況,在沒有執行到我們下的斷點處,就退出了除錯頁面,其實這個是現在加固平臺必要選擇的一種方式,其實反除錯原理很簡單,就是在程式執行最早的時機比如so載入的時候即:JNI_OnLoad方法中,讀取本程序的status檔案,檢視TracerPid欄位是否為0,如果不為0,那麼就表示自己的程序被別人跟蹤了,也就是attach了,那麼這時候立馬退出程式,下面我們使用IDA在attach程序成功之後,檢視本程序的status資訊:
看到這裡的TracerPid為11340,不為0,表示被11340程序attach了,那麼我們可以檢視一下這個程序是誰:
其實這個程序就是我們在裝置中安插的android_server,它用於和IDA進行通訊。
好了到這裡,我們可以看到愛加密做了反除錯檢測,但是按照之前的那篇文章中,我們可以給JNI_OnLoad函式下斷點,然後找到檢測程式碼,把對應的arm指令改成空指令,檢測失效了,但是這裡我們知道愛加密的兩個so檔案被處理了,IDA沒法分析了,那麼這裡我們該怎麼辦呢?如何應對反除錯呢?其實我們可以藉助IDA可以修改暫存器和記憶體資料的特性來做到?
首先我們上面分析了反除錯的原理,一般在native程式碼去做檢測的話,都是用fopen系統函式開啟status檔案,然後用fgets函式讀取一行的內容,這個是國際慣例的,操作檔案都是用的fopen函式的
好了,那麼這裡思路就有了:既然反除錯肯定用到了fopen和fgets這兩個函式,那麼我們直接像給dvmDexFileOpenPartial下斷點的方式一樣,給這兩個函式下斷點,然後執行到fgets斷點處的時候,發現如果是讀取TracerPid這行內容的時候,就開始修改記憶體內容,把TracerPid欄位的值改成0,或者修改R0暫存器的內容,跳過反除錯檢測
這兩個函式是在libc.so檔案中的,我們可以把裝置的/system/lib/libc.so使用adb pull到本地即可,然後用IDA得到他的相對地址,在除錯頁面得到基地址,然後相加得到絕對地址,跳轉即可,但是這裡不用這種複雜的方式,有兩種方式可以進行跳轉:
第一種方式:在Modules介面,找到libc.so,然後在找到這兩個函式,就可以得到他們的絕對地址了
然後使用G鍵,跳轉下斷點即可:
第二種方式:也是最簡單的方式,就是G鍵,本身就有可以直接輸入函式名進行跳轉的功能
下斷點:
看到了吧,這種方式是不是非常簡單高效
好了到這裡就給這兩個函式下好了斷點,當然這裡還需要給dvmDexFileOpenPartial函式下斷點,一切弄好了之後,這時候我們再次執行:
停在了fopen斷點處,我們使用F8單步除錯,看到R7暫存器中的內容是/proc/...,我們直接點選R7檢視全部內容:
內容有點長,大致的內容是:/proc/self/cmdline.debug.atrace.app_cmdlines,這個是幹什麼的?
我們看看這個目錄內容:
發現沒有這個檔案內容,只有cmdline檔案,但是這裡先不管他了,我們知道這個肯定不是讀取status檔案的,那我們直接略過這個斷點,點選F9執行到下一個斷點,中間過程先忽略,一路F9,直到執行到了fopen這個斷點:
果然,這裡使用了fopen來讀取status檔案了,點選R7暫存器檢視全部內容:
這個16396就是我們本程序的id:
到這裡,我們知道下一個斷點肯定是fgets,所以點選F9進入到fgets斷點處:
這裡還看不到什麼資訊,我們繼續點選F8單步除錯:
途中,會看到有memchr和memcpy這兩個重要函式,這個也是操作字串的核心點,繼續往下走:
到了fgets函式結束的地方,我們看到了R0暫存器的內容是Name...點選R0檢視全部內容:
全部內容是:Name: der.crackme0201;這個就是status檔案的第一行內容:
到這裡,我們知道了,開始讀取status檔案的每行內容了,但是到TracerPid那行還要繼續執行5次fgets函式,所以還會進入5次斷點,為了節省時間,這裡點選5次F9,直接執行到讀取TracerPid那行的內容的fgets斷點處:
看到了關鍵的內容了TracerPid欄位了,這時候,我們開啟Hex View 檢視16進位制的記憶體資料:
但是我們看到,這個並沒有和除錯頁面View位置相對應,我們可以這麼操作:
在暫存器視窗檢視到R0暫存器的內容:
這裡就是TracerPid欄位在記憶體的地址,記錄一下,然後在Hex View頁面中使用G鍵,進行跳轉,這裡一定要注意是在HexView,而不是除錯頁面,除錯頁面使用G鍵跳轉到的是指令地址了。
好了,這裡我們看到了TracerPid的記憶體內容了,這裡我們就開始修改吧,選擇我們要修改的內容:是11340那裡:
選擇內容開始處,右擊,選擇Edit,進入修改狀態:
改了之後的內容是橘黃色的,修改完成之後,在點選右鍵,選擇Apply changes:
完成修改,顏色變成灰土色了:
注意:
這裡其實還可以直接修改暫存器R0的值:
這時候就表示修改成了,我們繼續使用F8單步除錯下去:
這裡就開始把TracerPid欄位的值和0作比較了,我們點選R0暫存器檢視全部內容:
這裡的值已經被改成了0,所以這裡就騙過去了。繼續執行,我們會發現,又進入了fopen函式的斷點處,而且檢視還是讀取status檔案,這個也不好奇,因為是反除錯檢測肯定是一個輪訓機制的,所以肯定會反覆的讀取的這個檔案,fopen走多次也是正常的,但是這個反除錯肯定是在子執行緒的,所以只要到了主執行緒中解密dex檔案就肯定到了dvmDexFileOpenPartial,所以這裡會多次重複上面的操作,修改多次TracerPid的值,這裡就不在演示了,我在操作的過程中修改了三次,當沒有在走fopen函式的時候,遇到了這個錯誤,這裡不關心,直接點選ok就可以了。
再次點選執行:
這裡說明已經改開始解密dex檔案了,應該離成功不遠了,繼續執行:
終於到了我們想要的地方了,到這裡就好辦了,直接點選Shirt+F2,開啟指令碼執行視窗,執行下面指令碼:
static main(void)
{
auto fp, dex_addr, end_addr;
fp = fopen(“F:\\dump.dex”, “wb”);
end_addr = r0 + r1;
for ( dex_addr = r0; dex_addr < end_addr; dex_addr ++ )
fputc(Byte(dex_addr), fp);
}
把記憶體中的dex儲存到F:\dump.dex中,這裡不再解釋了,之前的一篇文章已經介紹過了,這裡R0暫存器就是dex在記憶體中的起始地址,R1暫存器就是dex檔案的大小:
我們使用G鍵,可以在HexView頁面中檢視R0暫存器中的地址內容:
看到了吧,這裡就是dex的標頭檔案格式。
四、還原應用apk
我們得到了記憶體中的dex資料之後,可以使用baksmali工具轉化成smali原始碼,檢視程式碼邏輯即可,這裡不再演示了。
然後最後還有一步:還原apk
首先我們修改反編譯之後的AndroidManifest.xml中:
把這段內容刪除,如果有自己的Application的話,就改成自己的Application即可,同時刪除assets目錄下面的檔案。
然後使用apktool進行回編譯,這時候,先不要著急簽名apk,而是替換classes.dex:
我們把上面得到的dump.dex改成classes.dex然後直接用壓縮軟體,替換未簽名的apk中的dex檔案即可
最後在進行簽名操作,完成還原apk工作。
五、總結愛加密的破解流程
好了到這裡,我們算是脫殼成功了,下面來總結一下吧:
目標:
在脫殼的過程中,我們就一個目標:dump處記憶體中的dex檔案
但是在上面分析了愛加密的加固流程之後,發現他做了這些事:
1、把源程式apk加密處理放到了assets目錄下的ijiami.dat,也同時在assets\ijm_lib目錄下新增兩個so檔案:libexec.so和libexecmain.so,這裡兩個so檔案用來處理整個apk解密,動態載入等邏輯,但是我們用IDA檢視得知,這兩個so檔案被加密處理了
2、新增自己的殼Application:SuperApplication類,這個類中的attachContext方法中,首先把assets目錄中的兩個so檔案copy到應用的files目錄下,然後在使用System.load方法,載入這個files目錄中的兩個so檔案
3、我們在給dvmDexFileOpenPartial下斷點,進行除錯的時候,發現有反除錯檢測,因為無法給JNI_OnLoad下斷點來去除反除錯功能的arm指令,所以只能去修改記憶體資料,把TracerPid的值變成0,騙過檢測了。這裡我們的思路就是給fopen和fgets這兩個函式下斷點,因為我們知道反除錯的原理就是讀取本程序的status檔案,然後獲取TracerPid那行內容即可,所以這裡肯定用到了fopen和fgets函式,在使用fgets這個函式的時候,會讀取每行內容,那麼我們只要發現在讀取到TracerPid那行內容的時候,去修改記憶體值,把TracerPid欄位的值改成0即可。
4、有了上面的反除錯思路之後,我們就開始進行操作了,但是在操作的過程中發現多次執行了fopen和fgets函式,而且我們需要修改多次TracerPid的值,原因很簡單,因為是反除錯檢測,肯定是在子執行緒中輪訓去檢測這個值,所以會執行多次很正常,所以我們要修改多次TracerPid的值,騙過檢測,直到當在主執行緒中,程式碼執行到了解密dex檔案的時候,即到了dvmDexFileOpenPartial函式處的斷點處為止
5、最後修改多次TracerPid值,騙過檢測,到了dvmDexFileOpenPartial這裡,這時候,在執行dump指令碼,把記憶體中的dex資料dump到本地即可。
通過上面的除錯和破解流程其實不難發現,愛加密的流程是這樣的:
1》fopen—/proc/self/cmdline.debug.atrace.app_cmdlines
2》fgets—-com.droider.crackme0201
3》dvmLoadNativeCode–載入libexec.so
4》dvmLoadNativeCode–載入libexecmain.so
5》建立反除錯執行緒(通過檢查是否存在除錯程序)
6》呼叫fopen—-開啟/proc/pid/status
7》呼叫fgets—讀取除錯程序pid
這裡除了dvmDexFileOpenPartial函式,還有一個重要的函式dvmLoadNativeCode,它是載入和初始化so的函式,如果感興趣的同學,可以去給這個函式下斷點看看執行邏輯。
所以我們只要記住我們的目的只有一個:達到dvmDexFileOpenPartial函式處,dump處記憶體中的dex檔案,就算是完成脫殼工作
六、總結
到這裡我們就分析完了如何去脫掉愛加密的殼,其實在之前說過,現在各個加固平臺的原理都差不多,最後看到的就是各家的加固演算法了,所以我們在脫殼的過程中目標也很明確,就是dump出記憶體中的dex檔案即可。不管他上層再怎麼牛逼的加密拆分操作,到了記憶體肯定是完整的dex檔案了,所以現在加固平臺也是一個思想就是不讓你dump出來,就是讓你給dvmDexFileOpenPartial函式下斷點失敗,除錯失敗。
《Android應用安全防護和逆向分析》
點選立即購買:京東 天貓
更多內容:點選這裡
關注微信公眾號,最新Android技術實時推送