1. 程式人生 > >Android反除錯筆記

Android反除錯筆記

1)程式碼執行時間檢測

通過取系統時間,檢測關鍵程式碼執行耗時,檢測單步除錯,類似函式有:time,gettimeofday,clock_gettime.

也可以直接使用匯編指令RDTSC讀取,但測試ARM64有相容問題。

time_t t1, t2;
time (&t1);
/* Parts of Important Codes */
time (&t2);
if (t2 - t1 > 2) {
    puts ("debugged");
}

2)檢測 procfs 檔案系統變化

程序的狀態資訊能通過 procfs 系統反饋給使用者空間,除錯會使程序狀態發生變化:

char
file [PATH_LEN]; char line [LINE_LEN]; snprintf (file, PATH_LEN-1, "/proc/%d/status", pid); FILE *fp = fopen (file, "r"); while (fgets (line, LINE_LEN-1, fp)) { if (strncmp (line, "TracerPid:", 10) == 0) { if (0 != atoi (&line[10])) { /* encrypt random .TEXT code */
} break; } } fclose (fp);

類似可以檢測的介面還有:

/proc/pid/status
/proc/pid/task/pid/status
/proc/pid/stat
/proc/pid/task/pid/stat
/proc/pid/wchan
/proc/pid/task/pid/wchan

3)利用訊號機制

ARM程式下斷點,偵錯程式完成兩件事:

  1. 儲存目標地址處指令
  2. 將目標地址處指令替換成斷點指令
指令集 指令
Arm 0x01, 0x00, 0x9f, 0xef
Thumb 0x01, 0xde
Thumb2 0xf0, 0xf7, 0x00, 0xa0

當命中斷點時,系統產生SIGTRAP訊號,偵錯程式收到訊號後完成下面操作:

  1. 恢復斷點處原指令
  2. 回退被跟蹤程序的當前PC

這時當控制權回到被除錯程式時,正好執行斷點位置指令。這就是 ARM 平臺斷點的基本原理。

可以看到,斷點是通過處理 SIGTRAP 訊號來實現的,假如我們自己註冊 SIGTRAP 的訊號處理函式,並在程式中主動執行中斷指令觸發中斷。

在中斷處理函式中,NOP 掉斷點指令,程式可正常執行。但在除錯狀態下,偵錯程式遇到斷點指令時,會去恢復原先指令,由於不是偵錯程式下的斷點,所以恢復會失敗,而偵錯程式會繼續第2步操作,回退PC暫存器,程式會在此處無限迴圈。

4)軟體斷點檢測

斷點會替換記憶體中原有指令,因此通過檢測記憶體中的斷點指令,可以檢測除錯:

#include<stdlib.h>
#include<stdio.h>
#include<elf.h>
#include<string.h>
#include<unistd.h>
#include<dlfcn.h>

voidcheckBreakPoint();
unsignedlonggetLibAddr(constchar *lib);

#define LOG_TAG "ANTIDBG_DEMO"

#include<android/log.h>
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

intmain(){
    dlopen ("./libdemo.so", RTLD_NOW);
    sleep (60);
    checkBreakPoint ();

    return 0;
}

unsignedlonggetLibAddr(constchar *lib){
    puts ("Enter getLibAddr");
    unsigned long addr = 0;
    char lineBuf[256];

    snprintf (lineBuf, 256-1, "/proc/%d/maps", getpid ());
    FILE *fp = fopen (lineBuf, "r");
    if (fp == NULL) {
        perror ("fopen failed");
        goto bail;
    }
    while (fgets (lineBuf, sizeof(lineBuf), fp)) {
        if (strstr (lineBuf, lib)) {
            char *temp = strtok (lineBuf, "-");
            addr = strtoul (temp, NULL, 16);
            break;
        }
    }
bail: 
    fclose(fp);
    return addr;
}

voidcheckBreakPoint(){
    int i, j;
    unsigned int base, offset, pheader;
    Elf32_Ehdr *elfhdr;
    Elf32_Phdr *ph_t;

    base = getLibAddr ("libdemo.so");
    if (base == 0) {
        LOGI ("getLibAddr failed");
        return;
    }

    elfhdr = (Elf32_Ehdr *) base;
    pheader = base + elfhdr->e_phoff;

    for (i = 0; i < elfhdr->e_phnum; i++) {
        ph_t = (Elf32_Phdr*)(pheader + i * sizeof(Elf32_Phdr)); // traverse program header

        if ( !(ph_t->p_flags & 1) ) continue;
        offset = base + ph_t->p_vaddr;
        offset += sizeof(Elf32_Ehdr) + sizeof(Elf32_Phdr) * elfhdr->e_phnum;

        char *p = (char*)offset;
        for (j = 0; j < ph_t->p_memsz; j++) {
            if(*p == 0x01 && *(p+1) == 0xde) {
                LOGI ("Find thumb bpt %p", p);
            } else if (*p == 0xf0 && *(p+1) == 0xf7 && *(p+2) == 0x00 && *(p+3) == 0xa0) {
                LOGI ("Find thumb2 bpt %p", p);
            } else if (*p == 0x01 && *(p+1) == 0x00 && *(p+2) == 0x9f && *(p+3) == 0xef) {
                LOGI ("Find arm bpt %p", p);
            }
            p++;
        }
    }
}

