1. 程式人生 > >Apk脫殼聖戰之---脫掉 愛加密 的殼

Apk脫殼聖戰之---脫掉 愛加密 的殼

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

一、前言

今天是端午節,然而小編不能吃粽子了,只能繼續破解之路,今天我們來看一下在瞭解了破解三部曲之後,如何開始脫掉各個市場中的apk殼,關於破解三部曲在之前已經介紹了:

第一篇:Android中使用Eclipse動態除錯smali原始碼

第二篇:Android中使用IDA動態除錯so原始碼

第三篇: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技術實時推送


           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述