Post

Thread Environment Block

Thread Environment Block

TEB는 스레드에 대한 정보를 포함하고 있는 구조체입니다.

프로세스 가상 메모리 영역에 존재하며, NtCurrentTEB 함수를 통해 획득할 수 있습니다.
함수 내부에서는 Segment Register를 통해 TEB 주소를 획득합니다.

1
2
3
4
// x86 architecture
ntdll!NtdllNtCurrentTeb:
77de9fe0 64a118000000    mov     eax,dword ptr fs:[00000018h]
77de9fe6 c3              ret

x64 아키텍처에서는 NtCurrentTEB 함수 자체는 지원하나, 인라인 함수로 대체되었습니다.

1
2
3
4
__forceinline struct _TEB* NtCurrentTeb (VOID)
{
    return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self));
}

마찬가지로 함수 내부에서는 세그먼트 레지스터를 통해 주소를 가져옵니다.

1
2
// x64 architecture
00007FF62BDD225B  mov         rax,qword ptr gs:[30h]

Windbg !teb 명령을 통해서도 확인이 가능하며, 파라미터로 주소가 전달되지 않으면 현재 스레드에 대한 TEB 정보가 조회됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
0:000> !teb
TEB at 003f9000
    ExceptionList:        0019f810
    StackBase:            001a0000
    StackLimit:           0019d000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 003f9000
    EnvironmentPointer:   00000000
    ClientId:             00003844 . 00004dd8
    RpcHandle:            00000000
    Tls Storage:          00724068
    PEB Address:          003f6000
    LastErrorValue:       0
    LastStatusValue:      c0000034
    Count Owned Locks:    0
    HardErrorMode:        0

dt_TEB

