小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
只有知道了反调试是怎么实现的才能更好的过反调试,调试在代码保护中扮演着很重要的角色,虽然不能完全阻止攻击者,但是还是能加大攻击者的时间成本,一般与加壳结合使用,核心还是加壳部分。
反调试可以分为两类:一类是检测,另一类是攻击,前者是去想各种办法去检测程序是否在被调试,如果正在被调试的话做出一些“反”的举措,比如退出等等,这种一般最为常见,其越过方法就是,找到代码检测的位置,通过frida进行hook,修改其返回值即可,这里先介绍下,常见的反调试技术。
三种反调试技术:Self-Debugging 反调试、轮训检测反调试和Java层反调试
Self-Debugging 反调试
Self-Debugging 是指父进程创建一个子进程,并用子进程调试父进程的技术。
通过ptrace函数实现,一个进程被调试时,只有两个状态:运行和暂停。
暂停状态又分为以下几种:
1.signal-delivery-stop状态
当一个进程收到除SIGKILL外的信号时,内核将选择进程内的任意一个线程处理这个信号,
如果被选择的线程正在被调试,则这个线程进入了此状态(线程进入暂停状态,调试器使用Waitpid函数等待这个事件,并取得这个信号)。此时,进程并没有真的收到这个信号,而且这个信号可以被调试器丢弃,导致进程永远无法收到这个信号。
2.group-stop状态
3.syscal-stop和ptrace-event-stop状态
轮询检测反调试
实现原理
读取进程的/proc/{pid}/status文件,通过该文件得到调试当前进程的调试器。
status文件的字段信息解释如下:
Name:进程名
State:表示进程的状态
Tgid:线程组ID,一般指进程名
Pid:线程ID,他的值和gettid函数的返回值相等
PPid:父进程的进程id
TracerPid:实现调试功能的进程ID,值为0表示当前进程未被检测。
方案实现
通过检测status文件内的Tracerpid字段的值判断当前进程或线程是否正在被调试。
java层反调试
在androidManifest.xml文件的Application标签中设置android:debuggable的属性为false即可。