ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [리버싱 핵심원리 study] 46장 TEB & 47장 PEB
    Reverse Engineering 2021. 2. 15. 21:34

    1. TEB(Thread Environment Block)

    프로세스에서 실행되는 스레드에 대한 정보를 담고 있는 구조체로, 스레드 별로 TEB 구조체가 하나씩 할당된다. OS 종류별로 구조체 형태가 달라진다. MSDN에 기술된 TEB 구조체는 아래와 같다.

     

    typedef struct _TEB {
      PVOID Reserved1[12];
      PPEB  ProcessEnvironmentBlock;
      PVOID Reserved2[399];
      BYTE  Reserved3[1952];
      PVOID TlsSlots[64];
      BYTE  Reserved4[8];
      PVOID Reserved5[26];
      PVOID ReservedForOle;
      PVOID Reserved6[4];
      PVOID TlsExpansionSlots;
    } TEB, *PTEB;

     

    WinDbg 디버깅을 통해 구조체의 각 멤버를 계산할 수 있는데 중요한 멤버로는 다음과 같은 것들이 있다. (+는 offset)

     

    - +0x000 NtTib

    - +0x030 ProcessEnvironmentBlock

     

    (1) NtTib

    TEB 구조체의 첫 번째 멤버로 NtTib 구조체를 가리킨다. 

    typedef struct _NT_TIB
    {
         PEXCEPTION_REGISTRATION_RECORD ExceptionList;
         PVOID StackBase;
         PVOID StackLimit;
         PVOID SubSystemTib;
         union
         {
              PVOID FiberData;
              ULONG Version;
         };
         PVOID ArbitraryUserPointer;
         PNT_TIB Self;
    } NT_TIB, *PNT_TIB;

    위 구조체중 ExceptionList 멤버는 _EXCEPTION_REGISTRATION_RECORD 구조체의 연결 리스트를 가리키는 포인터로, Windows OS 예외 처리 메커니즘에 이용된다. Self 멤버는 구조체 자신을 가리키는 셀프 포인터이다.

     

    (2) ProcessEnvironmentBlock

    PEB 구조체를 가리키는 포인터이다.

     

    위에서 설명한 구조체는 WinDbg 커널 디버깅을 통해 구해낸 멤버 값이다. 유저모드에서는 Ntdll.NtCurrentTeb() API를 이용하여 TEB 구조체 주소를 계산해낼 수 있다. NtCurrentTeb() API 내부 구조는 다음과 같다.

     

    NtCurrentTeb() API

    FS 세그먼트 레지스터는 16비트 레지스터로, Segment Descriptor Table의 index 값으로 작용하여서 TEB 구조체 주소에 접근한다.

     

    2. PEB(Process Environment Block)

    PEB는 프로세스 정보를 담고 있는 구조체로 TEB와 마찬가지로 굉장히 많은 양의 멤버 변수를 갖고 있다. TEB 구조체의 +0x030 멤버가 PEB 구조체의 포인터임을 이용하여 접근할 수 있다. MSDN에 기술된 PEB 구조체는 아래와 같다.

     

    typedef struct _PEB {
      BYTE                          Reserved1[2];
      BYTE                          BeingDebugged;
      BYTE                          Reserved2[1];
      PVOID                         Reserved3[2];
      PPEB_LDR_DATA                 Ldr;
      PRTL_USER_PROCESS_PARAMETERS  ProcessParameters;
      PVOID                         Reserved4[3];
      PVOID                         AtlThunkSListPtr;
      PVOID                         Reserved5;
      ULONG                         Reserved6;
      PVOID                         Reserved7;
      ULONG                         Reserved8;
      ULONG                         AtlThunkSListPtr32;
      PVOID                         Reserved9[45];
      BYTE                          Reserved10[96];
      PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
      BYTE                          Reserved11[128];
      PVOID                         Reserved12[1];
      ULONG                         SessionId;
    } PEB, *PPEB;

    마찬가지로 WinDbg 디버깅을 통해 멤버들을 구해낼 수 있으며, 리버싱에 중요한 멤버들은 다음과 같다.

     

    - +0x002 BeingDebugged

    - +0x008 ImageBaseAddress

    - +0x00c Ldr

    - +0x018 ProcessHeap

    - +0x068 NtGlobalFlag

     

    (1) BeingDebugged

    현재 프로세스가 디버깅을 당하는지 판단할 수 있는 멤버로 디버깅 중이면 1, 그렇지 않은 경우 0이 세팅된다. 이 멤버 변수를 조사하는 API로 kernelbase.IsDebuggerPresent() API가 있는데 다음과 같은 형태로 EAX 레지스터에 해당 멤버 변수의 값을 옮겨 반환하는 것을 확인할 수 있다.

     

    IsDebuggerPresent() API

     

    (2) ImageBaseAddress

    프로세스의 ImageBase를 나타낸다. ImageBase를 구하는 API로 GetModuleHandle() API가 있는데, argument로 NULL을 넘기게 되면 현재 실행 중인 프로세스의 ImageBase를 반환한다. 내부 코드를 살펴보면 다음과 같이 ImageBaseAddress의 값을 참조한다.

     

    GetModuleHandle() API

     

    (3) Ldr

    _PEB_LDR_DATA 구조체의 포인터로 프로세스에 로딩된 모듈(DLL)의 로딩 베이스 주소를 직접 구할 수 있는 방법을 제공한다. 

     

    (4) ProcessHeap & NtGlobalFlag

    안티 디버깅 기법에 활용할 수 있는 멤버로, 프로세스가 디버깅 중일 때 특정 값을 갖게 된다.

     

    3. Comment

    처음에는 예전에 운영체제 과목을 수강할 때 배웠던 PCB(Process Control Block)에 대응되는 내용을 배운 건가 싶었는데 PCB 구조체는 찾아보니 또 따로 있다고 한다. 

    반응형

    댓글

Designed by Tistory.