Author: Crystal
0X01 jni 反调试介绍
为了避免我们的so文件被动态分析,我们通常在so中加入一些反调试代码,常见的Java native反调试方法有以下几种。 1、直接调用ptrace(PTRACE_TRACEME, 0, 0, 0)。 2、根据上面说的/proc/$pid/status中TracerPid行显示调试程序的pid的原理, 可以写一个方法检查下这个值, 如果!=0就退出程序。 3、检查代码执行的间隔时间。 4、扫描常见调试器端口,看是否正在被调试。
0X02 环境搭建
Android 开发环境 : Android studio 2.2.2 Android NDK 开发 环境搭建:
http://www.jianshu.com/p/d8cde65cb4f7
0x03 反调试技术实现
1.直接调用ptrace(PTRACE_TRACEME, 0, 0, 0) ptrace有一个很重要的特定:一个进程只能被一个进程调试。根据这个特点,只需要在自己的进程中调用ptrace就能一定程度上阻止被其他调试器调试。下面是jni 中代码实现
代码示例 void Debug_ptrace() { ptrace(PTRACE_TRACEME, 0, 0, 0); }
2.根据/proc/$pid/status中TracerPid行显示调试程序的pid的原理, 可以写一个方法检查下这个值(看TracerPid 有没有进程附加在该进程上就退出程序)。
代码示例 void Debug_TracerPid() { int pid; FILE *fd; char filename[MAX]; char line[MAX]; pid = getpid(); sprintf(filename, "/proc/%d/status", pid);// 读取proc/pid/status中的TracerPid while (true) { fd = fopen(filename, "r"); while (fgets(line, MAX, fd)) { if (strncmp(line, "TracerPid", 9) == 0) { int statue = atoi(&line[10]); LOGD("########## statue = %d,%s", statue, line); fclose(fd); if (statue != 0) { LOGD("########## here"); int ret = kill(pid, SIGKILL); LOGD("########## kill = %d", ret); return; } break; } } sleep(CHECK_TIME); } }
- 检查代码执行的间隔时间。返回的是毫秒时间,一般下断点单步调试时间会变长,可以在关键代码处加上时间判断来达到反调试效果。 //计算代码运行时间
代码示例 int CalculateTime() { long start, end; long a; //start time start = clock(); //do something a = 255.0 / 16.0; //end time end = clock(); long str = (end - start); return str; }
4.扫描常见调试器端口,看是否正在被调试。IDA 常见附加调试端口为23946端口,也可以添加其他常用调试器端口来检测
代码示例 int ScanPort() { char szLines[1024] = {0}; int nFind = 0; FILE *fp = fopen("/proc/net/tcp", "r"); if (fp != NULL) { while (fgets(szLines, sizeof(szLines), fp)) { //23946端口 if (strstr(szLines, "00000000:5D8A")) { nFind = 1; exit(0); } } fclose(fp); } else { printf("fopen error\r\n"); } if (nFind == 0) { return 0; } return 0; }
0x04 总结
至此,这些简单的java native层反调试方法就总结到这里。希望这篇文章能对需要的朋友有所帮助。
0X05 参考文献
参考Android应用方法隐藏及反调试技术浅析的0×03反调试初探:http://www.freebuf.com/articles/terminal/80996.html 参考 jin 实现反调试 :http://burningcodes.net/