2015년 7월 9일 목요일

3.Dynamic_Debugging

Dynamic 안티 디버깅

  • 프로그램의 코드를 트레이시아하지 못하도록 지속적으로 방해하는 기법이다. Static에 비해 난이도가 높으며 회피 방법 또한 어렵다.

Dynamic 안티 디버깅의 목적

  • 내부 코드와 데이터를 리버싱으로부터 감추고 보호하는 것
  • 보통 PE 프로텍터들에게 많이 사용되며, 핵심 알고리즘을 보호하기 위하여 사용된다.
  • 디버거로 해당 프로그램이 실행될 수는 있을지언정 원본 프로그램의 핵심 코드(OEP)로 트레이싱하여 찾아갈 수 없도록 방해한다.

예외(Exception)

  • 보통 예외가 발생하면 SEH(Structured Exception Handling)메커니즘에 의해 OS에서 예외를 받아서 프로세스에 득록된 SEH를 호출해준다. 그러나 디버기(Debuggee)에서 예외가 발생하면 디버거(Debugger)에서 예외처리를 담당한다. 바로 이러한 특징을 이용하여 정상 실행되는 경우와 디버깅 당하는 경우를 판별해서 서로 다른 동작을 수행할 수 있는 안티 디버깅 기법이다.

SEH(Structured Exception Handling)

  • Windows OS의 예외
    • EXCEPTION DATATYPE MISALIGNMENT
    • EXCEPTION BREAKPOINT
    • EXCEPTION SINGLE STEP
    • EXCEPTION ACCESS VIOLATION
    • EXCEPTION IN PAGE ERROR
    • EXCEPTION ILLEGAL INSTRUCTION
    • EXCEPTION NONCONTINUABLE EXCEPTION
    • EXCEPTION INVALID DISPOSITION
    • EXCEPTION ARRAY BOUNDS EXCEEDED
    • EXCEPTION FLT DENORMAL OPERAND
    • EXCEPTION FLT DIVIDE BY ZERO
    • EXCEPTION FLT INEXACT RESULT
    • EXCEPTION FLT INVALUD OPERATION
    • EXCEPTION FLT STACK CHECK
    • EXCEPTION FLT UNDERFLOW
    • EXCEPTION INT DIVIDE BY ZERO
    • EXCEPTION INT OVERFLOW
    • EXCEPTION PRIV INSTUCTION
    • EXCEPTION STACK OVERFLOW

EXCEPTION BREAKPOINT

  • BreakPoint 명령어를 이용하여 예외를 발생시키면 일반 실행인 경우 등록된 SEH가 자동 실행되겠지만, 디버깅 실행의 경우 즉시 실행이 멈춰지고 제어권은 디버거로 넘어온다.
  • 디버깅 중이라도 관련 예외를 OS에게 넘겨 SEH가 자동 실행되도록 만들 수 있다.
    • 예외 처리기 내부에서 static 안티 디버깅 기법을 적절히 사용한다면 디버깅 여부를 쉽게 판별이 가능해 진다.
    • 예외 처리기 내부에 EIP값이 어떻게 변경될지 모른다.
  • 곧 디버깅을 계속 진행하기 위에 결국 예외처리기를 따라 들어가야한다
  • 회피방법 : Ollydbg옵션 수정하면 해결 가능하다.
    • Debugging options -> Exceptions(tab) -> INT3 breaks(check!)

SetUnhandledExceptionFilter()

  • kernel32!UnhandledExceptionFilter() API의 내부에서 static 안티 디버깅 기법인 ntdll!NtQueryInformationProcess(ProcessDebugPort) API를 호출하여 프로세스의 디버깅 여부를 판별한다.
  • 디버깅 중이라면 예외를 디버거에게 넘겨주며, Kernel32!SetUnhandledExceptionFilter() API를 이용하면 시스템의 마지막예외 처리기(Top Level Exception Filter)를 변경시킬 수 있다.
  • 회피방법 : static & Dynamic을 혼합한 기법으로, 먼저 Static 기법인 Kernel32!UnhandledExceptionFilter()내부에서 호출되는 ntdll!NtQueryInfomationProcess() API를(API 후킹 등의 방법으로)무력화한다.
    그 후 SetUnhandledExceptionFilter() API 호출에 의해 등록된 Exception Filter를 따라가서 정상 실행인 경우 어느 주소로 분기하는지 확인하면 된다.

