Android so注入(inject)和Hook技術學習(一)

  之前對Android so的注入只是經過現有的框架,並無去研究so注入原理,趁如今有時間正好拿出來研究一下。html

  首先來看注入流程。Android so的注入流程以下:android

attach到遠程進程 -> 保存寄存器環境 -> 獲取目標程序的mmap, dlopen, dlsym, dlclose 地址 -> 遠程調用mmap函數申請內存空間用來保存參數信息 -> 向遠程進程內存空間寫入加載模塊名和調用函數->遠程調用dlopen函數加載so文件 -> 遠程調用dlsym函數獲取目標函數地址->使用ptrace_call遠程調用被注入模塊的函數 -> 調用 dlclose 卸載so文件 -> 恢復寄存器環境 -> 從遠程進程detach(進程暫停->ptrace函數調用,其餘函數遠程調用->進程恢復)git

  下面咱們經過代碼來實現這個流程。首先建立目錄及文件:github

  jni
      inject.c
      Android.mk
      Application.mkshell

  在編寫代碼以前,咱們先熟悉一下pt_regs結構體:  app

pt_regs結構的定義:
    struct pt_regs{
        long uregs[18];
    };
    #define ARM_cpsr uregs[16]    存儲狀態寄存器的值
    #define ARM_pc uregs[15]    存儲當前的執行地址   
    #define ARM_lr uregs[14]    存儲返回地址
    #define ARM_sp uregs[13]    存儲當前的棧頂地址
    #define ARM_ip uregs[12]
    #define ARM_fp uregs[11]
    #define ARM_10 uregs[10]
    #define ARM_9 uregs[9]
    #define ARM_8 uregs[8]
    #define ARM_7 uregs[7]
    #define ARM_6 uregs[6]
    #define ARM_5 uregs[5]
    #define ARM_4 uregs[4]
    #define ARM_3 uregs[3]
    #define ARM_2 uregs[2]
    #define ARM_1 uregs[1]
    #define ARM_0 uregs[0]        存儲R0寄存器的值,函數調用後的返回值會存儲在R0寄存器中

在經過ptrace改變遠程進程的執行流程以前,須要先讀取和保存遠程進程的全部寄存器的值,在ARM處理器下,ptrace函數中data參數的regs爲pt_regs結構的指針,從遠程進程獲取的寄存器值將存儲到該結構中。在遠程進程執行detach操做以前,須要將遠程進程的原寄存器的環境恢復,保證遠程進程原有的執行流程不被破壞。若是不恢復寄存器的值,則執行detach操做以後會致使遠程進程崩潰。框架

