외규장각 도서 환수 모금 캠페인

Search Results for 'Detecting Degugger'

1 POSTS

  1. 2007.06.19 Detecting Application Debugger

Detecting Application Debugger

Posted 2007. 6. 19. 14:51, Filed under: Study/Computer Science
================================================================================
Title : Detecting Application Debugger

Author : proXima
Contact : proxima ]at[ postech.ac.kr
Date : 2006/11/09 - 2006/11/15
================================================================================

보통 reverse engineering을 하기 위해서는 debugger와 disassembler를 사용한다.
하지만 어떤 프로그램들에는 anti-debug 루틴이 들어있어, debugger를 사용하기 어렵게 하기도 한다.
이 글에서는 간단하게 사용할 수 있는 몇 가지 방법을 소개하도록 하겠다.

PLUS 06학번들을 뽑을 때 냈던 문제에도 간단한 anti-debug 루틴이 들어있다.


1. IsDebuggerPresent
Win32 API 중에 IsDebuggerPresent 라는 함수가 있다. 만약 debug가 attach 된 프로세스에서 이 함수를 실행하게 되면 1이 리턴된다. WinXP에서 제공하는 IsDebuggerPresent 함수의 내부를 살펴보자.

앞으로 나오는 모든 코드에 포함된 숫자들은 16진수 값이다.


mov eax, dword ptr fs:[18]
mov eax, dword ptr ds:[eax+30]
mov eax, dword ptr ds:[eax+2]
retn
 
위에서 보는 것과 같이 매우 간단하다.
이렇게 간단한 코드가 어떻게 debugger를 디텍트할 수 있는지 살펴보자.

코드의 첫 줄을 보자. fs:[18] 을 볼 수 있다.
fs는 file segment로, fs:[0]에는 SEH(Structured Exception Handler)가 위치한다.
SEH 구조체의 내용 중에 TEB(Thread Environment Block)의 포인터가 존재하는데,
그 포인터의 위치가 바로 fs:[18] 이다.
첫 줄의 의미는, eax에 TEB의 스타트 포인트를 가져온다는 것이다.

두 번째 줄을 보자. ds:[eax+30] 에는 무엇이 있을까?
TEB 구조체에서 0x30 오프셋에 있는 내용은 PEB(Process Environment Block)의 포인터이다.
PEB에는 프로세스의 컨텍스트나 쓰레드 목록, 핸들 테이블 등, 프로세스에 specific한 정보들이 들어있다.

마지막줄을 보자. ds:[eax+2] 에는 무엇이 있을까?
결국 PEB의 0x02 오프셋에 있는 내용을 확인하겠다는 것인데,
PEB의 0x02 오프셋에는 BeingDebugged 라는 1바이트짜리 플래그가 들어있다.
디버거가 attach될 경우에는 이 BeingDebugged 플래그가 1이 되는데,
IsDebuggerPresent는 바로 이 플래그 값을 확인하여 자신이 디버그 당하고 있는지를 확인하는 것이다.

IsDebuggerPresent 함수를 직접 사용하는 경우는 함수에 BreakPoint를 걸어 건너뛰기 쉬우므로,
인라인 어셈을 이용하여 직접 어셈 코드를 적어주는 것도 하나의 방법이 될 수 있다.


2. Using Exception
디버거로 프로그램을 디버깅 하다가
데이터 혹은 코드를 잘못 건드리는 바람에 exception이 발생한 적 없는가?
보통은 디버거로 실행하는 중에 exception이 발생하게 되면,
프로그램 내부에 있는 exception handler보다 디버거가 먼저 exception을 캐치한다.
그것을 이용하여 디버깅을 조금 곤란하게 할 수 있다.

하지만 이 방법은 위험하고 또 오히려 프로그램을 짜는 입장에서 스스로 디버깅을 하다가
곤란해지는 경우가 생길 수 있으므로 별로 추천하고 싶지는 않다.

간단하게 소개만 하도록 하겠다.


int SEH1(unsigned int code, LPEXCEPTION_POINTERS ep)
{
  if(code == EXCEPTION_ILLEGAL_INSTRUCTION)
  {
    // (2)
    return EXCEPTION_EXECUTE_HANDLER;
  } else {
    // not expected!!!
    return EXCEPTION_CONTINUE_SEARCH;
  }
}

:
:
:

{
  :
  :
  :
  __try {
    // (1)
    __asm __emit 0x8f // intentional illegal instruction
  } __except {
    // (2)
  }
}

 
연속으로 실행되어야 하는 코드들이 있다고 하면,
그것을 위와 같은 코드에 두 개 혹은 세 개로 나누어 쓸 수 있게 된다.
(1) 이라고 된 부분에 첫 부분을 쓰고,
(2) 라고 된 부분에 두번째 부분을 쓰고,
(3) 라고 된 부분에 세번째 부분을 쓴다.

__asm __emit 0x8f 는 일부러 없는 인스트럭션을 실행하도록 하여 EXCEPTION_ILLEGAL_INSTRUCTION 예외를 발생시키는 역할을 한다.

그러면 실행하는 도중에 (1)의 코드가 실행되고 illegal instruction의 예외가 발생한다.
예외가 발생한 경우에 만약 디버거가 붙어있다면, 디버거가 예외를 잡아내고
더 이상 진행할 수 없는 상태가 된다. (물론 상태를 변경한다면 계속 진행할 수 있다.)

디버거가 붙어있지 않다면 SEH1의 함수 내부로 들어가 (2)가 실행된 뒤 리턴되어 (3)이 실행된다.
__try - __except 구문을 사용하는 함수에 넘어오는 인자는 (2)에서는 사용할 수가 없다.



3. NtGlobalFlag


mov eax, dword ptr fs:[30]
mov eax, dword ptr ds:[eax+68]
 

fs:[30]이 다시 등장했다.
위에서도 설명했듯이 fs:[30]에는 PEB가 존재하는데, 그 PEB의 0x68 오프셋에는 NtGlobalFlag라는 값이 들어있다.
1번에서 설명한 IsDebuggerPresent와 비슷하지만, 다른 점이라면 IsDebuggerPresent는 Windows에서 공식적으로 제공해 주는 함수인 반면, NtGlobalFlag는 그렇지 않다는 점이다.
만약 위의 코드가 실행된 뒤에 eax에 0x70의 값이 들어있다면, being debugged이다.


위에서 세 가지의 debugger detect 방법을 설명하였다.
실제로 위의 방법들이 전부는 아니다.
debugger를 찾아내는 방법들은 더 많이 있으며, 이런 방법으로도 찾아낼 수 있다는 것을 소개한 정도로 마치도록 하겠다.
Response : ,


Recent Posts

Recent Comments

Recent Trackbacks

Total hit (Today , Yesterday )

Admin Write Post