Win32 Thread Information Block - Win32 Thread Information Block

Beim Rechnen ist der Win32-Thread-Informationsblock (TIB) eine Datenstruktur in Win32 auf x86 , in der Informationen zum aktuell ausgeführten Thread gespeichert werden . Es wird auch als Thread Environment Block (TEB) für Win32 bezeichnet. Es stammt von einer ähnlichen Struktur in OS / 2 ab und ist auf 32-Bit-Systemen mit einer ähnlichen Struktur abwärtskompatibel .

Die TIB ist für Windows 9x offiziell undokumentiert. Das DDK der Windows NT-Serie (sowie die MinGW / ReactOS-Implementierung) enthält eine Struktur NT_TIB in winnt.h, die den subsystemunabhängigen Teil dokumentiert. Noch bevor TIB effektiv dokumentiert wurde, haben viele Anwendungen bereits damit begonnen, ihre Felder als Teil der API zu verwenden . Insbesondere das erste Feld, das den SEH-Frame enthält, wird direkt vom Code referenziert, der vom Microsoft-eigenen Compiler erstellt wurde. Der für das Win32-Subsystem spezifische Teil des TEB ist nicht dokumentiert, aber Wine enthält eine TEB-Definition in winternl.h.

Die TIB kann verwendet werden, um viele Informationen über den Prozess abzurufen, ohne die Win32-API aufzurufen. Beispiele sind das Emulieren von GetLastError (), GetVersion (). Über den Zeiger auf den PEB kann auf die Importtabellen (IAT), Prozessstartargumente, den Bildnamen usw. zugegriffen werden. Der Zugriff erfolgt über das FS-Segmentregister unter 32-Bit-Windows und über GS unter 64-Bit-Windows.

Inhalt der TIB unter Windows

Diese Tabelle basiert auf Wines Arbeit an Microsoft Windows- Interna.

Bytes /
Typ
Offset (32-Bit, FS) Offset (64-Bit, GS) Windows-Versionen Beschreibung
Zeiger FS: [0x00] GS: [0x00] Win9x und NT Aktueller SEH-Rahmen ( Structured Exception Handling )

Hinweis: Die 64-Bit-Version von Windows verwendet stattdessen das Abwickeln des Stapels im Kernelmodus .

