反调试技术
反调试技术
反调试技术用于防止程序被调试
一般分为利用函数进行检测或者直接将调试权限清0
IsDebuggerPresent
原理
IsDebuggerPresent是Windows API提供的函数,用于确定调用进程是否由用户模式调试器进行调试。
当调试器存在时, IsDebuggerPresent( )函数返回的是一个非0值
.
API获取PEB.BeingDebugged
的值来判断是否处于被调试状态。进程处于被调试状态时,PEB.BeingDebugged的值被设置为1,反之为0.
1 | BOOL WINAPI IsDebuggerPresent(void); |
样例代码
1 | if(IsDebuggerPresent()){ |
1 | call IsDebuggerPresent |
绕过
如图,为一个IsDebuggerPresent()
函数,如果正在被调试就会返回非零值
查看汇编
若返回值为非零值
方法一:
修改jnz 指令为jz指令
绕过成功
方法二:
利用OD修改PEB.BeingDebugged 改为0.
PEB的结构指针存储在TEB中,fs:[0x30]是PEB fs:[0x18]是TEB。
CheckRemoteDebuggerPresent
原理
CheckRemoteDebuggerPresent是Windows API提供的函数,用于检测是否正在调试指定的进程
于IsDebuggerPresent不同,它可以在多线程的情况下进行使用
NtQueryInformationProcess
原理
NtQueryInformationProcess( )是一个接受一个信息类的参数用于查询的函数。
kernel32的CheckRemoteDebuggerPresent()
函数内部通过调用NtQueryInformationProcess()
来
检测调试, 而NtQueryInformationProcess
内部则是查询EPROCESS
结构体的DebugPort
字段, 当进
程正在被调试时, 返回值为0xffffffff.
TLS反调试
TLS原本是用于多线程情况下的数据同步,分动态绑定和静态绑定两种用法
而其中的静态绑定可用于反调试
TLS变量
同一个线程里面调用的各个函数都可以访问、但其他线程无法访问的变量(被称为static memory local to a thread 线程局部静态变量)
因此,如果将
TLS回调函数
静态绑定反调试主要体现在回调函数中
程序可以提供一个或多个TLS回调函数,以支持TLS数据对象的附加初始化和终止
尽管通常只有一个回调函数,但回调函数是作为数组实现的,以便在需要时可以添加额外的回调函数
如果有多个回调函数,则按其地址在数组中出现的顺序调用每个函数。空指针终止数组。空列表是完全有效的(不支持回调),在这种情况下,回调数组只有一个成员—— null ptr(空指针)
线程结束时会调用回调函数
1 | void NTAPI tls_callback(PVOID Dllhandle, DWORD Reason, PVOID Reserved) { |
绕过
修改ret的值
如果回调函数里面的不是强制退出的话就直接静态分析
花指令
所谓花指令,是指在程序中完全冗余,不影响程序功能却会对逆向工程产生干扰的指令。
不可执行花指令
例如
1 | .text:0040102C jnz short near ptr loc_40102E+1 |
这段汇编用jnz指令往后面跳了一行,由于IDA用的是递归下降反汇编算法,会错误识别然后导致无法反汇编,并且后面的代码以数据块的方式展现出来
只能将花指令nop掉,让IDA从数据块开头开始执行递归下降反汇编
再把反汇编出来的指令定义为函数,即可正常的反汇编
当然也可以用OD进行修改
可执行花指令
SMC(self-Modifying Code)
SMC(self-Modifying Code),就是在真正执行某一段代码时,程序会对自身的该段代码进行自修改,只有在修改后的代码才是可汇编,可执行的。在程序未对该段代码进行修改之前,在静态分析状态下,均是不可读的字节码,IDA之类的反汇编器无法识别程序的正常逻辑。是一种反调试代码技术。
示例
程序执行的时候先将数据块解码再执行
选择使用idc脚本进行处理
1 |
|
解码后再手动定义函数进行反汇编