안티 디버깅에는 2가지의 그룹이 있습니다.

static그룹 -> 맨 처음 실행될 때 안티 디버깅이 실행, 한번만 해제하면 되는것 입니다.

dymamic그룹 -> 실행 중에 계속 해제를 해주어야 함, 디버거 트레이싱을 방해하는 것 입니다.

 

디버깅 트레이싱이란? F8

 

안티 디버깅은 디버기 프로세스에서 자신이 디버기 당하는지 여부를 파악하는 기법

발견하면 종료코드를 실행하거나(대부분) 실행에 방해를 하는 코드를 실행

 

안티디버깅의 목적

디버거 탐지방법

디버거 환경탐지

디버거 강제 분리

회피 방법은 탐지 코드에서 얻어오는 정보를 변경함

 

현재 프로세스 디버깅을 판단하기 위해 PEB 구조체 정보 이용 합니다.

PEB 구조체 정보를 이용하는 것이 현재 가장 잘 사용되는 안티 디버깅 기법입니다.

PEB 구조체 주소는 FS 세그먼트 레지스터가 가르키는 TEB 구조체를 이용하여 구할 수 있습니다.

 

안티디버깅에 사용되는 중요 PEB 멤버

+0x002 BeingDebugged : Uchar

+0x00c Ldr                  : ptr32 _PEB_LDR_DATA

+0x018 ProcessHeap       : Ptr32 Void

+0x068 NtGlobalFlag       : Uint4B


 

TEB

TEB는 이미지 로더와 다양한 윈도우 DLL에 대한 컨텍스트 정보를 담고 있으며이들 요소들이 유저모드에서 구동되기 때문에 유저모드에서 쓰기가 가능한 구조체가 필요 했습니다. 그래서 이 구조체는 커널모드에서만 쓰기가 가능한 시스템 주소 공간이 아닌 프로세스 주소 공간에 위치합니다.


 

PEB

유저 주소상에 존재하는 PEB는 이미지 로더힙관리자그외 윈도우 시스템 DLL등 유저모드상에서 접근할 필요가 있는 정보를 가지고 있습니다.

 

FS 레지스터

08386부터 등장 하였으며 BASE Address 0xffdf000이며 커널 모드 에서는 KPCR(Kernel’s Processor Control Regin) 구조체를 유저모드에서는 TEB 구조체를 가르키고 있습니다.

 FS:[0] TEB의 시작 위치를 가지고 있습니다.





PEB구조체를 구하는 방법은 4가지가 있습니다.
[1] FS 레지스터를 사용하는 방법
[2] NtCurrentTeb()
를 사용하는 방법
[3] ZwQueryInformationProcess()
를 사용하는 방법
[4] GetThreadContext(), GetThreadSelectorEntry()
를 사용하는 방법


[1]
FS
라는 세그먼트 레지스터가 존재하는데, 이 레지스터가 TEB를 지정합니다
따라서 PEB를 구하기 위해 FS:[0x30]을 가져옵니다.


[2]
ntdll.dll
NtCurrentTeb() 함수를 사용하는 방법입니다. 이 함수는 내부적으로 첫번째 방법과 마찬가지로 FS 레지스터를 사용합니다.
TEB
를 구하고 TEB+0x30을 가져옵니다.

[3]
ZwQueryInformationProcess
의 두번째 인자에 ProcessBasicInformation를 넣어 호출하면 PROCESS_BASIC_INFORMATION를 얻을 수 있습니다
[4]
첫번째 방법과 마찬가지로 FS 레지스터를 읽어오는데, API를 이용합니다.

 

안티 디버깅은 OS 의존성이 있기 때문에 사전에 이를 확인하는 것이 좋습니다.

다양한 디버거 플러그인들이 있고, 계속 변형된 버전이 나오고, 플러그인에서 지원되지 않는 방법이 존재하기 때문에 동작 원리와 기본 회피 방법을 공부하는 것이 큰 도움이 됩니다.


 

