反調試——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這個調試器是做了一些反反調試器的功能的。