2015년 7월 9일 목요일

2.Static_Debugging

Static anti debugging

Static 안티 디버깅

Static 안티 디버깅의 목적

  • 디버깅 당하는지 여부 파악하는 기법으로, 만약 디버깅 중이라고 판단되면 일반 실행과는 다른 코드(주로 종료 코드)를 실행하는 것이 핵심.

PEB

  • 디버깅 여부 판단하기 위해 PEB(Process Enviroment Block)구조체 정보를 이용할 수 있다.
  • 가장 널리 사용되는 안티 디버깅 기법이다.
  • window xp sp3의 peb 구조체에서 안티디버깅 기법에 사용되는 멤버
    • +0x002 BeingDebugged : UChar : 디버깅 여부를 표시하는 Flag로 사용
    • +0x00c Ldr : Ptr32 PEB LDR DATA : Heap 메모리 특성과 관련
    • +0x018 ProcessHeap : Ptr32 Void : Heap 메모리 특성과 관련
    • +0x068 NtglobalFlah : Uint4B : Heap 메모리 특성과 관련
  • 참고
    • PEB 주소 구하는 방법 : MOV EAX, DWORD PTR FS:[0x30] ;FS[0x30] = address of PEB
    • TEB(Thread Environment Block)을 구하고 ProcessEnvironmentBlock 멤버(+0x30 옵셋)를 이용하는 방법)
      • MOV EAX, DWORD PTR FS:[0x18] ;FS[0x18] = addressof TEB
      • MOV EAX, DWORD PTR DS:[EAX+0x30] ; DS[EAX+0x30]=address of PEB

BeingDebugged(+0x2)

  • PEB.BeingDebugged 멤버(+0x2)의 값은 디버깅 중일 때 1(True)로 세팅되고, 일반 실행인 경우 0(False)으로 세팅
IsDebuggerPresent()
  • 회피 방법 : OllyDbg의 Edit 명령을 이용하여 PEB.BeingDebugged 값을 0(False)으로 변경하면 된다.

Ldr (+0xC)

  • 디버깅 프로세스는 힙(heap)메모리 영역에 자신이 디버깅 당하는 프로세스라는 표시를 한다.
  • 메모리에 사용되지 않는 영역에 0xfeeefeee 값으로 채워 버린다. (프로세스가 디버깅을 당할 때 나타아는 흔적)
  • PEB.Ldr 멤버는 PEB LDR DATA 구조체를 가리키는 포인터이다. PEB LDR DATA 구조체는 힙 메모리 영역에 생성되기 때문에 이 영역을 scan해보면 쉽게 알 수 있다.
  • 회피방법 : 0xfeeefeee로 채워진 영역을 NULL로 덮어쓰면 된다. 0xfeeefeee영역에 메뉴 ‘Binary - Fill with 00’s’를 누르면 0으로 채워진다.

Process Heap(+0x18)

  • HEAP 구조체를 가리키는 포인터
    GetProcessHeap()
  • IsDebuggerPresent()와 비슷하다. TEB -> PEB -> PEB.Processheap 순서
  • 회피방법 : Heap.Flags = 2, Heap.ForceFlags = 0으로 세팅하면 된다.

NtGlobalFlag(+0x68)

  • 디버깅 중일 때 PEB.NtGlobalFlag 멤버(+0x68)의 값은 0x70으로 세팅된다.
  • 회피방법 : PEB.NtglobalFlag = 0으로 세팅하면 된다.

_

