Регистр FS

Тема в разделе "WASM.BEGINNERS", создана пользователем 808Problem, 1 мар 2023.

Метки:
  1. 808Problem

    808Problem Member

    Публикаций:
    0
    Регистрация:
    1 мар 2023
    Сообщения:
    31
    Доброе утро! Люди, проясните пожалуйста.
    Слышал, что регистр FS как-то связан с потоками, тогда вопрос, почему при переключении потоков регистр FS не меняется, но указывает на TEB активного? Вот например: В fs регистре лежит 0x0053, когда кликаю на это число в x64dbg попадаю на указатель начала структуры TEB именно текущего потока. Как вычисляется с помощью этого магического числа 0x0053 указатель на TEB текущего потока с помощью FS ? - опишите пожалуйста этот процесс подробно, очень интересно.
     
    Последнее редактирование: 1 мар 2023
  2. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    525
    https://devblogs.microsoft.com/oldnewthing/20190520-00/?p=102503
     
    808Problem и Mikl___ нравится это.
  3. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    887
    808Problem и Mikl___ нравится это.
  4. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    В сегментных регистрах лежат всегда одинаковые значения, которые называют "селекторы".
    Селектор - это указатель на 8-байтную запись в глобальной таблице дескрипторов GDT, где хранятся "дескрипторы" сегментов памяти. Каждый дескриптор описывает свойства сегмента, к примеру его тип (кода/данных), базу сегмента в памяти, лимит (макс.адрес) и атрибуты. Поскольку в РМ память виртуальная, то для всех процессов и потоков эти значения всегда одинаковы (внутри одной линейки Windows/Linux), за исключением сегмента задачи TSS (Task-State-Segment). Когда планировщик переключает потоки, в TSS сбрасывается состояние регистров предыдущей задачи на момент переключения.

    Командой dg (с аргументом в виде селектора) в отладчике WinDbg можно просмотреть значения всех дескрипторов. В юзер-отладчике x64Dbg видно, что в сег.регистрах лежат всего три селектора с номерами 2Bh, 33h, 53h - вот пример вывода дампа их дескрипторов:

    Код (Text):
    1. 0: kd> r gdtr
    2. ----------------------
    3. gdtr=fffff80000b91000    <----- адрес таблицы GDT в сис.памяти (лежит в регистре GDTR текущего CPU)
    4.  
    5. 0: kd> r gdtl
    6. ----------------------
    7. gdtl=007f                <----- размер GDT (мл.слово в GDTR)
    8.  
    9. 0: kd> dg 2b 53          <----- запрашиваем дамп в диапазоне от 2B до 53
    10. ----------------------
    11.                                                     P Si Gr Pr Lo
    12. Sel        Base              Limit          Type    l ze an es ng Flags
    13. ---- ----------------- ----------------- ---------- - -- -- -- -- --------
    14. 002B 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3
    15. 0033 00000000`00000000 00000000`00000000 Code RE Ac 3 Nb By P  Lo 000002fb
    16. 003B 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
    17. 0043 00000000`00b92080 00000000`00000067 TSS32 Busy 0 Nb By P  Nl 0000008b
    18. 004B 00000000`0000ffff 00000000`0000f800 <Reserved> 0 Nb By Np Nl 00000000
    19. 0053 ffffffff`fffa2000 00000000`00003c00 Data RW Ac 3 Bg By P  Nl 000004f3
    20.  
    21. 0: kd> r gdtr
    22. gdtr=fffff80000b91000    <--- адрес GDT для CPU-0
    23.  
    24. 0: kd> ~1                <--- меняем CPU на 1
    25.  
    26. 1: kd> r gdtr
    27. gdtr=fffff880009f24c0    <--- адрес GDT для CPU-1
    28.  
    29. 1: kd> dg 2b 53
    30.                                                     P Si Gr Pr Lo
    31. Sel        Base              Limit          Type    l ze an es ng Flags
    32. ---- ----------------- ----------------- ---------- - -- -- -- -- --------
    33. 002B 00000000`00000000 00000000`ffffffff Data RW Ac 3 Bg Pg P  Nl 00000cf3
    34. 0033 00000000`00000000 00000000`00000000 Code RE Ac 3 Nb By P  Lo 000002fb
    35. 003B 00000000`00000000 00000000`00000000 <Reserved> 0 Nb By Np Nl 00000000
    36. 0043 00000000`009ebec0 00000000`00000067 TSS32 Busy 0 Nb By P  Nl 0000008b
    37. 004B 00000000`0000ffff 00000000`0000f880 <Reserved> 0 Nb By Np Nl 00000000
    38. 0053 ffffffff`fffdd000 00000000`00007c00 Data RW Ac 3 Bg By P  Nl 000004f3
    Система создаёт таблицу GDT для каждого CPU в отдельности, что видно по столбцу "Base" в дескрипторах 43/53.
     
    Последнее редактирование: 1 мар 2023
    M0rg0t, 808Problem и Mikl___ нравится это.
  5. 808Problem

    808Problem Member

    Публикаций:
    0
    Регистрация:
    1 мар 2023
    Сообщения:
    31
    Спасибо. Понятно
    --- Сообщение объединено, 1 мар 2023 ---
    Проясните пожалуйста, а то новичок:
    Под сис.памятью вы понимаете - RAM(оперативную)?
    Я правильно понимаю, что под CPU в данном контексте - вы имеете в виду ЯДРО процессора? Если так, тогда получается, что система в оперативной памяти резервирует место для хранения таблицы GTD под каждое ядро, но вопрос, а как программа понимает, к GTD какого ядра ей обратиться, чтобы при взятии измененного указателя на TEB потока по селектору 0x0053 - не ошибиться?
     
  6. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.242
    ось разруливает, а не прикладная программа, драйвер же может изменять это поведение.
    что такое сис память определяется особенностями оси. к примеру, в сис память входит и своп.
     
    808Problem нравится это.
  7. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Скачайте книги Руссиновича и Рихтера, там всё описано.
    Глобальная вирт.память делится на 2 части - нижняя половина юзеру, а верхнюю система забирает себе. Имеются "кольца защиты" 0-3, номера которых хранятся как-раз в селекторах сегментных регистров (см.поле CPL/DPL, 2 мл.бита из 16-ти). Когда ОС выделяет себе сегменты памяти, то выставляет CPL=0, а в сегментах юзера ставит CPL=3. Так она запрещает юзверю проникать в своё пространство. Селекторы ядра всегда чётные, а юзера нечётные.

    В логах WinDbg, кольцо защиты указывается в столбце "PL" (Privilege Level) атрибутов. Можно запросить весь дамп GDT в диапазоне селекторов 00-7F, только здесь отладчик путается, и выдаёт неправильные номера селекторов (без учёта 3 мл.бит). В таблице GDT x64, селектор(10h) это всегда секция-кода ядра, хотя на чистом х32 (без WOW64) он имел строго значение(08h):
    Код (Text):
    1. 0: kd> dg 00 80
    2. ****************
    3.                                                         P Si Gr Pr Lo
    4. Sel         Base               Limit           Type     l ze an es ng  Flags
    5. ----  -----------------  -----------------  ----------  - -- -- -- --  --------
    6. 0000  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
    7. 0008  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
    8. 0010  00000000`00000000  00000000`00000000  Code RE Ac  0 Nb By P  Lo  0000029b
    9. 0018  00000000`00000000  00000000`ffffffff  Data RW Ac  0 Bg Pg P  Nl  00000c93
    10. 0020  00000000`00000000  00000000`ffffffff  Code RE Ac  3 Bg Pg P  Nl  00000cfb
    11. 0028  00000000`00000000  00000000`ffffffff  Data RW Ac  3 Bg Pg P  Nl  00000cf3
    12. 0030  00000000`00000000  00000000`00000000  Code RE Ac  3 Nb By P  Lo  000002fb
    13. 0038  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
    14. 0040  00000000`00b92080  00000000`00000067  TSS32 Busy  0 Nb By P  Nl  0000008b
    15. 0048  00000000`0000ffff  00000000`0000f800  <Reserved>  0 Nb By Np Nl  00000000
    16. 0050  ffffffff`fffdf000  00000000`00003c00  Data RW Ac  3 Bg By P  Nl  000004f3
    17. 0058  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
    18. 0060  00000000`00000000  00000000`ffffffff  Code RE     0 Bg Pg P  Nl  00000c9a
    19. 0068  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
    20. 0070  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
    21. 0078  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl  00000000
    22. 0080  Unable to get descriptor
    23. ------------------------------
    24.  
    25. 0: kd> r gdtr
    26. gdtr=fffff80000b91000
    27.  
    28. 0: kd> dq fffff80000b91000
    29. fffff800`00b91000   00000000`00000000 00000000`00000000  <---- сырой Raw-дамп GDT
    30. fffff800`00b91010   00209b00`00000000 00cf9300`0000ffff
    31. fffff800`00b91020   00cffb00`0000ffff 00cff300`0000ffff
    32. fffff800`00b91030   0020fb00`00000000 00000000`00000000
    33. fffff800`00b91040   00008bb9`20800067 00000000`fffff800
    34. fffff800`00b91050   ff40f3fd`f0003c00 00000000`00000000
    35. fffff800`00b91060   00cf9a00`0000ffff 00000000`00000000
    36. fffff800`00b91070   00000000`00000000 00000000`00000000
    • В нёдрах системы, процесс описывает структура "_EPROCESS", в которой имеется поле с идентификатором "Cid" (clientId) - по нему система отличает один процесс от другого. Первым членом в структуре _EP является "Pcb" или "Process-Control-Block" (блок управления процессом, структурирован как KPROCESS).

    • Любой процесс имеет хоть 1 поток (основной), и для системы это структура "_ETHREAD" со своим ID. Она так-же начинается с блока управления "Tcb" = KTHREAD. По смещению 300h от начала структуры родителя "_EPROCESS" прописано поле "ThreadListHead", со связанным списком на структуры "_ETHREAD", которые описывают потоки данного процесса.

    • Структуры _EP и _ET лежат в пространстве ядра с CPL=0, поэтому юзеру не доступны. В его пространство (нижняя половина вирт.адресов с CPL=3) система кидает структуру "РЕВ" (блок окружения процесса), а так-же "TEB" для каждого из тредов процесса.

    Вот пример того, как собрать инфу например об AkelPad.exe
    1. Сначала запрашиваем дамп всех процессов, что получить указатели на их структуры "EPROCESS".
    2. Находим в дампе свой AkelPad и передаём адрес команде !process
    3. Видим в логах ID процесса + двух его потоков и прочую инфу, включая линки на PEB+TEB в пространстве юзера. При смене потока, именно адрес TEB записывается в дескриптор(53) регистра FS:

    Код (Text):
    1. 0: kd> !process 0 0
    2. **** NT ACTIVE PROCESS DUMP ****
    3. ......
    4. PROCESS fffffa800292c060
    5.     SessionId: 1         Cid: 0a68    Peb:    7efdf000  ParentCid  : 05f0
    6.     DirBase  : 68db9000  ObjectTable: fffff8a0021f9740  HandleCount: 87.
    7.     Image: AkelPad.exe
    8. ---------------------------------------------------
    9. 0: kd> !process fffffa800292c060 4
    10. PROCESS fffffa800292c060
    11.     SessionId: 1         Cid: 0a68    Peb:    7efdf000  ParentCid  : 05f0
    12.     DirBase  : 68db9000  ObjectTable: fffff8a0021f9740  HandleCount: 87.
    13.     Image: AkelPad.exe
    14.         THREAD fffffa8004191b50  Cid 0a68.0a6c  Teb: 7efdb000  Win32Thread: fffff900c1e74c30 WAIT
    15.         THREAD fffffa8003b7d060  Cid 0a68.0a70  Teb: 7efd8000  Win32Thread: 0000000000000000 WAIT
    16.  
    17. ----------- Фрагмент структуры EPROCESS -----------------------------------------
    18.  
    19. 0: kd> dt _eprocess fffffa800292c060
    20. ntdll!_EPROCESS
    21.    +0x000 Pcb                : _KPROCESS
    22.    +0x180 UniqueProcessId    : 0x00000000`00000a68 Void  <--- PID процесса
    23.    +0x198 ProcessQuotaUsage  : [2] 0x2858
    24.    +0x1d8 VirtualSize        : 0x4f89000
    25.    +0x210 WorkingSetPage     : 0x68a3d
    26.    +0x2d8 ImageFileName      : [15]  "AkelPad"
    27.    +0x300 ThreadListHead     : _LIST_ENTRY [0x00000000`00000000 - 0xfffffa80`04191f78]  <--- список указателей на "_ETHREAD'ы"
    28.    +0x318 Wow64Process       : (null)
    29.    +0x320 ActiveThreads      : 0x7efde000
    30.    +0x330 Peb                : 0x00000000`00000001 _PEB
    31.    +0x428 HighestUserAddress : 0xfffffa80`02842480 Void
    32.    +0x440 VadRoot            : _MM_AVL_TABLE
    33.  
    Так, чтобы правильно жонглировать структурами процессов и потоков, системе достаточно знать их ID.
    Какое из ядер процессора будет исполнять тред, назначает планировщик потоков "Scheduler", но функцией SetProcessAffinityMask() даже юзер (с определёнными правами) сможет назначить конкретные ядра для своих поток, освобождая от этой задачи системный планировщик.
     
    Последнее редактирование: 1 мар 2023
    M0rg0t, Thetrik, 808Problem и ещё 1-му нравится это.
  8. 808Problem

    808Problem Member

    Публикаций:
    0
    Регистрация:
    1 мар 2023
    Сообщения:
    31
    Спасибо большое, что уделили мне время и написали такой подробный ответ!