Windbg를 통해 확인한 TEB 구조체는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
0:000> dt_teb
ntdll!_TEB
   +0x000 NtTib            : _NT_TIB
   +0x01c EnvironmentPointer : Ptr32 Void
   +0x020 ClientId         : _CLIENT_ID
   +0x028 ActiveRpcHandle  : Ptr32 Void
   +0x02c ThreadLocalStoragePointer : Ptr32 Void
   +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
   +0x034 LastErrorValue   : Uint4B
   +0x038 CountOfOwnedCriticalSections : Uint4B
   +0x03c CsrClientThread  : Ptr32 Void
   +0x040 Win32ThreadInfo  : Ptr32 Void
   +0x044 User32Reserved   : [26] Uint4B
   +0x0ac UserReserved     : [5] Uint4B
   +0x0c0 WOW32Reserved    : Ptr32 Void
   +0x0c4 CurrentLocale    : Uint4B
   +0x0c8 FpSoftwareStatusRegister : Uint4B
   +0x0cc ReservedForDebuggerInstrumentation : [16] Ptr32 Void
   +0x10c SystemReserved1  : [26] Ptr32 Void
   +0x174 PlaceholderCompatibilityMode : Char
   +0x175 PlaceholderHydrationAlwaysExplicit : UChar
   +0x176 PlaceholderReserved : [10] Char
   +0x180 ProxiedProcessId : Uint4B
   +0x184 _ActivationStack : _ACTIVATION_CONTEXT_STACK
   +0x19c WorkingOnBehalfTicket : [8] UChar
   +0x1a4 ExceptionCode    : Int4B
   +0x1a8 ActivationContextStackPointer : Ptr32 _ACTIVATION_CONTEXT_STACK
   +0x1ac InstrumentationCallbackSp : Uint4B
   +0x1b0 InstrumentationCallbackPreviousPc : Uint4B
   +0x1b4 InstrumentationCallbackPreviousSp : Uint4B
   +0x1b8 InstrumentationCallbackDisabled : UChar
   +0x1b9 SpareBytes       : [23] UChar
   +0x1d0 TxFsContext      : Uint4B
   +0x1d4 GdiTebBatch      : _GDI_TEB_BATCH
   +0x6b4 RealClientId     : _CLIENT_ID
   +0x6bc GdiCachedProcessHandle : Ptr32 Void
   +0x6c0 GdiClientPID     : Uint4B
   +0x6c4 GdiClientTID     : Uint4B
   +0x6c8 GdiThreadLocalInfo : Ptr32 Void
   +0x6cc Win32ClientInfo  : [62] Uint4B
   +0x7c4 glDispatchTable  : [233] Ptr32 Void
   +0xb68 glReserved1      : [29] Uint4B
   +0xbdc glReserved2      : Ptr32 Void
   +0xbe0 glSectionInfo    : Ptr32 Void
   +0xbe4 glSection        : Ptr32 Void
   +0xbe8 glTable          : Ptr32 Void
   +0xbec glCurrentRC      : Ptr32 Void
   +0xbf0 glContext        : Ptr32 Void
   +0xbf4 LastStatusValue  : Uint4B
   +0xbf8 StaticUnicodeString : _UNICODE_STRING
   +0xc00 StaticUnicodeBuffer : [261] Wchar
   +0xe0c DeallocationStack : Ptr32 Void
   +0xe10 TlsSlots         : [64] Ptr32 Void
   +0xf10 TlsLinks         : _LIST_ENTRY
   +0xf18 Vdm              : Ptr32 Void
   +0xf1c ReservedForNtRpc : Ptr32 Void
   +0xf20 DbgSsReserved    : [2] Ptr32 Void
   +0xf28 HardErrorMode    : Uint4B
   +0xf2c Instrumentation  : [9] Ptr32 Void
   +0xf50 ActivityId       : _GUID
   +0xf60 SubProcessTag    : Ptr32 Void
   +0xf64 PerflibData      : Ptr32 Void
   +0xf68 EtwTraceData     : Ptr32 Void
   +0xf6c WinSockData      : Ptr32 Void
   +0xf70 GdiBatchCount    : Uint4B
   +0xf74 CurrentIdealProcessor : _PROCESSOR_NUMBER
   +0xf74 IdealProcessorValue : Uint4B
   +0xf74 ReservedPad0     : UChar
   +0xf75 ReservedPad1     : UChar
   +0xf76 ReservedPad2     : UChar
   +0xf77 IdealProcessor   : UChar
   +0xf78 GuaranteedStackBytes : Uint4B
   +0xf7c ReservedForPerf  : Ptr32 Void
   +0xf80 ReservedForOle   : Ptr32 Void
   +0xf84 WaitingOnLoaderLock : Uint4B
   +0xf88 SavedPriorityState : Ptr32 Void
   +0xf8c ReservedForCodeCoverage : Uint4B
   +0xf90 ThreadPoolData   : Ptr32 Void
   +0xf94 TlsExpansionSlots : Ptr32 Ptr32 Void
   +0xf98 MuiGeneration    : Uint4B
   +0xf9c IsImpersonating  : Uint4B
   +0xfa0 NlsCache         : Ptr32 Void
   +0xfa4 pShimData        : Ptr32 Void
   +0xfa8 HeapData         : Uint4B
   +0xfac CurrentTransactionHandle : Ptr32 Void
   +0xfb0 ActiveFrame      : Ptr32 _TEB_ACTIVE_FRAME
   +0xfb4 FlsData          : Ptr32 Void
   +0xfb8 PreferredLanguages : Ptr32 Void
   +0xfbc UserPrefLanguages : Ptr32 Void
   +0xfc0 MergedPrefLanguages : Ptr32 Void
   +0xfc4 MuiImpersonation : Uint4B
   +0xfc8 CrossTebFlags    : Uint2B
   +0xfc8 SpareCrossTebBits : Pos 0, 16 Bits
   +0xfca SameTebFlags     : Uint2B
   +0xfca SafeThunkCall    : Pos 0, 1 Bit
   +0xfca InDebugPrint     : Pos 1, 1 Bit
   +0xfca HasFiberData     : Pos 2, 1 Bit
   +0xfca SkipThreadAttach : Pos 3, 1 Bit
   +0xfca WerInShipAssertCode : Pos 4, 1 Bit
   +0xfca RanProcessInit   : Pos 5, 1 Bit
   +0xfca ClonedThread     : Pos 6, 1 Bit
   +0xfca SuppressDebugMsg : Pos 7, 1 Bit
   +0xfca DisableUserStackWalk : Pos 8, 1 Bit
   +0xfca RtlExceptionAttached : Pos 9, 1 Bit
   +0xfca InitialThread    : Pos 10, 1 Bit
   +0xfca SessionAware     : Pos 11, 1 Bit
   +0xfca LoadOwner        : Pos 12, 1 Bit
   +0xfca LoaderWorker     : Pos 13, 1 Bit
   +0xfca SkipLoaderInit   : Pos 14, 1 Bit
   +0xfca SkipFileAPIBrokering : Pos 15, 1 Bit
   +0xfcc TxnScopeEnterCallback : Ptr32 Void
   +0xfd0 TxnScopeExitCallback : Ptr32 Void
   +0xfd4 TxnScopeContext  : Ptr32 Void
   +0xfd8 LockCount        : Uint4B
   +0xfdc WowTebOffset     : Int4B
   +0xfe0 ResourceRetValue : Ptr32 Void
   +0xfe4 ReservedForWdf   : Ptr32 Void
   +0xfe8 ReservedForCrt   : Uint8B
   +0xff0 EffectiveContainerId : _GUID
   +0x1000 LastSleepCounter : Uint8B
   +0x1008 SpinCallCount    : Uint4B
   +0x1010 ExtendedFeatureDisableMask : Uint8B

NtTib

ExceptionList

SEH에 대한 엔트리 주소입니다. try~catch와 같은 예외처리를 사용한 경우, 세그먼트 레지스터를 통해 SEH 최상단에 등록됩니다.
해당 핸들러는 안티 디버깅에도 활용될 수 있습니다.

