공부해요/리버싱_핵심원리

51. Static 안티 디버깅

yenas0 2025. 1. 22. 09:51
반응형

Static 안티 디버깅의 목적
Static 안티 디버깅은 디버깅 과정에서 자신이 디버깅 당하는지 여부를 확인하고, 디버깅 중이라고 판단되면 일반 실행과 다른 동작(주로 종료)을 수행하는 기술

 

구현방법

  1. 디버거 탐지: 디버거의 존재 여부를 확인.
  2. 디버깅 환경 탐지: 디버깅 환경의 흔적을 탐지.
  3. 디버거 강제 분리: 디버거와의 연결을 강제로 해제.

 

 

PEB

현재 프로세스의 디버깅 여부 판단 위해 PEB를 사용한다. (process environment block)

안티 디버깅 시에 사용되는 멤버는 아래와 같다.

+0x002 BeingDebugged    : UChar
+0x00c Ldr              : Ptr32 _PEB_LDR_DATA
+0x018 ProcessHeap      : Ptr32 Void
+0x068 NtGlobalFlag     : Uint4B

1. BeingDebugged

  • 디버깅 여부를 나타내는 플래그
  • 1이면 현재 프로세스가 디버깅 중이라는 뜻

2. Ldr

  • 디버깅 프로세스는 힙 메모리 영역에 디버깅 흔적을 남김
  • 디버깅 중일 때 사용되지 않는 힙 메모리에 0xFEEEFEEE 값을 채워 넣음
  • 디버깅 흔적을 확인하여 디버깅 여부를 판별 가능

3. Process Heap

  • HEAP 구조체를 가리키는 포인터
  • 디버깅 여부를 판단하기 위해 힙 구조를 분석하는 데 사용

4. NtGlobalFlag

  • 디버깅 여부를 나타내는 글로벌 플래그
  • 특정 값이 설정되어 있으면 디버깅 상태로 판단 가능

 

 

실습 - StaAD_PEB.exe

https://github.com/reversecore/book/blob/master/%EC%8B%A4%EC%8A%B5%EC%98%88%EC%A0%9C/07_Anti_Debugging/51_Static_Anti_Debugging/bin/StaAD_PEB.exe

 

book/실습예제/07_Anti_Debugging/51_Static_Anti_Debugging/bin/StaAD_PEB.exe at master · reversecore/book

리버싱 핵심원리 - 소스 코드 및 실습 예제. Contribute to reversecore/book development by creating an account on GitHub.

github.com

 

위에거 다운받고 올리디디버거에 돌리면

 

이렇게.. 디버깅 중이라고 뜨게 된다

 

회피하기

다시 시작해서 main함수 시작으로 가보았다.

밑에 내려서 보다보면 IsDebuggerPresent()값이 보인다. 아까 했을 때 얘에서 값이 1이면 디버깅 중인걸 알 수 있었으니까 0으로 바꾸면 안티 디버깅을 피할 수 있다.

 

조금 더 내리면 PEB.Ldr도 있음

 

40107B (CALL EAX): ntdll.NtCurrentTeb API 호출

40107D (MOV EBX, PEB 주소): EBX 레지스터에 PEB 주소 저장

401090~40109E: 로컬 변수([EBP-2C] ~ [EBP-28])를 EEFEEEFE 값으로 초기화

4010A1 (MOV ESI, PEB.Ldr 주소): ESI 레지스터에 PEB 구조체의 Ldr 주소 저장

 

쭉 내려 보면

루프로 되어있다. 4010B0부터 4010DA까지

4010C7에서 EDI는 PEB.Ldr주소에서 읽어온 4바이트 갑이고 [ECX]는 EEFEEEFE. (PEB.Ldr에서 EEFEEEFE로 초기화된 영역을 찾는거임)

탐지 회피하려면 PEB.Ldr로 가서 저 EEFEEEFE영역을 NELL로 덮으면 된다.

 

PEB.ProcessHeap부분도 있는데 여기서 PEB.ProcessHEap.Flags랑 PEB.ProcessHEap.ForceFlags를 체크하는 안티 디버깅 기법

401112: MOV 명령으로 EDI 레지스터에 PEB.ProcessHeap 구조체 시작 주소를 저장

401115:  [EDI+C]를 통해 PEB.ProcessHeap.Flags 값을 2로 변경

40113F: [EDI+10]을 통해 PEB.ProcessHeap.ForceFlags 값을 0으로 변경하여 PEB.ProcessHeap 관련 안티 디버깅을 무력화한다

 

PEB.NtGlobalFlag임

401168이 PEB.NtGlobalFlag이다. 이걸 0으로 바꾸면 됨

 

 

 

NtQueryInformationProcess란?

NtQueryInformationProcess는 Windows NT 계열에서 제공하는 함수로, 특정 프로세스에 대한 정보를 쿼리한다