5)inotify 檔案系統監控

inotify 是一個核心用於通知使用者態檔案系統變化的機制,當檔案被訪問,修改,刪除等時使用者態可以快速感知。

1.使用 inotify_init() 初始化一個 inotify 例項並返回檔案描述符,每個檔案描述符都關聯了一個事件佇列:

int fd = inotify_init ();

2.拿到這個檔案描述符後下一步就告訴核心,哪些檔案發生哪些事件時你得通知我,通過函式 inotify_add_watch 實現:

int wd = inotify_add_watch (fd, path, mask);

第一個引數即 inotify_init 返回的檔案描述符,path 表示關注的目標路徑,可以是檔案目錄等。mask 表示關注的事件的掩碼,如 IN_ACCESS 代表訪問,IN_MODIFY 代表修改等

相應的,可以通過 inotify_rm_watch 來刪除一個watch:

int ret = inotify_rm_watch (fd, wd);

這樣,每當監視的檔案發生變化時,核心便給 fd 關聯的事件佇列裡面塞一個檔案事件。檔案事件用一個 inotify_event 結構表示,可以通過 read 來讀取:

structinotify_event {
        __s32           wd;             /* watch descriptor */
        __u32           mask;           /* watch mask */
        __u32           cookie;         /* cookie to synchronize two events */
        __u32           len;            /* length (including nulls) of name */
        char            name[0];        /* stub for possible name */
};
size_t len = read (fd, buf, LEN);
  • 通過監視 /proc/pid/maps 檔案的開啟事件,可防針對 360 加固的 dump 脫殼

  • 檔案變化與事件觸發非必然聯絡,例如 /proc/pid/status 中的 TracerPid 值在被除錯時是變化的,但其變化沒有事件發生,原因未知可能與 inofity 的核心實現有關

6)ptrace()

ptrace() 是 Linux 的一個系統呼叫,也是 Linux 下 gdb 等偵錯程式實現的基礎。它提供了 Linux 下一個程序跟蹤另一個程序暫存器、記憶體等的能力。

由於 ptrace() 到一個執行緒後,任何訊號都將導致執行緒STOP 並將控制權交由呼叫者 ,因此如果利用每個執行緒只能有一個ptrace跟蹤 來防止附加的話,需要處理好這個關係:

while (waitpid (g_childPid, &stat, 0) ) {
    if (WIFEXITED (stat) || WIFSIGNALED(stat)) {
        XXX_DEBUG_LOG ("waitpid : child died\n");
        exit (11);
    }
    ptrace (PTRACE_CONT, g_childPid, NULL, NULL);
}

7)多程序的反除錯實現


相關推薦

Android除錯筆記

