最近在网上搜索Android的Inject与Hook,发现很多都因为时间久远而失效了,试了很多方案,最终找到了一个,特地来转载分享一下,本人的三星S6 6.0.1系统测试可用,另外4.2 4.4也都测试通过。

另外加上了注释便于大家理解。


1.inject.c
 
 
   [java]  
   view plain 
    copy 
   
 
 
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. #include <sys/uio.h>  
15.       
16. #if defined(__i386__)      
17. #define pt_regs         user_regs_struct      
18. #elif defined(__aarch64__)  
19. #define pt_regs         user_pt_regs    
20. #define uregs   regs  
21. #define ARM_pc  pc  
22. #define ARM_sp  sp  
23. #define ARM_cpsr    pstate  
24. #define ARM_lr      regs[30]  
25. #define ARM_r0      regs[0]    
26. #define PTRACE_GETREGS PTRACE_GETREGSET  
27. #define PTRACE_SETREGS PTRACE_SETREGSET  
28. #endif      
29.       
30. #define ENABLE_DEBUG 1      
31.       
32. #if ENABLE_DEBUG      
33. #define  LOG_TAG "INJECT"      
34. #define  LOGD(fmt, args...)  __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG, fmt, ##args)      
35. #define DEBUG_PRINT(format,args...) \      
36.     LOGD(format, ##args)      
37. #else      
38. #define DEBUG_PRINT(format,args...)      
39. #endif      
40.       
41. #define CPSR_T_MASK     ( 1u << 5 )      
42.       
43. #if defined(__aarch64__)      
44. const char *libc_path = "/system/lib64/libc.so";      
45. const char *linker_path = "/system/bin/linker64";      
46. #else  
47. const char *libc_path = "/system/lib/libc.so";      
48. const char *linker_path = "/system/bin/linker";      
49. #endif  
50.       
51. int ptrace_readdata(pid_t pid,  uint8_t *src, uint8_t *buf, size_t size)      
52. {      
53. long i, j, remain;      
54.     uint8_t *laddr;         
55. long);  
56.       
57.     union u {      
58. long val;      
59. char chars[bytes_width];      
60.     } d;      
61.       
62.     j = size / bytes_width;      
63.     remain = size % bytes_width;      
64.       
65.     laddr = buf;      
66.       
67. for (i = 0; i < j; i ++) {      
68. 0);      
69.         memcpy(laddr, d.chars, bytes_width);      
70.         src += bytes_width;      
71.         laddr += bytes_width;      
72.     }      
73.       
74. if (remain > 0) {      
75. 0);      
76.         memcpy(laddr, d.chars, remain);      
77.     }      
78.       
79. return 0;      
80. }      
81.   
82. /*
83. Func : 将size字节的data数据写入到pid进程的dest地址处
84. @param dest: 目的进程的栈地址
85. @param data: 需要写入的数据的起始地址
86. @param size: 需要写入的数据的大小,以字节为单位
87. */  
88. int ptrace_writedata(pid_t pid, uint8_t *dest, uint8_t *data, size_t size)      
89. {      
90. long i, j, remain;      
91.     uint8_t *laddr;      
92. long);  
93.       
94. //很巧妙的联合体,这样就可以方便的以字节为单位写入4字节数据,再以long为单位ptrace_poketext到栈中    
95.     union u {      
96. long val;      
97. char chars[bytes_width];      
98.     } d;      
99.       
100.     j = size / bytes_width;      
101.     remain = size % bytes_width;      
102.       
103.     laddr = data;  
104.   
105. //先以4字节为单位进行数据写入  
106.       
107. for (i = 0; i < j; i ++) {      
108.         memcpy(d.chars, laddr, bytes_width);      
109.         ptrace(PTRACE_POKETEXT, pid, dest, d.val);      
110.       
111.         dest  += bytes_width;      
112.         laddr += bytes_width;      
113.     }      
114.       
115. if (remain > 0) {  
116. //为了最大程度的保持原栈的数据,先读取dest的long数据,然后只更改其中的前remain字节,再写回  
117. 0);      
118. for (i = 0; i < remain; i ++) {      
119.             d.chars[i] = *laddr ++;      
120.         }      
121.       
122.         ptrace(PTRACE_POKETEXT, pid, dest, d.val);     
123.     }      
124.       
125. return 0;      
126. }      
127.   
128. /*
129. 功能总结:
130. 1,将要执行的指令写入寄存器中,指令长度大于4个long的话,需要将剩余的指令通过ptrace_writedata函数写入栈中;
131. 2,使用ptrace_continue函数运行目的进程,直到目的进程返回状态值0xb7f(对该值的分析见后面红字);
132. 3,函数执行完之后,目标进程挂起,使用ptrace_getregs函数获取当前的所有寄存器值,方便后面使用ptrace_retval函数获取函数的返回值。
133. */  
134. #if defined(__arm__) || defined(__aarch64__)  
135. int ptrace_call(pid_t pid, uintptr_t addr, long *params, int num_params, struct pt_regs* regs)      
136. {      
137. int i;     
138. #if defined(__arm__)   
139. int num_param_registers = 4;  
140. #elif defined(__aarch64__)   
141. int num_param_registers = 8;  
142. #endif  
143.   
144. for (i = 0; i < num_params && i < num_param_registers; i ++) {      
145.         regs->uregs[i] = params[i];      
146.     }      
147.       
148. //      
149. // push remained params onto stack      
150. //      
151. if (i < num_params) {      
152. long) ;      
153. void *)regs->ARM_sp,(uint8_t *)& params[i], (num_params - i) * sizeof(long));      
154.     }      
155. //将PC寄存器值设为目标函数的地址  
156.     regs->ARM_pc = addr;   
157. //进行指令集判断   
158. if (regs->ARM_pc & 1) {      
159. /* thumb */      
160.         regs->ARM_pc &= (~1u);      
161. // #define CPSR_T_MASK  ( 1u << 5 )  CPSR为程序状态寄存器  
162.         regs->ARM_cpsr |= CPSR_T_MASK;      
163. else {      
164. /* arm */      
165.         regs->ARM_cpsr &= ~CPSR_T_MASK;      
166.     }      
167.       
168. //设置子程序的返回地址为空,以便函数执行完后,返回到null地址,产生SIGSEGV错误,详细作用见后面的红字分析  
169. 0;      
170.       
171. /*
172.     *Ptrace_setregs就是将修改后的regs写入寄存器中,然后调用ptrace_continue来执行我们指定的代码
173.     */  
174. if (ptrace_setregs(pid, regs) == -1       
175. 1) {      
176. "error\n");      
177. return -1;      
178.     }      
179.       
180. int stat = 0;    
181.     waitpid(pid, &stat, WUNTRACED);    
182. /* WUNTRACED告诉waitpid,如果子进程进入暂停状态,那么就立即返回。如果是被ptrace的子进程,那么即使不提供WUNTRACED参数,也会在子进程进入暂停状态的时候立即返回。
183.     对于使用ptrace_cont运行的子进程,它会在3种情况下进入暂停状态:①下一次系统调用;②子进程退出;③子进程的执行发生错误。这里的0xb7f就表示子进程进入了暂停状态,且发送的错误信号为11(SIGSEGV),它表示试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据。那么什么时候会发生这种错误呢?显然,当子进程执行完注入的函数后,由于我们在前面设置了regs->ARM_lr = 0,它就会返回到0地址处继续执行,这样就会产生SIGSEGV了!*/  
184.       
185. //这个循环是否必须我还不确定。因为目前每次ptrace_call调用必定会返回0xb7f,不过在这也算是增加容错性吧~  
186.       
187. //通过看ndk的源码sys/wait.h以及man waitpid可以知道这个0xb7f的具体作用。首先说一下stat的值:高2字节用于表示导致子进程的退出或暂停状态信号值,低2字节表示子进程是退出(0x0)还是暂停(0x7f)状态。0xb7f就表示子进程为暂停状态,导致它暂停的信号量为11即sigsegv错误。  
188. while (stat != 0xb7f) {    
189. if (ptrace_continue(pid) == -1) {    
190. "error\n");    
191. return -1;    
192.         }    
193.         waitpid(pid, &stat, WUNTRACED);    
194.     }    
195.       
196. return 0;      
197. }      
198.   
199. #elif defined(__i386__)      
200. long ptrace_call(pid_t pid, uintptr_t addr, long *params, int num_params, struct user_regs_struct * regs)      
201. {      
202. long) ;      
203. void *)regs->esp, (uint8_t *)params, (num_params) * sizeof(long));      
204.       
205. long tmp_addr = 0x00;      
206. long);      
207. char *)&tmp_addr, sizeof(tmp_addr));       
208.       
209.     regs->eip = addr;      
210.       
211. if (ptrace_setregs(pid, regs) == -1       
212. 1) {      
213. "error\n");      
214. return -1;      
215.     }      
216.       
217. int stat = 0;    
218.     waitpid(pid, &stat, WUNTRACED);    
219. while (stat != 0xb7f) {    
220. if (ptrace_continue(pid) == -1) {    
221. "error\n");    
222. return -1;    
223.         }    
224.         waitpid(pid, &stat, WUNTRACED);    
225.     }    
226.       
227. return 0;      
228. }      
229. #else       
230. #error "Not supported"      
231. #endif      
232.       
233. int ptrace_getregs(pid_t pid, struct pt_regs * regs)      
234. {      
235. #if defined (__aarch64__)  
236. int regset = NT_PRSTATUS;  
237.         struct iovec ioVec;  
238.           
239.         ioVec.iov_base = regs;  
240.         ioVec.iov_len = sizeof(*regs);  
241. if (ptrace(PTRACE_GETREGSET, pid, (void*)regset, &ioVec) < 0) {      
242. "ptrace_getregs: Can not get register values");     
243. " io %llx, %d", ioVec.iov_base, ioVec.iov_len);   
244. return -1;      
245.     }      
246.       
247. return 0;     
248. #else  
249. if (ptrace(PTRACE_GETREGS, pid, NULL, regs) < 0) {      
250. "ptrace_getregs: Can not get register values");      
251. return -1;      
252.     }      
253.       
254. return 0;     
255. #endif       
256. }      
257.       
258. int ptrace_setregs(pid_t pid, struct pt_regs * regs)      
259. {       
260. #if defined (__aarch64__)  
261. int regset = NT_PRSTATUS;  
262.         struct iovec ioVec;  
263.           
264.         ioVec.iov_base = regs;  
265.         ioVec.iov_len = sizeof(*regs);  
266. if (ptrace(PTRACE_SETREGSET, pid, (void*)regset, &ioVec) < 0) {      
267. "ptrace_setregs: Can not get register values");      
268. return -1;      
269.     }      
270.       
271. return 0;     
272. #else  
273. if (ptrace(PTRACE_SETREGS, pid, NULL, regs) < 0) {      
274. "ptrace_setregs: Can not set register values");      
275. return -1;      
276.     }      
277.       
278. return 0;     
279. #endif       
280. }      
281.       
282. int ptrace_continue(pid_t pid)      
283. {      
284. if (ptrace(PTRACE_CONT, pid, NULL, 0) < 0) {      
285. "ptrace_cont");      
286. return -1;      
287.     }      
288.       
289. return 0;      
290. }      
291.       
292. int ptrace_attach(pid_t pid)      
293. {      
294. if (ptrace(PTRACE_ATTACH, pid, NULL, 0) < 0) {      
295. "ptrace_attach");      
296. return -1;      
297.     }      
298.       
299. int status = 0;      
300.     waitpid(pid, &status , WUNTRACED);      
301.       
302. return 0;      
303. }      
304.       
305. int ptrace_detach(pid_t pid)      
306. {      
307. if (ptrace(PTRACE_DETACH, pid, NULL, 0) < 0) {      
308. "ptrace_detach");      
309. return -1;      
310.     }      
311.       
312. return 0;      
313. }  
314.   
315.   
316. //显然,这里面核心的就是get_module_base函数:  
317. /*
318. 此函数的功能就是通过遍历/proc/pid/maps文件,来找到目的module_name的内存映射起始地址。
319. 由于内存地址的表达方式是startAddrxxxxxxx-endAddrxxxxxxx的,所以会在后面使用strtok(line,"-")来分割字符串
320. 如果pid = -1,表示获取本地进程的某个模块的地址,
321. 否则就是pid进程的某个模块的地址。
322. */      
323.       
324. void* get_module_base(pid_t pid, const char* module_name)      
325. {      
326.     FILE *fp;      
327. long addr = 0;      
328. char *pch;      
329. char filename[32];      
330. char line[1024];      
331.       
332. if (pid < 0) {      
333. /* self process */      
334. "/proc/self/maps", pid);      
335. else {      
336. "/proc/%d/maps", pid);      
337.     }      
338.       
339. "r");      
340.       
341. if (fp != NULL) {      
342. while (fgets(line, sizeof(line), fp)) {      
343. if (strstr(line, module_name)) {  
344. //分解字符串为一组字符串。line为要分解的字符串,"-"为分隔符字符串。  
345. "-" );  
346. //将参数pch字符串根据参数base(表示进制)来转换成无符号的长整型数    
347. 16 );     
348.       
349. if (addr == 0x8000)      
350. 0;      
351.       
352. break;      
353.             }      
354.         }      
355.       
356.         fclose(fp) ;      
357.     }      
358.       
359. return (void *)addr;      
360. }      
361.   
362. /*
363. 该函数为一个封装函数,通过调用get_module_base函数来获取目的进程的某个模块的起始地址,然后通过公式计算出指定函数在目的进程的起始地址。
364. */  
365. void* get_remote_addr(pid_t target_pid, const char* module_name, void* local_addr)      
366. {      
367. void* local_handle, *remote_handle;   
368.       
369. //获取本地某个模块的起始地址  
370. 1, module_name);  
371. //获取远程pid的某个模块的起始地址  
372.     remote_handle = get_module_base(target_pid, module_name);      
373.       
374. "[+] get_remote_addr: local[%llx], remote[%llx]\n", local_handle, remote_handle);      
375. /*这需要我们好好理解:local_addr - local_handle的值为指定函数(如mmap)在该模块中的偏移量,然后再加上rempte_handle,结果就为指定函数在目的进程的虚拟地址*/  
376. void * ret_addr = (void *)((uintptr_t)local_addr + (uintptr_t)remote_handle - (uintptr_t)local_handle);      
377.       
378. #if defined(__i386__)      
379. if (!strcmp(module_name, libc_path)) {      
380. 2;      
381.     }      
382. #endif      
383. return ret_addr;      
384. }      
385.   
386. //根据name找到pid  
387. int find_pid_of(const char *process_name)      
388. {      
389. int id;      
390. 1;      
391.     DIR* dir;      
392.     FILE *fp;      
393. char filename[32];      
394. char cmdline[256];      
395.       
396.     struct dirent * entry;      
397.       
398. if (process_name == NULL)      
399. return -1;      
400.       
401. "/proc");      
402. if (dir == NULL)      
403. return -1;      
404.       
405. while((entry = readdir(dir)) != NULL) {      
406.         id = atoi(entry->d_name);      
407. if (id != 0) {      
408. "/proc/%d/cmdline", id);      
409. "r");      
410. if (fp) {      
411.                 fgets(cmdline, sizeof(cmdline), fp);      
412.                 fclose(fp);      
413.       
414. if (strcmp(process_name, cmdline) == 0) {      
415. /* process found */      
416.                     pid = id;      
417. break;      
418.                 }      
419.             }      
420.         }      
421.     }      
422.       
423.     closedir(dir);      
424. return pid;      
425. }      
426.       
427. uint64_t ptrace_retval(struct pt_regs * regs)      
428. {      
429. #if defined(__arm__) || defined(__aarch64__)  
430. return regs->ARM_r0;      
431. #elif defined(__i386__)      
432. return regs->eax;      
433. #else      
434. #error "Not supported"      
435. #endif      
436. }      
437.       
438. uint64_t ptrace_ip(struct pt_regs * regs)      
439. {      
440. #if defined(__arm__) || defined(__aarch64__)   
441. return regs->ARM_pc;     
442. #elif defined(__i386__)      
443. return regs->eip;      
444. #else      
445. #error "Not supported"      
446. #endif      
447. }      
448.   
449. //总结一下ptrace_call_wrapper,它的完成两个功能:  
450. //一是调用ptrace_call函数来执行指定函数,执行完后将子进程挂起;  
451. //二是调用ptrace_getregs函数获取所有寄存器的值,主要是为了获取r0即函数的返回值。    
452. int ptrace_call_wrapper(pid_t target_pid, const char * func_name, void * func_addr, long * parameters, int param_num, struct pt_regs * regs)       
453. {      
454. "[+] Calling %s in target process.\n", func_name);      
455. if (ptrace_call(target_pid, (uintptr_t)func_addr, parameters, param_num, regs) == -1)      
456. return -1;      
457.       
458. if (ptrace_getregs(target_pid, regs) == -1)      
459. return -1;      
460. "[+] Target process returned from %s, return value=%llx, pc=%llx \n",       
461.             func_name, ptrace_retval(regs), ptrace_ip(regs));      
462. return 0;      
463. }      
464.   
465. //远程注入  
466. int inject_remote_process(pid_t target_pid, const char *library_path, const char *function_name, const char *param, size_t param_size)      
467. {      
468. int ret = -1;      
469. void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr, *dlerror_addr;      
470. void *local_handle, *remote_handle, *dlhandle;      
471. 0;      
472.     uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;      
473.       
474.     struct pt_regs regs, original_regs;       
475. long parameters[10];      
476.       
477. "[+] Injecting process: %d\n", target_pid);      
478.       
479. //①ATTATCH,指定目标进程,开始调试  
480. if (ptrace_attach(target_pid) == -1)      
481. goto exit;     
482.       
483. //②GETREGS,获取目标进程的寄存器,保存现场  
484. if (ptrace_getregs(target_pid, ®s) == -1)      
485. goto exit;      
486.       
487. /* save original registers */      
488.     memcpy(&original_regs, ®s, sizeof(regs));      
489.       
490. //③通过get_remote_addr函数获取目的进程的mmap函数的地址,以便为libxxx.so分配内存  
491.       
492. /*
493.         需要对(void*)mmap进行说明:这是取得inject本身进程的mmap函数的地址,由于mmap函数在libc.so  
494.         库中,为了将libxxx.so加载到目的进程中,就需要使用目的进程的mmap函数,所以需要查找到libc.so库在目的进程的起始地址。
495.     */  
496. void *)mmap);      
497. "[+] Remote mmap address: %llx\n", mmap_addr);  
498.   
499. /* call mmap (null, 0x4000, PROT_READ | PROT_WRITE | PROT_EXEC,
500.                              MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
501.     匿名申请一块0x4000大小的内存
502.     */  
503. 0] = 0;  // addr      
504. 1] = 0x4000; // size      
505. 2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot      
506. 3] = MAP_ANONYMOUS | MAP_PRIVATE; // flags      
507. 4] = 0; //fd      
508. 5] = 0; //offset      
509.       
510. if (ptrace_call_wrapper(target_pid, "mmap", mmap_addr, parameters, 6, ®s) == -1)      
511. goto exit;      
512.       
513. //⑤从寄存器中获取mmap函数的返回值,即申请的内存首地址:  
514.     map_base = ptrace_retval(®s);    
515.       
516. //⑥依次获取linker中dlopen、dlsym、dlclose、dlerror函数的地址:  
517. void *)dlopen );      
518. void *)dlsym );      
519. void *)dlclose );      
520. void *)dlerror );      
521.       
522. "[+] Get imports: dlopen: %llx, dlsym: %llx, dlclose: %llx, dlerror: %llx\n",      
523.             dlopen_addr, dlsym_addr, dlclose_addr, dlerror_addr);      
524.       
525. "library path = %s\n", library_path);      
526. //⑦调用dlopen函数:  
527. /*
528.     ①将要注入的so名写入前面mmap出来的内存
529.     ②写入dlopen代码
530.     ③执行dlopen("libxxx.so", RTLD_NOW ! RTLD_GLOBAL) 
531.     RTLD_NOW之类的参数作用可参考:
532.     http://baike.baidu.com/view/2907309.htm?fr=aladdin 
533.     ④取得dlopen的返回值,存放在sohandle变量中
534.     */  
535. 1);    
536.           
537. 0] = map_base;         
538. 1] = RTLD_NOW| RTLD_GLOBAL;       
539.       
540. if (ptrace_call_wrapper(target_pid, "dlopen", dlopen_addr, parameters, 2, ®s) == -1)      
541. goto exit;      
542.       
543. void * sohandle = ptrace_retval(®s);      
544. if(!sohandle) {  
545. if (ptrace_call_wrapper(target_pid, "dlerror", dlerror_addr, 0, 0, ®s) == -1)      
546. goto exit;      
547.           
548.             uint8_t *errret = ptrace_retval(®s);    
549. 100];  
550. 100);  
551.     }  
552.       
553. //⑧调用dlsym函数  
554. /*
555.     等同于hook_entry_addr = (void *)dlsym(sohandle, "hook_entry");
556.     */   
557. #define FUNCTION_NAME_ADDR_OFFSET       0x100      
558. 1);      
559. 0] = sohandle;         
560. 1] = map_base + FUNCTION_NAME_ADDR_OFFSET;       
561.       
562. if (ptrace_call_wrapper(target_pid, "dlsym", dlsym_addr, parameters, 2, ®s) == -1)      
563. goto exit;      
564.       
565. void * hook_entry_addr = ptrace_retval(®s);      
566. "hook_entry_addr = %p\n", hook_entry_addr);      
567.       
568. //⑨调用hook_entry函数:  
569. #define FUNCTION_PARAM_ADDR_OFFSET      0x200      
570. 1);      
571. 0] = map_base + FUNCTION_PARAM_ADDR_OFFSET;        
572.     
573. if (ptrace_call_wrapper(target_pid, "hook_entry", hook_entry_addr, parameters, 1, ®s) == -1)      
574. goto exit;          
575.       
576. "Press enter to dlclose and detach\n");      
577.     getchar();      
578. 0] = sohandle;         
579.       
580. //⑩调用dlclose关闭lib:  
581. if (ptrace_call_wrapper(target_pid, "dlclose", dlclose, parameters, 1, ®s) == -1)      
582. goto exit;      
583.       
584. /* restore */      
585. //⑪恢复现场并退出ptrace:  
586.     ptrace_setregs(target_pid, &original_regs);      
587.     ptrace_detach(target_pid);      
588. 0;      
589.       
590. exit:      
591. return ret;      
592. }      
593.       
594. int main(int argc, char** argv) {      
595.     pid_t target_pid;      
596. "system_server");  
597. if (-1 == target_pid) {    
598. "Can't find the process\n");    
599. return -1;    
600.     }    
601. //target_pid = find_pid_of("/data/test");      
602. "/data/libhello.so", "hook_entry",  "I'm parameter!", strlen("I'm parameter!"));      
603. return 0;    
604. }  
 

Android.mk application.mk 
 
 
   [html]  
   view plain 
    copy 
   
 
 
1. APP_ABI :=arm64-v8a armeabi-v7a  
 

 
 
   [html]  
   view plain 
    copy 
   
 
 
1. LOCAL_PATH := $(call my-dir)    
2.     
3. include $(CLEAR_VARS)    
4. LOCAL_MODULE := inject     
5. LOCAL_SRC_FILES := inject.c     
6.     
7. #shellcode.s    
8.     
9. LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog    
10.     
11. #LOCAL_FORCE_STATIC_EXECUTABLE := true    
12.     
13. include $(BUILD_EXECUTABLE)    
 

2.inject的测试so 
 
 
   [html]  
   view plain 
    copy 
   
 
 
1. #include <unistd.h>    
2. #include <stdio.h>    
3. #include <stdlib.h>    
4. #include <android/log.h>    
5. #include <elf.h>    
6. #include <fcntl.h>    
7.     
8. #define LOG_TAG "DEBUG"    
9. #define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)      
10.     
11. int hook_entry(char * a){    
12. pid = %d\n", getpid());    
13.     LOGD("Hello %s\n", a);    
14.     return 0;    
15. }