Bloque de información de subprocesos Win32 - Win32 Thread Information Block

En informática , el bloque de información de subprocesos de Win32 (TIB) es una estructura de datos en Win32 en x86 que almacena información sobre el subproceso que se está ejecutando actualmente . También se conoce como Thread Environment Block (TEB) para Win32. Descendió y es compatible con versiones anteriores en sistemas de 32 bits con una estructura similar en OS / 2 .

El TIB está oficialmente indocumentado para Windows 9x. El DDK de la serie Windows NT (así como la implementación de MinGW / ReactOS) incluye una estructura NT_TIB en winnt.h que documenta la parte independiente del subsistema. Incluso antes de que TIB fuera documentado de manera efectiva, muchas aplicaciones ya han comenzado a usar sus campos y son efectivamente parte de la API . El primer campo que contiene el marco SEH, en particular, es referenciado directamente por el código producido por el propio compilador de Microsoft. La parte específica del subsistema Win32 del TEB no está documentada, pero Wine incluye una definición de TEB en winternl.h.

El TIB se puede utilizar para obtener mucha información sobre el proceso sin llamar a la API de Win32. Los ejemplos incluyen emular GetLastError (), GetVersion (). A través del puntero al PEB se puede acceder a las tablas de importación (IAT), los argumentos de inicio del proceso, el nombre de la imagen, etc. Se accede desde el registro de segmento FS en Windows de 32 bits y GS en Windows de 64 bits.

Contenido de TIB en Windows

Esta tabla se basa en el trabajo de Wine en los componentes internos de Microsoft Windows .

Bytes /
Tipo
desplazamiento (32 bits, FS) desplazamiento (64 bits, GS) Versiones de Windows Descripción
puntero FS: [0x00] GS: [0x00] Win9x y NT Trama de manejo de excepciones estructurado actual (SEH)

Nota: la versión de 64 bits de Windows usa desenrollado de pila realizado en modo kernel .

puntero FS: [0x04] GS: [0x08] Win9x y NT Pila Base / Parte inferior de la pila (alta dirección)
puntero FS: [0x08] GS: [0x10] Win9x y NT Límite de pila / Techo de pila (dirección baja)
puntero FS: [0x0C] GS: [0x18] Nuevo Testamento SubSystemTib
puntero FS: [0x10] GS: [0x20] Nuevo Testamento Datos de fibra
puntero FS: [0x14] GS: [0x28] Win9x y NT Ranura de datos arbitraria
puntero FS: [0x18] GS: [0x30] Win9x y NT Dirección lineal de TEB
Fin de la parte independiente del subsistema NT ; a continuación son dependientes de Win32
puntero FS: [0x1C] GS: [0x38] Nuevo Testamento Puntero de entorno
puntero FS: [0 x 20] GS: [0x40] Nuevo Testamento ID de proceso (en algunas distribuciones de Windows, este campo se usa como 'DebugContext')
puntero FS: [0x24] GS: [0x48] Nuevo Testamento ID de hilo actual
puntero FS: [0x28] GS: [0 x 50] Nuevo Testamento Mango de RPC activo
puntero FS: [0x2C] GS: [0x58] Win9x y NT Dirección lineal de la matriz de almacenamiento local de subprocesos
puntero FS: [0x30] GS: [0x60] Nuevo Testamento Dirección lineal de Process Environment Block (PEB)
4 FS: [0x34] GS: [0x68] Nuevo Testamento Último número de error
4 FS: [0x38] GS: [0x6C] Nuevo Testamento Recuento de secciones críticas propias
puntero FS: [0x3C] GS: [0x70] Nuevo Testamento Dirección del hilo del cliente CSR
puntero FS: [0 x 40] GS: [0x78] Nuevo Testamento Información del hilo de Win32
124 FS: [0x44] GS: [0x80] NT, vino Información del cliente Win32 (NT), datos privados de user32 (Wine), 0x60 = LastError (Win95 y 98), 0x74 = LastError (WinME)
puntero FS: [0xC0] GS: [0x100] Nuevo Testamento Reservado para Wow64. Contiene un puntero a FastSysCall en Wow64.
4 FS: [0xC4] GS: [0x108] Nuevo Testamento Local actual
4 FS: [0xC8] GS: [0x10C] Nuevo Testamento Registro de estado del software FP
216 FS: [0xCC] GS: [0x110] NT, vino Reservado para OS (NT), datos privados de kernel32 (Wine)
aquí: FS: [0x124] 4 NT Puntero a la estructura KTHREAD (ETHREAD)
4 FS: [0x1A4] GS: [0x2C0] Nuevo Testamento Código de excepción
18 FS: [0x1A8] GS: [0x2C8] Nuevo Testamento Pila de contexto de activación
24 FS: [0x1BC] GS: [0x2E8] NT, vino Bytes de reserva (NT), datos privados ntdll (Wine)
40 FS: [0x1D4] GS: [0x300] NT, vino Reservado para OS (NT), datos privados ntdll (Wine)
1248 FS: [0x1FC] GS: [0x350] NT, vino GDI TEB Batch (SO), datos privados vm86 (Wine)
4 FS: [0x6DC] GS: [0x838] Nuevo Testamento Región GDI
4 FS: [0x6E0] GS: [0x840] Nuevo Testamento Bolígrafo GDI
4 FS: [0x6E4] GS: [0x848] Nuevo Testamento Cepillo GDI
4 FS: [0x6E8] GS: [0x850] Nuevo Testamento ID de proceso real
4 FS: [0x6EC] GS: [0x858] Nuevo Testamento ID de hilo real
4 FS: [0x6F0] GS: [0x860] Nuevo Testamento Identificador de proceso en caché de GDI
4 FS: [0x6F4] GS: [0x868] Nuevo Testamento ID de proceso de cliente GDI (PID)
4 FS: [0x6F8] GS: [0x86C] Nuevo Testamento ID de subproceso de cliente GDI (TID)
4 FS: [0x6FC] GS: [0x870] Nuevo Testamento Información de configuración regional de subprocesos GDI
20 FS: [0x700] GS: [0x878] Nuevo Testamento Reservado para la aplicación del usuario
1248 FS: [0x714] GS: [0x890] Nuevo Testamento Reservado para GL (ver ref. Vino para detalles internos)
4 FS: [0xBF4] GS: [0x1250] Nuevo Testamento Último valor de estado
532 FS: [0xBF8] GS: [0x1258] Nuevo Testamento Búfer estático UNICODE_STRING
puntero FS: [0xE0C] GS: [0x1478] Nuevo Testamento También conocido como DeallocationStack, establece la dirección de inicio real del búfer de pila, de ahí el límite de pila real: es unas pocas páginas menos que el campo de límite de pila (que oculta las páginas de protección utilizadas para detectar desbordamientos de pila).
puntero[] FS: [0xE10] GS: [0x1480] Nuevo Testamento Ranuras TLS, 4/8 bytes por ranura, 64 ranuras
8 FS: [0xF10] GS: [0x1680] Nuevo Testamento Enlaces TLS (estructura LIST_ENTRY)
4 FS: [0xF18] GS: [0x1690] Nuevo Testamento VDM
4 FS: [0xF1C] GS: [0x1698] Nuevo Testamento Reservado para RPC
4 FS: [0xF28] GS: [0x16B0] Nuevo Testamento Modo de error de subproceso (RtlSetThreadErrorMode)
4 FS: [0xF78] GS: [0x1748] Nuevo Testamento Bytes de pila garantizados
Esta no es la mesa completa; ver ref. vino para todos los campos hasta FS: [0xfb4] / GS: [17c8]. Las versiones más recientes de Windows amplían aún más el tamaño de TIB, hasta 0x1000 / 0x1838 en Windows 10. Algunos de los campos adjuntos se eliminan, lo que genera definiciones contradictorias.

