Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android native反調試方式及使用IDA繞過反調試

Android native反調試方式及使用IDA繞過反調試

編輯:關於Android編程

0x00

為了避免我們的so文件被動態分析,我們通常在so中加入一些反調試代碼,常見的Android native反調試方法有以下幾種。

1、直接調用ptrace(PTRACE_TRACEME, 0, 0, 0),參考Android Native反調試。

2、根據上面說的/proc/$pid/status中TracerPid行顯示調試程序的pid的原理, 可以寫一個方法檢查下這個值, 如果!=0就退出程序。參考Android Native反調試,用JNI實現APK的反調試。

3、檢查代碼執行的間隔時間,參考Android應用方法隱藏及反調試技術淺析的0×03反調試初探。

4、檢測手機上的一些硬件信息,判斷是否在調試器中,參考Android應用方法隱藏及反調試技術淺析的0×03反調試初探。

0x01

那麼我們如何過掉這些反調試呢?

我們以阿裡比賽第二題為例,參考安卓動態調試七種武器之孔雀翎 – Ida Pro。

我們講解兩種方式:

1、Ida Patch so

2、Ida動態修改內存數據和寄存器數值

我們首先講解Ida Patch so,有幾處都可以patch。我們從易到難依次講解。

第一處:

我們在JNI_ONLOAD下斷點,如下圖:

\

依次單步執行到BLX R7

\

我們發現當執行完這步後,我們的ida就退出了,說明反調試代碼是從這個入口進入執行的。那麼我們只要把這個入口給NOP掉,就可以繞過反調試了。

Patch so就是修改so中的二進制代碼,然後再重新簽名生成新的apk。Patch so,需要修改的本地so中的代碼,而不是內存中的,所以我們需要通過上圖內存中指令地址減去so在內存中的基地址來獲取這條指令在本地so文件中的偏移。那麼so在內存中的基地址怎麼獲取呢?按Crtl+s。

\

我們看到libcrackme.so的基地址是AB732000,用BLX R7的地址AB733C58減去AB732000,等於1C58。

然後我們雙開ida,在另一個ida中打開libcrackme.so,按G,然後輸入1C58,果然我們調到了BLX R7的位置,如下圖:

\

下面就要把這行代碼NOP,可以修改為00 00 00 00,也可以修改為00 00 A0 E1。

\

修改後點擊右鍵,applay change。然後重新簽名生成apk,再次運行apk,ida調試時就沒有反調試的干擾了。

第二處:

我們按F7進入BLX R7的內部執行,如下圖:

\

是創建了一個線程去執行反調試,這裡有個小技巧,如果我們想回到剛才的函數BLX R7,怎麼辦呢?選擇寄存器LR,然後點擊右鍵選擇Jump即可,同理選擇PC是跳到當前的位置。

\

這個線程執行的函數體是sub_AB7336A4,如下圖:

\

sub_AB7336A4函數體如下:

\

這個方法循環執行sub_AB73330C。我們進入sub_AB73330C,懷疑這裡就是真正檢查是否處於調試狀態的地方,但是代碼經過了嚴重的混淆,所以找不到反調試的代碼。

那怎麼辦呢?在0x00中我們談到了常見的反調試代碼,最常見的是第二種方式,第二種方式檢查的過程中會調用fopen,所以我們在libc的fopen方法下斷點,來是哪個函數調用的fopen,基本上就可以斷定這個函數是反調試代碼。

首先我們需要找到fopen的位置,按Alt+T,然後輸入fopen關鍵字,如下圖:

\

找到fopen後,代碼是這樣的:

\

此時按P,就可以變成代碼形式。如下圖,在fopen處下斷點。
\

點擊F9,繼續運行,我們看到程序停在fopen處,此時LR就是剛剛我們談到的sub_AB73330C,如下圖:

\

所以我們可以確定sub_AB73330C就是進行反調試的代碼。我們可以看到這個函數是被sub_AB7336A4調用的。

\

點擊右側的CODE XREF:sub_AB7336A4就能進入到調用sub_AB73330C的地方。在sub_AB7336A4函數上按F5,就能看到對應的C語言代碼。如下:

\

可見程序是在sub_AB73330C循環檢測是否被反調試的。

此時我們可以用和第一處一樣的方式,找到本地so中對應的方法,然後Patch so,Nop掉對應的方法,然後重新簽名,重新運行。

第三處:

其實第三處和第二處原理是一樣的,只不過這裡不使用Nop了,sub_AB73330C開始和結束的匯編代碼如下:

開始時:

\

結束時:

\

所以我們可以把AB733310的代碼修改為AB73363C處的代碼,不執行任何操作,直接返回。

0x02

Ida動態修改內存數據和寄存器數值

我們看到反調試方法第二點,代碼如下:

void be_attached_check()
{
    try
    {
        const int bufsize = 1024;
        char filename[bufsize];
        char line[bufsize];
        int pid = getpid();
        sprintf(filename, "/proc/%d/status", pid);
        FILE* fd = fopen(filename, "r");
        if (fd != nullptr)
        {
            while (fgets(line, bufsize, fd))
            {
                if (strncmp(line, "TracerPid", 9) == 0)
                {
                    int statue = atoi(&line[10]);
                    LOGD("%s", line);
                    if (statue != 0)
                    {
                        LOGD("be attached !! kill %d", pid);
                        fclose(fd);
                        int ret = kill(pid, SIGKILL);
                    }
                    break;
                }
            }
            fclose(fd);
        } else
        {
            LOGD("open %s fail...", filename);
        }
    } catch (...)
    {

    }

}
我們發現該程序會用fopen ()打開/proc/[pid]/status這個文件,隨後會用fgets()和strcmp()來比較,於是我們在strcmp()處下個斷點,然後讓hex view的數據與R0同步。每次點擊繼續,我們都會看到strstr傳入的參數。當傳入的參數變為TracerPid:XXXX的時候我們停一下。因為在正常情況下,TracerPid的值應該是0。但是當被調試的時候就會變成調試器的pid。

我們在strcmp下斷點:

\

程序會在此處斷下,當我們發現R0地址中的內容為TracerPid:XXXX時,我們停一下,如下圖:

\

R0的裡面存的地址是AB731B25,裡面的內容為,如下圖:

\

我們可以通過修改內存值的方式來過掉這一次反調試。

\

把TracerPid改為0,如下圖:

\

然後點擊Apply changes。這樣就可以過掉這次反調試。我們在前面也看到了,程序是在一個循環中進行反調試檢查,所以這樣的方試只是過了其中一次反調試。

不推薦使用這種方式,最好使用Patch So的方式。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved