티스토리 뷰

본 문서는 원문 저자인 Massimiliano Tomassoli의 허락 하에 번역이 되었으며, 원문과 관련된 모든 저작물에 대한 저작권은 원문 저자인 Massimiliano Tomassoli에 있음을 밝힙니다. 


http://expdev-kiuhnm.rhcloud.com



최신 윈도우즈 익스플로잇 개발 03. 구조적 예외 처리 (SEH)


hackability.kr (김태범)

hackability_at_naver.com or ktb88_at_korea.ac.kr

2016.07.19



예외 처리(핸들러)는 각 스레드에 단일 링크드 리스트로 구성되어 있습니다. 리스트의 노드들은 스택에 할당되게 됩니다.

 

리스트의 해드는 TEB (Thread Environment Block)의 초기에 위치한 포인터에 의해 가리켜지며 코드에서 새로운 예외 처리를 생성하게 되면 새로운 노드는 리스트의 해드에 추가 되고 TEB의 포인터는 새로운 노드를 가리키게 됩니다.

 

각각의 노드는 _EXCEPTION_REGISTRATION_RECORD 타입을 가지며 핸들러의 주소와 리스트의 다음 노드의 포인터를 갖습니다. 이상하게도 마지막 노드의 다음 포인터는 NULL 이 아니라 0xffffffff를 갖습니다. 아래는 해당 정의에 대한 내용입니다.


0:000> dt _EXCEPTION_REGISTRATION_RECORD

ntdll!_EXCEPTION_REGISTRATION_RECORD

   +0x000 Next             : Ptr32 _EXCEPTION_REGISTRATION_RECORD

   +0x004 Handler          : Ptr32     _EXCEPTION_DISPOSITION


TEB는 선택자(selector) fs (fs:[0]) 를 통해 접근이 가능하기 때문에 코드에서는 다음과 같이 보입니다.


1
2
3
4
5
6
7
8
9
mov    eax, dword ptr fs:[00000000h]      ; retrieve the head
push   eax                                ; save the old head
lea    eax, [ebp-10h]
mov    dword ptr fs:[00000000h], eax      ; set the new head
.
.
.
mov    ecx, dword ptr [ebp-10h]           ; get the old head (NEXT field of the current head)
mov    dword ptr fs:[00000000h], ecx      ; restore the old head
cs


컴파일러는 보통 한 개의 글로벌 핸들러를 등록하는데 이는 실행 되는 프로그램 영역과 호출에 대한 적절한 행위들을 알고 있습니다.

 

스레드 별로 각각의 TEB를 갖고 있기 때문에 운영체제에서는 fs 에 의해 선택된 세그먼트가 적합한 TEB를 가리킬 수 있도록 보장합니다. (현재 스레드들 중 한 개) TEB 의 주소를 구하기 위해서는 fs:[18h] 의 위치를 읽는데 이는 TEB를 가리킵니다.

 

TEB를 출력하면 다음과 같습니다.


0:000> !teb

TEB at 7efdd000

    ExceptionList:        003ef804          <-----------------------

    StackBase:            003f0000

    StackLimit:           003ed000

    SubSystemTib:         00000000

    FiberData:            00001e00

    ArbitraryUserPointer: 00000000

    Self:                 7efdd000

    EnvironmentPointer:   00000000

    ClientId:             00001644 . 00000914

    RpcHandle:            00000000

    Tls Storage:          7efdd02c

    PEB Address:          7efde000

    LastErrorValue:       2

    LastStatusValue:      c0000034

    Count Owned Locks:    0

    HardErrorMode:        0


fs TEB를 가리키는지 확인해봅시다.


0:000> dg fs

                                  P Si Gr Pr Lo

Sel    Base     Limit     Type    l ze an es ng Flags

---- -------- -------- ---------- - -- -- -- -- --------

0053 7efdd000 00000fff Data RW Ac 3 Bg By P  Nl 000004f3


위에서 말했듯, fs:18h TEB의 주소를 갖고 있습니다.


0:000> ? poi(fs:[18])

Evaluate expression: 2130563072 = 7efdd000


poi는 포인터에 대한 역참조이며 ‘?’는 연산을 위해 사용됩니다. ExceptionList 에서 가리키는 포인터의 이름을 확인해봅시다.


0:000> dt nt!_NT_TIB ExceptionList

ntdll!_NT_TIB

   +0x000 ExceptionList : Ptr32 _EXCEPTION_REGISTRATION_RECORD


이 뜻은 각각의 노드들이 _EXCEPTION_REGISTRATION_RECORD의 인스턴스임을 뜻합니다. 전체 리스트를 확인하려면 !slist 를 입력하면 됩니다.


0:000> !slist $teb _EXCEPTION_REGISTRATION_RECORD

SLIST HEADER:

   +0x000 Alignment          : 3f0000003ef804

   +0x000 Next               : 3ef804

   +0x004 Depth              : 0

   +0x006 Sequence           : 3f


SLIST CONTENTS:

003ef804

   +0x000 Next             : 0x003ef850 _EXCEPTION_REGISTRATION_RECORD

   +0x004 Handler          : 0x6d5da0d5     _EXCEPTION_DISPOSITION  MSVCR120!_except_handler4+0

003ef850

   +0x000 Next             : 0x003ef89c _EXCEPTION_REGISTRATION_RECORD

   +0x004 Handler          : 0x00271709     _EXCEPTION_DISPOSITION  +0

003ef89c

   +0x000 Next             : 0xffffffff _EXCEPTION_REGISTRATION_RECORD

   +0x004 Handler          : 0x77e21985     _EXCEPTION_DISPOSITION  ntdll!_except_handler4+0

ffffffff

   +0x000 Next             : ???? 

   +0x004 Handler          : ???? 

Can't read memory at ffffffff, error 0


기억할 점은 $teb TEB의 주소입니다.

 

간단히 예외 핸들러 체인을 확인하려면 다음과 같이 입력하면 됩니다.


0:000> !exchain

003ef804: MSVCR120!_except_handler4+0 (6d5da0d5)

  CRT scope  0, func:   MSVCR120!doexit+116 (6d613b3b)

003ef850: exploitme3+1709 (00271709)

003ef89c: ntdll!_except_handler4+0 (77e21985)

  CRT scope  0, filter: ntdll!__RtlUserThreadStart+2e (77e21c78)

                func:   ntdll!__RtlUserThreadStart+63 (77e238cb)


또는 직접 예외 핸들러 체인을 확인할 수 있습니다.


0:000> dt 003ef804 _EXCEPTION_REGISTRATION_RECORD

MSVCR120!_EXCEPTION_REGISTRATION_RECORD

   +0x000 Next             : 0x003ef850 _EXCEPTION_REGISTRATION_RECORD

   +0x004 Handler          : 0x6d5da0d5     _EXCEPTION_DISPOSITION  MSVCR120!_except_handler4+0

0:000> dt 0x003ef850 _EXCEPTION_REGISTRATION_RECORD

MSVCR120!_EXCEPTION_REGISTRATION_RECORD

   +0x000 Next             : 0x003ef89c _EXCEPTION_REGISTRATION_RECORD

   +0x004 Handler          : 0x00271709     _EXCEPTION_DISPOSITION  +0

0:000> dt 0x003ef89c _EXCEPTION_REGISTRATION_RECORD

MSVCR120!_EXCEPTION_REGISTRATION_RECORD

   +0x000 Next             : 0xffffffff _EXCEPTION_REGISTRATION_RECORD

   +0x004 Handler          : 0x77e21985     _EXCEPTION_DISPOSITION  ntdll!_except_handler4+0


댓글