inject.c的代碼以下:  函數

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <sys/user.h>
  4 #include <asm/ptrace.h>
  5 #include <sys/ptrace.h>
  6 #include <sys/wait.h>
  7 #include <sys/mman.h>
  8 #include <dlfcn.h>
  9 #include <dirent.h>
 10 #include <unistd.h>
 11 #include <string.h>
 12 #include <elf.h>
 13 #include <android/log.h>
 14 
 15 #if defined(__i386__)  
 16 #define pt_regs user_regs_struct  
 17 #endif
 18 
 19 #define LOG_TAG "INJECT"
 20 #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
 21 #define CPSR_T_MASK (1u << 5)
 22 
 23 const char* libc_path = "/system/lib/libc.so";
 24 const char* linker_path = "/system/bin/linker";
 25 
 26 /*--------------------------------------------------
 27 *   功能:   向目標進程指定的地址中讀取數據
 28 *
 29 *   參數:
 30 *           pid       須要注入的進程pid
 31 *           src       須要讀取的目標進程地址
 32 *           buf       須要讀取的數據緩衝區
 33 *           size      須要讀取的數據長度
 34 *
 35 *   返回值: -1
 36 *--------------------------------------------------*/
 37 int ptrace_readdata(pid_t pid, uint8_t *src, uint8_t *buf, size_t size){
 38     uint32_t i, j, remain;
 39     uint8_t *laddr;
 40 
 41     union u{
 42         long val;
 43         char chars[sizeof(long)];
 44     }d;
 45 
 46     j = size/4;
 47     remain = size%4;
 48     laddr = buf;
 49 
 50     for(i = 0; i<j; i++){
 51         //從內存地址src中讀取四個字節
 52         d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0);
 53         memcpy(laddr, d.chars, 4);
 54         src += 4;
 55         laddr += 4;
 56     }
 57 
 58     if(remain > 0){
 59         d.val = ptrace(PTRACE_PEEKTEXT, pid, src, 0);
 60         memcpy(laddr, d.chars, remain);
 61     }
 62     return 0;
 63 }
 64 
 65 /*--------------------------------------------------
 66 *   功能:   向目標進程指定的地址中寫入數據
 67 *
 68 *   參數:
 69 *           pid       須要注入的進程pid
 70 *           dest      須要寫入的目標進程地址
 71 *           data      須要寫入的數據緩衝區
 72 *           size      須要寫入的數據長度
 73 *
 74 *   返回值: -1
 75 *--------------------------------------------------*/
 76 int ptrace_writedata(pid_t pid, uint8_t *dest, uint8_t *data, size_t size){
 77     uint32_t i, j, remain;
 78     uint8_t *laddr;
 79     
 80     union u{
 81         long val;
 82         char u_data[sizeof(long)];
 83     }d;
 84 
 85     j = size/4;
 86     remain = size%4;
 87 
 88     laddr = data;
 89 
 90     //先4字節拷貝
 91     for(i = 0; i<j; i++){
 92         memcpy(d.u_data, laddr, 4);
 93         //往內存地址中寫入四個字節,內存地址由dest給出
 94         ptrace(PTRACE_POKETEXT, pid, dest, d.val);
 95 
 96         dest += 4;
 97         laddr += 4;
 98     }
 99 
100     //最後不足4字節的,單字節拷貝
101     //爲了最大程度的保持原棧的數據,須要先把原程序最後四字節讀出來
102     //而後把多餘的數據remain覆蓋掉四字節中前面的數據
103     if(remain > 0){        
104         d.val = ptrace(PTRACE_PEEKTEXT, pid, dest, 0);    //從內存地址中讀取四個字節,內存地址由dest給出
105         for(i = 0; i<remain; i++){
106             d.u_data[i] = *laddr++;        
107         }
108         ptrace(PTRACE_POKETEXT, pid, dest, d.val);
109     }
110     return 0;
111 }
112 
113 /*--------------------------------------------------
114 *   功能:   獲取指定進程的寄存器信息
115 *
116 *   返回值: 失敗返回-1
117 *--------------------------------------------------*/
118 int ptrace_getregs(pid_t pid, struct pt_regs *regs){
119     if(ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0){
120         perror("ptrace_getregs: Can not get register values.");
121         return -1;
122     }
123     return 0;
124 }
125 
126 /*--------------------------------------------------
127 *   功能:   修改目標進程寄存器的值
128 *
129 *   參數:
130 *           pid        須要注入的進程pid
131 *           pt_regs    須要修改的新寄存器信息
132 *
133 *   返回值: -1
134 *--------------------------------------------------*/
135 int ptrace_setregs(pid_t pid, struct pt_regs *regs){
136     if(ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0){
137         perror("ptrace_setregs:Can not set regsiter values.");
138         return -1;
139     }
140     return 0;
141 }
142 
143 /*--------------------------------------------------
144 *   功能:   恢復程序運行
145 *
146 *   參數:
147 *           pid        須要注入的進程pid
148 *
149 *   返回值: -1
150 *--------------------------------------------------*/
151 int ptrace_continue(pid_t pid){
152     if(ptrace(PTRACE_CONT, pid, NULL, 0) < 0){
153         perror("ptrace_cont");
154         return -1;
155     }
156     return 0;
157 }
158 
159 /*--------------------------------------------------
160 *   功能:   附加進程
161 *
162 *   返回值: 失敗返回-1
163 *--------------------------------------------------*/
164 int ptrace_attach(pid_t pid){
165     if(ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0){
166         perror("ptrace_attach");
167         return -1;
168     }
169     return 0;
170 }
171 
172 // 釋放對目標進程的附加調試  
173 int ptrace_detach(pid_t pid)  
174 {  
175     if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) {  
176         perror("ptrace_detach");  
177         return -1;  
178     }  
179   
180     return 0;  
181 }  
182 /*--------------------------------------------------
183 *   功能:   獲取進程中指定模塊的首地址
184 *    原理:  經過遍歷/proc/pid/maps文件,來找到目的module_name的內存映射起始地址。
185 *    因爲內存地址的表達方式是startAddrxxxxxxx-endAddrxxxxxxx的,因此經過使用strtok(line,"-")來分割字符串獲取地址
186 *    若是pid = -1,表示獲取本地進程的某個模塊的地址,不然就是pid進程的某個模塊的地址
187 *   參數:
188 *           pid             須要注入的進程pid, 若是爲0則獲取自身進程
189 *           module_name        須要獲取模塊路徑
190 *
191 *   返回值: 失敗返回NULL, 成功返回addr
192 *--------------------------------------------------*/
193 void *get_module_base(pid_t pid, const char* module_name)
194 {
195     FILE* fp;
196     long addr = 0;
197     char* pch;
198     char filename[32];
199     char line[1024];
200     
201     if(pid < 0){
202         snprintf(filename, sizeof(filename), "/proc/self/maps");
203     }else{
204         snprintf(filename, sizeof(filename), "/proc/%d/maps", pid);
205     }
206 
207     fp = fopen(filename, "r");
208 
209     if(fp != NULL){
210         while(fgets(line, sizeof(line), fp)){
211             if(strstr(line, module_name)){
212                 pch = strtok(line, "-");
213                 //將參數pch字符串根據參數base(表示進制)來轉換成無符號的長整型數 
214                 addr = strtoul(pch, NULL, 16);
215                 if(addr == 0x8000)
216                     addr = 0;
217                 break;
218             }
219         }
220         fclose(fp);
221     }
222     return (void*)addr;
223 }
224 
225 
226 /*--------------------------------------------------
227 *   功能:   獲取目標進程中函數指針
228 *
229 *   參數:
230 *           target_pid          須要注入的進程pid
231 *           module_name            須要獲取的函數所在的lib庫路徑
232 *           local_addr            須要獲取的函數所在當前進程內存中的地址
233 *
234 *           目標進程中函數指針 = 目標進程模塊基址 - 自身進程模塊基址 + 內存中的地址
235 *
236 *   返回值: 失敗返回NULL, 成功返回ret_addr
237 *--------------------------------------------------*/
238 void* get_remote_addr(pid_t target_pid, const char* module_name, void* local_addr){
239     void* local_handle, *remote_handle;
240     //獲取本地某個模塊的起始地址
241     local_handle = get_module_base(-1, module_name);
242     //獲取遠程pid的某個模塊的起始地址
243     remote_handle = get_module_base(target_pid, module_name);
244     
245     LOGD("[+]get remote address: local[%x], remote[%x]\n", local_handle, remote_handle);
246 
247     //local_addr - local_handle的值爲指定函數(如mmap)在該模塊中的偏移量,而後再加上remote_handle,結果就爲指定函數在目標進程的虛擬地址
248     void* ret_addr = (void*)((uint32_t)local_addr - (uint32_t)local_handle) + (uint32_t)remote_handle;
249     return ret_addr;
250 }
251 
252 /*--------------------------------------------------
253 *   功能:   經過進程的名稱獲取對應的進程pid
254 *   原理:  經過遍歷/proc目錄下的全部子目錄,獲取這些子目錄的目錄名(通常就是進程的進程號pid)。
255 *            獲取子目錄名後,就組合成/proc/pid/cmdline文件名,而後依次打開這些文件,cmdline文件
256 *            裏面存放的就是進程名,經過這樣就能夠獲取進程的pid了
257 *   返回值: 未找到返回-1
258 *--------------------------------------------------*/
259 int find_pid_of(const char* process_name){
260     int id;
261     pid_t pid = -1;
262     DIR* dir;
263     FILE* fp;
264     char filename[32];
265     char cmdline[296];
266     
267     struct dirent* entry;
268     
269     if(process_name == NULL){
270         return -1;
271     }
272     
273     dir = opendir("/proc");
274     if(dir == NULL){
275         return -1;
276     }
277 
278     while((entry = readdir(dir)) != NULL){
279         id = atoi(entry->d_name);
280         if(id != 0){
281             sprintf(filename, "/proc/%d/cmdline", id);
282             fp = fopen(filename, "r");
283             if(fp){
284                 fgets(cmdline, sizeof(cmdline), fp);
285                 fclose(fp);// 釋放對目標進程的附加調試   
286 
287                 if(strcmp(process_name, cmdline) == 0){
288                     pid = id;
289                     break;
290                 }
291             }
292         }
293     }
294     closedir(dir);
295     return pid;
296 }
297 
298 long ptrace_retval(struct pt_regs* regs){
299     return regs->ARM_r0;
300 }
301 
302 long ptrace_ip(struct pt_regs* regs){
303     return regs->ARM_pc;
304 }
305 
306 /*--------------------------------------------------
307 *   功能:   調用遠程函數指針
308 *    原理:    1,將要執行的指令寫入寄存器中,指令長度大於4個long的話,須要將剩餘的指令經過ptrace_writedata函數寫入棧中;
309 *            2,使用ptrace_continue函數運行目的進程,直到目的進程返回狀態值0xb7f(對該值的分析見後面紅字);
310 *            3,函數執行完以後,目標進程掛起,使用ptrace_getregs函數獲取當前的全部寄存器值,方便後面使用ptrace_retval函數獲取函數的返回值。
311 *   參數:
312 *           pid             須要注入的進程pid
313 *           addr             調用的函數指針地址
314 *           params          調用的參數
315 *           num_params      調用的參數個數
316 *           regs            遠程進程寄存器信息(ARM前4個參數由r0 ~ r3傳遞)
317 *
318 *   返回值: 失敗返回-1
319 *--------------------------------------------------*/
320 int ptrace_call(pid_t pid, uint32_t addr, long* params, uint32_t num_params, struct pt_regs* regs){
321     uint32_t i;
322     for(i = 0; i<num_params && i < 4; i++){
323         regs->uregs[i] = params[i];
324     }
325     
326     if(i < num_params){
327         regs->ARM_sp -= (num_params - i) * sizeof(long);
328         ptrace_writedata(pid, (void*)regs->ARM_sp, (uint8_t*)&params[i], (num_params - i)*sizeof(long));
329     }
330     //將PC寄存器值設爲目標函數的地址
331     regs->ARM_pc = addr;
332     ////指令集判斷
333     if(regs->ARM_pc & 1){
334         /* thumb */
335         regs->ARM_pc &= (~1u);
336         regs->ARM_cpsr |= CPSR_T_MASK;
337     }else{
338          /* arm */   
339         regs->ARM_cpsr &= ~CPSR_T_MASK;
340     }
341     ///設置子程序的返回地址爲空,以便函數執行完後,返回到null地址,產生SIGSEGV錯誤
342     regs->ARM_lr = 0;
343 
344     //將修改後的regs寫入寄存器中,而後調用ptrace_continue來執行咱們指定的代碼
345     if(ptrace_setregs(pid, regs) == -1 || ptrace_continue(pid) == -1){
346         printf("error.\n");
347         return -1;
348     }
349 
350     int stat = 0;
351     /* WUNTRACED告訴waitpid,若是子進程進入暫停狀態,那麼就當即返回。若是是被ptrace的子進程,那麼即便不提供WUNTRACED參數,也會在子進程進入暫停狀態的時候當即返回。
352     對於使用ptrace_cont運行的子進程,它會在3種狀況下進入暫停狀態:①下一次系統調用;②子進程退出;③子進程的執行發生錯誤。這裏的0xb7f就表示子進程進入了暫停狀態,
353     且發送的錯誤信號爲11(SIGSEGV),它表示試圖訪問未分配給本身的內存, 或試圖往沒有寫權限的內存地址寫數據。那麼何時會發生這種錯誤呢?顯然,當子進程執行完注入的
354     函數後,因爲咱們在前面設置了regs->ARM_lr = 0,它就會返回到0地址處繼續執行,這樣就會產生SIGSEGV了!
355     */   
356     waitpid(pid, &stat, WUNTRACED);
357     /*stat的值:高2字節用於表示致使子進程的退出或暫停狀態信號值,低2字節表示子進程是退出(0x0)仍是暫停(0x7f)狀態。
358     0xb7f就表示子進程爲暫停狀態,致使它暫停的信號量爲11即sigsegv錯誤。*/
359     while(stat != 0xb7f){
360         if(ptrace_continue(pid) == -1){
361             printf("error.\n");
362             return -1;
363         }
364         waitpid(pid, &stat, WUNTRACED);
365     }
366     return 0;
367 }
368 
369 /*--------------------------------------------------
370 *   功能:   調用遠程函數指針
371 *
372 *   參數:
373 *           pid            須要注入的進程pid
374 *           func_name      調用的函數名稱, 此參數僅做Debug輸出用
375 *           func_addr      調用的函數指針地址
376 *           param          調用的參數
377 *           param_num      調用的參數個數
378 *           regs           遠程進程寄存器信息(ARM前4個參數由r0 ~ r3傳遞)
379 *
380 *   返回值: 失敗返回-1
381 *--------------------------------------------------*/
382 int ptrace_call_wrapper(pid_t target_pid, const char* func_name, void* func_addr, long* param, int param_num, struct pt_regs* regs){
383     LOGD("[+]Calling %s in target process.\n", func_name);
384     if(ptrace_call(target_pid, (uint32_t)func_addr, param, param_num, regs) == -1)
385         return -1;
386     if(ptrace_getregs(target_pid, regs) == -1){
387         return -1;
388     }
389     LOGD("[+] Target process returned from %s, return value = %x, pc = %x \n", func_name, ptrace_retval(regs), ptrace_ip(regs));
390     return 0;
391 }
392 
393 /*--------------------------------------------------
394 *   功能:   遠程注入
395 *
396 *   參數:
397 *           target_pid          須要注入的進程Pid
398 *           library_path           須要注入的.so路徑
399 *           function_name          .so中導出的函數名
400 *           param                 函數的參數
401 *            param_size            參數大小,以字節爲單位
402 *
403 *   返回值: 注入失敗返回-1
404 *--------------------------------------------------*/
405 int inject_remote_process(pid_t target_pid, const char* library_path, const char* function_name, const char* param, size_t param_size){
406     int ret = -1;
407     void* mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;
408     void *local_handle, *remote_handle, *dlhandle;
409     uint8_t *map_base = 0;
410     uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;
411 
412     struct pt_regs regs, original_regs;
413     extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s, _dlsym_addr_s, _dlsym_param2_s, _dlclose_addr_s, _inject_start_s, _inject_end_s, _inject_function_param_s, _saved_cpsr_s, _saved_r0_pc_s;
414 
415     uint32_t code_length;
416     long parameters[10];
417     
418     LOGD("[+] Injecting process: %d\n", target_pid);
419 
420     //①ATTATCH,指定目標進程,開始調試
421     if(ptrace_attach(target_pid) == -1){
422         goto exit;
423     }
424 
425     //②GETREGS,獲取目標進程的寄存器,保存現場
426     if(ptrace_getregs(target_pid, &regs) == -1)
427         goto exit;
428 
429     //保存原始寄存器
430     memcpy(&original_regs, &regs, sizeof(regs));
431 
432     //③經過get_remote_addr函數獲取目標進程的mmap函數的地址,以便爲libxxx.so分配內存
433     //因爲mmap函數在libc.so庫中,爲了將libxxx.so加載到目標進程中,就須要使用目標進程的mmap函數,因此須要查找到libc.so庫在目標進程的起始地址。
434     mmap_addr = get_remote_addr(target_pid, libc_path, (void*)mmap);    //libc_path = "/system/lib/libc.so"
435     LOGD("[+] Remote mmap address: %x\n", mmap_addr);
436 
437     parameters[0] = 0;  // 設置爲NULL表示讓系統自動選擇分配內存的地址
438     parameters[1] = 0x4000;  // 映射內存的大小
439     parameters[2] = PROT_READ | PROT_WRITE |PROT_EXEC;  // 表示映射內存區域可讀可寫可執行
440     parameters[3] = MAP_ANONYMOUS | MAP_PRIVATE;  // 創建匿名映射
441     parameters[4] = 0;  //若須要映射文件到內存中,則爲文件的fd
442     parameters[5] = 0;  //文件映射偏移量
443 
444     //④經過ptrace_call_wrapper調用mmap函數,在目標進程中爲libxxx.so分配內存
445     if(ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, &regs) == -1)
446         goto exit;
447     //⑤從寄存器中獲取mmap函數的返回值,即申請的內存首地址:
448     map_base = ptrace_retval(&regs);
449 
450     //⑥依次獲取linker中dlopen、dlsym、dlclose、dlerror函數的地址
451     dlopen_addr = get_remote_addr(target_pid, linker_path, (void*)dlopen);
452     dlsym_addr = get_remote_addr(target_pid, linker_path, (void*)dlsym);
453     dlclose_addr = get_remote_addr(target_pid, linker_path, (void*)dlclose);
454     dlerror_addr = get_remote_addr(target_pid, linker_path, (void*)dlerror);
455     
456     LOGD("[+] Get imports: dlopen: %x, dlsym: %x, dlclose: %x, dlerror: %x\n", dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);
457 
458     printf("library path = %s\n", library_path);
459     //⑦調用dlopen函數
460     //(1)將要注入的so名寫入前面mmap出來的內存
461     ptrace_writedata(target_pid, map_base, library_path, strlen(library_path) + 1);
462 
463     parameters[0] = map_base;
464     parameters[1] = RTLD_NOW | RTLD_GLOBAL;
465 
466     //(2)執行dlopen
467     if(ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, &regs) == -1){
468         goto exit;
469     }
470     //(3)取得dlopen的返回值,存放在sohandle變量中
471     void* sohandle = ptrace_retval(&regs);
472     
473     //⑧調用dlsym函數
474     //爲functionname另找一塊區域
475     #define FUNCTION_NAME_ADDR_OFFSET 0X100
476     ptrace_writedata(target_pid, map_base + FUNCTION_NAME_ADDR_OFFSET, function_name, strlen(function_name) + 1);
477     parameters[0] = sohandle;
478     parameters[1] = map_base + FUNCTION_NAME_ADDR_OFFSET;
479 
480     //調用dlsym
481     if(ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, &regs) == -1)
482         goto exit;
483     void* hook_entry_addr = ptrace_retval(&regs);
484     LOGD("hooke_entry_addr = %p\n", hook_entry_addr);
485 
486     //⑨調用被注入函數hook_entry
487     #define FUNCTION_PARAM_ADDR_OFFSET 0X200
488     ptrace_writedata(target_pid, map_base + FUNCTION_PARAM_ADDR_OFFSET, parameters, strlen(parameters) + 1);
489     parameters[0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;
490 
491     if(ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, &regs) == -1)
492         goto exit;
493     //⑩調用dlclose關閉lib
494     printf("Press enter to dlclose and detach.\n");
495     getchar();
496     parameters[0] = sohandle;
497 
498     if(ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, &regs) == -1)
499         goto exit;
500     
501     //⑪恢復現場並退出ptrace
502     ptrace_setregs(target_pid, &original_regs);
503     ptrace_detach(target_pid);
504     ret = 0;
505 
506 exit:
507     return ret;
508 }
509 
510 int main(int argc, char** argv) {    
511     pid_t target_pid;    
512     target_pid = find_pid_of("com.bbk.appstore");    
513     if (-1 == target_pid) {  
514         printf("Can't find the process\n");  
515         return -1;  
516     }  
517     //target_pid = find_pid_of("/data/test");    
518     inject_remote_process(target_pid, "/data/local/tmp/libentry.so", "hook_entry",  "Fuck you!", strlen("Fuck you!"));    
519     return 0;  
520 }  

