对反调试IsDebuggerPresent的研究
本帖最后由 白云点缀的蓝 于 2021-11-6 10:54 编辑简介:IsDebuggerPresent是确定调用进程是否由用户模式的调试器调试。下面是简单写的一个反调试代码
#include <stdio.h>
#include <Windows.h>
int main() {
int IsDebug= IsDebuggerPresent();
if (IsDebug) {
MessageBoxA(NULL, "调试中", "温馨提示", NULL);
return EXIT_FAILURE;
}
MessageBoxA(NULL, "未被调试", "温馨提示", NULL);
return EXIT_SUCCESS;
}
反调试主要逻辑:IsDebuggerPresent()
下面这个是c++的函数原型
BOOL IsDebuggerPresent();
官方文档地址:https://docs.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-isdebuggerpresent
返回值说明:
如果当前进程在调试器的上下文中运行,则返回值非零。
如果当前进程未在调试器的上下文中运行,则返回值为零。
也就是说只要返回值是非0就说明被od,或者其他调试工具调试中
我们只要判断返回值就行
这里我用的int类型的变量来接收返回值,因为bool类型就是int类型的重命名
typedef int BOOL;
int IsDebug= IsDebuggerPresent();
在c语言中非0就是真,也就是说用if来判断是否正在被调试中
如果被调试就弹出对话框,提示你调试中
if (IsDebug) {
MessageBoxA(NULL, "调试中", "温馨提示", NULL);
return EXIT_FAILURE;
}
如果未被调试,就执行如下代码
MessageBoxA(NULL, "未被调试", "温馨提示", NULL);
return EXIT_SUCCESS;
}
下面我们来运行调试一下
当我们直接运行不调试时,提示如下
因为调试了就无法知道IsDebuggerPresent的返回值,所以我直接打印一下返回值
打印代码:
printf("%d\n", IsDebug);
运行后可以看到打印了0
下面我们进行调试然后跟踪一下反汇编代码
下图红色部分为调用IsDebuggerPresent函数
跟踪进入isDebuggerPresent函数内部
可以看到eax的值变为了00E74000
取出eax+2地址里面的值
然后把eax的值进行返回
然后把返回的值进行赋值给IsDebug
在计算机中,每一个变量都有一个地址,就是忘IsDebug地址里写入eax存的值,也就是1
00A148A4mov dword ptr ,eax
可以看到有一个比较,如果IsDebug为0那么就跳过提示调试中
if (IsDebug) {
00A148B8cmp dword ptr ,0
00A148BCje __$EncStackInitStart+66h (0A148E2h)
可以看到IsDebug为1,所以je不会跳转
然后执行下面的弹窗
MessageBoxA(NULL, "调试中", "温馨提示", NULL);
00A148BEmov esi,esp
00A148C0push 0
00A148C2push offset string "\xce\xc2\xdc\xb0\xcc\xe1\xca\xbe" (0A17B34h)
00A148C7push offset string "\xb5\xf7\xca\xd4\xd6\xd0" (0A17BE0h)
00A148CCpush 0
00A148CEcall dword ptr
00A148D4cmp esi,esp
00A148D6call __RTC_CheckEsp (0A11230h)
当执行完如下代码时弹出了信息框
如果未被调试执行如下代码:
MessageBoxA(NULL, "未被调试", "温馨提示", NULL);
00A148E2mov esi,esp
00A148E4push 0
00A148E6push offset string "\xce\xc2\xdc\xb0\xcc\xe1\xca\xbe" (0A17B34h)
00A148EBpush offset string "\xce\xb4\xb1\xbb\xb5\xf7\xca\xd4" (0A17BE8h)
00A148F0push 0
00A148F2call dword ptr
00A148F8cmp esi,esp
00A148FAcall __RTC_CheckEsp (0A11230h)
return EXIT_SUCCESS;
00A148FFxor eax,eax
有哪些方式可以过反调试呢?
可以通过修改IsDebuggerPresent函数的返回值为0实现过反调试
这里我把eax的值改为0
修改完后点击运行,可以发现成功跳过了
另外一种方式是把je改为jmp,直接绕过反调试
在od中过反调试的方法如下
过反调试的第一种方式(适合代码被加壳,被vm,也适合无壳)
CTRL+G搜索IsDebuggerPresent
我们在头部下断
执行到retn处可以看到eax的值为1
双击eax,把1改为0
然后我们F9运行
可以看到成功绕过了反调试
未修改任何数据的情况下,可以看到检测到了
过反调试的第二钟方式(适合未加壳)
通过修改je为jmp来实现绕过反调试
我们先在IsDebuggerPresent头部下断
然后点击运行,可以看到调用这个IsDebuggerPresent函数的call
因为在调用call时,会把cal指令的下一条指令压入堆栈
选择堆栈第一条指令,然后回车快速跳转到call前的下一条指令
根据前面的分析,我们可以知道下面那一条je语句就是关键
我们把这条语句改为jmp即可实现过反调试
JMP SHORT 00A148E2
然后F9运行,可以看到成功绕过了反调试
插件的实现原理是将PEB的BeginDebugged直接赋值为0 赞一个,有空也可以普及一下CheckRemoteDebuggerPresent
这两个API是最常见的反调试API 地板亦是同理板凳{:5_187:} 直接修改API的返回值麽? 列明 发表于 2021-9-26 13:33
直接修改API的返回值麽?
retn执行前后 学习支持康康 学习一下反调试 感谢分享 这就去淦VMP内核反调试(huaji){:5_188:} 多谢分享多谢分享