Zeiger FS: [0x04] GS: [0x08] Win9x und NT Stapel Basis / unten im Stapel (hohe Adresse)
Zeiger FS: [0x08] GS: [0x10] Win9x und NT Stapelbegrenzung / Stapeldecke (niedrige Adresse)
Zeiger FS: [0x0C] GS: [0x18] NT SubSystemTib
Zeiger FS: [0x10] GS: [0x20] NT Faserdaten
Zeiger FS: [0x14] GS: [0x28] Win9x und NT Beliebiger Datensteckplatz
Zeiger FS: [0x18] GS: [0x30] Win9x und NT Lineare Adresse von TEB
Ende des unabhängigen Teils des NT-Subsystems ; unten sind Win32- abhängig
Zeiger FS: [0x1C] GS: [0x38] NT Umgebungszeiger
Zeiger FS: [0x20] GS: [0x40] NT Prozess-ID (in einigen Windows-Distributionen wird dieses Feld als 'DebugContext' verwendet)
Zeiger FS: [0x24] GS: [0x48] NT Aktuelle Thread-ID
Zeiger FS: [0x28] GS: [0x50] NT Aktiver RPC-Griff
Zeiger FS: [0x2C] GS: [0x58] Win9x und NT Lineare Adresse des gewinde lokalen Speicher - Array
Zeiger FS: [0x30] GS: [0x60] NT Lineare Adresse des Prozessumgebungsblock (PEB)
4 FS: [0x34] GS: [0x68] NT Letzte Fehlernummer
4 FS: [0x38] GS: [0x6C] NT Anzahl der eigenen kritischen Abschnitte
Zeiger FS: [0x3C] GS: [0x70] NT Adresse des CSR-Client-Threads
Zeiger FS: [0x40] GS: [0x78] NT Win32-Thread-Informationen
124 FS: [0x44] GS: [0x80] NT, Wein Win32-Clientinformationen (NT), private Benutzer32-Daten (Wine), 0x60 = LastError (Win95 & 98), 0x74 = LastError (WinME)
Zeiger FS: [0xC0] GS: [0x100] NT Reserviert für Wow64. Enthält einen Zeiger auf FastSysCall in Wow64.
4 FS: [0xC4] GS: [0x108] NT Aktuelles Gebietsschema
4 FS: [0xC8] GS: [0x10C] NT FP Software Status Register
216 FS: [0xCC] GS: [0x110] NT, Wein Reserviert für OS (NT), private
Kernel32- Daten (Wine) : FS: [0x124] 4 NT-Zeiger auf KTHREAD (ETHREAD) -Struktur
4 FS: [0x1A4] GS: [0x2C0] NT Ausnahmecode
18 FS: [0x1A8] GS: [0x2C8] NT Aktivierungskontextstapel
24 FS: [0x1BC] GS: [0x2E8] NT, Wein Ersatzbytes (NT), ntdll private Daten (Wine)
40 FS: [0x1D4] GS: [0x300] NT, Wein Reserviert für OS (NT), ntdll private Daten (Wine)
1248 FS: [0x1FC] GS: [0x350] NT, Wein GDI TEB Batch (OS), private vm86-Daten (Wine)
4 FS: [0x6DC] GS: [0x838] NT GDI Region
4 FS: [0x6E0] GS: [0x840] NT GDI Pen
4 FS: [0x6E4] GS: [0x848] NT GDI-Pinsel
4 FS: [0x6E8] GS: [0x850] NT Echte Prozess-ID
4 FS: [0x6EC] GS: [0x858] NT Echte Thread-ID
4 FS: [0x6F0] GS: [0x860] NT GDI zwischengespeicherter Prozesshandle
4 FS: [0x6F4] GS: [0x868] NT GDI-Client-Prozess-ID (PID)
4 FS: [0x6F8] GS: [0x86C] NT GDI-Client-Thread-ID (TID)
4 FS: [0x6FC] GS: [0x870] NT Informationen zum Gebietsschema des GDI-Threads
20 FS: [0x700] GS: [0x878] NT Reserviert für Benutzeranwendung
1248 FS: [0x714] GS: [0x890] NT Reserviert für GL (Interna siehe Weinreferenz)
4 FS: [0xBF4] GS: [0x1250] NT Letzter Statuswert
532 FS: [0xBF8] GS: [0x1258] NT Statischer UNICODE_STRING-Puffer
Zeiger FS: [0xE0C] GS: [0x1478] NT Auch als DeallocationStack bezeichnet, legt es die tatsächliche Startadresse des Stapelpuffers fest, daher das tatsächliche Stapellimit: Es liegt einige Seiten unter dem Feld für das Stapellimit (das die Schutzseiten verbirgt, die zum Erkennen von Stapelüberläufen verwendet werden).
Zeiger[] FS: [0xE10] GS: [0x1480] NT TLS-Steckplätze, 4/8 Bytes pro Steckplatz, 64 Steckplätze
8 FS: [0xF10] GS: [0x1680] NT TLS-Links (LIST_ENTRY-Struktur)
4 FS: [0xF18] GS: [0x1690] NT VDM
4 FS: [0xF1C] GS: [0x1698] NT Reserviert für RPC
4 FS: [0xF28] GS: [0x16B0] NT Thread-Fehlermodus (RtlSetThreadErrorMode)
4 FS: [0xF78] GS: [0x1748] NT Garantierte Stapelbytes
Dies ist nicht die vollständige Tabelle; siehe Weinreferenz für alle Felder bis FS: [0xfb4] / GS: [17c8]. Neuere Windows-Versionen erweitern die Größe von TIB weiter auf 0x1000 / 0x1838 in Windows 10. Einige der angehängten Felder werden entfernt, was zu widersprüchlichen Definitionen führt.

FS (für 32-Bit) oder GS (für 64-Bit) werden einer TIB zugeordnet, die in einen Datenblock eingebettet ist, der als TDB (Thread-Datenbank) bekannt ist. Die TIB enthält die threadspezifische Ausnahmebehandlungskette und den Zeiger auf das TLS (Thread Local Storage). Der Thread Local Storage ist nicht mit dem C Local Storage identisch.