IsDebuggerPresent()

IsDebuggerPresent() API PEB.BeingDebugged(PEB 구조체 +0x002)의 값을 참조하여 디버깅 여부를 판별 합니다.



IsDebugg가 실행됨을 확인 할수 있습니다.

F7을 따라서 가보도록 하겠습니다.



 

네 괜히 따라갔다가 피 봤습니다.

여기가 아니었네요. 한 시간 헤맸습니다. 왜 없지? 하면서 하하 ㅠㅠㅠ

 



isDebuggerpresent()는 함수 이기 때문에, 함수 호출을 할거 생각해서 calls 함수들의 목록을 살펴 보았습니다.

 




커널영역에서 호출됨을 확인하고, 브레이크 포인터를 걸어주고 따라가서 확인해 보겠습니다.


 


TEB 구조체를 이용해서 PEB 구조체를 찾는모습이 보입니다.

TEB 주소를 구하고 FS[0x18] -> TEB

여기서 DS[EAX+0x30] -> PEB

그리고 PEB에서 +0x2한 것이, +0x002 BeingDebugged : Uchar 이 값입니다.

이 값이 디버거로 실행될시 1로 셋팅되고, 그냥 실행될시 0으로 셋팅이 됩니다.



따라가서 패치를 해주면은

 



 

디버거없다라고 출력이되면서 우회함을 알수 있습니다.

 

 

 

+0x068 NtGlobalFlag : Uint4B

프로세스가 디버깅 중일 때는 NtGlobalFlag 0x70으로 셋팅 되어 집니다.

 



아래는 0x70과 비교해서 디버깅의 여부를 확인하는 코드이며 PEB의 주소값 +68인 것을 알고 있으니



FS:[30]의 주소로가서, 주소값 +68을 하게 되면은 0x70이 박혀있음을 확인할 수 있습니다.

이 값을 변경해준다면은 우회할 수 있게 됩니다.

 

Ldr(+0xc)

디버깅 프로세스는 힙 메모리 영역에 자신이 디버깅 당하는 프로세스라는 표시를 합니다.

힙영역에 사용하지 않은 영역을 0xFEEEFEEE값으로 채워버리는 것 입니다.

 

같은방식으로 FS:[30]으로 찾아간 뒤에 주소값에서 +c를 해 줍니다.



이 주소를 찾아 아래로 내려가면은 FEEEFEEE가 가득 차있는 것을 볼 수 있습니다.

NULL로 덮어쓰면은 회피 가능 합니다.

 



 




 

GetProcessHeap(+0x18)

PEB.ProcessHeap멤버에서 Flags멤버(+0xc) FoceFlags멤버(+0x10)은 정상 실행일 때는 2 0으로 셋팅이 됩니다. 디버거로 실행될때는특정한 값으로 셋팅 됩니다.



즉 저 값들을 2 0으로 셋팅 해주면은 우회 할 수 있습니다.

 

 

 

NtQueryinformationProcess()

 

디버거 탐지에 사용되는 것은 ProcessDebugPort(0x7) ProcessDebugObjectHandle(0x1E) ProcessDebugFlags(0x1F) 입니다.

 

이중 0x7은 프로세스가 디버깅 중일 때 할당 됩니다. ProcessInformationClass 파라미터에 0x값을 입력하면 debugPort를 얻을 수 있습니다.

ProcessDebugPort(0x7)이 디버깅중이 아니라면 0이 셋팅 되고, 디버깅중 이라면 0xffffff가 셋팅 됩니다. 그래서 이 값을 바꿔주면 우회가 가능 합니다.

 

 

 

CheckRemoteDebuggerPresent() 안티디버깅

[i] IsDebuggerPresent()Api와 비슷하게 디버깅 여부를 판별해주는 함수 입니다.

안에 NtQueryinformationProcess API를 이용 하고 있습니다.

 



 

CheckRemoteDebuggerPresent()의 정보를 받아와서 Call로 실행을 시킵니다.

