Атрибуты структуры KUSER_SHARED_DATA

Тема в разделе "WASM.X64", создана пользователем Marylin, 28 дек 2024.

Метки:
  1. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Всем привет!
    Что-то я запутался в атрибутах KUSER_SHARED_DATA.
    Известно, что эта структура ядра отображается в каждый пользовательский процесс по одинаковому адресу 0x7FFE0000 на обоих системах х32/64. В ядре она так-же имеет фиксированный адрес 0xfffff780`00000000, даже не смотря на активный ASLR.
    Код (Text):
    1.  
    2. 0: kd> dt _kuser_shared_data  NtSystemRoot  0x7ffe0000
    3. nt!_KUSER_SHARED_DATA
    4.    +0x030 NtSystemRoot : [260]  "C:\Windows"
    5.  
    6. 0: kd> dt _kuser_shared_data  NtSystemRoot  0xfffff78000000000
    7. nt!_KUSER_SHARED_DATA
    8.    +0x030 NtSystemRoot : [260]  "C:\Windows"
    9.  
    10. ;//-------- Одинаковая область памяти ------------------------
    11.  
    12. 0: kd> dq 0x7ffe0000
    13. 00000000`7ffe0000  0f99a027`00000000 0000002a`c7a26e51
    14. 00000000`7ffe0010  8c895d3c`0000002a 01db58f0`01db58f0
    15. 00000000`7ffe0020  ffffffd6`1729f800 86648664`ffffffd6
    16. 00000000`7ffe0030  0057005c`003a0043 006f0064`006e0069
    17. 00000000`7ffe0040  00000000`00730077 00000000`00000000
    18. 00000000`7ffe0050  00000000`00000000 00000000`00000000
    19. 00000000`7ffe0060  00000000`00000000 00000000`00000000
    20. 00000000`7ffe0070  00000000`00000000 00000000`00000000
    21.  
    22. 0: kd> dq 0xfffff78000000000
    23. fffff780`00000000  0f99a027`00000000 0000002a`c7a26e51
    24. fffff780`00000010  8c895d3c`0000002a 01db58f0`01db58f0
    25. fffff780`00000020  ffffffd6`1729f800 86648664`ffffffd6
    26. fffff780`00000030  0057005c`003a0043 006f0064`006e0069
    27. fffff780`00000040  00000000`00730077 00000000`00000000
    28. fffff780`00000050  00000000`00000000 00000000`00000000
    29. fffff780`00000060  00000000`00000000 00000000`00000000
    30. fffff780`00000070  00000000`00000000 00000000`00000000
    Дальше смотрим на атрибуты страниц - под юзером стоит только(R) причём страница чистая без атрибута "Dirty" (хотя каким-то образом тики в поле KSYSTEM_TIME обновляются), а вот в ядре страница грязная(D) с атрибутами уже W/E. Но что примечательно, это один и тот-же физический фрейм с номером PFN=0x01E6. Как такое может быть?
    Код (Text):
    1. 0: kd> !cmkd.ptelist -v 0x7ffe0000
    2. VA=000000007FFE0000
    3.   PXE Idx=000  Va=FFFFF6FB7DBED000  Contents=2AB000004C2F5867  Hard Pfn=0004C2F5  Attr=---DA--UWEV
    4.   PPE Idx=001  Va=FFFFF6FB7DA00008  Contents=015000004FB80867  Hard Pfn=0004FB80  Attr=---DA--UWEV
    5.   PDE Idx=1FF  Va=FFFFF6FB40001FF8  Contents=025000002A5CB867  Hard Pfn=0002A5CB  Attr=---DA--UWEV
    6.   PTE Idx=1E0  Va=FFFFF680003FFF00  Contents=82D00000001E6025  Hard Pfn=000001E6  Attr=----A--UR-V  <-----
    7.  
    8. 0: kd> !cmkd.ptelist -v 0xfffff78000000000
    9. VA=FFFFF78000000000
    10.   PXE Idx=1EF  Va=FFFFF6FB7DBEDF78  Contents=000000000019D063  Hard Pfn=0000019D  Attr=---DA--KWEV
    11.   PPE Idx=000  Va=FFFFF6FB7DBEF000  Contents=00000000001E8063  Hard Pfn=000001E8  Attr=---DA--KWEV
    12.   PDE Idx=000  Va=FFFFF6FB7DE00000  Contents=00000000001E7063  Hard Pfn=000001E7  Attr=---DA--KWEV
    13.   PTE Idx=000  Va=FFFFF6FBC0000000  Contents=00000000001E6163  Hard Pfn=000001E6  Attr=-G-DA--KWEV  <-----
    Первое, что приходит на ум - страница ядра мапится в юзерспейс, но я попробовал написать код с MapViewOfFile() и обнаружил, что мой процесс отдал клиентскому уже другой физ.фрейм (скопировал?). Вопрос: какой механизм использует Windows для отображения KUSER_SHARED_DATA, и как могут назначаться разные атрибуты одному PFN ?
     
  2. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.486
    Адрес:
    Россия, Нижний Новгород
    Атрибуты назначаются не самой физической странице (у них никаких атрибутов нет), а отображению.
    PFN - это просто число, порядковый номер физической страницы, а все атрибуты описывает "окно", которое на неё смотрит. В данном случае у тебя два разных "окна" - два PTE с разными атрибутами, которые описывают одну и ту же страничку.
    Через юзермодный путь никто не писал, поэтому D = 0, а через ядерный активно пишет само ядро - поэтому у него D = 1.
    И отобразить эту страничку на запись тебе ядро не даст, потому что так ты мог бы сразу испортить что-то во всех процессах, поэтому ядро просто создаёт копию этой странички в адресном пространстве твоего процесса и отдаёт её тебе с запрошенными правами.

    То же самое с DLL'ками: например, ntdll тоже грузится во все процессы по одному и тому же адресу, и тоже её физическая память делится со всеми. Но стоит тебе сделать VirtualProtect и что-то туда записать - ядру прилетает исключение, оно видит, что страничка CoW, создаёт её копию в твоём процессе - и разрешает запись.
    И теперь ты работаешь исключительно со своей копией, а остальные процессы всё так же разделяют память между собой.
     
    Marylin и MaKsIm нравится это.
  3. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Всё это логично, и ты говоришь о типичном маппинге.
    Но в случае с KUSER_SHARED_DATA у страниц ядра/юзера почему-то нет атрибута CoW, и при записи данных из юм в хвост структуры, на моей Win7-x64 данные прямиком уходят в ядро. Видимо это какой-то глюк отладчика WinDbg, поскольку механизм CoW всё-таки работает. Я тестил по такому алго..
    Код (Text):
    1. 0: kd> !process 0 0 Test.exe
    2. PROCESS fffffa8004508310
    3.     SessionId: 1   Cid: 0cb0   Peb: 7fffffdf000  ParentCid: 0e70
    4.     Image: Test.EXE
    5.  
    6. 0: kd> .process /p fffffa8004508310    <-----------// Подключаюсь к своему процессу
    7. Implicit process is now fffffa80`04508310
    8.  
    9. ;//--------- Записи PTE: юзера = FFFFF680003FFF00, и ядра = FFFFF6FBC0000000 ----------------
    10. ;//--------- при этом фрейм один и тот же: PFN = 01E6 ---------------------------------------
    11.  
    12. 0: kd> !cmkd.ptelist -v 7ffe0000
    13. VA=000000007FFE0000
    14.   PDE Idx=1FF  Va=FFFFF6FB40001FF8  Contents=0240000015968867  Hard Pfn=00015968  Attr=---DA--UWEV
    15.   PTE Idx=1E0  Va=FFFFF680003FFF00  Contents=82800000001E6025  Hard Pfn=000001E6  Attr=----A--UR-V
    16.  
    17. 0: kd> !cmkd.ptelist -v 0xfffff78000000000
    18. VA=FFFFF78000000000
    19.   PDE Idx=000  Va=FFFFF6FB7DE00000  Contents=00000000001E7063  Hard Pfn=000001E7  Attr=---DA--KWEV
    20.   PTE Idx=000  Va=FFFFF6FBC0000000  Contents=00000000001E6163  Hard Pfn=000001E6  Attr=-G-DA--KWEV
    21.  
    22. ;//--------- Атрибуты в записях PTE -----------------------------------------------
    23.  
    24. 0: kd> dt _mmpte_hardware FFFFF680003FFF00  <-------- User
    25. nt!_MMPTE_HARDWARE
    26.    +0x000 Valid            : 0y1
    27.    +0x000 Owner            : 0y1
    28.    +0x000 WriteThrough     : 0y0
    29.    +0x000 CacheDisable     : 0y0
    30.    +0x000 Accessed         : 0y1
    31.    +0x000 Dirty            : 0y0
    32.    +0x000 LargePage        : 0y0
    33.    +0x000 Global           : 0y0
    34.    +0x000 CopyOnWrite      : 0y0   <------+---// биты CoW, Write, Execute сброшены
    35.    +0x000 Write            : 0y0   <------+
    36.    +0x000 PageFrameNumber  : 0y000000000000000000000000000111100110 (0x1e6)  <------- PFN
    37.    +0x000 SoftwareWsIndex  : 0y00000111101 (0x3d)
    38.    +0x000 NoExecute        : 0y1
    39.  
    40. 0: kd> dt _mmpte_hardware FFFFF6FBC0000000  <-------- Kernel
    41. nt!_MMPTE_HARDWARE
    42.    +0x000 Valid            : 0y1
    43.    +0x000 Owner            : 0y0
    44.    +0x000 WriteThrough     : 0y0
    45.    +0x000 CacheDisable     : 0y0
    46.    +0x000 Accessed         : 0y1
    47.    +0x000 Dirty            : 0y1
    48.    +0x000 LargePage        : 0y0
    49.    +0x000 Global           : 0y1
    50.    +0x000 CopyOnWrite      : 0y0   <----------// бит CoW сброшен
    51.    +0x000 Write            : 0y1
    52.    +0x000 PageFrameNumber  : 0y000000000000000000000000000111100110 (0x1e6)
    53.    +0x000 SoftwareWsIndex  : 0y00000000000 (0)
    54.    +0x000 NoExecute        : 0y0
    И вообще атрибут CoW в дефолте назначается страницам, или только после VirtualProtect() + Write уже выделенной странице? Ладно, пробуем что-нибудь записать в хвост структуры. У меня в ней 75 элементов, которые занимают 0x05f0 байт:
    Код (Text):
    1. 0: kd> dt _kuser_shared_data 7ffe0000 TickCountMultiplier -v
    2. struct _KUSER_SHARED_DATA, 75 elements, 0x5f0 bytes
    3.    +0x004 TickCountMultiplier : 0xf99a027
    4.  
    5. 0: kd> ea 7ffe05f0 "wasm.in"  <-------------- Запись строки в хвост!
    6.  
    7. 0: kd> db 7ffe05f0 L20
    8. 00000000`7ffe05f0  77 61 73 6d 2e 69 6e 00-00 00 00 00 00 00 00 00  wasm.in.........
    9. 00000000`7ffe0600  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    10.  
    11. 0: kd> db 0xfffff780000005f0 L20
    12. fffff780`000005f0  77 61 73 6d 2e 69 6e 00-00 00 00 00 00 00 00 00  wasm.in.........  <---- Отобразилась в ядре!
    13. fffff780`00000600  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    Расширение CMKD отладчика от "CodeMachine" выводит карту регионов ядерной памяти KVAS (Kernel Virtual Addr Space) - как видим это "SharedSystemPage", причём этот атрибут имеет только страница KUSER_SHARED_DATA:
    Код (Text):
    1. 0: kd> !cmkd.kvas
    2. ### Start            End                                  Length Type
    3. 000 ffff080000000000 fffff67fffffffff     ee8000000000 ( 238 TB) SystemSpace
    4. 001 fffff68000000000 fffff6ffffffffff       8000000000 ( 512 GB) PageTables
    5. 002 fffff70000000000 fffff77fffffffff       8000000000 ( 512 GB) HyperSpace
    6. 003 fffff78000000000 fffff78000000fff             1000 (   4 KB) SharedSystemPage  <-------//
    7. 004 fffff78000001000 fffff7ffffffffff       7ffffff000 ( 511 GB) CacheWorkingSet
    8. 005 fffff80000000000 fffff87fffffffff       8000000000 ( 512 GB) LoaderMappings
    9. 006 fffff88000000000 fffff89fffffffff       2000000000 ( 128 GB) SystemPTEs
    10. 007 fffff8a000000000 fffff8bfffffffff       2000000000 ( 128 GB) PagedPool
    11. 008 fffff90000000000 fffff97fffffffff       8000000000 ( 512 GB) SessionSpace
    12. 009 fffff98000000000 fffffa7fffffffff      10000000000 (   1 TB) DynamicKernelVa
    13. 010 fffffa8000000000 fffffa80038fffff          3900000 (  57 MB) PfnDatabase
    14. 011 fffffa8003800000 fffffa80c03fffff         bcc00000 (   2 GB) NonPagedPool
    15. 012 ffffffffffc00000 ffffffffffffffff           400000 (   4 MB) HalReserved
    16.  
    17. 0: kd> !cmkd.kvas 0xfffff78000000000
    18. kvas : Show region containing fffff78000000000
    19. ### Start            End                                  Length Type
    20. 003 fffff78000000000 fffff78000000fff             1000 (   4 KB) SharedSystemPage
    Но например структуры "gSharedInfo, GdiSharedHandleTable, KernelCallbackTable" тоже мапятся из ядра в юзерспейс, но почему-то здесь не отображаются. Выходит у них какой-то другой механизм проецирования? Какие вообще бывают?

    А вот атрибуты в PTE системных DLL - здесь тоже бит CoW сброшен:
    Код (Text):
    1. 0: kd> !peb @$peb
    2. PEB at 000007fffffdf000
    3.     BeingDebugged:            Yes
    4.     ImageBaseAddress:         0000000000400000
    5.     Ldr                       00000000777b2e40
    6.     Ldr.Initialized:          Yes
    7.             Base  TimeStamp                      Module
    8.           400000  6770ae2b Dec 29 08:04:27 2024  F:\Test.EXE
    9.         77680000  66f77d60 Sep 28 08:52:00 2024  C:\Windows\SYSTEM32\ntdll.dll
    10.         77460000  66f77da6 Sep 28 08:53:10 2024  C:\Windows\system32\kernel32.dll
    11.      7fefd250000  66f77da7 Sep 28 08:53:11 2024  C:\Windows\system32\KERNELBASE.dll  <---------//
    12.      7feff750000  56f58ae0 Mar 26 00:00:48 2016  C:\Windows\system32\msvcrt.dll
    13.  
    14. 0: kd> !cmkd.ptelist  7fefd250000 -v
    15. VA=000007FEFD250000
    16.   PDE Idx=1E9 Va=FFFFF6FB41FFBF48 Contents=1200000008464867 Hard Pfn=00008464 Attr=---DA--UWEV
    17.   PTE Idx=050 Va=FFFFF683FF7E9280 Contents=8F2000009C8F7025 Hard Pfn=0009C8F7 Attr=----A--UR-V
    18.  
    19. 0: kd> dt _mmpte_hardware FFFFF683FF7E9280
    20. nt!_MMPTE_HARDWARE
    21.    +0x000 Valid            : 0y1
    22.    +0x000 Owner            : 0y1
    23.    +0x000 WriteThrough     : 0y0
    24.    +0x000 CacheDisable     : 0y0
    25.    +0x000 Accessed         : 0y1
    26.    +0x000 Dirty            : 0y0
    27.    +0x000 LargePage        : 0y0
    28.    +0x000 Global           : 0y0
    29.    +0x000 CopyOnWrite      : 0y0  <-------- Бит CoW сброшен
    30.    +0x000 Write            : 0y0
    31.    +0x000 PageFrameNumber  : 0y000000000000000010011100100011110111 (0x9c8f7)
    32.    +0x000 SoftwareWsIndex  : 0y00011110010 (0xf2)
    33.    +0x000 NoExecute        : 0y1
    В общем что-то не складывается пока полная картина..
    Для тестов я использовал такой код: 2 одинаковых процесса, просто во втором закоментировал VirtualProtect() и просто читал из адреса 0x7ffe05f0. Как результат CoW работает, и строка второму процессу не доступна, чего собственно и стоило ожидать.
    Код (ASM):
    1. format   pe64 console
    2. include 'win64ax.inc'
    3. entry    start
    4. ;//-----------
    5. .data
    6. OldProtect      dq  0
    7. ;//-----------
    8. section '.text' code readable executable
    9. start:   sub     rsp,8
    10.         cinvoke  _getch
    11.  
    12.          invoke  VirtualProtect,0x7ffe0000,0x1000,PAGE_READWRITE,OldProtect
    13.         cinvoke  printf,<10,' Ret: %x'>,eax   ; возвращает ОК=1
    14.  
    15.          mov     rax,'wasm.in'
    16.          mov     qword[0x7ffe05f0],rax
    17.  
    18.         cinvoke  printf,<10,' %s'>,0x7ffe05f0
    19.  
    20. @exit:  cinvoke  _getch
    21.         cinvoke  exit, 0
    22. ;//-----------
    23. section '.idata' import data readable
    24. library  msvcrt,'msvcrt.dll',kernel32,'kernel32.dll'
    25. include 'api\msvcrt.inc'
    26. include 'api\kernel32.inc'
    27.  
     
  4. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    137
    Механизм проецирования можно посмотреть, тут инит ядра, тут мап в процесс.

    Не известно как это работает, но открыть на запись usd нельзя, иначе можно контролировать время и инжектить в процессы.
     
    Marylin нравится это.
  5. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Интересно однако работает механизм "CopyOnWrite" на физ.уровне.
    Сейчас проверил атрибуты в РТЕ до и после вызова VirtualProtect() - таблица страниц не меняется вообще, а вот номер фрейма PFN в записи РТЕ уже становится другой. То-есть вирт.адрес остаётся прежний, а данные с него копируются в один из свободных фреймов физ.памяти:
    Код (Text):
    1. ;//------------ Смотрю атрибуты в РТЕ до вызова VirtualProtect() --------
    2. ;//------------ РТЕ = FFFFF680003FFF00, PFN = 01E6 ----------------------
    3.  
    4. 0: kd> !pte 7ffe0000
    5.                                            VA 000000007ffe0000
    6. PXE at FFFFF6FB7DBED000    PPE at FFFFF6FB7DA00008    PDE at FFFFF6FB40001FF8    PTE at FFFFF680003FFF00
    7. contains 02D00000A4F07867  contains 03100000BAA4A867  contains 032000008A84B867  contains 83D00000001E6005
    8. pfn a4f07     ---DA--UWEV  pfn baa4a     ---DA--UWEV  pfn 8a84b     ---DA--UWEV  pfn 1e6       -------UR-V
    9.  
    10. 0: kd> dt _mmpte_hardware FFFFF680003FFF00
    11. nt!_MMPTE_HARDWARE
    12.    +0x000 Valid            : 0y1
    13.    +0x000 Owner            : 0y1
    14.    +0x000 WriteThrough     : 0y0
    15.    +0x000 CacheDisable     : 0y0
    16.    +0x000 Accessed         : 0y0  <----------
    17.    +0x000 Dirty            : 0y0  <----------
    18.    +0x000 LargePage        : 0y0
    19.    +0x000 Global           : 0y0
    20.    +0x000 CopyOnWrite      : 0y0  <----------
    21.    +0x000 Write            : 0y0  <----------
    22.    +0x000 PageFrameNumber  : 0y000000000000000000000000000111100110 (0x1e6)  <----------
    23.    +0x000 SoftwareWsIndex  : 0y00000111101 (0x3d)
    24.    +0x000 NoExecute        : 0y1
    25.  
    26. ;//------------ Теперь атрибуты в РТЕ после VirtualProtect() -------------------
    27. ;//------------ РТЕ тот-же: FFFFF680003FFF00, а вот PFN уже: 12В51С -------------
    28.  
    29. 0: kd> !pte 7ffe0000
    30.                                            VA 000000007ffe0000
    31. PXE at FFFFF6FB7DBED000    PPE at FFFFF6FB7DA00008    PDE at FFFFF6FB40001FF8    PTE at FFFFF680003FFF00
    32. contains 02D0000064038867  contains 0310000019BFB867  contains 03200001128BC867  contains 83D000012B51C847
    33. pfn 64038     ---DA--UWEV  pfn 19bfb     ---DA--UWEV  pfn 1128bc    ---DA--UWEV  pfn 12b51c    ---DА--UW-V
    34.  
    35. 0: kd> dt _mmpte_hardware FFFFF680003FFF00
    36. nt!_MMPTE_HARDWARE
    37.    +0x000 Valid            : 0y1
    38.    +0x000 Owner            : 0y1
    39.    +0x000 WriteThrough     : 0y0
    40.    +0x000 CacheDisable     : 0y0
    41.    +0x000 Accessed         : 0y1  <----------
    42.    +0x000 Dirty            : 0y1  <----------
    43.    +0x000 LargePage        : 0y0
    44.    +0x000 Global           : 0y0
    45.    +0x000 CopyOnWrite      : 0y0  <----------
    46.    +0x000 Write            : 0y1  <----------
    47.    +0x000 PageFrameNumber  : 0y000000000000000100101011010100011100 (0x12b51c)  <----------
    48.    +0x000 SoftwareWsIndex  : 0y00000111101 (0x3d)
    49.    +0x000 NoExecute        : 0y1
    Но как показывают логи, бит CoW всё-равно не меняется ни в старом, ни в новом фрейме, и это остаётся загадкой. Инфа от Ahimov с намёком на выгружаемый пул подтолкнула на мысль, что может KUSER_SHARED_DATA юзает аналогичный механизм проекции "PageFile-Backed Sections" как описано у мягких здесь. Но как это проверить - пока хз.

    По сути записи в РТЕ могут быть разного типа, а не только "Hard".
    Например "Soft" описывает сброшенную в файл-подкачки "Pagefile" страницу, и т.д. Но опять-же при просмотре РТЕ как "Soft", вместо валидной маски я получую какую-то лажу (поле PageFileHigh не может иметь такое значение). Да и по ссылке выше система выставляет бит "Owner" именно в записи "Hard". В общем нужно копать дальше..
    Код (Text):
    1. 0: kd> dt _mmpte FFFFF680003FFF00 -b
    2. nt!_MMPTE
    3.    +0x000 u                : <unnamed-tag>
    4.       +0x000 VolatileLong     : 0x83d00001`2b51c847
    5.       +0x000 Hard             : _MMPTE_HARDWARE
    6.          +0x000 Valid            : 0y1
    7.          +0x000 Owner            : 0y1
    8.          +0x000 WriteThrough     : 0y0
    9.          +0x000 CacheDisable     : 0y0
    10.          +0x000 Accessed         : 0y1
    11.          +0x000 Dirty            : 0y1
    12.          +0x000 LargePage        : 0y0
    13.          +0x000 Global           : 0y0
    14.          +0x000 CopyOnWrite      : 0y0
    15.          +0x000 Write            : 0y1
    16.          +0x000 PageFrameNumber  : 0y000000000000000100101011010100011100 (0x12b51c)
    17.          +0x000 SoftwareWsIndex  : 0y00000111101 (0x3d)
    18.          +0x000 NoExecute        : 0y1
    19.  
    20.       +0x000 Soft             : _MMPTE_SOFTWARE
    21.          +0x000 Valid            : 0y1
    22.          +0x000 Unused           : 0y11
    23.          +0x000 InStore          : 0y0
    24.          +0x000 SwizzleBit       : 0y0
    25.          +0x000 Protection       : 0y00010 (0x2)
    26.          +0x000 Prototype        : 0y0
    27.          +0x000 Transition       : 0y1
    28.          +0x000 PageFileLow      : 0y1100
    29.          +0x000 UsedPageTableEntries : 0y1101010001 (0x351)
    30.          +0x000 Reserved         : 0y001010 (0xa)
    31.          +0x000 PageFileHigh     : 0y10000011110100000000000000000001 (0x83d00001)
    32.  
    33.       +0x000 Proto            : _MMPTE_PROTOTYPE
    34.          +0x000 Valid            : 0y1
    35.          +0x000 ReadOnly         : 0y1
    36.          +0x000 Unused0          : 0y01
    37.          +0x000 SwizzleBit       : 0y0
    38.          +0x000 Protection       : 0y00010 (0x2)
    39.          +0x000 Prototype        : 0y0
    40.          +0x000 Unused1          : 0y11001 (0x19)
    41.          +0x000 ProtoAddress     : 0y100000111101000000000000000000010010101101010001 (0x83d000012b51)
    42.  
    43.       +0x000 TimeStamp        : _MMPTE_TIMESTAMP
    44.          +0x000 MustBeZero       : 0y1
    45.          +0x000 Unused           : 0y011
    46.          +0x000 SwizzleBit       : 0y0
    47.          +0x000 Protection       : 0y00010 (0x2)
    48.          +0x000 Prototype        : 0y0
    49.          +0x000 Transition       : 0y1
    50.          +0x000 PageFileLow      : 0y1100
    51.          +0x000 Reserved         : 0y0010101101010001 (0x2b51)
    52.          +0x000 GlobalTimeStamp  : 0y10000011110100000000000000000001 (0x83d00001)
    53.  
    54.       +0x000 Trans            : _MMPTE_TRANSITION
    55.          +0x000 Valid            : 0y1
    56.          +0x000 Write            : 0y1
    57.          +0x000 WriteThrough     : 0y1
    58.          +0x000 CacheDisable     : 0y0
    59.          +0x000 SwizzleBit       : 0y0
    60.          +0x000 Protection       : 0y00010 (0x2)
    61.          +0x000 Prototype        : 0y0
    62.          +0x000 Transition       : 0y1
    63.          +0x000 PageFrameNumber  : 0y000000000000000100101011010100011100 (0x12b51c)
    64.          +0x000 Unused           : 0y1000001111010000 (0x83d0)
    65.  
    66.       +0x000 Subsect          : _MMPTE_SUBSECTION
    67.          +0x000 Valid            : 0y1
    68.          +0x000 Unused0          : 0y011
    69.          +0x000 SwizzleBit       : 0y0
    70.          +0x000 Protection       : 0y00010 (0x2)
    71.          +0x000 Prototype        : 0y0
    72.          +0x000 Unused1          : 0y11001 (0x19)
    73.          +0x000 SubsectionAddress: 0y100000111101000000000000000000010010101101010001 (0x83d000012b51)
    74.  
    75.       +0x000 List             : _MMPTE_LIST
    76.          +0x000 Valid            : 0y1
    77.          +0x000 OneEntry         : 0y1
    78.          +0x000 filler0          : 0y01
    79.          +0x000 SwizzleBit       : 0y0
    80.          +0x000 Protection       : 0y00010 (0x2)
    81.          +0x000 Prototype        : 0y0
    82.          +0x000 Transition       : 0y1
    83.          +0x000 filler1          : 0y00101011010100011100 (0x2b51c)
    84.          +0x000 NextEntry        : 0y10000011110100000000000000000001 (0x83d00001)
    85. 0: kd>
     
  6. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    137
    GdiSharedHandleTable проецируется как секция вот:
    Код (Text):
    1.             // map a READ_ONLY view of the hmgr shared handle table into the
    2.             // process's address space
    3.             //
    4.  
    5.             PVOID BaseAddress = NULL;
    6.             SIZE_T CommitSize =  0;
    7.             OBJECT_ATTRIBUTES ObjectAttributes;
    8.             UNICODE_STRING UnicodeString;
    9.             HANDLE SectionHandle = NULL;
    10.  
    11.             ntStatus = ObOpenObjectByPointer( gpHmgrSharedHandleSection,
    12.                                             0L,
    13.                                             (PACCESS_STATE) NULL,
    14.                                             SECTION_ALL_ACCESS,
    15.                                             (POBJECT_TYPE) NULL,
    16.                                             KernelMode,
    17.                                             &SectionHandle);
    18.  
    19.             if (NT_SUCCESS(ntStatus))
    20.             {
    21.                 ntStatus = ZwMapViewOfSection(
    22.                                 SectionHandle,
    23.                                 NtCurrentProcess(),
    24.                                 &BaseAddress,
    25.                                 0L,
    26.                                 0L,
    27.                                 NULL,
    28.                                 &CommitSize,
    29.                                 ViewUnmap,
    30.                                 0L,
    31.                                 PAGE_READONLY
    32.                                 );
    33.  
    34.                 if (NT_SUCCESS(ntStatus))
    35.                 {
    36.                     //
    37.                     // set table address
    38.                     //
    39.                     // we must set the GdiSharedHandleTable value
    40.                     // to the shared table pointer so that if GDI32 gets
    41.                     // unloaded and re-loaded it can still get the pointer.
    42.                     //
    43.                     // NOTE: we also depend on this pointer being initialized
    44.                     // *BEFORE* we make any GDI or USER call to the kernel
    45.                     // (which has the automatic side-effect of calling this
    46.                     // routine.
    47.                     //
    48.  
    49.                     Peb->GdiSharedHandleTable =
    50.                             (PVOID)BaseAddress;
    51.                 }
    KernelCallbackTable не может загружать ядро, так как это таблица ссылок на интернал(не экспортируемые, в отличие от Ki*) юзер процедуры. Для такой операции вначале юзер слой должен передать массив в ядро, а оно вернуть назад этот массив. В этих действиях нужды небыло и указатель на таблицу загружался при инит юзер, может в новых версиях поменялось ?
     
    Marylin нравится это.
  7. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Ahimov, ну вот здесь тоже у ZwMapViewOfSection() атрибут стоит "PAGE_READONLY", в то время как для CoW нужен "PAGE_WRITECOPY". Каким образом/механизмом расшариваются такие секции, когда я пытаюсь получить к ней доступ на запись в своём процессе?
    --- Сообщение объединено, 30 дек 2024 ---
    Блин, сейчас переписал свой тест/код, пытаясь в VirtualProtect() вместо "PAGE_READWRITE" установить "PAGE_WRITECOPY". Оказывается для структуры KUSER_SHARED_DATA система запрещает данный атрибут, отправив прожку в крэш. Тогда создал ещё одну секцию "МАР" с дефолтным атрибутом(R) - это сработало, и в записи РТЕ получил заветный бит CoW. Теперь сомнений нет, что KUSER_SHARED_DATA мапится по какой-то другой схеме, не используя стандартный "CopyOnWrite". Осталось узнать этот механизм..
    Код (ASM):
    1. format   pe64 console
    2. include 'win64ax.inc'
    3. entry    start
    4. ;//-----------
    5. section '.MAP' data readable
    6. map             db   0
    7. ;//-----------
    8. section '.data' data readable writeable
    9. OldProtect      dq  0
    10. ;//-----------
    11. section '.text' code readable executable
    12. start:   sub     rsp,8
    13.         cinvoke  _getch
    14.  
    15.          invoke  VirtualProtect,map,0x1000,\;0x7ffe0000,0x1000,\
    16.                                 PAGE_WRITECOPY,OldProtect
    17.         cinvoke  printf,<10,' Ret: %x'>,eax
    18.  
    19.          invoke  VirtualProtect,0x7ffe0000,0x1000,\
    20.                                 PAGE_READWRITE,OldProtect
    21.         cinvoke  printf,<10,' Ret: %x'>,eax
    22.  
    23.          mov     rax,'wasm.in'
    24.          mov     qword[0x7ffe05f0],rax
    25.  
    26.         cinvoke  printf,<10,' %s'>,0x7ffe05f0
    27. @exit:  cinvoke  _getch
    28.         cinvoke  exit, 0
    29. ;//-----------
    30. section '.idata' import data readable
    31. library  msvcrt,'msvcrt.dll',kernel32,'kernel32.dll'
    32. include 'api\msvcrt.inc'
    33. include 'api\kernel32.inc'
    Далее логи в отладчике.
    Секция "МАР" идёт первой и расположена по адресу 0x00401000:
    Код (Text):
    1.  
    2. ;//----------- до VirtualProtect() -----------------------------
    3. 0: kd> !pte 401000
    4.                                            VA 0000000000401000
    5. PXE at FFFFF6FB7DBED000    PPE at FFFFF6FB7DA00000    PDE at FFFFF6FB40000010    PTE at FFFFF68000002008
    6. contains 02E0000085DCC867  contains 02F00000AEECD867  contains 0300000039BCE867  contains 9940000036BD5025
    7. pfn 85dcc     ---DA--UWEV  pfn aeecd     ---DA--UWEV  pfn 39bce     ---DA--UWEV  pfn 36bd5     ----A--UR-V
    8.  
    9. 0: kd> dt _mmpte_hardware FFFFF68000002008
    10. nt!_MMPTE_HARDWARE
    11.    +0x000 Valid            : 0y1
    12.    +0x000 Owner            : 0y1
    13.    +0x000 WriteThrough     : 0y0
    14.    +0x000 CacheDisable     : 0y0
    15.    +0x000 Accessed         : 0y1
    16.    +0x000 Dirty            : 0y0
    17.    +0x000 LargePage        : 0y0
    18.    +0x000 Global           : 0y0
    19.    +0x000 CopyOnWrite      : 0y0  <-------------- CoW сброшен
    20.    +0x000 Write            : 0y0
    21.    +0x000 PageFrameNumber  : 0y000000000000000000110110101111010101 (0x36bd5)
    22.    +0x000 SoftwareWsIndex  : 0y00110010100 (0x194)
    23.    +0x000 NoExecute        : 0y1
    24.  
    25. ;//----------- после VirtualProtect() ------------------------------
    26. ;//----------- в атрибутах РТЕ появился бит(С) ---------------------
    27.  
    28. 0: kd> !pte 401000
    29.                                            VA 0000000000401000
    30. PXE at FFFFF6FB7DBED000    PPE at FFFFF6FB7DA00000    PDE at FFFFF6FB40000010    PTE at FFFFF68000002008
    31. contains 02E0000085DCC867  contains 02F00000AEECD867  contains 0300000039BCE867  contains 9940000036BD5225
    32. pfn 85dcc     ---DA--UWEV  pfn aeecd     ---DA--UWEV  pfn 39bce     ---DA--UWEV  pfn 36bd5     C---A--UR-V
    33.  
    34. 0: kd> dt _mmpte_hardware FFFFF68000002008
    35. nt!_MMPTE_HARDWARE
    36.    +0x000 Valid            : 0y1
    37.    +0x000 Owner            : 0y1
    38.    +0x000 WriteThrough     : 0y0
    39.    +0x000 CacheDisable     : 0y0
    40.    +0x000 Accessed         : 0y1
    41.    +0x000 Dirty            : 0y0
    42.    +0x000 LargePage        : 0y0
    43.    +0x000 Global           : 0y0
    44.    +0x000 CopyOnWrite      : 0y1  <-------------- CoW взведён!
    45.    +0x000 Write            : 0y0
    46.    +0x000 PageFrameNumber  : 0y000000000000000000110110101111010101 (0x36bd5)
    47.    +0x000 SoftwareWsIndex  : 0y00110010100 (0x194)
    48.    +0x000 NoExecute        : 0y1
     
  8. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Вот ещё вариант, где к предыдущим добавлены 2 команды: !pfn и !vad.
    Первую нашёл по этому линку где говорится, что расшаренные/промапленные страницы могут использовать тип РТЕ "Prototype" - в данном случае у себя получил "Blink/Share count = 00000036" до VirtualProtect(), и на 1 один меньше 35 после (когда сработал CoW).

    А со второй !vad ситуация вообще не понятна - здесь атрибуты у системных DLL стоят уже "WRITECOPY" (хотя в записях РТЕ их нету), однако до VirtualProtect() приватных страниц было 95, а после стало 99 (сумма в столбце Commit). Настораживает так-же тип "Pagefile-backed section" для файлов подкачки, и их кол-во. В поле "Start" указаны адреса, без младших 12-бит:
    Код (Text):
    1. 0: kd> !process 0 0 Test.exe
    2. PROCESS fffffa8003efb7b0
    3.     SessionId: 1  Cid: 0f50    Peb: 7fffffdf000  ParentCid: 0880
    4.     DirBase: 111d60000  ObjectTable: fffff8a00388d100  HandleCount: 7.
    5.     Image: Test.EXE
    6.  
    7. 0: kd> !cmkd.ptelist 0xfffff78000000000 -v
    8. ptelist : Using fffff78000000000 as VA=FFFFF78000000000
    9.   PXE Idx=1EF Va=FFFFF6FB7DBEDF78 Contents=000000000019D063 Hard Pfn=0000019D Attr=---DA--KWEV
    10.   PPE Idx=000 Va=FFFFF6FB7DBEF000 Contents=00000000001E8063 Hard Pfn=000001E8 Attr=---DA--KWEV
    11.   PDE Idx=000 Va=FFFFF6FB7DE00000 Contents=00000000001E7063 Hard Pfn=000001E7 Attr=---DA--KWEV
    12.   PTE Idx=000 Va=FFFFF6FBC0000000 Contents=00000000001E6163 Hard Pfn=000001E6 Attr=-G-DA--KWEV
    13.  
    14. 0: kd> !pfn 000001E6
    15.     PFN 000001E6 at address FFFFFA8000005B20
    16.     Flink  FFFFF800029FC680  Blink/Share count 00000036  PteAddress FFFFF6FBC0000000
    17.     Reference count  0001    Used entry count  0000      Cached  Color 0  Priority 5
    18.     Restore pte  00000080    Containing page   0001E7    Active      PRW
    19.     Shared  ReadInProgress   WriteInProgress
    20.  
    21. 0: kd> !process fffffa8003efb7b0 1
    22. PROCESS fffffa8003efb7b0
    23. ..........
    24.        VadRoot fffffa8003e38170. Vads 22.  Clone 0. Private 95. Modified 0. Locked 0.
    25. ..........
    26.  
    27. 0: kd> !vad fffffa8003e38170
    28. VAD             level      start      end    commit
    29. fffffa8003f4bd70 ( 3)         10       1f         0 Mapped       READWRITE          Pagefile-backed section
    30. fffffa80045daf80 ( 4)         20       2f         0 Mapped       READWRITE          Pagefile-backed section
    31. fffffa8004291d60 ( 2)         30       6f         6 Private      READWRITE
    32. fffffa80045b76a0 ( 3)         70       73         0 Mapped       READONLY           Pagefile-backed section
    33. fffffa8004111810 ( 1)         80       80         1 Private      READWRITE
    34. fffffa8003e61180 ( 4)         90       f6         0 Mapped       READONLY           \Windows\System32\locale.nls
    35. fffffa800560c4b0 ( 3)        120      12f         6 Private      READWRITE
    36. fffffa80040e8110 ( 5)        130      22f        32 Private      READWRITE
    37. fffffa80040e4160 ( 4)        2f0      2ff         6 Private      READWRITE
    38. fffffa8003c67980 ( 2)        400      403         2 Mapped  Exe  EXECUTE_WRITECOPY  \Test.EXE
    39. fffffa8003c3a520 ( 4)      77830    7794e         4 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\kernel32.dll
    40. fffffa800558d150 ( 3)      77950    77aee        15 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\ntdll.dll
    41. fffffa80045dc1d0 ( 4)      7efe0    7f0df         0 Mapped       READONLY           Pagefile-backed section
    42. fffffa8003e38170 ( 0)      7f0e0    7ffdf         0 Private      READONLY
    43. fffffa80056ffc10 ( 3)      7ffe0    7ffef        -1 Private      READONLY      <-------------------- KUSER_SHARED_DATA
    44. fffffa80041b1f70 ( 2)      7fffb    7fffb         1 Private      READWRITE
    45. fffffa8004465dc0 ( 4)   7fefd4f0 7fefd556         3 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\KernelBase.dll
    46. fffffa8004305160 ( 3)   7fefd9d0 7fefda6e         7 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\msvcrt.dll
    47. fffffa8004515e30 ( 4)   7feffc50 7feffc50         0 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\apisetschema.dll
    48. fffffa80041b4d60 ( 1)   7fffffb0 7fffffd2         0 Mapped       READONLY           Pagefile-backed section
    49. fffffa8004305700 ( 3)   7fffffdd 7fffffde         2 Private      READWRITE
    50. fffffa800453c5e0 ( 2)   7fffffdf 7fffffdf         1 Private      READWRITE
    51.  
    52. Total VADs: 22   Average level: 3   Maximum depth: 5
    53.  
    54. ;//------------------------------------------------------------------------------
    55. ;//----------------- После VirtualProtect() -------------------------------------
    56. ;//------------------------------------------------------------------------------
    57.  
    58. 0: kd> !process fffffa8004615060 1
    59. PROCESS fffffa8004615060
    60. ..........
    61.        VadRoot fffffa8003e38170 Vads 22 Clone 0 Private 99. Modified 0. Locked 0.
    62. ..........
    63.  
    64. 0: kd> !pfn 000001E6
    65.     PFN 000001E6 at address FFFFFA8000005B20
    66.     Flink  FFFFF800029FC680  Blink/Share count 00000035  PteAddress FFFFF6FBC0000000
    67.     Reference count  0001    Used entry count  0000      Cached  Color 0  Priority 5
    68.     Restore pte  00000080    Containing page   0001E7    Active      PRW
    69.     Shared  ReadInProgress   WriteInProgress
    70.  
    71. 0: kd> !vad fffffa8003e38170
    72. VAD             level      start      end    commit
    73. fffffa8003f4bd70 ( 3)         10       1f         0 Mapped       READWRITE          Pagefile-backed section
    74. fffffa80045daf80 ( 4)         20       2f         0 Mapped       READWRITE          Pagefile-backed section
    75. fffffa8004291d60 ( 2)         30       6f         6 Private      READWRITE
    76. fffffa80045b76a0 ( 3)         70       73         0 Mapped       READONLY           Pagefile-backed section
    77. fffffa8004111810 ( 1)         80       80         1 Private      READWRITE
    78. fffffa8003e61180 ( 4)         90       f6         0 Mapped       READONLY           \Windows\System32\locale.nls
    79. fffffa800560c4b0 ( 3)        120      12f         6 Private      READWRITE
    80. fffffa80040e8110 ( 5)        130      22f        32 Private      READWRITE
    81. fffffa80040e4160 ( 4)        2f0      2ff         8 Private      READWRITE
    82. fffffa8003c67980 ( 2)        400      403         2 Mapped  Exe  EXECUTE_WRITECOPY  \Test.EXE
    83. fffffa8003c3a520 ( 4)      77830    7794e         4 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\kernel32.dll
    84. fffffa800558d150 ( 3)      77950    77aee        15 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\ntdll.dll
    85. fffffa80045dc1d0 ( 4)      7efe0    7f0df         0 Mapped       READONLY           Pagefile-backed section
    86. fffffa8003e38170 ( 0)      7f0e0    7ffdf         0 Private      READONLY
    87. fffffa80056ffc10 ( 3)      7ffe0    7ffef        -1 Private      READONLY
    88. fffffa80041b1f70 ( 2)      7fffb    7fffb         1 Private      READWRITE
    89. fffffa8004465dc0 ( 4)   7fefd4f0 7fefd556         3 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\KernelBase.dll
    90. fffffa8004305160 ( 3)   7fefd9d0 7fefda6e         7 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\msvcrt.dll
    91. fffffa8004515e30 ( 4)   7feffc50 7feffc50         0 Mapped  Exe  EXECUTE_WRITECOPY  \Windows\System32\apisetschema.dll
    92. fffffa80041b4d60 ( 1)   7fffffb0 7fffffd2         0 Mapped       READONLY           Pagefile-backed section
    93. fffffa8004305700 ( 3)   7fffffdd 7fffffde         2 Private      READWRITE
    94. fffffa800453c5e0 ( 2)   7fffffdf 7fffffdf         1 Private      READWRITE
    95.  
    96. Total VADs: 22   Average level: 3   Maximum depth: 5
     
    Последнее редактирование: 4 янв 2025