androi 安全里面一项手段是防止应用被动态分析。动态分析一般是通过gdb调试汇编或c代码。于是就有了一项安全手段:反调试技术。
反调试技术很多,其中一项比较常见的是 检测 TracerPid ,其原理是:程序正常状态下 其 TracerPid 为 0,当处于调试状态时候, TracerPid 为调试那个进程pid, 也就是非0 ,app 会间隔检测自己的TracerPid,一旦发现非0,就判断为程序被调试,立即退出程序。
一、使用gdb调试android app
1、先关闭SELinux (在真机(target)操作)
-
stevenrao@android-ndk-r16b$ adb shell
-
shell@hammerhead:/ $ su
-
root@hammerhead:/ # setenforce 0
-
root@hammerhead:/ # gete
-
getenforce getevent
-
root@hammerhead:/ # getenforce
-
Permissive
2、获取被调试的app 进程pid (在真机(target)操作)
-
root@hammerhead:/ # ps | grep test
-
u0_a55 8821 177 454040 51184 ffffffff 4011b73c S com.example.stevenrao.test
进程pid 为 8821 状态是 S,关于ps的状态码如下
-
D uninterruptible sleep (usually IO)
-
R running or runnable (on run queue)
-
S interruptible sleep (waiting for an event to complete)
-
T stopped by job control signal
-
t stopped by debugger during the tracing
-
W paging (not valid since the 2.6.xx kernel)
-
X dead (should never be seen)
-
Z defunct ("zombie") process, terminated but not reaped by its parent
查看 TracerPid
-
130|root@hammerhead:/system/xbin # cat /proc/8821/status | grep TracerPid
-
TracerPid: 0
3、用gdbserver attach (在真机(target)操作)
-
我刷的是google原生系统,包里面含有gdbserver,如果没有,可以在网上下载
-
root@hammerhead:/ # gdbserver remote:1234 --attach 8821
查看gdbserver pid
root@hammerhead:/ # ps |grep gdbserver
-
root 12167 5873 628 216 c0278e0c 000342f4 S gdbserver
再次查看 TracerPid
-
127|root@hammerhead:/ # cat /proc/8821/status | grep TracerPid
TracerPid: 12167
ps查看app 进程状态
-
root@hammerhead:/ # ps | grep test
-
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)操作)
这一节直接可以跳过,用来完善调试流程,和本文主题无关
-
#端口映射,本机所有发给1234端口的tcp包,都转发给手机设备的1234端口上
-
stevenrao@~$ adb forward tcp:1234 tcp:1234
-
-
#我本就有arm-eabi-gdb 程序,没有的去网上下载
-
stevenrao@~$ /data/code/aosp-4.4.4_r1/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin/arm-eabi-gdb
-
GNU gdb (GDB) 7.3.1-gg2
-
Copyright (C) 2011 Free Software Foundation, Inc.
-
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
-
This is free software: you are free to change and redistribute it.
-
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
-
and "show warranty" for details.
-
This GDB was configured as "--host=x86_64-linux-gnu --target=arm-linux-android".
-
For bug reporting instructions, please see:
-
<http://source.android.com/source/report-bugs.html>.
-
-
#设置指令架构
-
(gdb) set architecture arm
-
-
#设置调试程序
-
(gdb) file /data/code/aosp-4.4.4_r1/out/target/product/hammerhead/symbols/system/bin/app_process
-
-
#设置带符号信息的lib查找路径
-
(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/
-
-
#连接端口
-
(gdb) target remote :1234
-
Remote debugging using :1234
-
-
#对于 32 位 ARM,如果您的指令中没有符号,gdb 就不清楚自己正在反汇编哪个指令集(ARM 或 Thumb)。要指定缺少符号信息时选为默认指令集的指令集,请设置以下属性:
-
(gdb) set arm fallback-mode arm # or thumb
-
-
#查看栈
-
(gdb) bt
-
#0 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10
-
#1 0x40182642 in android::Looper::pollInner (this=0x475926e8, timeoutMillis=<optimized out>) at system/core/libutils/Looper.cpp:223
-
#2 0x4018286c in android::Looper::pollOnce (this=0x475926e8, timeoutMillis=-1, outFd=0x0, outEvents=0x0, outData=0x0)
-
at system/core/libutils/Looper.cpp:191
-
#3 0x4022b5ac in pollOnce (timeoutMillis=<optimized out>, this=<optimized out>) at system/core/include/utils/Looper.h:176
-
#4 android::NativeMessageQueue::pollOnce (this=0x4758f6f8, env=0x4179cbe0, timeoutMillis=<optimized out>)
-
at frameworks/base/core/jni/android_os_MessageQueue.cpp:97
-
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
-
-
(gdb) f 0
-
#0 epoll_wait () at bionic/libc/arch-arm/syscalls/epoll_wait.S:10
-
10 mov r7, ip
-
-
#汇编调试
-
(gdb) ni
-
11 cmn r0, #(MAX_ERRNO + 1)
-
-
#查看寄存器
-
(gdb) info register
-
r0 0xfffffffc 4294967292
-
r1 0xbeb26080 3199361152
-
r2 0x10 16
-
r3 0x7fffffff 2147483647
二、修改内核代码, 使TracerPid始终为0
1、修改内核源代码
关于内核如何编译,请参考我的另一篇http://blog.chinaunix.net/uid-27105712-id-5785215.html
要修改的文件涉及到两个
kernel/msm/fs/proc/base.c
-
static int proc_pid_wchan(struct task_struct *task, char *buffer)
-
{
-
unsigned long wchan;
-
char symname[KSYM_NAME_LEN];
-
-
wchan = get_wchan(task);
-
-
if (lookup_symbol_name(wchan, symname) < 0)
-
if (!ptrace_may_access(task, PTRACE_MODE_READ))
-
return 0;
-
else
-
return sprintf(buffer, "%lu", wchan);
-
else
-
return sprintf(buffer, "%s", symname);
-
}
改成
-
static int proc_pid_wchan(struct task_struct *task, char *buffer)
-
{
-
unsigned long wchan;
-
char symname[KSYM_NAME_LEN];
-
-
wchan = get_wchan(task);
-
-
if (lookup_symbol_name(wchan, symname) < 0)
-
if (!ptrace_may_access(task, PTRACE_MODE_READ))
-
return 0;
-
else
-
return sprintf(buffer, "%lu", wchan);
-
else
-
{
-
if (strstr(symname, "trace")) {
-
return sprintf(buffer, "%s", "sys_epoll_wait");
-
}
-
return sprintf(buffer, "%s", symname);
-
}
-
}
kernel/msm/fs/proc/array.c 134 行
-
static const char * const task_state_array[] = {
-
"R (running)", /* 0 */
-
"S (sleeping)", /* 1 */
-
"D (disk sleep)", /* 2 */
-
"T (stopped)", /* 4 */
-
"t (tracing stop)", /* 8 */
-
"Z (zombie)", /* 16 */
-
"X (dead)", /* 32 */
-
"x (dead)", /* 64 */
-
"K (wakekill)", /* 128 */
-
"W (waking)", /* 256 */
-
};
改成
-
static const char * const task_state_array[] = {
-
"R (running)", /* 0 */
-
"S (sleeping)", /* 1 */
-
"D (disk sleep)", /* 2 */
-
"T (stopped)", /* 4 */
-
// "t (tracing stop)", /* 8 */
-
"S (sleeping)", /* 8 */
-
"Z (zombie)", /* 16 */
-
"X (dead)", /* 32 */
-
"x (dead)", /* 64 */
-
"K (wakekill)", /* 128 */
-
"W (waking)", /* 256 */
-
};
kernel/msm/fs/proc/array.c 134 行
-
seq_printf(m,
-
"State:\t%s\n"
-
"Tgid:\t%d\n"
-
"Pid:\t%d\n"
-
"PPid:\t%d\n"
-
"TracerPid:\t%d\n"
-
"Uid:\t%d\t%d\t%d\t%d\n"
-
"Gid:\t%d\t%d\t%d\t%d\n",
-
get_task_state(p),
-
task_tgid_nr_ns(p, ns),
-
pid_nr_ns(pid, ns),
-
ppid, tpid,
-
cred->uid, cred->euid, cred->suid, cred->fsuid,
-
cred->gid, cred->egid, cred->sgid, cred->fsgid);
改成
-
seq_printf(m,
-
"State:\t%s\n"
-
"Tgid:\t%d\n"
-
"Pid:\t%d\n"
-
"PPid:\t%d\n"
-
"TracerPid:\t%d\n"
-
"Uid:\t%d\t%d\t%d\t%d\n"
-
"Gid:\t%d\t%d\t%d\t%d\n",
-
get_task_state(p),
-
task_tgid_nr_ns(p, ns),
-
pid_nr_ns(pid, ns),
-
ppid, /*tpid*/0,
-
cred->uid, cred->euid, cred->suid, cred->fsuid,
-
cred->gid, cred->egid, cred->sgid, cred->fsgid);
2、重新编译内核,并刷入内核到真机上
参考我的另外一个文章http://blog.chinaunix.net/uid-27105712-id-5785215.html
3、测试
参考前面 一.3 节
-
root@hammerhead:/ # cat /proc/1952/status | grep TracerPid
-
TracerPid: 0
-
root@hammerhead:/ # ps | grep test
-
u0_a55 1952 179 451984 50920 ffffffff 4010373c S com.example.stevenrao.test
再也看不到调试状态了。
阅读(6021) | 评论(1) | 转发(0) |