본문 바로가기

Reversing/Anti-Debugging

[static 안티디버깅] IsDebuggerPresent

 

'  IsDebuggerPresent  '

 

설명

호출 프로세스가 사용자 모드 디버거에 의해 디버깅되는지 여부를 확인합니다.

 

 

반환값

현재 프로세스가 디버거의 컨텍스트에서 실행 중인 경우 반환 값은 0이 아닌 값입니다.

현재 프로세스가 디버거의 컨텍스트에서 실행되고 있지 않으면 반환 값은 0입니다.

 

 

 

CODE

#include <stdio.h>
#include <Windows.h>

void anti() {
	if (IsDebuggerPresent()) {
		MessageBox(NULL, "Detect", "", MB_OK);
	}
}


int main()
{
	anti();
	return 0;
}

 

 

 

Disassemble

main()

 

 

IsDebuggerPresent() 함수의 반환 값으로 현재 프로세스가 디버깅 중인지 eax 구분을 하여 분기를 일으킨다.

 

IsDebugPresent()

 

IsDebuggerPresent() 함수의 내부 형태 이다.

 

 

mov eax, dword ptr fs:[0x00000030]

FS 세그먼트는 Window에서 현재 실행 중인 스레드를 설명하는 데이터 구조인 Win32 TIB

(Thread Information Block) 를 가리킨다.

 

0x30 오프셋에는 PEB의 선형 주소가 있다.

 

 

movzx eax, byte ptr ds:[eax+0x2]

 

PEB의 선형 주소로 부터 2Byte 떨어진 저장된 값을 가져온다.

 

typedef struct _PEB {
  BYTE                          Reserved1[2];
  BYTE                          BeingDebugged;
  BYTE                          Reserved2[1];
  PVOID                         Reserved3[2];
  PPEB_LDR_DATA                 Ldr;
  PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
  PVOID                         Reserved4[3];
  PVOID                         AtlThunkSListPtr;
  PVOID                         Reserved5;
  ULONG                         Reserved6;
  PVOID                         Reserved7;
  ULONG                         Reserved8;
  ULONG                         AtlThunkSListPtr32;
  PVOID                         Reserved9[45];
  BYTE                          Reserved10[96];
  PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
  BYTE                          Reserved11[128];
  PVOID                         Reserved12[1];
  ULONG                         SessionId;
} PEB, *PPEB;

 

PEB 0x2는 BeingDebugged가 있는 곳으로 프로세스가 디버깅 되고있는지 판단한다.

 

정리하면 PEB의 선형 주소로 부터 2Byte 떨어진 BeingDebugged에서 디버깅 여부를 판단하여 eax 레지스터 에 복사한다.

 

 

 

 

실습

IsDebuggerPresent() 리턴

 

현재 프로세스가 디버거의 컨텍스트에서 실행 중인 경우 0이 아닌 값을 반환하므로

 

EAX 레지스터 값을 0으로 패치 해주거나 다음 명령어인 test eax,eax 명령어에서

분기 명령어를 강제로 패치 해주면 되겠다.

 

 

정리하면

1. IsDebuggerPresent()  호출 후 EAX 레지스터 값을 0으로 변경

2. IsDebuggerPresent() 시작점 retn 패치

3. 호출 후 반환되는 eax 값을 통해 분기되는 명령어 패치  (jmp  0xEB)

 

해당 방법으로 IsDebuggerPresent()  함수를 우회하거나 무력화 할 수 있다.