In der TIB gespeicherte Stapelinformationen

Ein Prozess sollte frei sein, den Stapel seiner Threads zu verschieben, solange er die in der TIB gespeicherten Informationen entsprechend aktualisiert. Einige Felder sind der Schlüssel zu diesem Thema: Stapelbasis, Stapelbegrenzung, Freigabestapel und garantierte Stapelbytes, die jeweils bei den Offsets 0x8, 0x10, 0x1478 und 0x1748 in 64 Bit gespeichert sind. Verschiedene Windows-Kernelfunktionen lesen und schreiben diese Werte, insbesondere um Stapelüberläufe von anderen Lese- / Schreibseitenfehlern zu unterscheiden (ein Lesen oder Schreiben auf eine Seite, die zwischen den Stapelgrenzen in garantierten Stapelbytes geschützt ist, generiert eine Stapelüberlaufausnahme anstelle eines Zugriffs Verstoß). Der Freigabestapel ist wichtig, da mit der Windows-API die Anzahl der geschützten Seiten geändert werden kann: Mit der Funktion SetThreadStackGuarantee kann der aktuelle Speicherplatz sowohl gelesen als auch vergrößert werden. Um es zu lesen, liest es das Feld GuaranteedStackBytes, und um es zu vergrößern, müssen Stack-Seiten freigegeben werden. Das Festlegen von Stapellimits ohne Festlegen von DeallocationStack führt wahrscheinlich zu einem merkwürdigen Verhalten in SetThreadStackGuarantee. Beispielsweise werden die Stapelgrenzen auf falsche Werte überschrieben. Verschiedene Bibliotheken rufen SetThreadStackGuarantee auf. Beispielsweise verwendet die .NET CLR sie zum Einrichten des Thread-Stapels.

Zugriff auf die TIB

Die TIB des aktuellen Threads kann als der Segmentversatz zugegriffen werden Register FS (x86) oder GS (x64).

Es ist nicht üblich, auf die TIB-Felder durch einen Versatz von zuzugreifen FS:[0] , sondern zuerst einen linearen selbstreferenzierenden Zeiger darauf abzurufen, der unter gespeichert ist FS:[18h] . Dieser Zeiger kann mit Zeigerarithmetik verwendet werden oder zu einem gegossen werden struct Zeiger .

Mit Microsoft Windows SDK oder ähnlichem kann ein Programmierer eine in winnt.h named definierte Inline-Funktion verwenden, NtCurrentTeb die die Adresse des aktuellen Thread-Informationsblocks als zurückgibt NT_TIB * .

Alternative Zugriffsmethoden für IA-32- Architekturen sind wie folgt:

// gcc (AT&T-style inline assembly).
void *getTIB(void) {
    register void *pTIB;
#if defined(__x86_64__) || defined(__amd64__)
    __asm__("movq %%gs:0x30, %0" : "=r" (pTIB));
#elif defined(__i386__)
    __asm__("movl %%fs:0x18, %0" : "=r" (pTIB));
#else
#error unsupported architecture
#endif
    return pTIB;
}
// gcc (named address spaces, same as the inline assembly version on -O1 or -ftree-ter).
void *getTIB(void) {
#if defined(__x86_64__) || defined(__amd64__)
#ifndef __SEG_GS
#error unsupported GCC version
#endif
    return *(void *__seg_gs *) 0x30;
#elif defined(__i386__)
#ifndef __SEG_FS
#error unsupported GCC version
#endif
    return *(void *__seg_fs *) 0x18;
#else
#error unsupported architecture
#endif
}
// Microsoft C
__declspec(naked)
void *getTIB() {
    __asm mov EAX, FS:[18h]
    __asm ret
}
// Using Microsoft's intrinsics instead of inline assembly (works for both X86 and X64 architectures)
void *getTIB() {
#ifdef _M_IX86
    return (void *)__readfsdword(0x18);
#elif _M_AMD64
    return (void *)__readgsqword(0x30);
#else
#error unsupported architecture
#endif
}

Siehe auch

Verweise

Weiterführende Literatur

Externe Links