android hook 架構 libinject 如何?so注入

來源:互聯網
上載者:User

標籤:

前面兩篇

android hook 架構 libinject2 簡介、編譯、運行

android hook 架構 libinject2 如何?so注入  

實際運行並分析了 Android中的so注入(inject)和掛鈎(hook) - For both x86 and arm 這個部落格給出了 libinject 改進版的代碼。

 

今天分析一下古河大神原始的 libinject 的源碼,libinject2 與 原始的 libinject 大部分代碼是一致的,各種 ptrace 的封裝函數基本照抄,但有一點很不一樣,古河的 libinject 在執行so注入及執行注入的so內的hook函數時,是將一連串的函數構造成一塊統一的 shellcode ,然後整塊shellcode 寫入目標進程 mmap 出來的一塊地址,設定目標進程寄存器,一次性調用。 而 libinject2 是分開多次設定目標進程的記憶體和寄存器,並多次調用實現同樣的效果。從代碼可讀性看,libinject2 更清晰易懂。這一篇文章只分析兩者不同的部分。

 

首先,shellcode 代碼寫在一個單獨的彙編檔案裡, shellcode.s  , 將需要在目標進程執行的 dlopen,dlsym,dlclose, 及hook函數都先用彙編寫好,各個函數的真真實位址和參數的真實值由 inject.c 裡的函數動態指定,這份彙編會與 inject.c 編譯後的彙編連結在一起

.global _dlopen_addr_s.global _dlopen_param1_s.global _dlopen_param2_s.global _dlsym_addr_s.global _dlsym_param2_s.global _dlclose_addr_s.global _inject_start_s.global _inject_end_s.global _inject_function_param_s.global _saved_cpsr_s.global _saved_r0_pc_s.data_inject_start_s:        @ debug loop3:        @sub r1, r1, #0        @B 3b        @ dlopen        ldr r1, _dlopen_param2_s        ldr r0, _dlopen_param1_s        ldr r3, _dlopen_addr_s        blx r3        subs r4, r0, #0        beq     2f        @dlsym        ldr r1, _dlsym_param2_s        ldr r3, _dlsym_addr_s        blx r3        subs r3, r0, #0        beq 1f        @call our function        ldr r0, _inject_function_param_s        blx r3        subs r0, r0, #0        beq 2f1:        @dlclose        mov r0, r4        ldr r3, _dlclose_addr_s        blx r32:        @restore context                    ldr r1, _saved_cpsr_s        msr cpsr_cf, r1        ldr sp, _saved_r0_pc_s        ldmfd sp, {r0-pc}_dlopen_addr_s:.word 0x11111111_dlopen_param1_s:.word 0x11111111_dlopen_param2_s:.word 0x2_dlsym_addr_s:.word 0x11111111_dlsym_param2_s:.word 0x11111111_dlclose_addr_s:.word 0x11111111_inject_function_param_s:.word 0x11111111_saved_cpsr_s:.word 0x11111111_saved_r0_pc_s:.word 0x11111111_inject_end_s:.space 0x400, 0.end

這裡插入一下,怎麼在android裡使用這份代碼呢,仍然是建立一個module,然後 Android.mk 如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE    := injectLOCAL_SRC_FILES := ../inject.c ../shellcode.sLOCAL_ARM_MODE := armLOCAL_CFLAGS := -ginclude $(BUILD_EXECUTABLE)

在Android.mk檔案目錄下執行 ndk-build 即可

 

libinject 的注入過程如下:

int inject_remote_process( pid_t target_pid, const char *library_path, const char *function_name, void *param, size_t param_size )
{ int ret = -1; void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr; void *local_handle, *remote_handle, *dlhandle; uint8_t *map_base; struct pt_regs regs, original_regs; extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, _saved_cpsr_s, _saved_r0_pc_s; // shellcode.s 彙編代碼定義的變數 long parameters[10]; DEBUG_PRINT( "[+] Injecting process: %d\n", target_pid );

         if ( ptrace_attach( target_pid ) == -1 )
              return EXIT_SUCCESS;

if ( ptrace_getregs( target_pid, &regs ) == -1 )                goto exit;        /* save original registers */        memcpy( &original_regs, &regs, sizeof(regs) ); // 第一步,attach目標進程,並保留注入前的寄存器狀態        mmap_addr = get_remote_addr( target_pid, "/system/lib/libc.so", (void *)mmap );        /* call mmap */        parameters[0] = 0;      // addr        parameters[1] = 0x4000; // size        parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot        parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags        parameters[4] = 0; //fd        parameters[5] = 0; //offset        DEBUG_PRINT( "[+] Calling mmap in target process.\n" );

         if ( ptrace_call( target_pid, (uint32_t)mmap_addr, parameters, 6, &regs ) == -1 )
            goto exit;

if ( ptrace_getregs( target_pid, &regs ) == -1 )                goto exit;        map_base = (uint8_t *)regs.ARM_r0; // 第二步,在目標進程執行 mmap 分配一塊記憶體        dlopen_addr = get_remote_addr( target_pid, linker_path, (void *)dlopen );        dlsym_addr = get_remote_addr( target_pid, linker_path, (void *)dlsym );        dlclose_addr = get_remote_addr( target_pid, linker_path, (void *)dlclose );        remote_code_ptr = map_base + 0x3C00;        local_code_ptr = (uint8_t *)&_inject_start_s; // 本進程 shellcode 的起始地址        _dlopen_addr_s = (uint32_t)dlopen_addr;        _dlsym_addr_s = (uint32_t)dlsym_addr;        _dlclose_addr_s = (uint32_t)dlclose_addr; //第三步,擷取目標進程 dlopen,dlsym,dlclose函數地址並賦值給彙編檔案定義的變數        code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s;        dlopen_param1_ptr = local_code_ptr + code_length + 0x20;        dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH;        saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH;        inject_param_ptr = saved_r0_pc_ptr + MAX_PATH; // 設定dlopen,dlsym等函數的參數相對於彙編代碼起始地址的地址

         strcpy( dlopen_param1_ptr, library_path );
        _dlopen_param1_s = REMOTE_ADDR( dlopen_param1_ptr, local_code_ptr, remote_code_ptr );

/* dlopen parameter 1: library name */        DEBUG_PRINT( "[+] _dlopen_param1_s: %x\n", _dlopen_param1_s );        /* dlsym parameter 2: function name */        strcpy( dlsym_param2_ptr, function_name );        _dlsym_param2_s = REMOTE_ADDR( dlsym_param2_ptr, local_code_ptr, remote_code_ptr );        DEBUG_PRINT( "[+] _dlsym_param2_s: %x\n", _dlsym_param2_s );        /* saved cpsr */        _saved_cpsr_s = original_regs.ARM_cpsr;        /* saved r0-pc */        memcpy( saved_r0_pc_ptr, &(original_regs.ARM_r0), 16 * 4 ); // r0 ~ r15        _saved_r0_pc_s = REMOTE_ADDR( saved_r0_pc_ptr, local_code_ptr, remote_code_ptr );        DEBUG_PRINT( "[+] _saved_r0_pc_s: %x\n", _saved_r0_pc_s );        /* Inject function parameter */        memcpy( inject_param_ptr, param, param_size );        _inject_function_param_s = REMOTE_ADDR( inject_param_ptr, local_code_ptr, remote_code_ptr );        DEBUG_PRINT( "[+] _inject_function_param_s: %x\n", _inject_function_param_s );//第四步,計算要執行的 dlopen,dlsym函數及參數在目標進程內相對於前面mmap出來的地址的地址        DEBUG_PRINT( "[+] Remote shellcode address: %x\n", remote_code_ptr );        ptrace_writedata( target_pid, remote_code_ptr, local_code_ptr, 0x400 );//第五步: 將整塊shellcode代碼寫入目標進程的記憶體        memcpy( &regs, &original_regs, sizeof(regs) );        regs.ARM_sp = (long)remote_code_ptr;        regs.ARM_pc = (long)remote_code_ptr;         ptrace_setregs( target_pid, &regs ); // 第六步,修改目標進程的棧頂指標 sp 執行shellcode 的初始位置,且設定pc寄存器也指向這個位置        ptrace_detach( target_pid ); // 第七步,detach目標進程,目標進程接下去會開始執行shellcode        // inject succeeded        ret = 0;exit:        return ret;}

我們看到,libinject 沒有將 original_regs 恢複到目標進程的ptrace 操作,其實shellcode裡執行完hook函數後,最後會執行  @restore context   的代碼,這幾句就是恢複寄存器狀態的

 

android hook 架構 libinject 如何?so注入

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.