저 내부함수로 들어가게 되면은 NtQueryInformationProcess를 이용함을 알 수 있습니다.

 

 







내부 함수의 모습 입니다.

우회방법은 그 밑에 점프문을 우회시켜주는 방법과 ProcessDebugFlags(0x1f)의 인자값 bDebugFlag값을 변경해주는 것 입니다.

 

 

FindWindow 함수 회피



이 함수는 잘 알려져있는 이름 혹은 환경등을 검색하여 그 조건이 맞다면은 디버깅을 중지시키는 안티디버깅 입니다.

즉 디버거가 시스템 안에서 구동되어 질 때 쉽게 찾을 수 있습니다.

chFind = FindWindow(L”ollydbg”,0);등의 소스 입니다.

chind NULL이 아니면 윈도우의 핸들을 찾은것이고, 종료 시킬것 입니다.

 

 

우회하는 방법으로는 find call 함수로 FindWindowA 를 찾고, class에서의 값을 변조시키는 방법으로 우회가 가능하다. GetWinddowText등도 비슷한 함수 입니다.

 

 

NtQuerySystemInformation()

디버깅 환경을 체크하는 안티 디버깅 기법에 대한 설명

이 기법은 현재 OS Debug Mode로 부팅되었는지 판단하는 안티 디버깅 기법이다.

ntdll!NtQuerySystemInformatin()API는 현재 동작중인 OS 시스템에 대한 다양 한 정보를 구할수 있는 함수입니다.

API가 리턴되면 시스템 디버그 모드인 경우 debugger Enabled 1이 셋팅 됩니다.

회피 방법으로는 올리디버거로 불가능하고 boot파일을 수정하거나 명령입력을 해야 합니다.

그러면 OS가 일반 모드로 부팅 됩니다.

 

 

 

 

NtQueryObject

 

디버거가 실행 중일 경우 : DebugObject 타입의 객체가 생성

 -> DebugObject 타입의 객체 생성 유무를 검사하여 디버깅 여부 검사

TypeName 필드를 유니코드  “DebugObject”와 비교 후

   TotalNumberOfObject 필드 또는 TotalNumberHandles 필드 검사

→ 0이라면 정상 상태

→ 0보다 크다면 디버깅 상태

 

우회방법 : 스택에 저장되는 “DebugObject” 대신 다른 값을 넣어줌

 

 

 

 

NtSetInformationThread
ntdll!NtSetInformationThread
ZwSetInformationThread 시스템 함수를 감싸고 있습니다.

아래는 함수 타입 설명이다.

NTSYSAPI NTSTATUS NTAPI NtSetInformationThread(
    IN HANDLE ThreadHandle,
    IN THREAD_INFORMATION_CLASS ThreadInformationClass,
    IN PVOID ThreadInformation,
    IN ULONG ThreadInformationLength
);

 

디버깅 당하는 쪽(디버기)에서 강제로 디버거를 떼어내는 기법에 대한 설명 입니다.

ZwSetInformationThread() API를 사용하면 자신을 디버깅하고 있는 디버거를 뗴어낼 수 있습니다.

첫째 인자 - 스레드에게 정보 셋팅

두째 인자 에 ThreadHide From Debugger(0x11) 값을 입력하면 디버거 프로세스가 분리 됩니다. 그래서 이 두째 인자를 0으로 셋팅 해주거나 API를 후킹 하는 방식으로 파라미터를 조작 할 수 있다.

 

'CAT-Security > 미분류' 카테고리의 다른 글

[시스템 기초] 스터디(1주차)  (0) 2012.11.08
[안티디버깅] UPX packer 이해  (0) 2012.11.08
[안티디버깅] Anti-Debuging(안티디버깅) 기초  (2) 2012.11.08
리버싱 워게임 사이트  (0) 2012.10.27
system 링크  (0) 2012.07.21
cogegate 300문제 풀이(ida)  (0) 2012.06.09