NtQueryInformationProcess()

  • ntdll!NtQueryInfomationProcess() API를 이용하면 프로세스의 디버깅 관련 정보를 비롯하여 다양한 정보를 얻을 수 있다.
  • 구조체 변수 중 디버거 탐지에 사용되는 것 : PROCESSINFOCLASS ProcessInformationClass 변수에서 ProcessDebugPort(0x7),ProcessDebugObjecthandle(0x1E), ProcessDebugFlags(0x1F)
  • 회피방법 : 특정입력(ProcessInfomationClass)값들에 대하여 출력(리턴 - Process Infomation) 값을 조작하는 것.
    • 특정입력 : ProcessDebugPort(0x7), ProcessDebugObjectHandle(0x1E), ProcessDebugFlags(0x1F)
    • API가 한두 번 정도 호출되는 거라면 디버거에서 수동으로 조작을 하고, 반복적으로 호출된다면 API 후킹을 시켜버리면 된다.
    • 보통 plugin(Advanced)를 이용하여 자동으로 API를 후킹한다.
      • jmp를 통한 후킹은 보통 함수 시작부분에 넣는다.
      • PE프로텍트의 API 후킹 탐지 기법이 있으면, 뒤에 하는게 좋다.
        • NtQueryInfomationProcess() API시작 주소의 첫 바이트를 읽어서 후킹 여부를 확인한다.
ProcessDebugPort(0x7)
  • 디버깅 중이 아니면, dwDebugPort 변수에 0이 세팅된다.
  • 디버깅 중이라면 0xffffffff 이 세팅 된다.

CheckRemoteDebuggerPresent()

  • IsDebuggerPresent() API와 비슷하게 디버깅 여부를 판별해 주는 함수
  • 차이 : CheckRemoteDebuggerPresent()는 다를 프로세스의 디버깅 여부까지 판단할 수 있다.
  • 내부 코드를 보면 NtQueryInfomationProcess(ProcessDebugPort) API를 이용한다.

ProcessDebugObjectHandle(0x1E)

  • 프로세스가 디버깅 중이면 Debug Object Handle은 값이 존재하며, 디버깅 중이 아니라면 Debug Object Handle은 NULL이 된다.

ProcessDebugFlags(0x1F)

  • ProcessDebugFlags(0x1F)를 입력하여 Debug flag를 구하며, 값이 0이면 디버깅 상태이고, 1이면 디버깅이 아니다.

NtQuerySystemInfomation()

  • 현재 OS가 Debug mode로 부팅되었는지를 판단하는 안티 디버깅 기법이다.
    • Debug mode는 windbg를 이용한 커널 디버깅하는 경우를 의미한다.

SystemKernelDebuggerInfomation(0x23)

회피방법 : windows xp 의 경우 boot.ini를 편집하고 ‘/debugport=com1 /baudrate=115200 /Debug’ 값을 제거한다. windows 7 인 경우 cmd에서 ‘bcdedit /debug off’ 명령을 내리면 된다. 그리고 재부팅하면, 일반모드(normal mode)로 부팅된다.

NtQueryObject()

  • 시스템에서 어떤 디버거가 다른 프로세스를 디버깅 중이라면 그 때 DebugObject 타입의 커널 객체가 생성되는데, 그 DebugObject의 존재를 확인하는 것이다.
  • NtQueryObject() API는 시스템의 다양한 종류의 커널 객체 정보를 구해오는 함수이다.

ZwSetInfomationThread()

  • 디버깅 당하는 쪽(디버기)에서 강제로 디버거를 떼어내는(Detech) 기법에 대한 설명이다. ZwSetInformationThread() API를 사용하면 자신을 디버깅하고 있는 디버거를 떼어낼 수 있다.
  • 스레드에게 정보를 세팅하는 System Native API입니다.
  • 회피방법 : ZwSetInfomationThread() API가 호출되기 직전에 스택에 저장된 두 번째 파라미터 ThreadInfomationClass 값을 살펴보고 ThreadHideFromDebugger(0x11) 값이 입력된 경우라면 0으로 변경해주면 된다.
    ZWSetInformationThread() API를 후킹하여 같은 방식으로 파라미터를 조작하면 된다.

TLS 콜백 함수

  • Entry Point 코드보다 먼저 실행되는 특징 때문에 안티 디버깅에 많이 활용된다.TLS 콜백 함수 내에서 IsDebuggingPresent() 등의 함수로 간단히 디버깅 여부를 판별하여 프로그램을 계속 실행할지 말지 결정할 수 있다.

댓글 없음:

댓글 쓰기