Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1856970
  • 博文数量: 38
  • 博客积分: 690
  • 博客等级: 中士
  • 技术积分: 3715
  • 用 户 组: 普通用户
  • 注册时间: 2012-06-27 14:06
文章分类

全部博文(38)

文章存档

2018年(8)

2016年(4)

2015年(2)

2014年(1)

2013年(3)

2012年(20)

分类: Android平台

2018-05-17 20:22:15

androi 安全里面一项手段是防止应用被动态分析。动态分析一般是通过gdb调试汇编或c代码。于是就有了一项安全手段:反调试技术。

反调试技术很多,其中一项比较常见的是 检测 TracerPid ,其原理是:程序正常状态下 其 TracerPid 为 0,当处于调试状态时候, TracerPid 为调试那个进程pid, 也就是非0 ,app 会间隔检测自己的TracerPid,一旦发现非0,就判断为程序被调试,立即退出程序。

一、使用gdb调试android app

1、先关闭SELinux (在真机(target)操作)


  1. stevenrao@android-ndk-r16b$ adb shell
  2. shell@hammerhead:/ $ su
  3. root@hammerhead:/ # setenforce 0
  4. root@hammerhead:/ # gete
  5. getenforce getevent
  6. root@hammerhead:/ # getenforce
  7. Permissive

2、获取被调试的app 进程pid (在真机(target)操作)


  1. root@hammerhead:/ # ps | grep test
  2. u0_a55 8821 177 454040 51184 ffffffff 4011b73c S com.example.stevenrao.test

进程pid 为 8821 状态是 S,关于ps的状态码如下

  1. D uninterruptible sleep (usually IO)
  2. R running or runnable (on run queue)
  3. S interruptible sleep (waiting for an event to complete)
  4. T stopped by job control signal
  5. t stopped by debugger during the tracing
  6. W paging (not valid since the 2.6.xx kernel)
  7. X dead (should never be seen)
  8. Z defunct ("zombie") process, terminated but not reaped by its parent
查看 TracerPid

  1. 130|root@hammerhead:/system/xbin # cat /proc/8821/status | grep TracerPid
  2. TracerPid: 0


3、用gdbserver attach (在真机(target)操作)

  1. 我刷的是google原生系统,包里面含有gdbserver,如果没有,可以在网上下载
  2. root@hammerhead:/ # gdbserver remote:1234 --attach 8821

查看gdbserver pid
root@hammerhead:/ # ps |grep gdbserver 

  1. root 12167 5873 628 216 c0278e0c 000342f4 S gdbserver
再次查看 TracerPid

  1. 127|root@hammerhead:/ # cat /proc/8821/status  | grep TracerPid   
    TracerPid:      12167
ps查看app 进程状态

  1. root@hammerhead:/ # ps | grep test
  2. u0_a55 8821 177 454040 51184 ffffffff 4011b73c t com.example.stevenrao.test
看到没有,TracerPid 变成 12167. ps 状态也变成 t( stopped by debugger during the tracing )


4、使用gdb 客户端连上gdb server 调试(在PC机(host)操作)

这一节直接可以跳过,用来完善调试流程,和本文主题无关

  1. #端口映射,本机所有发给1234端口的tcp包,都转发给手机设备的1234端口上
  2. stevenrao@~$ adb forward tcp:1234 tcp:1234

  3. #我本就有arm-eabi-gdb 程序,没有的去网上下载
  4. stevenrao@~$ /data/code/aosp-4.4.4_r1/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin/arm-eabi-gdb
  5. GNU gdb (GDB) 7.3.1-gg2
  6. Copyright (C) 2011 Free Software Foundation, Inc.
  7. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
  8. This is free software: you are free to change and redistribute it.
  9. There is NO WARRANTY, to the extent permitted by law. Type "show copying"
  10. and "show warranty" for details.
  11. This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".
  12. For bug reporting instructions, please see:
  13. <http://source.android.com/source/report-bugs.html>.

  14. #设置指令架构
  15. (gdb) set architecture arm

  16. #设置调试程序
  17. (gdb) file /data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/bin/app_process

  18. #设置带符号信息的lib查找路径
  19. (gdb) set solib-search-path /data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/lib/:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/bin:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/lib/drm/:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/lib/egl/:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/lib/hw/:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/lib/ssl/engines/:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/lib/soundfx/:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/vendor/lib/:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/system/vendor/lib/:/data/code/aosp-4.4.4_r1/out/target/product/hammerhead/system/vendor/lib/egl/

  20. #连接端口
  21. (gdb) target remote :1234
  22. Remote debugging using :1234

  23. #对于 32 位 ARM,如果您的指令中没有符号,gdb 就不清楚自己正在反汇编哪个指令集(ARM 或 Thumb)。要指定缺少符号信息时选为默认指令集的指令集,请设置以下属性:
  24. (gdb) set arm fallback-mode arm # or thumb

  25. #查看栈
  26. (gdb) bt
  27. #0 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10
  28. #1 0x40182642 in android::Looper::pollInner (this=0x475926e8, timeoutMillis=<optimized out>) at system/core/libutils/Looper.cpp:223
  29. #2 0x4018286c in android::Looper::pollOnce (this=0x475926e8, timeoutMillis=-1, outFd=0x0, outEvents=0x0, outData=0x0)
  30.     at system/core/libutils/Looper.cpp:191
  31. #3 0x4022b5ac in pollOnce (timeoutMillis=<optimized out>, this=<optimized out>) at system/core/include/utils/Looper.h:176
  32. #4 android::NativeMessageQueue::pollOnce (this=0x4758f6f8, env=0x4179cbe0, timeoutMillis=<optimized out>)
  33.     at frameworks/base/core/jni/android_os_MessageQueue.cpp:97
  34. Backtrace stopped: previous frame identical to this frame (corrupt stack?)

  35. (gdb) f 0
  36. #0 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10
  37. 10 mov r7, ip

  38. #汇编调试
  39. (gdb) ni
  40. 11 cmn r0, #(MAX_ERRNO + 1)

  41. #查看寄存器
  42. (gdb) info register
  43. r0 0xfffffffc 4294967292
  44. r1 0xbeb26080 3199361152
  45. r2 0x10 16
  46. r3 0x7fffffff 2147483647