Timing Check

  • 트레이싱하는 경우 시간이 걸릴 수 바께 없다는 점을 이용한 안티 디버깅 기법.

시간 간격 측정 방법

  • Counter based method
    • RDTSC(cpu의 카운터(counter)를 이용)
      kernel32!QueryPerformanceCounter()/ntdll!NtQueryPerformanceCounter()
      kernel32!GerTickCount()
    • Time based method(실제 시간이용한 방법)
      timeGerTime()
      ftime()

RDTSC(Read Time Stamp counter)

  • EDX:EAX 형식으로 읽어오는 어셈블리 명령어
  • 회피방법
    1. 트레이싱을 하지 말고 RUN으로 해당 코드를 넘어간다.
    2. 두 번째 RDTSC 결과 값(EDX:EAX)을 조작한다.
      첫 번째 결과 값과 비슷하도록 조작하면 cmp문을 통과할 수 있다.
    3. 조건 분기 명령어(cmp/jcc)실행을 조작한다.
      Jcc멸령어는 CF(Carry Flag)또는 ZF(Zero Flag)의 영향을 받는다.
    4. 커널 드라비어를 이용하여 RDTSC 명령을 무력화시킬 수 있다.
      Plugin 중에 있으니까 알아보자.

Trap Flag

  • Trap Flag(TF)는 EFLAGS 레지스터의 9번째(index 8) 비트이다.

Single Step

  • TF 값을 1로 세팅하면 CPU는 single step 모드로 변경된다. 변경 후 CPU는 Single Step 모드에서 하나의 명령어를 실행시킨 후 EXCEPTION SINGLE STEP 예외를 발생시킨다. 이후 Trap Flag는 자동으로 치기화(0)이 된다.
  • EXCEPTION SINGLE STEP예외는 SEH 결합하여 디버거를 탐지하기 위한 안티 디버깅 기법에 사용된다.
  • 회피방법 : Ollydbg옵션을 통해 가능.
    Debugging options -> Exceptions(tab) -> Single step break(check)

INT 2D

  • 커널모드에서 작동하는 Break Point 예외를 발생시키는 명령어.
  • 유저모드에서도 예외를 발생시킨다.(디버깅 실행의 경우네는 예외를 방생시키지 않는다)
  • 특징
    1. 1바이트 무시
      Obfuscated Code 효과를 보여줌(Obfuscated Code : Code Byte Ordering을 변경해서 프로그램의 코드를 혼란스럽게 만드는 것)
    2. BP까지 그대로 실행 ( Ollydbg경우, 디버거 마다 다르다,)
  • 회피방법 : 코드패치

0xCC 탐지(Detection)

  • BP(Break Point)의 x86 Instuction은 0xCC 이다.
    • 0xCC는 Opcode로 사용될 수도 있지만, Displacement, Immediate, 데이터 주소 등으로 사용될 수도 있다.

API Break Point

  • API에 설치된 BP를 확인해서 현재 디버깅을 당하는지 판단하는 방법
  • 일반적으로 API코드 시작 부분에 BP를 설치하므로 첫 바이트가 CC인지 검사해서 디버깅 중이라고 판단할 수 있다.
  • Serach for -> Name in all modules를 사용하여 All names 다이얼로 간단히 BP를 설치할 수 있다.
  • 회피방법 : API에 BP를 설치할 때 되도록 코드의 첫바이트를 피해서 중간쯤에 설치한다. 또는 Hardware BP를 설치하는 것도 하나의 방법이다.

Checksum 비교

  • 회피방법 : CRC계산 영역에 BP를 걸지 않거나 패치를 하지 않으면 Checksum anti debugging을 무력화 시킬 수 있다.
    • 가장 좋은 방법 : CRC 비교 구문을 패치하는 것,

댓글 없음:

댓글 쓰기