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/