' NtQueryInformationProcess() '
설명
지정된 프로세스에 대한 정보를 검색합니다.
함수 원형

NtQueryInformationProcess는 ZwQueryInformationProcess 의 wrapper function이며,
ring3 에서는 두 함수의 기능이 동일 하다.
ntdll 라이브러리는 중요한 함수이므로 직접 호출을 하지않고 간접 호출을 한다.
2번쨰 파라미터인 ProcessInformationClass 에서
ProcessDebugPort (0x07), ProcessDebugObjectHandle (0x1E),ProcessDebugFlags (0x1F)
정보 유형을 가져와서 디버깅 중인지 여부를 체크 할 수 있다.
ProcessInformationClass는 enum (열거형)으로써 다음과 같다.
typedef enum _PROCESSINFOCLASS
{
ProcessBasicInformation = 0,
ProcessQuotaLimit,
ProcessIoCounters,
ProcessVmCounters,
ProcessTimes,
ProcessBasePriority,
ProcessraisePriority,
ProcessDebugPort = 7, // 0x7
ProcessExceptionPort,
ProcessAccessToken,
ProcessLdtInformation,
ProcessLdtSize,
ProcessDefaultHardErrorMode,
ProcessIoPortHandlers,
ProcessPooledUsageAndLimits,
ProcessWorkingSetWatch,
ProcessUserModeIOPL,
ProcessEnalbeAlignmentFaultFixup,
ProcessPriorityClass,
ProcessWx86Information,
ProcessHandleCount,
ProcessAffinityMask,
ProcessPriorityBoost,
MaxProcessInfoClass,
ProcessWow64Inforamtion = 26,
ProcessImageFileName = 27,
ProcessDebugObjectHandle = 30, // 0x1E
ProcessDebugFlags = 31, // 0x1F
} PROCESSINFOCLASS, * PPROCESSINFOCLASS;
ProcessDebugPort (0x07)
프로세스가 디버깅 중일떄 DebugPort 가 할당된다.
프로세스가 디버깅 중일 경우 ProcessInformation 파라미터의 변수에 0이 아닌값이 셋팅된다. (0xFFFFFFFF)
디버깅 중이 아니라면 0으로 셋팅된다.
CODE
#include<windows.h>
#include<stdio.h>
typedef enum _PROCESSINFOCLASS
{
ProcessBasicInformation = 0,
ProcessQuotaLimit,
ProcessIoCounters,
ProcessVmCounters,
ProcessTimes,
ProcessBasePriority,
ProcessraisePriority,
ProcessDebugPort = 7, // 0x7
ProcessExceptionPort,
ProcessAccessToken,
ProcessLdtInformation,
ProcessLdtSize,
ProcessDefaultHardErrorMode,
ProcessIoPortHandlers,
ProcessPooledUsageAndLimits,
ProcessWorkingSetWatch,
ProcessUserModeIOPL,
ProcessEnalbeAlignmentFaultFixup,
ProcessPriorityClass,
ProcessWx86Information,
ProcessHandleCount,
ProcessAffinityMask,
ProcessPriorityBoost,
MaxProcessInfoClass,
ProcessWow64Inforamtion = 26,
ProcessImageFileName = 27,
ProcessDebugObjectHandle = 30, // 0x1E
ProcessDebugFlags = 31, // 0x1F
} PROCESSINFOCLASS, * PPROCESSINFOCLASS;
typedef NTSTATUS(WINAPI* PNtQUERYINFORMATIONPROCESS) (
_In_ HANDLE ProcessHandle,
_In_ PROCESSINFOCLASS ProcessInformationClass,
_Out_ PVOID ProcessInformation,
_In_ ULONG ProcessInformationLength,
_Out_opt_ PULONG ReturnLength
);
BOOL anti()
{
BOOL result = FALSE;
DWORD Buffer;
PNtQUERYINFORMATIONPROCESS pNtQueryInformationProcess;
HMODULE h_ntdll = LoadLibraryA("ntdll.dll");
pNtQueryInformationProcess = (PNtQUERYINFORMATIONPROCESS)GetProcAddress(h_ntdll, "NtQueryInformationProcess");
pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugPort, &Buffer, 4, 0);
if (Buffer == 0)
MessageBoxA(NULL, "No Detect", "", MB_OK);
else
MessageBoxA(NULL, "Detect", "", MB_OK);
return 0;
}
int main()
{
anti();
return 0;
}
ntdll 라이브러리 호출을 하기위해 LoadLibraryA -> GetProcAddress 로 주소를 불러온다.
ntdll 라이브러리는 주요 API를 지닌 중요한 라이브러리기 떄문에 직접 호출이 불가능하고
간접호출을 하여야한다.
DebugPort를 할당받을 ProcessInformation 파라미터에 Buffer 변수를 넣는다.
Disassemble