1)程式碼執行時間檢測 通過取系統時間,檢測關鍵程式碼執行耗時,檢測單步除錯,類似函式有:time,gettimeofday,clock_gettime. 也可以直接使用匯編指令RDTSC讀取,但測試ARM64有相容問題。 time_t t1, t2; time (&

一個android除錯的學習

前言 初學android逆向除錯,用阿里上次的比賽練練手,第二題就是一個包含android反除錯機制的題目,於是仔細除錯分析了一下其反除錯的原理,記錄下來。 除錯方法 這個apk核心功能在so檔案中實現,於是試圖動態除錯so檔案,在關鍵函式下斷點之後,

Android除錯之 AntiEmulator 檢測安卓模擬器

八種方法檢測是否存在模擬器 檢查特定的幾個關鍵點 0×1 檢測“/dev/socket/qemud”,“/dev/qemu_pipe”這兩個通道 程式碼demo: Java 123456789101112131415161718private

Android 除錯、so檔案注入

關鍵程式碼: Thread t=new Thread(new Runnable() { @Override public void run() {

Android安全/應用逆向--29--在JNI_onload函式處下斷點避開針對IDA的除錯

7-6、在JNI_onload函式處下斷點避開針對IDA的反除錯 為了防止apk中的so檔案被動態除錯,開發者往往會使用一些反除錯手段來干擾黑客的動態除錯。其中最常見的就是在so檔案中檢測TracerPid值。通過在JNI_onload下斷點即可避開反除錯。 反

Android學習筆記整理(5)--Android程式除錯

每個Android應用上線之前都會進行一系列的測試,確保應用能夠正常使用。通常使用JUnit單元測試,另外還可以使用LogCat(日誌控制檯)來除錯錯誤。一、JUnit單元測試1.配置JUnit環境在進行JUnit測試時,我們需要在AndroidManifest.xml的&l

Android native除錯方式及使用IDA繞過除錯

    0x00     為了避免我們的so檔案被動態分析,我們通常在so中加入一些反除錯程式碼,常見的Android native反除錯方法有以下幾種。     1、直接呼叫ptrace(PTRACE_TRACEME, 0, 0, 0),參考Android Native反除

Ubuntu下使用gdb遠端除錯android native程式筆記

使用gdb遠端除錯android native程式1.準備工作:android native程式:demoandroid 上執行的除錯工具:gdbserver,該程式位於ndk目錄/prebuilt/a

android 中 ril 層除錯筆記和理解

 這段時間一直在弄android5.0 , 對 SELinux有了一定的瞭解,  上週是在折騰 4G 模組, 搞 ril  層的東西. 以前沒有好好理解 ril 層是怎樣工作的, 以前在網上看關於 ril 的文章, 感覺看不懂, 後來忙其它方面的東西, 沒有深入瞭解 ri

ANDROID編譯工具APKTOOL原始碼除錯過程

APKTOOL是目前反編譯ANDROID apk的主要工具,可以反編譯出APK裡的資原始檔和smali程式碼,而有些APK開發者為了防止自己的程式碼被反編譯,針對APKTOOL工具加固程式碼,使得APKTOOL無法執行正常,比如這篇文章介紹的Android應用資

阿里雲播放器除錯心得,android的學習筆記

   接觸android接近一個月,摸爬滾打實屬不易,加上又有諸多瑣事纏身,讓原本定下的計劃遲遲沒有完成。。    對於基礎知識的急於求成,處於一種有一些功利化的學習心態,所以適時的複習顯得空前重要。。   談談對安卓的理解,不論對錯,只對自己的理解做一些記錄:    

android 編譯 除錯入門資料

0x01 反編譯出錯 1.插入無效指令是部分逆向工具崩潰 原理:大部分逆向工具都是線性讀取位元組碼並解析, 如dex2jar,baksmali,apktool等,當遇到無效位元組碼時,就會引起反編譯工具解析失敗。例如:新版的dex2jar 遇到這種情況任然沒法轉化成jar,

修改Android手機核心,繞過除錯

0x1.手機裝置環境 Model number: Nexus 5 OS Version: Android 4.4.4 KTU84P Kernel Version: 3.4.0-gd59db4e 0x2.Android核心提取 查詢Android裝置的boot分割槽

Android:日常學習筆記(7)———探究UI開發(1)

tac calling repl action its 內容 schema lesson try Android:日常學習筆記(7)———探究UI開發(1) 常用控件的使用方法 TextView 說明:TextView是安卓中最為簡單的一個控件,常用來在界面上顯示一段文本信

Android:日常學習筆記(7)———探究UI開發(4)

this 活動 eal enc panel .html http 中間 編寫 Android:日常學習筆記(7)———探究UI開發(4) UI概述 View 和 ViewGrou   Android 應用中的所有用戶界面元素都是使用 View 和 ViewGroup 對象

Android:日常學習筆記(9)———探究廣播機制

ora rri enabled cas 管理 encoding protect 其他 acc Android:日常學習筆記(9)———探究廣播機制 引入廣播機制 Andorid廣播機制   廣播是任何應用均可接收的消息。系統將針對系統事件(例如:系統啟動或設備開始充電時)傳

Android:日常學習筆記(10)———使用LitePal操作數據庫

分享 數據 turn find netstat price 彈出 category 模式 Android:日常學習筆記(10)———使用LitePal操作數據庫 引入LitePal 什麽是LitePal   LitePal是一款開源的Android數據庫框架,采用了對象關系

android編譯odex文件

lis 目錄 trac 依賴 andro xheditor span sys 放置 關於android的反編譯工具,相信大家並不陌生 如APK-TOOL,dex2jar APK-TOOL 用於反編譯出布局文件 下載地址http://code.google.co

Android菜鳥筆記- 獲取未安裝的APK圖標、版本號、包名、名稱、是否安裝、安裝、打開

ack ear 例如 start true intent ble post oca 周末閑來無事,把Android的基礎知識拿出來復習復習,今天主題是《獲取未安裝的APK圖標、版本號、包名、名稱、是否安裝、跳轉安裝、打開》 一、獲取APK圖標 通常讀取APK的圖標能夠用

Android群英傳筆記——摘要,概述,新的出發點,溫故而知新,能夠為師矣!

ram hide 基本 pretty 工具 log 透明 scroll 好的 Android群英傳筆記——摘要。概述,新的出發點,溫故而知新。能夠為師矣! 當工作的越久,就越感到力不從心了,基礎和理解才是最重要的,所以買了兩本書,醫生的《An