829 字
4 分钟
基于rdtsc的反调试函数的内联汇编实现
什么是 rdtsc 指令
rdtsc(Read Time-Stamp Counter):
- 读取 CPU 的时间戳计数器
- 返回自系统启动以来的 CPU 时钟周期数
- 结果是一个 64 位值,存储在
edx:eax(高 32 位在edx,低 32 位在eax)
反调试原理
在我们进行逆向调试的过程中会进行单步调试,在前一步和后一步的调试过程中所花费的时间明显会多于程序运行这两步的时间。因此我们就可以利用该原理使用 rdtsc 指令,使程序发现它正在被调试,从而进行防御反调试。
简单来说:正常执行速度很快,调试时会有明显延迟,通过检测时间差来判断是否被调试。
代码实现
#include <stdio.h>#include <stdlib.h>#include <windows.h>
int CheckTime() { unsigned int delta_allow = 0x1000; // 阈值
unsigned int timeLowStart, timeHighStart, timeLowEnd, timeHighEnd, delta;
__asm { // 第一次记录cpu的时间 rdtsc mov timeLowStart, eax mov timeHighStart, edx }
__asm { // 冷却时间的代码 nop nop nop nop }
__asm { // 第二次记录cpu的时间 rdtsc mov timeLowEnd, eax mov timeHighEnd, edx }
// 如果高32位发生了变化,说明被调试了 if (timeHighEnd != timeHighStart) { return 1; }
delta = timeLowEnd - timeLowStart; // 计算低32位的差值
// 如果差值大于阈值,说明被调试了 if (delta > delta_allow) { return 1; }
return 0;}
int main() { if (CheckTime()) { printf("发现被调试"); exit(0); // 结束程序 } else { printf("通过检测"); } system("pause"); return 0;}实现思路详解
1. 记录开始时间
rdtsc // 读取时间戳计数器mov timeLowStart, eax // 保存低32位mov timeHighStart, edx // 保存高32位2. 插入”冷却”代码
nopnopnopnop这部分代码的作用是:
- 在正常执行时,只占用几个CPU周期
- 在调试时,由于单步执行,会产生明显的时间延迟
3. 记录结束时间并比较
rdtsc // 再次读取时间戳mov timeLowEnd, eax // 保存低32位mov timeHighEnd, edx // 保存高32位4. 检测逻辑
- 高32位检查:如果高32位发生变化,说明时间跨度非常大,肯定被调试了
- 低32位检查:计算差值,如果超过阈值(0x1000),也认为是被调试
应用场景
这种反调试技术常用于:
- 软件保护:防止程序被静态分析和动态调试
- 游戏反作弊:检测是否被外挂程序注入或调试
- 恶意代码防御:增加逆向分析难度
- License验证:防止验证逻辑被绕过
绕过方法
作为逆向工程师,常见的绕过方法包括:
- 修改阈值:将
delta_allow改为一个很大的值 - NOP填充:将检测函数的全部代码替换为 nop
- 插件辅助:使用反反调试插件(如 ScyllaHide)
- 虚拟化:在虚拟机中运行,配合时间控制
总结
上面的代码是该反调试函数的内联汇编实现对程序的一种保护手段。通过 rdtsc 指令巧妙地利用了调试与正常执行之间的时间差异,是一种简单但有效的反调试技术。
理解这种技术不仅能帮助我们在开发时保护程序,也能让我们在逆向分析时更好地识别和绕过这类保护。
分享
如果这篇文章对你有帮助,欢迎分享给更多人!
基于rdtsc的反调试函数的内联汇编实现
https://chaojixin.ren/posts/基于rdtsc的反调试函数的内联汇编实现/ 部分信息可能已经过时