NTSTATUS NtQueryInformationProcess(
    HANDLE ProcessHandle,
    PROCESSINFOCLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength
);

 

ProcessHandle: 정보를 가져올 프로세스의 핸들

ProcessInformationClass: 가져올 정보의 유형을 지정

ProcessInformation: 결과 정보를 저장할 버퍼

ProcessInformationLength: 결과 버퍼의 크기

ReturnLength: 결과로 반환된 데이터의 크기 (optional)

 

디버거 탐지 활용 -> 이 함수는 디버거 붙어있느닞 확인이 가능하다. ProcessInformationClass에 따라 다른 정보를 쿼리한다

 

  • ProcessDebugPort
    디버거가 연결된 포트 확인. 값이 0이 아니면 디버거가 연결되어 있음.
  • ProcessDebugObjectHandle
    디버거 핸들 확인. 핸들이 유효하면 디버거가 붙어 있음.
  • ProcessDebugFlags
    디버깅 방지 플래그 확인. 값이 0이면 디버깅 가능 상태.

 

 

 

NtQuerySystemInformation()

디버깅 환경을 체크하는 안티 디버깅 기법, 현재 운영체제가 Debug Mode로 부팅되었는지를 판단하는 안티 디버깅 기법

시스템 정보(프로세스 목록이나, 스레드, 메모리 상태)를 가져온다

NTSTATUS NtQuerySystemInformation(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);

 

SystemInformationClass: 가져올 정보 종류 (예: 시스템 프로세스 정보, 핸들 테이블 등)

SystemInformation: 결과가 저장될 버퍼

SystemInformationLength: 결과 버퍼 크기

ReturnLength: 반환된 데이터 크기

 

디버깅 환경 어케 탐지?

1. SystemKernelDebuggerInformation: 커널 디버거 활성화 되어있는지 확인. TRUE면 디버거 활성화

2. SystemProcessInformation: 시스템의 모든 프로세스 목록 가져옴. 이걸로 알려진 디버거 프로세스 이름 탐지할수있음

3. 핸들 테이블 스캔: 특정 디버거 프로세스가 열어놓은 핸들을 탐지함

 

 

 

NtQueryObject()

커널 객체의 속성, 상태, 이름 등을 쿼리

NTSTATUS NtQueryObject(
    HANDLE Handle,
    OBJECT_INFORMATION_CLASS ObjectInformationClass,
    PVOID ObjectInformation,
    ULONG ObjectInformationLength,
    PULONG ReturnLength
);

 

Handle: 정보를 가져올 커널 객체의 핸들

ObjectInformationClass: 가져올 정보의 유형 (예: 객체 기본 정보, 객체 이름 정보 등)

ObjectInformation: 결과를 저장할 버퍼

ObjectInformationLength: 결과 버퍼 크기

ReturnLength: 반환된 데이터 크기

 

어케 탐지하냐

윈도우에서 디버거 프로세스 실행시에 커널은 프로세스에 DebugObject라는 특별한 커널 객체를 생성한다. 이 객체를 통해 프로세스가 디버깅 중인지 확인이 가능함

- NtQueryObject로 특정 핸들이 debugObject인지 확인

 

 

ZwSetInformationThread()

특정 스레드의 속성이나 상태를 설정하는데에 사용.

안티 디버깅에서는 디버거가 프로세스나 스레드에 연결못하도록 방해

NTSTATUS ZwSetInformationThread(
    HANDLE ThreadHandle,
    THREADINFOCLASS ThreadInformationClass,
    PVOID ThreadInformation,
    ULONG ThreadInformationLength
);

 

 

 

ThreadHandle: 설정할 스레드의 핸들

ThreadInformationClass: 설정할 정보의 종류를 지정

ThreadInformation: 설정할 데이터

ThreadInformationLength: 데이터 크기

 

안티 디버깅에서의 활용

ZwSetInformationThread는 특정 ThreadInformationClass 값을 사용해 디버거가 연결된 상태를 방해하거나 탐지할 수 있음

회피하려면 ZwsetInformaionThread() API가 호출되기 직전에 스택에 저장된 ThreadInformationClass 값을 살펴보고 ThreadHideFromDebugger값이 입력되어있으면 0으로 변경해야된다

 

 

TLS 콜백 함수

TLS 콜백 함수는 프로그램의 Entry Point 코드보다 먼저 실행되는 특징 때문에 안티 디버깅 기법으로 자주 활용된다

이 함수는 디버깅 여부를 판별하는 IsDebuggerPresent() 같은 함수를 호출해 디버깅 상태를 확인하고, 프로그램 실행 여부를 결정할 수 있음

자체적으로 안티 디버깅 기법은 아니지만, 실행 순서의 특성을 활용해 디버깅을 방해하는 용도로 사용

 

반응형