Android安全-SO動態庫注入

關於這方面技術,網上已經有大把的實現。在此,我只是記錄下本身的學習過程。
php


0x1 原理

    所謂的SO注入就是將代碼拷貝到目標進程中,並結合函數重定向等其餘技術,最終達到監控或改變目標進程行爲的目的。Android是基於Linux內核的操做系統,而在Linux下SO注入基本是基於調試API函數ptrace實現的,一樣Android的SO注入也是基於ptrace函數,要完成注入還需獲取root權限。
html


0x2 流程

    注入過程以下:
linux

        0x01 獲取目標進程的pid,關聯目標進程;web

        0x02 獲取並保存目標進程寄存器值;
數組

        0x03 獲取目標進程的dlopen,dlsym函數的絕對地址;
函數

        0x04 獲取並保存目標進程的堆棧,設置dlopen函數的相關參數,將要注入的SO的絕對路徑壓棧;
學習

        0x05 調用dlopen函數;
ui

        0x06 調用dlsym函數,獲取SO中要執行的函數地址;
spa

        0x07 調用要執行的函數;
操作系統

        0x08 恢復目標進程的堆棧,恢復目標進程寄存器值,解除關聯,完成SO動態庫注入;

        (注:實際上,0x06和0x07並不屬於SO動態庫注入的步驟,然而僅僅注入是徹底沒有意義的,一般咱們須要執行SO中的函數)


0x3 實現

    0x01 獲取目標進程的pid,關聯目標進程:

        經過遍歷查找/proc/pid/cmdline文件中是否含有目標進程名process_name,如有則進程名對應的進程號即爲pid。接着,直接調用函數ptrace_attach(pid)便可完成關聯。

    0x02 獲取並保存目標進程寄存器值:

        直接調用ptrace(PTRACE_GETREGS, pid, NULL, &saved_regs),固然saved_regs要定義爲全局變量。

    0x03 獲取目標進程的dlopen,dlsym函數的絕對地址:

        大概思路是這樣的:首先經過遍歷/proc/pid/maps文件分別獲得本進程中dlopen函數所在動態庫的基地址local_module_base和目標進程dlopen函數所在動態庫的基地址remote_module_base,接着獲取本進程dlopen函數的絕對地址local_addr = (void*)dlopen。須要明白的是,不一樣進程中相同的動態庫中的同一個函數的偏移地址必定是同樣的,因此目標進程dlopen函數的絕對地址爲:local_addr - local_module_base + remote_module_base。dlsym同理,再也不詳述。

    0x04 獲取並保存目標進程的堆棧,設置dlopen函數的相關參數,將要注入的SO的絕對路徑壓棧:

        當咱們的要執行的函數的某些參數須要壓入堆棧的時候,就須要提早保存堆棧狀態,調用ptrace_readdata(pid, (void *)regs.ARM_sp, (void *)sbuf, sizeof(sbuf)),其中sbuf爲char數組,用來存放堆棧。調用ptrace_writedata(pid, (void *)regs.ARM_sp, (void *)so_path, strlen(so_path) + 1),其中so_path爲SO的絕對路徑。函數傳參規則:前四個參數分別由寄存器r0、r一、r二、r3存放,超過四個參數則壓入堆棧。

    0x05 調用dlopen函數:

        參數設置好後,設置ARM_pc = dlopen_addr, ARM_lr = 0。調用ptrace_setregs(pid, regs)寫入修改後的寄存器值,調用ptrace_continue( pid )使目標進程繼續運行。(注:dlopen_addr爲0x03獲取到的目標進程dlopen函數的絕對地址,ARM_lr = 0的目的在於當目標進程執行完dlopen函數,使目標進程發生異常,從而讓本進程從新得到控制權)

    0x06 調用dlsym函數,獲取SO中要執行的函數地址:

        實現方式與調用dlopen函數相似,再也不詳述。

    0x07 調用要執行的函數:

        實現方式與調用dlopen函數相似,再也不詳述。

    0x08 恢復目標進程的堆棧,恢復目標進程寄存器值,解除關聯,完成SO動態庫注入:

        調用ptrace_writedata(pid, (uint8_t *)saved_regs.ARM_sp, (uint8_t *)sbuf, sizeof(sbuf))恢復堆棧,調用ptrace_setregs(pid, &saved_regs)恢復寄存器值,調用ptrace_detach(pid)解除關聯,完成SO動態庫注入。


0x4 代碼

    貼一下主要邏輯代碼:

pid_t pid = find_pid_of("xxx");
ptrace_attach(pid);
uint32_t *inject_so_of(pid_t pid, const char *so_path) {
    int status = 0;
    struct pt_regs regs;
    memcpy(&regs, &saved_regs, sizeof(regs));
    ptrace_readdata(pid, (void *)regs.ARM_sp, (void *)sbuf, sizeof(sbuf));
    ptrace_writedata(pid, (void *)regs.ARM_sp, (void *)so_path, strlen(so_path) + 1);
    uint32_t parameters[2];
    parameters[0] = regs.ARM_sp;
    parameters[1] = RTLD_NOW;
    if ( ptrace_call(pid, find_dlopen_addr(pid), parameters, 2, &regs ) == -1 )
        DPRINTF("dlopen error\n");
    ptrace_getregs(pid, &regs);
    uint32_t r0 = regs.ARM_r0;
    DPRINTF("[+2]\t注入動態庫成功,返回的句柄爲: %x\n", r0);
    ptrace_setregs(pid, &saved_regs);
    ptrace_writedata(pid, (uint8_t *)saved_regs.ARM_sp, (uint8_t *)sbuf, sizeof(sbuf));
    ptrace_detach(pid);
    return (uint32_t *)r0;
}

0x5 參考

    玩轉ptrace:http://blog.csdn.net/sealyao/article/details/6710772

    《轉載》linux動態庫注入:http://blog.chinaunix.net/uid-7247280-id-2060516.html

    發個Android平臺上的注入代碼:http://bbs.pediy.com/showthread.php?t=141355

相關文章
相關標籤/搜索