리버싱핵심원리

Reverse Engineering Chap 46

키흐 2016. 2. 3. 14:38

Chapter 46 TEB


 TEB는 프로세스에서 실행되는 스레드에 대한 정보를 담고 있는 구조체이다. 스레드별로 TEB 구조체가 하나씩 할당된다. 또한 TEB 구조체는 OS 종류별로 그 모양이 조금씩 달라지며 세부적인 내용에 대해서는 문서화 되어있다.


다음은 TEB 구조체의 정의이다.





위는 각각 Windows XP SP3, Windows 7의 TEB 구조체이다. 구성을 보면 Windows 7 이 XP보다 구조체가 더 커진 것을 확인 할 수 있다.


위의 많은 멤버중 유저 모드 디버깅에 중요한 멤버들은 다음과 같다.


먼저 TEB 구조체의 첫번째 멤버는  _NT_TIB 구조체이다. _NT_TIB 구조체의 정의는 다음과 같다. TIB는 Thread Information Block의 줄임말이다.


가장 첫번째 멤버인 ExceptionList 멤버는 _EXCEPTION_REGISTRATION_RECORD 구조체의 연결리스트를 가리키고 있다. 이것은 SEH(Structed Exception Handler)라고 하는 Windows OS의 예외 처리 메커니즘에 사용된다.(48장 참고) Self 멤버는 _NT_TIB 구조체의 셀프포인터이다. _NT_TIB 구조체는 TEB 구조체의 첫번째 멤버이기 때문에 이는 TEB 구조체의 포인터이기도 하다.


이제 TEB 구조체에 유저모드에서 접근하는 방법에 대해서 알아볼 것이다.

Ntdll.NtCurrentTeb() API는 현재 스레드의 TEB 구조체 주소를 리턴하는 함수이다. 이 함수가 어떻게 구현 되어 있는지 OllyDbg를 통해서 확인해보면, 해당 API의 코드는 다음과 같다.

MOV EAX,DWORD PTR FS:[18]

RETN

 매우 간단한 코드로, 단순이 FS:[18] 주소의 값을 리턴하는 것이다. 그렇다면 이제 FS 세그먼트 레지스터에 대해서 알아볼것이다.


FS 세그먼트 레지스터는 현재 스레드의 TEB를 지시하는데 사용된다. IA32 시스템에서 프로세스의 가상 메모리 크기는 4GB이므로 32비트 크기의 포인터를 이용해야 전체 메모리 공간이 접근이 가능하다. 그러나 FS 레지스터의 크기는 16바이트이다. FS 세그먼트 레지스터는 TEB를 지시하는데 사용되지만, 직접 TEB 주소를 가리키는 것이 아니라 실제 TEB 주소를 갖고 있는 Segment Descriptor Table의 Index 값을 갖고 있는 것이다.


GDTR 레지스터에 Segment Descriptor Table의 시작 주소가 저장 되어있고 FS 레지스터에 그 인덱스가 저장 되어있다. 


따라서 FS:[0x18]은 Segment Descriptor Table에서 0x18 인덱스에 있는 주소 값에 있는 값을 의미한다. 이는 TEB에서 _NT_TIB 구조체 내의 Self 멤버를 의미하며 이는 _NT_TIB 구조체의 주소이자 TEB 구조체의 주소를 의미한다. 허나 0x18 인덱스의 Self 멤버의 값에 접근하지 않고 바로 FS:0 으로 접근하여 TEB의 주소를 구할 수도 있다.


하여 마지막으로 FS 레지스터 인덱스의 중요한 멤버들은 다음과 같다.

FS:[0x30] = TEB.ProcessEnvironmentBlock = PEB 시작 주소

 FS:[0x30]은 TEB 구조체 내의 ProcessEnvironmentBlock 멤버의 값을 의미하는데 이는 PEB의 주소를 의미한다. PEB에 대해서는 다음 챕터에서 다룰 예정이다.


FS:[0] = TEB.NtTib.ExceptionList = SEH 시작 주소

 위에서 언급하였듯이 FS:[0]은 _NT_TIB 구조체의 첫번째 멤버인 ExceptionList를 의미한다. 이는 SEH의 시작 주소를 의미한다. SEH는 48 챕터에서 다룰 예정이다.