본문 바로가기

Reversing/Anti-Debugging

[static 안티디버깅] NtQueryInformationProcess()

 

 

'  NtQueryInformationProcess()  '

 

 

 

 

설명

지정된 프로세스에 대한 정보를 검색합니다.

 

 

 

함수 원형

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

anti()

 

LoadLibraryA() 로 ntdll 라이브러리 모듈을 불러온다.

GetProcAddress()로 NtQueryInformationProcess 함수의 주소를 가져온다.

GetProcAddress() 함수가 성공적으로 호출되면 NtQueryInformationProcess의 주소가 [ebp-20]에 저장된다.

PUSH 7 > ProcessDebugPort 인자로 넣고 호출된다.

 

call dword ptr ss:[ebp-0x20] -> NtQueryInformationProcess이 호출되고 3번쨰 버퍼인 [ebp-14]에 DebugPort가 할당된다.

현재 디버깅 환경 중이므로 0xFFFFFFFF 가 셋팅된 모습.

 

[ebp-14]

후에 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

anti()

 

PUSH 1E > ProcessDebugObjectHandle 인자로 넣고 호출된다.

 

call dword ptr ss:[ebp-0x2C] -> NtQueryInformationProcess이 호출되고 3번쨰 파라미터 [ebp-20]에

hDebugObject Handle값이 할당된다.

 

[ebp-20]

 

현재 디버깅 환경 중이므로 [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

anti()

PUSH 1F > ProcessDebugFlags 인자로 넣고 호출된다.

 

call dword ptr ss:[ebp-0x20] -> NtQueryInformationProcess이 호출되고 3번쨰 파라미터 [ebp-14]에

ProcessDebugFlags 값이 할당된다.

 

 

[ebp-14]

 

현재 디버깅 환경 중이므로 [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 함수를 우회한다.