Блок информации потока (TIB/TEB) в Windows: структура и управление стеком
Win32 Thread Information Block
Блок информации потока (TIB/TEB) в Win32: структура данных для получения информации о потоке без API. Доступ через сегменты FS/GS. PEB, IAT и аргументы процесса.
Сравнивайте с английским: нажмите на абзац — оригинал откроется в окне. Кнопка EN под абзацем показывает его прямо в тексте.
Введение
Блок информации о потоке (TIB) или блок окружения потока (TEB) — это структура данных в Win32 на x86, хранящая информацию о текущем выполняющемся потоке. Она берет свое начало от и сохраняет обратную совместимость на 32-битных системах с аналогичной структурой в OS/2. TIB может использоваться для получения большого объема информации о процессе без вызова Win32 API. Примеры включают эмуляцию функций GetLastError и GetVersion. Через указатель на PEB можно получить доступ к таблицам импорта (IAT), аргументам запуска процесса, имени образа и т.д. Доступ к TIB осуществляется из сегмента FS в 32-разрядной Windows и GS в 64-разрядной Windows.
The Thread Information Block (TIB) or Thread Environment Block (TEB) is a data structure in Win32 on x86 that stores information about the currently running thread. It descended from, and is backward compatible on 32 bit systems with, a similar structure in OS/2. The TIB can be used to get a lot of information on the process without calling Win32 API. Examples include emulating GetLastError , GetVersion Through the pointer to the PEB one can obtain access to the import tables (IAT), process startup arguments, image name, etc. It is accessed from the FS segment register on 32 bit Windows and GS on 64 bit Windows.
Информация о стеке, хранящаяся в TIB
Процесс должен иметь возможность свободно перемещать стек своих потоков, если он соответствующим образом обновляет информацию, хранящуюся в TIB. Ключевыми для этого являются несколько полей: база стека, предел стека, стек деаллокации и гарантированный размер стека, которые соответственно хранятся в смещениях 0x8, 0x10, 0x1478 и 0x1748 в 64-битной системе. Различные функции ядра Windows читают и записывают эти значения, в частности, для различения переполнения стека и других ошибок страниц чтения/записи (чтение или запись страницы, защищенной в пределах гарантированного размера стека, вызовет исключение переполнения стека вместо нарушения доступа). Стек деаллокации важен, поскольку Windows API позволяет изменять количество защищенных страниц: функция SetThreadStackGuarantee позволяет как читать текущий размер, так и увеличивать его. Для чтения используется поле GuaranteedStackBytes, а для увеличения требуется освобождение страниц стека. Установка пределов стека без установки DeallocationStack, вероятно, приведет к некорректной работе SetThreadStackGuarantee, например, к перезаписи границ стека неверными значениями. Различные библиотеки вызывают SetThreadStackGuarantee, например, NET CLR использует ее для настройки стека своих потоков.
A process should be free to move the stack of its threads as long as it updates the information stored in the TIB accordingly. A few fields are key to this matter: stack base, stack limit, deallocation stack, and guaranteed stack bytes, respectively stored at offsets 0x8, 0x10, 0x1478 and 0x1748 in 64 bits. Different Windows kernel functions read and write these values, specially to distinguish stack overflows from other read/write page faults (a read or write to a page guarded among the stack limits in guaranteed stack bytes will generate a stack overflow exception instead of an access violation). The deallocation stack is important because Windows API allows to change the amount of guarded pages: the function SetThreadStackGuarantee allows both read the current space and to grow it. In order to read it, it reads the GuaranteedStackBytes field, and to grow it, it uses has to uncommit stack pages. Setting stack limits without setting DeallocationStack will probably cause odd behavior in SetThreadStackGuarantee. For example, it will overwrite the stack limits to wrong values. Different libraries call SetThreadStackGuarantee, for example the NET CLR uses it for setting up the stack of their threads.