二、修改内核代码, 使TracerPid始终为0

1、修改内核源代码

关于内核如何编译,请参考我的另一篇http://blog.chinaunix.net/uid-27105712-id-5785215.html

要修改的文件涉及到两个

kernel/msm/fs/proc/base.c

  1. static int proc_pid_wchan(struct task_struct *task, char *buffer)
  2. {
  3.         unsigned long wchan;
  4.         char symname[KSYM_NAME_LEN];

  5.         wchan = get_wchan(task);

  6.         if (lookup_symbol_name(wchan, symname) < 0)
  7.                 if (!ptrace_may_access(task, PTRACE_MODE_READ))
  8.                         return 0;
  9.                 else
  10.                         return sprintf(buffer, "%lu", wchan);
  11.         else
  12.                 return sprintf(buffer, "%s", symname);
  13. }


改成

  1. static int proc_pid_wchan(struct task_struct *task, char *buffer)
  2. {
  3.     unsigned long wchan;
  4.     char symname[KSYM_NAME_LEN];

  5.     wchan = get_wchan(task);

  6.     if (lookup_symbol_name(wchan, symname) < 0)
  7.         if (!ptrace_may_access(task, PTRACE_MODE_READ))
  8.             return 0;
  9.         else
  10.             return sprintf(buffer, "%lu", wchan);
  11.     else
  12.     {
  13.        if (strstr(symname, "trace")) {
  14.             return sprintf(buffer, "%s", "sys_epoll_wait");
  15.        }
  16.        return sprintf(buffer, "%s", symname);
  17.     }
  18. }

kernel/msm/fs/proc/array.c 134 行

  1. static const char * const task_state_array[] = {
  2.     "R (running)", /* 0 */
  3.     "S (sleeping)", /* 1 */
  4.     "D (disk sleep)", /* 2 */
  5.     "T (stopped)", /* 4 */
  6.     "t (tracing stop)", /* 8 */
  7.     "Z (zombie)", /* 16 */
  8.     "X (dead)", /* 32 */
  9.     "x (dead)", /* 64 */
  10.     "K (wakekill)", /* 128 */
  11.     "W (waking)", /* 256 */
  12. };

改成

  1. static const char * const task_state_array[] = {
  2.     "R (running)", /* 0 */
  3.     "S (sleeping)", /* 1 */
  4.     "D (disk sleep)", /* 2 */
  5.     "T (stopped)", /* 4 */
  6. // "t (tracing stop)", /* 8 */
  7.     "S (sleeping)", /* 8 */
  8.     "Z (zombie)", /* 16 */
  9.     "X (dead)", /* 32 */
  10.     "x (dead)", /* 64 */
  11.     "K (wakekill)", /* 128 */
  12.     "W (waking)", /* 256 */
  13. };

kernel/msm/fs/proc/array.c 134 行

  1. seq_printf(m,
  2.         "State:\t%s\n"
  3.         "Tgid:\t%d\n"
  4.         "Pid:\t%d\n"
  5.         "PPid:\t%d\n"
  6.         "TracerPid:\t%d\n"
  7.         "Uid:\t%d\t%d\t%d\t%d\n"
  8.         "Gid:\t%d\t%d\t%d\t%d\n",
  9.         get_task_state(p),
  10.         task_tgid_nr_ns(p, ns),
  11.         pid_nr_ns(pid, ns),
  12.         ppid, tpid,
  13.         cred->uid, cred->euid, cred->suid, cred->fsuid,
  14.         cred->gid, cred->egid, cred->sgid, cred->fsgid);

改成

  1. seq_printf(m,
  2.         "State:\t%s\n"
  3.         "Tgid:\t%d\n"
  4.         "Pid:\t%d\n"
  5.         "PPid:\t%d\n"
  6.         "TracerPid:\t%d\n"
  7.         "Uid:\t%d\t%d\t%d\t%d\n"
  8.         "Gid:\t%d\t%d\t%d\t%d\n",
  9.         get_task_state(p),
  10.         task_tgid_nr_ns(p, ns),
  11.         pid_nr_ns(pid, ns),
  12.         ppid, /*tpid*/0,
  13.         cred->uid, cred->euid, cred->suid, cred->fsuid,
  14.         cred->gid, cred->egid, cred->sgid, cred->fsgid);


2、重新编译内核,并刷入内核到真机上

参考我的另外一个文章http://blog.chinaunix.net/uid-27105712-id-5785215.html

3、测试

参考前面 一.3 节

  1. root@hammerhead:/ # cat /proc/1952/status | grep TracerPid
  2. TracerPid: 0
  3. root@hammerhead:/ # ps | grep test
  4. u0_a55 1952 179 451984 50920 ffffffff 4010373c S com.example.stevenrao.test
再也看不到调试状态了。


阅读(6041) | 评论(1) | 转发(0) |
0

上一篇:dex2oat 编译 脱壳

下一篇:畅谈linux下TCP(上)

给主人留下些什么吧!~~

猫须草2018-09-10 22:06:29

谢谢