MMORPG 유저라면 게임을 띄워놓고 치트엔진을 사용했던 경험이 한번씩은 있을겁니다. (..없나?)

만약 핵쉴드 혹은 게임가드가 붙어있는 게임에 치트엔진을 사용했다면 "프로세스를 열 수 없습니다" 메시지를 확인할 수 있습니다.

 

<그림 1 : 프로세스 열기 실패>

 

위와 같은 범용 치트엔진은 Win32 API인 OpenProcess를 통해서 프로세스에 접근을 하게 됩니다.

이 같은 방법을 막는데엔 여러가지 방법이 있겠지만, 백신같은 같은 보안 프로그램이 프로세스 핸들(오브젝트)를 보호하고 있다고 가정해보죠.

 HANDLE hProcess = NULL;
 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 3752);
 printf("%x %x",hProcess, GetLastError());

본 소스는 특정 프로세스(pid : 3752)의 핸들을 얻는 코드로, 치트엔진도 이와 같은 초벌작업을 합니다.

컴파일하여 출력하면 NULL과 5가 출력되는데, 5는 ERROR_ACCESS_DENIED 으로 액세스 거부를 뜻합니다.

(시스템 에러 코드 표 : http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx)

이처럼 정상적인 경로로 핸들을 얻지 못하는건 보안 프로그램에서 뭔가 작업(?)을 했다는 건데요.

지금부터 무슨 작업을 했길래 핸들을 얻지 못하는지 썰을 풀어보도록 하겠습니다.

 

# 본격 작업에 앞서서 핸들을 짚어보죠.

타겟 프로세스의 핸들을 찾는 과정을 windbg를 통해 트레이싱 해보겠습니다.

타겟은 국민 프로세스 지뢰찾기(winmine.exe)입니다.

치트엔진으로 winmine.exe을 오픈했으며, 프로세스 익스플로러로 이를 확인할 수 있습니다. 

 

< 그림 2 : Process Explorer로 프로세스 핸들 확인>

치트엔진에서 winmine.exe의 프로세스 핸들(오브젝트)를 가지고 있습니다. 여기서는 0x89AF5DA0이며, 프로세스 핸들이기 때문에  EPROCESS 구조체로도 표현이 가능합니다.

 EProcess.txt

 

프로세스 핸들을 보호해 볼까요?

우선 OpenProcess의 내부부터 살펴볼까요,

유저모드에서 sysenter를 타서 커널로 진입을 하여 NtOpenProcess를 여는건 누구나가 다 아는 사실일텐데요(모름 검색 고고~)

XP 커널 기준으로 NtOpenPorcess는 내부에서 ObOpenObjectByPointer, PsLookupProcessByProcessId, ObOpenObjectByPointer등과 같은 여러가지 API 들을 호출합니다.

자세한건 아래 첨부파일을 참조하세요.

NtOpenProcessCode.txt

여기서 ObOpenObjectByPointer라는 흥미로운 API가 있습니다.

MSDN의 설명을 빌리자면,  ( http://msdn.microsoft.com/en-us/library/windows/hardware/ff550985(v=vs.85).aspx )

The ObOpenObjectByPointer function opens an object referenced by a pointer and returns a handle to the object.

오브젝트를 열고 핸들(HANDLE)을 반환한다는군요.

NTSTATUS ObOpenObjectByPointer(
  _In_      PVOID Object,
  _In_      ULONG HandleAttributes,
  _In_opt_  PACCESS_STATE PassedAccessState,
  _In_      ACCESS_MASK DesiredAccess,
  _In_opt_  POBJECT_TYPE ObjectType,
  _In_      KPROCESSOR_MODE AccessMode,
  _Out_     PHANDLE Handle
);

중요한 것은 NtOpenProcess 실행 시 이 API의 Object값은 프로세스 핸들(오브젝트)이 된다는 점입니다.

뭔가 감이 오지 않나요? 이 API를 후킹해서 아래와 같은 코드를 작성하면 지뢰찾기 프로세스의 액세스 거부를 반환할 수 있습니다.

if (Object == 0x89AF5DA0) return STATUS_ACCESS_DENIED;

 

# ObOpenObjectByPointer 후킹 실전 코드

아래 링크는 대륙의 해커 dayed가 만든 후킹 소스입니다.

http://bbs.pediy.com/archive/index.php?t-67286.html

후킹 함수인 fake_ObOpenObjectByPointer() 함수를 살펴보면,

Object가 널이 아니면 -> Object가 프로세스이면 -> 보호된 프로세스가 자기자신 프로세스가 아니면 -> 보호된 프로세스와 Object가 일치하면 액세스 거부

이렇게 구성되어 있습니다.

wdk/ddk로 컴파일시 소스의 Notepad.exe부분만 타겟 프로세스로 바꿔주면 치트엔진에서 액세스가 거부되는 것을 볼 수 있습니다.

위와 언급한 코드처럼 하드코딩해서 입력해도 동작은 합니다.(많이 번거롭지만요)

 

# 마치며

이 외에도 오브젝트 관련 함수인 ObReferenceObjectByHandle() 함수를 후킹하는 방법도 있습니다.

만약 핸들을 보호하는것이 아닌 OpenProcess를 막고 싶다면 NtOpenProcess()를 후킹하는 게 가장 손쉬운 방법입니다.

+ Recent posts