调试机制
Linux
通过ptrace
系统调用来调试子进程
对于create类型,与正常创建子进程工序相同,通过fork创建子进程后使用traceme来告知内核它需要被调试,这样等到exec执行的时候内核就会产生SIGTRAP,此时调用wait的父进程就会接收到这个信号并ptrace子进程,从而使得调试优先于子进程的所有内容
而对于attach类型,是父进程直接使用ptrace去调试其他进程,如果此时子进程已经被调试那么就会报错
Windows
通过调试对象(或者说是API)来进行通信
Windows系统的复杂度比Linux高很多,所以调试相关的东西对于用户态来说基本都是API来操作
对于create类型,父进程CreateProcess时直接传入DEBUG_PROCESS的标志即可
对于attach类型,则是调用DebugActiveProcess的API来实现的
反调试
-
Windows
- PEB
当进程被调试时会在进程环境块中设置很多内容,这些内容都可以被检测到。包括BeingDebugged、NTGlobalFlags、调试堆、DebugPort等等 - API
例如ZwSetInformationThread
可以设置ThreadHideFromDebugger
标志,使得进程不接受被调试
- PEB
-
Linux
- ptrace(trace_me)
当使用trace_me后进程即会进入被调试的状态,此时别的进程就无法主动附加 - self/$pid/status
status中会显示tid、ppid等
- ptrace(trace_me)
-
x86通用
- 检测调试器特征
进程遍历 - 断点检查和HOOK
检查INT 3(0xcc)、HOOK调试函数 - 异常处理
调试器会优先接收子进程的异常,从而产生区别 - 父进程
Windows下正常的父进程应该是explorer.exe
(从文件管理器启动)、cmd.exe
(从命令行启动)、Services.exe
(系统服务)
Linux下正常的进程一般是由bash fork出来的
- 检测调试器特征
反反调试
几乎所有用户态反调试只要被抓到即可轻而易举地破解,所以关键问题在于发现反调试
而反调试的种类过于繁多,个人建议通读参考资料,当发现可疑代码时再行检查