上述代碼中,咱們要hook的進程名爲"com.bbk.appstore",咱們要將「libentry.so」注入到該進程中去。ui

Android.mk內容爲:spa

LOCAL_PATH := $(call my-dir)  
  
include $(CLEAR_VARS)  
LOCAL_MODULE := inject   
LOCAL_SRC_FILES := inject.c   
  
#shellcode.s  
  
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog  
  
#LOCAL_FORCE_STATIC_EXECUTABLE := true  
  
include $(BUILD_EXECUTABLE)  

Application.mk內容爲:

# 編譯生成的模塊文件運行支持的平臺
APP_ABI := armeabi-v7a    
# 編譯生成模塊運行支持的Andorid版本
APP_PLATFORM := android-19

在jni目錄下運行nkd-build編譯成生arm平臺下的可執行文件:

ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=./Android.mk NDK_APPLICATION_MK=./Application.mk

再來生成要注入的so,建立目錄及文件:

jni
    entry.c
    Android.mk
    Application.mk

entry.c的代碼爲:

#include <unistd.h>  
#include <stdio.h>  
#include <stdlib.h>  
#include <android/log.h>  
#include <elf.h>  
#include <fcntl.h>  
  
#define LOG_TAG "DEBUG"  
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)    
  
int hook_entry(char * a){  
    LOGD("Hook success, pid = %d\n", getpid());  
    LOGD("Hello %s\n", a);  
    return 0;  
}  

Android.mk文件:

LOCAL_PATH := $(call my-dir)  
  
include $(CLEAR_VARS)  
  
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog   
#LOCAL_ARM_MODE := arm  
LOCAL_MODULE    := entry
LOCAL_SRC_FILES := entry.c  
include $(BUILD_SHARED_LIBRARY)  

Application.mk文件內容跟上面同樣。一樣將entry.c進行編譯。而後將獲得inject和libentry.so push到/data/local/tmp目錄下,執行:

經過「/proc/pid/maps」查看被注入進程("com.bbk.appstore")的mmap,能夠看到咱們的so已經被加載了:

 經過「adb logcat -s INJECT」命令打印出log:

這就說明咱們的注入成功了。

參考資料:

https://blog.csdn.net/qq1084283172/article/details/53942648
https://melonwxd.github.io/2017/12/01/inject-3-hook/
https://www.cnblogs.com/wanyuanchun/p/4020756.html

相關文章
相關標籤/搜索