FS (para 32 bits) o GS (para 64 bits) se asigna a un TIB que está incrustado en un bloque de datos conocido como TDB (base de datos de subprocesos). El TIB contiene la cadena de manejo de excepciones específicas de subprocesos y el puntero al TLS (almacenamiento local de subprocesos). El almacenamiento local de subprocesos no es lo mismo que el almacenamiento local de C.

Apilar información almacenada en el TIB

Un proceso debe tener libertad para mover la pila de sus subprocesos siempre que actualice la información almacenada en el TIB en consecuencia. Algunos campos son clave para este asunto: base de pila, límite de pila, pila de desasignación y bytes de pila garantizados, almacenados respectivamente en las compensaciones 0x8, 0x10, 0x1478 y 0x1748 en 64 bits. Diferentes funciones del kernel de Windows leen y escriben estos valores, especialmente para distinguir los desbordamientos de pila de otras fallas de página de lectura / escritura (una lectura o escritura en una página protegida entre los límites de pila en bytes de pila garantizados generará una excepción de desbordamiento de pila en lugar de un violación). La pila de desasignación es importante porque la API de Windows permite cambiar la cantidad de páginas protegidas: la función SetThreadStackGuarantee permite tanto leer el espacio actual como aumentarlo. Para leerlo, lee el campo GuaranteedStackBytes y, para hacer que crezca, usa tiene que descomprimir las páginas de la pila. Establecer límites de pila sin establecer DeallocationStack probablemente causará un comportamiento extraño en SetThreadStackGuarantee. Por ejemplo, sobrescribirá los límites de la pila con valores incorrectos. Diferentes bibliotecas llaman SetThreadStackGuarantee, por ejemplo, .NET CLR lo usa para configurar la pila de sus subprocesos.

Accediendo al TIB

Se puede acceder al TIB del subproceso actual como un desplazamiento del registro de segmento FS (x86) o GS (x64).

No es común acceder a los campos TIB mediante un desplazamiento de FS:[0] , sino obtener primero un puntero de autorreferencia lineal almacenado en FS:[18h] . Ese puntero se puede usar con aritmética de punteros o convertirse en un puntero de estructura .

Usando Microsoft Windows SDK o similar, un programador podría usar una función en línea definida en winnt.h named NtCurrentTeb que devuelve la dirección del actual Thread Information Block como NT_TIB * .

Los métodos alternativos de acceso para las arquitecturas IA-32 son los siguientes:

// 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
}

Ver también

Referencias

Otras lecturas

enlaces externos