LoadLibraryA() 로 ntdll 라이브러리 모듈을 불러온다.
GetProcAddress()로 NtQueryInformationProcess 함수의 주소를 가져온다.
GetProcAddress() 함수가 성공적으로 호출되면 NtQueryInformationProcess의 주소가 [ebp-20]에 저장된다.
PUSH 7 > ProcessDebugPort 인자로 넣고 호출된다.
call dword ptr ss:[ebp-0x20] -> NtQueryInformationProcess이 호출되고 3번쨰 버퍼인 [ebp-14]에 DebugPort가 할당된다.
현재 디버깅 환경 중이므로 0xFFFFFFFF 가 셋팅된 모습.


후에 Buffer가 0인지 체크 후 분기하는 코드
ProcessDebugObjectHandle (0x1E)
프로세스가 디버깅 중일떄 Debug Object 객체가 생성된다.
프로세스가 디버깅 중이라면 Debug Object Handle은 값이 존재할 것이고
디버깅 중이 아니라면 NULL 이다.
CODE
BOOL anti()
{
BOOL result = FALSE;
HANDLE hDebugObject = NULL;
PNtQUERYINFORMATIONPROCESS pNtQueryInformationProcess;
HMODULE h_ntdll = LoadLibraryA("ntdll.dll");
pNtQueryInformationProcess = (PNtQUERYINFORMATIONPROCESS)GetProcAddress(h_ntdll, "NtQueryInformationProcess");
pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugObjectHandle, &hDebugObject, 4, 0);
if (hDebugObject == 0)
MessageBoxA(NULL, "No Detect", "", MB_OK);
else
MessageBoxA(NULL, "Detect", "", MB_OK);
return 0;
}
Disassemble

PUSH 1E > ProcessDebugObjectHandle 인자로 넣고 호출된다.
call dword ptr ss:[ebp-0x2C] -> NtQueryInformationProcess이 호출되고 3번쨰 파라미터 [ebp-20]에
hDebugObject Handle값이 할당된다.

현재 디버깅 환경 중이므로 [ebp-20] 영역에 handle이 할당 된 모습
후에 hDebugObject Handle 값 이 0인지 검사 후 분기하는 코드가 진행된다.
ProcessDebugFlags (0x1F)
DebugFlags를 확인 하여 디버깅 여부를 체크한다.
프로세스가 디버깅 중이라면 DebugFlags은 값은 0으로 셋팅되고
디버깅 중이 아니라면 1로 셋팅된다.
CODE
BOOL anti()
{
BOOL result = FALSE;
BOOL DebugFlag = TRUE;
PNtQUERYINFORMATIONPROCESS pNtQueryInformationProcess;
HMODULE h_ntdll = LoadLibraryA("ntdll.dll");
pNtQueryInformationProcess = (PNtQUERYINFORMATIONPROCESS)GetProcAddress(h_ntdll, "NtQueryInformationProcess");
pNtQueryInformationProcess(GetCurrentProcess(), ProcessDebugFlags, &DebugFlag, 4, 0);
if (DebugFlag == 0)
MessageBoxA(NULL, "Detect", "", MB_OK);
else
MessageBoxA(NULL, "No Detect", "", MB_OK);
return 0;
}
Disassemble

PUSH 1F > ProcessDebugFlags 인자로 넣고 호출된다.
call dword ptr ss:[ebp-0x20] -> NtQueryInformationProcess이 호출되고 3번쨰 파라미터 [ebp-14]에
ProcessDebugFlags 값이 할당된다.

현재 디버깅 환경 중이므로 [ebp-14] 영역에 DebugFlags가 0으로 셋팅된 모습
후에 DebugFlags 값 이 0인지 검사 후 분기하는 코드가 진행된다.
실습
NtQueryInformationProcess(ProcessHandle,ProcessDebugPort,buf,4,0)
> buf 값을 0으로 패치
NtQueryInformationProcess(ProcessHandle,ProcessDebugObjectHandle,buf,4,0)
> buf 값을 0 (NULL) 으로 패치
NtQueryInformationProcess(ProcessHandle,ProcessDebugFlags,buf,4,0)
> buf 값을 1로 패치
로 NtQueryInformationProcess 함수를 우회한다.
'Reversing > Anti-Debugging' 카테고리의 다른 글
| [Dynamic 안티디버깅] Assembly instructions (0) | 2024.02.25 |
|---|---|
| [static 안티디버깅] BlockInput() (0) | 2023.06.10 |
| [static 안티디버깅] NtSetInformationThread() (0) | 2023.06.09 |
| [static 안티디버깅] CheckRemoteDebuggerPresent() (0) | 2023.06.06 |
| [static 안티디버깅] IsDebuggerPresent (0) | 2023.06.05 |