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
- Pietrek, Matt (marzo de 1996). Secretos de programación de Windows 95 (pdf) . IDG. págs. 136-138 . ISBN 978-1-56884-318-6 . Consultado el 17 de julio de 2010 .