1
2
3
4
5
6
7
8
9
10
0:000> dx -r1 (*((ntdll!_NT_TIB *)0x2cc000))
(*((ntdll!_NT_TIB *)0x2cc000))                 [Type: _NT_TIB]
    [+0x000] ExceptionList    : 0x57f4b8 [Type: _EXCEPTION_REGISTRATION_RECORD *]
    [+0x004] StackBase        : 0x580000 [Type: void *]
    [+0x008] StackLimit       : 0x57d000 [Type: void *]
    [+0x00c] SubSystemTib     : 0x0 [Type: void *]
    [+0x010] FiberData        : 0x1e00 [Type: void *]
    [+0x010] Version          : 0x1e00 [Type: unsigned long]
    [+0x014] ArbitraryUserPointer : 0x0 [Type: void *]
    [+0x018] Self             : 0x2cc000 [Type: _NT_TIB *]

StackBase

해당 스레드에서 사용되는 스택의 시작 주소입니다. StackLimit에서 해당 값을 빼면 스택 크기를 구할 수 있습니다.

1
2
0:000> ?? int(@$teb->NtTib.StackBase) - int(@$teb->NtTib.StackLimit)
int 0n1044480

ThreadLocalStoragePointer

TLS에 대한 포인터입니다. 스레드 생성 시, 호출되는 콜백 함수는 안티 디버깅에 활용될 수 있습니다.

ProcessEnvironmentBlock

현재 프로세스의 PEB 주소를 나타냅니다.

DbgSsReserved

해당 값은 DebugActiveProcess 내부에서 참조됩니다.

1
2
3
4
5
6
7
0:013> u DebugActiveProcess
KERNELBASE!DebugActiveProcess:
00007ffc`7aa93b10 48895c2408      mov     qword ptr [rsp+8],rbx
00007ffc`7aa93b15 57              push    rdi
00007ffc`7aa93b16 4883ec20        sub     rsp,20h
00007ffc`7aa93b1a 8bd9            mov     ebx,ecx
00007ffc`7aa93b1c 48ff1595cd1000  call    qword ptr [KERNELBASE!_imp_DbgUiConnectToDbg (00007ffc`7aba08b8)]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0:013> uf ntdll!DbgUiConnectToDbg
ntdll!DbgUiConnectToDbg:
00007ffc`7d246e40 4883ec58        sub     rsp,58h
00007ffc`7d246e44 65488b042530000000 mov   rax,qword ptr gs:[30h]
00007ffc`7d246e4d 33c9            xor     ecx,ecx
00007ffc`7d246e4f 483988a8160000  cmp     qword ptr [rax+16A8h],rcx
00007ffc`7d246e56 7546            jne     ntdll!DbgUiConnectToDbg+0x5e (00007ffc`7d246e9e)  Branch

ntdll!DbgUiConnectToDbg+0x18:
00007ffc`7d246e58 48894c2428      mov     qword ptr [rsp+28h],rcx
00007ffc`7d246e5d 4c8d442420      lea     r8,[rsp+20h]
00007ffc`7d246e62 894c2438        mov     dword ptr [rsp+38h],ecx
00007ffc`7d246e66 0f57c0          xorps   xmm0,xmm0
00007ffc`7d246e69 48894c2430      mov     qword ptr [rsp+30h],rcx
00007ffc`7d246e6e 41b901000000    mov     r9d,1
00007ffc`7d246e74 f30f7f442440    movdqu  xmmword ptr [rsp+40h],xmm0
00007ffc`7d246e7a c744242030000000 mov     dword ptr [rsp+20h],30h
00007ffc`7d246e82 ba0f001f00      mov     edx,1F000Fh
00007ffc`7d246e87 65488b0c2530000000 mov   rcx,qword ptr gs:[30h]
00007ffc`7d246e90 4881c1a8160000  add     rcx,16A8h
00007ffc`7d246e97 e834a8fcff      call    ntdll!NtCreateDebugObject (00007ffc`7d2116d0)

다른 프로세스를 디버깅 중인 경우, DbgSsReserved 값은 0이 아닙니다. (디버거에 해당됨)
크기가 2인 배열이며 DbgSsReserved[1]에는 DebugObject 핸들이 존재합니다.

1
2
0:013> dt 0x0000000000228000 ntdll!_TEB
   +0x16a0 DbgSsReserved    : [2] 0x00000000`0800bfc0 Void
1
2
3
4
0:013> dx -r1 (*((ntdll!void * (*)[2])0x2296a0))
(*((ntdll!void * (*)[2])0x2296a0))                 [Type: void * [2]]
    [0]              : 0x800bfc0 [Type: void *]
    [1]              : 0x770 [Type: void *]

References

This post is licensed under CC BY 4.0 by the author.