吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 18122|回复: 38
收起左侧

[Android 原创] 基于HOOK的Anti-debug调用点trace和Anti-anti

[复制链接]
ThomasKing 发表于 2015-4-16 20:32
原帖:http://bbs.pediy.com/showthread.php?t=199671

基于HOOKAnti-debug调用点traceAnti-anti
一、概述
相信动态调试过SO的坛友对Anti并不陌生,比如读取/proc/self/status,/proc/self/task/xxx/status、stat文件查看状态TracePid和PPid,读取wchan查看进程等待,添加notify,模拟器检测等等。经过各种掉坑之后,虽然知道了这些检测方法,但如果elf文件被畸形不能静态分析(修复又是另外一回事了),也只能动态调试在这些关键API处下断点,也免不了掉坑调试崩溃,再来点指令混淆的话,调试起来确实比较恶心。虽然在Android平台同样也存在linux常用的ltrace(库函数trace)和strace(系统调用和信号trace)工具,但不能满足调试需求,还有检测ltrace的调试。废话不多说,直接进入正题(限于水平,难免会有疏漏和错误之处,请各位大大斧正,小弟感激不尽)。

二、调用点trace
注入Hook API函数,当然首选zygote进程是最方便的了(如果zygote不能注入的话,那就关文档去修改ROM吧)。HooK住函数之后,通常采用下面这种模式添加代码:
Xxxnew_fun(xxx){
         Before_call();
         Old_fun();
         After_call();
}
相信许多都知道ARM函数的调用流程,这里再啰嗦下 ARM汇编如何调用函数:
直接调用:BL/BLX _xxfun
函数指针调用:BL/BLX Rx
某些混淆代码:mov lr, [pc, #xx], 计算RxLdr PC, Rx
外部函数调用:BL/BLX _plt表项,plt表中load got表存在的函数地址到PC
被调函数一般模式:
Stmxx{Rx-Rx, lr}       /push
ldmxx{Rx-rx, pc}      /pop
函数的返回地址保存在lr寄存器中,之后被被调函数存在放栈上。只要lr的值未被修改,那么就保存着调用点的下一条指令地址!只要获取lr的值,那么就能跟踪到调用点。
知道了lr保存了调用点的值,获取lr的值也要注意时机。调用函数时lr的值已经被存在放栈上,修改lr也无关紧要。无法确定被调函数是否存在显式地给lr赋值或者函数调用,那要保证lr不被修改,故在函数入口点就保存lr的值是最佳也是最简单的选择。获取lr的值可以通过汇编来实现:
#define GETLR(store_lr)  \
         __asm__ __volatile__(    \
                   "mov %0, lr\n\t"      \
                   :        "=r"(store_lr)  \
         )
Hook函数模式:
Xxxnew_fun(xxx){
         Unsigned lr;
         GETLR(lr)
         Before_call();
         Old_fun();
         After_call();
}
来个实例,简单起见只Hook fopen函数:
FILE*new_fopen(const char *path,const char * mode){
         unsigned lr;
         GETLR(lr);
         if(strstr(path, "status") !=NULL){
                   LOGD(" Traced-fopenCall function: 0x%x\n", lr);
                   if(strstr(path,"task") != NULL){
                            LOGD("Traced-anti-task/status");
                   }else
                            LOGD("Traced-anti-status");
         }else if(strstr(path,"wchan") != NULL){
                   LOGD(" Traced-fopenCall function: 0x%x\n", lr);
                   LOGD("Traced-anti-wchan");
         }
         return old_fopen(path, mode);
}
注入后,某APK输出:

1 调用点
Logcat:

2  trace
Trace到了这个检测点,大概就知道这个函数想干什么了。动态调试时,也好准备跨坑而不是掉坑了。
除了直接获得这些调用点过坑外,还可以组合一些其他功能。比如监控APK启动时mmap分配内存,直接dd,便于大致分析某段代码做了什么,配合mprotect能起到一定的效果。当然,不必担心会监控到linker加载SO时mmap的无用信息,因为linker自身实现了mmap函数。
staticvoid* new_mmap(void* start,size_t length,int prot,int flags,int fd,off_toffset){
         unsigned lr;
         void* base = NULL;
         
         GETLR(lr);
         base = old_mmap(start, length, prot,flags, fd, offset);
         if((flags & MAP_ANONYMOUS) == 0){     //文件映射
                   char file_name[256];
                   char buf[256];
                   memset(buf, 0, 256);
                   sprintf(file_name,"/proc/self/fd/%d", fd);
                   if(readlink(file_name, buf,256) < 0){
                            LOGD("[E]Traced-mmap --> readlink %s error\n", file_name);
                            goto _done;
                   }
                   LOGD(" Traced-mmap--> [file] start = %p, length = 0x%x, filename = %s, offset = 0x%x",
                            start, length, buf,offset);
         }else{        //内存映射
                   LOGD(" Traced-mmap--> [mem] start = %p, length = 0x%x",
                            start, length);
         }
         LOGD(" Traced-mmap Callfunction: 0x%x, Ret address: 0x%x\n", lr, (unsigned)base);
_done:
         return base;
}

3
至于还能做什么,那就靠各位读者自行研究了吧。附上一些常见anti trace
三、Anti-anti
讨论一些常见的基于Hook的Anti-anti方法,欢迎讨论。
1、 status和stat
status和stat的Anti-anti方式类似,通过Hook fopen实现重定向到/data/local/tmp目录下:
sprintf(re_path,"/data/local/tmp/status");
if(!HasGenFile(re_path)){
charbuffer[BUFFERSIZE];
FILE*fpr, *fpw;
fpr =old_fopen(path, "r");
fpw =old_fopen(re_path, "w");
if(fpr== NULL || fpw == NULL){
           LOGD("[E]re-path [%s]failed", path);
           returnold_fopen(path, mode);
}
while(fgets(buffer,BUFFERSIZE, fpr) != NULL){
           if(strstr(buffer,"State") != NULL){
                    fputs("State:\tS(sleeping)\n", fpw);
           }
          if(strstr(buffer,"TracerPid") != NULL){
                    fputs("TracerPid:\t0\n",fpw);
           }else{
                    fputs(buffer,fpw);
           }
}
fclose(fpr);
fclose(fpw);
}
2、 wchan
和status类似,只是重定向时,将等待事件设置为sys_epoll_wait:
if(strstr(path, "wchan") != NULL){
LOGD("Anti-anti-wchan!");
strcpy(re_path,"data/local/tmp/wchan");
if(!HasGenFile(re_path)){
           FILE*fpw;
           fpw= old_fopen(re_path, "w");
           if(fpw== NULL){
                    LOGE("[E]re-path wchan failed!");
                    goto__normal;
           }
           fputs("sys_epoll_wait",fpw);
           fclose(fpw);
}
return old_fopen(re_path, mode);

3、 inotify_add_watch
检测mem、pagemem、task等读取事件。可以直接让其返回-1,但不推荐这么做。如果检测代码并未对返回值做判断,直接使用,这样Anti-anti会导致程序崩溃,我的做法是改变mask的值:

//监控打开和读事件
if(strstr(pathname, "mem") !=NULL){
LOGD("inotify_add_watch --> patch mem");
return old_inotify_add_watch(fd,pathname, 0x00000200);           //mem永远不会被删除,改为0也可以
//监控打开和读事件,防获取反调试线程信息
}else if(strstr(pathname, "task")!= NULL){
LOGD("inotify_add_watch --> patch task");
return old_inotify_add_watch(fd, pathname, 0x00000200);
4、 ptrace
这个函数算是用得比较多的吧,简单的检测代码是调用PTRACE_TRACEME,直接返回0就可以,不过现在这种方式很少了吧。某加固fork了进程去作ptrace,并写入一些数据。通过对ptrace hook,可以监控到写入数据。模拟这个通信过程就可以Anti-anti。具体就不展开了吧,相信各位读者可以做到了。
当然,还有一些Anti-anti方法,限于篇幅,就不展开了吧(让小弟学学各位大牛的Anti-anti方法吧)。
四、总结
做好Anti-trace和Anti-anti有些时候能大大节省时间,将精力专注于算法或者其他逻辑上。但也存在一些问题:
1、 HOOK检测
导出表HOOK检测:读取/system/lib/libc.so特定函数偏移,再获取本进程libc.so的基地址来检测是否有HOOK。(Patch方法:Hook fopen、dlopen和open函数)
Inline HooK检测:Inline Hook时要替换函数起始的字节码,可以检测一些比较奇怪的二进制码(BX pc等字节码)。
2、 LOGCAT
许多反调试都会起一个进程或者线程循环监控,此时anti-trace的输出会比较多,比如:

图 4
这看起来比较烦,而且很多都是相同的。可以利用调用点trace地址的唯一性进行过滤,让同一信息只输出一次即可,也可以写个apk,将信息通过AF_UNIX本地套接字发送给apk,利用数据库的优势来存储等等。
3、 SVC
有些关键性的API,为了隐藏,直接通过汇编实现系统调用。ARM系统调用时的调用号通过r7寄存器来传递的。如果编写时,没有手写花指令,直接通过扫描SVC字节码和附近的关于r7的寄存器赋值操作,可以获得一些搜索结果。不过为了隐藏,手写点花指令也是可以的。
比如:常用来刷cache的代码
staticvoid clearcache(char* begin, char *end)
{
         const int syscall = 0xf0002;
         __asm __volatile (
                   "mov          r0, %0\n"
                   "mov          r1, %1\n"
                   "mov          r7, %2\n"
                   "mov     r2, #0x0\n"
                   "svc     0x00000000\n"
                   :
                   :        "r" (begin), "r" (end), "r" (syscall)
                   :        "r0", "r1", "r7"
                   );
}


trace_anti_debug.zip

1.71 MB, 下载次数: 147, 下载积分: 吾爱币 -1 CB

基于HOOK的Anti-debug callee检测和Anti-anti.rar

354.9 KB, 下载次数: 80, 下载积分: 吾爱币 -1 CB

免费评分

参与人数 4热心值 +4 收起 理由
易木马 + 1 谢谢@Thanks!
微博2016 + 1 热心回复!
suno + 1 学习
巅烽2 + 1 支持大牛

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

巅烽2 发表于 2015-4-16 21:02
支持T哥哥
searchjack 发表于 2015-4-17 12:53
   赞一下, 不过打不开图片  不知道是不是网速问题
Hmily 发表于 2015-4-17 19:14
ThomasKing附件为给上传编辑到主题贴了,上传有什么问题吗?
蚯蚓翔龙 发表于 2015-4-18 21:44
看不懂。。。但既然是精华应该很厉害的
tree_fly 发表于 2015-4-18 22:42
写的很好
f2pjn0xo01 发表于 2015-4-19 00:43
好长,表示不太懂。。。
katkat 发表于 2015-4-19 11:46
大牛放大招了,支持。
aslinliw 发表于 2015-4-19 12:10
好像很厉害的样子!!!!!!
jvc2007 发表于 2015-4-20 10:43
支持 慢慢看
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-4-20 11:26

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表