关于 NtQueryInformationProcess 的反调试参考这篇文章
没错! 这也是我写的(可能这就是所谓的自己打自己把 /手动滑稽 |ू・ω・` ))
首先我们看下之前写的代码(部分):
status = NtQueryInformationProcess(
GetCurrentProcess(), // 进程句柄
0x7, // 要检索的进程信息类型,ProcessDebugPort:调试器端口号
&isDebuggerPresent, // 接收进程信息的缓冲区指针
sizeof(DWORD), // 缓冲区大小
NULL // 实际返回进程信息的大小
);
我的代码里的 NtQueryInformationProcess 中第二个参数使用 0x7(也就是 ProcessDebugPort)来检测程序是否被调试,当然第一步我们只做一个简单的验证,所以只关注 0x7 就可以。
但是在实际操作中,还要关注 0x1E、0x1F 。
测试程序还是上一篇里的,如果不知道效果看顶部的超链接,这里不再啰嗦。
简单验证
用 OD 打开程序(这里就用吾爱破解 OD 了,反正吾爱的 OD 也检测不到 NtQueryInformationProcess 的反调试,所以用什么 OD 都一样啦 )
就这样在入口点断下来 ——
然后不要着急调试。回到之前的源码,添加两行内容:
// ntdll 加载成功
if(hNtDll){
// 取 NtQueryInformationProcess 函数地址
NtQueryInformationProcess = (pfnNtQueryInformationProcess)GetProcAddress(hNtDll, "NtQueryInformationProcess");
// 新添加的两行代码,用来打印 ntdll.dll 地址、NtQueryInformationProcess 地址
std::cout << "hNtDll = " << std::hex << hNtDll << std::endl;
std::cout << "NtQueryInformationProcess = " << std::hex << NtQueryInformationProcess << std::endl;
...
...
运行下程序看下效果,经多次运行发下这两个值是固定不变的:
回到 OD 里,来到 0x771FF08 处,并下一个断点:
点击运行,发现程序断下,右下角堆栈里的内容证明我们断下的位置是正确的:
但这个调用并不是我们想要的,原因是函数的第二个参数为 0x24,而我们在源码里的是 0x7
继续点击运行,直到第二个参数变成 0x7 为止:
我们再回头看源码,NtQueryInformationProcess 是使用第三个参数来接收进程信息的:
status = NtQueryInformationProcess(
GetCurrentProcess(), // 进程句柄
0x7, // 要检索的进程信息类型,ProcessDebugPort:调试器端口号
&isDebuggerPresent, // 接收进程信息的缓冲区指针
sizeof(DWORD), // 缓冲区大小
NULL // 实际返回进程信息的大小
);
也就是说,003CF590 这个地址里存放 NtQueryInformationProcess 返回的数据,而这个数据,是判断是否有调试器附加的关键:
那现在思路就已经很清晰了,我们只需要让 003CF590 这个地址无法接收到这个数据就可以啦! 我是采用的粗暴手段,直接修改堆栈数据,把原来的 003CF590 改成 002CF590:
然后再次点击几次运行,确保之后没有再出现 第二个参数为 0x7 的调用。最后取消断点,运行程序:
发现反反调试已经生效 <{=....(嘎嘎嘎~)
全篇文章都那么正式好不习惯。最后一张图挽回下气氛,讲究 ——