反调试——2——深入NtQueryInformationProcess
ProcessDebugPort这个标志位里面涉及到的东西比较复杂,所以要展开来讲。
CheckRemoteDebuggerPresent():
主要就是调用这个函数如果程序在被调试就会返回非零值,如果没有被调试就会返回0。
但是前面我们也解析了,其实CheckRemoteDebuggerPresent内部调用的是NtQueryInformationProcess函数来处理的。
两个函数的共同本质:如果程序处于调试状态,这Nt函数会查询调试端口并返回,Check函数会返回一个bool值。
BOOL CheckRemoteDebuggerPresent(
HANDLE hProcess,
PBOOL pbDebuggerPresent
);
__kernel_entry NTSTATUS NtQueryInformationProcess(
HANDLE ProcessHandle,//进程句柄
PROCESSINFOCLASS ProcessInformationClass,//进程信息类型,传不同的值表示查进程不同的信息
PVOID ProcessInformation,//输出参数 存储进行信息的缓冲区
ULONG ProcessInformationLength,//缓冲区大小
PULONG ReturnLength//实际大小
);
进程信息类型:(这里面有相当多的消息)
//其中比较常用有文档记录的
typedef enum _PROCESSINFOCLASS {
ProcessDebugPort = 7,//调试端口
ProcessDebugObjectHandle = 30,//获取调试对象句柄,句柄为空表示未调试
ProcessDebugFlags = 31 //检测调试标志位为0表示处于调试状态
} PROCESSINFOCLASS;
代码实现简单的NtQueryInformationProcess函数调用
首先这里需要从DLL里面获得函数,这里由于PROCESSINFOCLASS是一个枚举值,而且值都是0x00这样类型的,所以这里我们可以直接使用DWORD来取代,更加方便:
typedef NTSTATUS(NTAPI *_NtQueryInformationProcess)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
//头文件
#pragma once
#include<Windows.h>
#include<iostream>
typedef NTSTATUS(NTAPI *_NtQueryInformationProcess)(
HANDLE ProcessHandle,
DWORD ProcessInformationClass,
PVOID ProcessInformation,
ULONG ProcessInformationLength,
PULONG ReturnLength
);
using namespace std;
void testBeginDebugged();
void testNtGlobalFlag();
void testProcessDebugPort();
void testNtQueryInformationProcess();
void testNtPort(_NtQueryInformationProcess NtQueryInformationProcess);
void testNtObjectHandle(_NtQueryInformationProcess NtQueryInformationProcess);
void testFlag(_NtQueryInformationProcess NtQueryInformationProcess);
//源文件
#include"TestC++.h"
void testBeginDebugged()
{
if (IsDebuggerPresent())
{
cout << "BeginDebugged验证失败,程序被调试" << endl;
}
else
{
cout << "BeginDebugged验证正常" << endl;
}
}
void testNtGlobalFlag()
{
DWORD IsDebug = 1;
__asm
{
push eax
mov eax, fs: [0x30]
mov eax, [eax + 0x68]
mov IsDebug, eax
pop eax
}
if (IsDebug == 0x70)
{
cout << "NtGlobalFlag验证失败,程序被调试" << endl;
}
else
{
cout << "NtGlobalFlag验证正常" << endl;
}
}
void testProcessDebugPort()
{
BOOL IsDebug = FALSE;
CheckRemoteDebuggerPresent(GetCurrentProcess(), &IsDebug);
if(IsDebug == TRUE)
{
cout << "ProcessDebugPort验证失败,程序被调试" << endl;
}
else
{
cout << "ProcessDebugPort验证正常,程序未被调试" << endl;
}
}
void testNtQueryInformationProcess()
{
HMODULE hDll = LoadLibraryW(L"Ntdll.dll");
_NtQueryInformationProcess NtQueryInformationProcess = (_NtQueryInformationProcess)GetProcAddress(hDll, "NtQueryInformationProcess");
testNtPort(NtQueryInformationProcess);
testNtObjectHandle(NtQueryInformationProcess);
testFlag(NtQueryInformationProcess);
}
void testNtPort(_NtQueryInformationProcess NtQueryInformationProcess)
{
HANDLE hProcess = GetCurrentProcess();
DWORD DebugPort;
NtQueryInformationProcess(hProcess,7,&DebugPort,sizeof(DWORD),NULL);
if (DebugPort != 0)
{
cout << "DebugPort验证失败,程序正在被调试" << endl;
}
else
{
cout << "DebugPort验证成功" << endl;
}
}
void testNtObjectHandle(_NtQueryInformationProcess NtQueryInformationProcess)
{
HANDLE hProcess = GetCurrentProcess();
HANDLE ObjectHandle;
NtQueryInformationProcess(hProcess, 30, &ObjectHandle, sizeof(ObjectHandle), NULL);
if (ObjectHandle != NULL)
{
cout << "调试端口验证失败,程序正在被调试" << endl;
}
else
{
cout << "调试端口验证成功" << endl;
}
}
void testFlag(_NtQueryInformationProcess NtQueryInformationProcess)
{
HANDLE hProcess = GetCurrentProcess();
BOOL Flags;
NtQueryInformationProcess(hProcess, 31, &Flags, sizeof(Flags), NULL);
if (Flags != 1)
{
cout << "调试端口验证失败,程序正在被调试" << endl;
}
else
{
cout << "调试端口验证成功" << endl;
}
}
int main()
{
printf("%s\n", "Welcome");
cout << "Welcome" << endl;
testBeginDebugged();
testNtGlobalFlag();
testProcessDebugPort();
testNtQueryInformationProcess();
return 0;
}
采用OD查看:
采用VS调试器查看:
采用直接运行:
这个我一直想不通,按理来说应该是都正常啊,然后我想了一下有没有可能是Debug模式的问题,所以我打开了release版本的:
运行Release版本的exe:
证明了刚刚的猜测,也可以看到od这个调试器是做了一些反反调试器的功能的。