ExGenRandom — Генератор псевдослучайных чисел ядра Windows NT

Тема в разделе "WASM.RESEARCH", создана пользователем galenkane, 3 июн 2026 в 01:16.

  1. galenkane

    galenkane Active Member

    Публикаций:
    4
    Регистрация:
    13 янв 2017
    Сообщения:
    475
    ExGenRandom — Генератор псевдослучайных чисел ядра Windows NT
    ОС: Windows 11 Build 26100 (ARM64)
    Отладчик: WinDbg Preview (Kernel Debugging via Serial)
    Целевая архитектура: ARM64 (Qualcomm Snapdragon)
    Экспорт nt!ExGenRandom — это фундаментальный генератор псевдослучайных чисел (PRNG) ядра Windows NT. На нём строятся все основные API генерации случайных чисел как в kernel-mode (RtlRandom, RtlRandomEx), так и косвенно в user-mode через криптографические примитивы. В этом исследовании разберём алгоритм целиком — от спинлока до финального XOR.

    Содержание
    1. Цепочка вызовов
    2. Дизассемблирование ExGenRandom
    3. Алгоритм LFG (Lagged Fibonacci Generator)
    4. Глобальные переменные и структура PRNG
    5. Обёртки: RtlRandom и RtlRandomEx
    6. BCrypt Pipeline и SmCrGenRandom
    7. Глобальные seed-переменные
    8. Спинлок и синхронизация
    9. Ветвь KeBugCheckEx
    10. Сводные таблицы
    11. Сравнение PRNG функций Windows
    12. Практические выводы

    1. Цепочка вызовов
    Код (Text):
    1.  
    2. ntdll!RtlRandom
    3.   └─► nt!RtlRandom
    4.         └─► nt!ExGenRandom (w0=1)
    5.               ├─► nt!KfRaiseIrql (DISPATCH_LEVEL)
    6.               ├─► nt!KiAcquireSpinLockInstrumented / SWPA
    7.               ├─► [LFG Algorithm: sub table[i], table[j] → result]
    8.               ├─► nt!KiReleaseSpinLockInstrumented / STLR
    9.               ├─► nt!KfLowerIrql
    10.               └─► XOR nt!ExpRNGAuxiliarySeed → return
    11. ntdll!RtlRandomEx
    12.   └─► nt!RtlRandomEx
    13.         └─► nt!ExGenRandom (w0=1)
    14. nt!BCryptGenRandom
    15.   ├─► nt!ExGetExtensionTable (CNG)
    16.   ├─► nt!KscpCfgCheckUserCallTargetEs (CFG)
    17.   └─► [CNG Provider callback]
    18. nt!SmCrGenRandom
    19.   └─► nt!BCryptGenRandom (tail call)
    20.  

    2. Дизассемблирование ExGenRandom
    Адрес:
    Код (Text):
    1. nt!ExGenRandom = 0xFFFFF801'B4582828
    Прототип:
    Код (Text):
    1. ULONG ExGenRandom(ULONG GeneratorIndex);
    Параметр w0 (GeneratorIndex) определяет, какой из двух генераторов использовать:
    - w0 = 0 — Генератор #0 (общесистемный)
    - w0 = 1 — Генератор #1 (используется RtlRandom/RtlRandomEx)
    Полная дизассембликация:
    Код (Text):
    1.  
    2. nt!ExGenRandom:
    3. ; ═══════════════════════════════════════════
    4. ; Пролог: PAC + сохранение регистров
    5. ; ═══════════════════════════════════════════
    6. fffff801`b4582828  pacibsp                         ; PAC signing
    7. fffff801`b458282c  stp   x19,x20,[sp,#-0x30]!      ; Сохранить callee-saved
    8. fffff801`b4582830  stp   x21,x22,[sp,#0x10]
    9. fffff801`b4582834  str   x23,[sp,#0x20]
    10. fffff801`b4582838  stp   fp,lr,[sp,#-0x10]!
    11. fffff801`b458283c  mov   fp,sp
    12. ; ═══════════════════════════════════════════
    13. ; Загрузка адреса спинлока + выравнивание
    14. ; ═══════════════════════════════════════════
    15. fffff801`b4582840  adrp  x8,nt!WheapSelBuffer+0xc00
    16. fffff801`b4582844  add   x20,x8,#0xC68            ; x20 = SpinLock
    17. fffff801`b4582848  tst   x20,#7                    ; Проверка выравнивания
    18. fffff801`b458284c  mov   w19,w0                     ; w19 = GeneratorIndex
    19. fffff801`b4582850  bne   +0x120                     ; → KeBugCheckEx если не выровнен
    20. ; ═══════════════════════════════════════════
    21. ; Повышение IRQL → DISPATCH_LEVEL (2)
    22. ; ═══════════════════════════════════════════
    23. fffff801`b4582854  mov   w0,#2
    24. fffff801`b4582858  bl    nt!KfRaiseIrql            ; IRQL = DISPATCH_LEVEL
    25. fffff801`b458285c  adrp  x8,nt!PpmPolicyConfigTable+0x140
    26. fffff801`b4582860  add   x21,x8,#0xB00             ; x21 = PpmPolicyConfigTable+0xb04
    27. fffff801`b4582864  ldr   w9,[x21,#4]               ; Флаги instrumentation
    28. fffff801`b4582868  mov   w8,#0x210000
    29. fffff801`b458286c  uxtb  w23,w0                     ; Сохранить старый IRQL в w23
    30. fffff801`b4582870  adrp  x22,nt!PopStateTransitonBlameStack+0x3a0
    31. fffff801`b4582874  tst   w9,w8                      ; Проверка флага 0x210000
    32. fffff801`b4582878  bne   +0x10c                     ; → Instrumented path если флаг установлен
    33. ; ═══════════════════════════════════════════
    34. ; Быстрый путь: SWPA (atomic spinlock)
    35. ; ═══════════════════════════════════════════
    36. fffff801`b458287c  mov   x8,#1
    37. fffff801`b4582880  swpa  x8,x8,[x20]               ; Atomic swap → spinlock
    38. fffff801`b4582884  cbz   x8,+0x10                   ; Если 0 → acquired, прыгаем
    39. fffff801`b4582888  mov   x0,x20                     ; Иначе → ждать
    40. fffff801`b458288c  bl    nt!KxWaitForSpinLockAndAcquire
    41. ; ═══════════════════════════════════════════
    42. ; Проверка: GeneratorIndex == 1 ?
    43. ; ═══════════════════════════════════════════
    44. fffff801`b4582890  cmp   w19,#1
    45. fffff801`b4582894  bne   +0x18                      ; Если != 1 → основной LFG path
    46. ; ═══════════════════════════════════════════
    47. ; Ветвь для Generator #1: проверка pending reseed
    48. ; ═══════════════════════════════════════════
    49. fffff801`b4582898  adrp  x10,nt!WheapSelBuffer+0xc00
    50. fffff801`b458289c  ldr   w8,[x10,#0xC70]            ; PendingReseedCounter
    51. fffff801`b45828a0  cbnz  w8,+0x144                  ; Если != 0 → reseed path
    52. ; ═══════════════════════════════════════════
    53. ; LFG Core: адресация таблицы генератора
    54. ; ═══════════════════════════════════════════
    55. fffff801`b45828a4  adrp  x8,nt!WheapSelBuffer+0xc00
    56. fffff801`b45828a8  add   x8,x8,#0xAA0               ; База PRNG таблиц
    57. fffff801`b45828ac  mov   x9,#0xE4                    ; Размер одного генератора
    58. fffff801`b45828b0  smaddl x12,w19,w9,x8             ; x12 = base + index * 0xE4
    59. ; Загрузка индексов i и j
    60. fffff801`b45828b4  ldp   w9,w8,[x12,#0xDC]          ; w9 = index_i, w8 = index_j
    61. fffff801`b45828b8  cmp   w9,#0x36                    ; Проверка: i < 54?
    62. fffff801`b45828bc  csinceq w11,wzr,w9               ; w11 = i (если i==54 → сброс в 0)
    63. fffff801`b45828c0  cmp   w8,#0x36                    ; Проверка: j < 54?
    64. fffff801`b45828c4  ldr   w9,[x12,w11 uxtw #2]       ; w9 = table[i]
    65. fffff801`b45828c8  csinceq w10,wzr,w8               ; w10 = j (если j==54 → сброс в 0)
    66. fffff801`b45828cc  ldr   w8,[x12,w10 uxtw #2]       ; w8 = table[j]
    67. ; ═══════════════════════════════════════════
    68. ; Вычисление: result = table[i] - table[j]
    69. ; ═══════════════════════════════════════════
    70. fffff801`b45828d0  sub   w19,w9,w8                   ; w19 = table[i] - table[j]
    71. fffff801`b45828d4  str   w19,[x12,w11 uxtw #2]      ; table[i] = result
    72. fffff801`b45828d8  stp   w11,w10,[x12,#0xDC]        ; Сохранить новые i, j
    73. ; ═══════════════════════════════════════════
    74. ; Освобождение спинлока
    75. ; ═══════════════════════════════════════════
    76. fffff801`b45828dc  ldr   w8,[x21,#4]                ; Флаги instrumentation
    77. fffff801`b45828e0  tbnz  w8,#0x10,+0x38             ; Если bit 4 → instrumented release
    78. ; Быстрый путь: STLR (store-release)
    79. fffff801`b45828e4  stlr  xzr,[x20]                   ; SpinLock = 0 (release)
    80. ; ═══════════════════════════════════════════
    81. ; Восстановление IRQL
    82. ; ═══════════════════════════════════════════
    83. fffff801`b45828e8  mov   w0,w23                      ; Старый IRQL
    84. fffff801`b45828ec  bl    nt!KfLowerIrql              ; IRQL restored
    85. ; ═══════════════════════════════════════════
    86. ; Финальный XOR с auxiliary seed
    87. ; ═══════════════════════════════════════════
    88. fffff801`b45828f0  adrp  x8,nt!WheapSelBuffer+0xc00
    89. fffff801`b45828f4  ldr   w8,[x8,#0xC74]             ; ExpRNGAuxiliarySeed (XOR mask)
    90. fffff801`b45828f8  eor   w0,w8,w19                   ; result ^= AuxiliarySeed
    91. ; ═══════════════════════════════════════════
    92. ; Эпилог: AUTIBSP + RET
    93. ; ═══════════════════════════════════════════
    94. fffff801`b45828fc  ldp   fp,lr,[sp],#0x10
    95. fffff801`b4582900  ldr   x23,[sp,#0x20]
    96. fffff801`b4582904  ldp   x21,x22,[sp,#0x10]
    97. fffff801`b4582908  ldp   x19,x20,[sp],#0x30
    98. fffff801`b458290c  autibsp                            ; PAC verify
    99. fffff801`b4582910  ret
    100. ; ═══════════════════════════════════════════
    101. ; Instrumented spinlock release
    102. ; ═══════════════════════════════════════════
    103. fffff801`b4582914  ldr   w8,[x22,#0x930]             ; Instrumentation enabled?
    104. fffff801`b4582918  cbnz  w8,-0x58                    ; Да → обычный STLR release
    105. fffff801`b458291c  ldr   lr,[sp,#8]
    106. fffff801`b4582920  mov   x0,x20
    107. fffff801`b4582924  xpaclri
    108. fffff801`b4582928  mov   x1,lr
    109. fffff801`b458292c  bl    nt!KiReleaseSpinLockInstrumented
    110. fffff801`b4582930  b     -0x54                       ; → restore IRQL
    111. ; ═══════════════════════════════════════════
    112. ; Instrumented spinlock acquire
    113. ; ═══════════════════════════════════════════
    114. fffff801`b4582934  ldr   w8,[x22,#0x930]
    115. fffff801`b4582938  cbnz  w8,-0x64                    ; → SWPA path
    116. fffff801`b458293c  mov   x0,x20
    117. fffff801`b4582940  bl    nt!KiAcquireSpinLockInstrumented
    118. fffff801`b4582944  b     -0x58                       ; → GeneratorIndex check
    119. ; ═══════════════════════════════════════════
    120. ; KeBugCheckEx: невалидное выравнивание
    121. ; ═══════════════════════════════════════════
    122. fffff801`b4582948  adrp  x8,nt!PpmPolicyConfigTable+0x140
    123. fffff801`b458294c  ldr   w8,[x8,#0xD60]
    124. fffff801`b4582950  tbnz  w8,#0,-0x08                 ; Retry если флаг установлен
    125. fffff801`b4582954  mov   x4,#0                       ; P4 = 0
    126. fffff801`b4582958  mov   x3,#8                       ; P3 = 8 (alignment size)
    127. fffff801`b458295c  mov   x2,x20                      ; P2 = SpinLock address
    128. fffff801`b4582960  mov   x1,#0                       ; P1 = 0
    129. fffff801`b4582964  mov   w0,#0x1F6                   ; BugCheck 0x1F6 = INVALID_CALLBACK
    130. fffff801`b4582968  bl    nt!KeBugCheckEx             ; BSOD
    131. ; ═══════════════════════════════════════════
    132. ; Reseed path: вытягивание seed из extra pool
    133. ; ═══════════════════════════════════════════
    134. fffff801`b458296c  sub   w9,w8,#1                    ; Decrement counter
    135. fffff801`b4582970  adrp  x8,nt!WheapSelBuffer+0xc00
    136. fffff801`b4582974  add   x8,x8,#0x760               ; Extra seed pool base
    137. fffff801`b4582978  str   w9,[x10,#0xC70]             ; Store new counter
    138. fffff801`b458297c  add   x8,x8,w9,uxtw #2           ; x8 = pool[counter-1]
    139. fffff801`b4582980  ldr   w19,[x8]                    ; w19 = seed value
    140. fffff801`b4582984  strb  wzr,[x8]                    ; Zero out seed[0]
    141. fffff801`b4582988  strb  wzr,[x8,#1]                 ; Zero out seed[1]
    142. fffff801`b458298c  strb  wzr,[x8,#2]                 ; Zero out seed[2]
    143. fffff801`b4582980  strb  wzr,[x8,#3]                 ; Zero out seed[3]
    144. fffff801`b4582994  b     -0xC4                       ; → Release spinlock
    145.  

    3. Алгоритм LFG (Lagged Fibonacci Generator)
    Ядро ExGenRandom реализует модифицированный алгоритм Lagged Fibonacci Generator (LFG) с параметром taп = 55 (таблица из 55 DWORD значений).
    Математическая модель:
    Код (Text):
    1.  
    2. table[i] = (table[i] - table[j]) mod 2^32
    3. result   = table[i]
    4. i = (i + 1) mod 55
    5. j = (j + 1) mod 55
    6. final    = result XOR AuxiliarySeed
    7.  
    Структура генератора (0xE4 байта):
    СмещениеРазмерОписание
    +0x000xDC (55 DWORD)State table — массив из 55 значений
    +0xDC4 байта (DWORD)Index i — текущая позиция первого лага
    +0xE04 байта (DWORD)Index j — текущая позиция второго лага
    Сброс индексов: Когда индекс достигает 0x36 (54), он сбрасывается в 0 инструкцией
    Код (Text):
    1. csinceq wN, wzr, wN
    — это реализация модульной арифметики
    Код (Text):
    1. index mod 55
    .
    Два генератора:
    ГенераторИндекс (w0)Адрес базыИспользование
    #00WheapSelBuffer+0xAA0Общесистемный (kernel internal)
    #11WheapSelBuffer+0xB84RtlRandom / RtlRandomEx

    4. Глобальные переменные и структура PRNG
    СимволАдресОписание
    PRNG Table Basent!WheapSelBuffer+0xAA0База массива из 2-х LFG генераторов (по 0xE4 байта)
    SpinLocknt!WheapSelBuffer+0xC68Спинлок для синхронизации PRNG (8 байт)
    PendingReseedCounternt!WheapSelBuffer+0xC70Счётчик отложенных reseed операций для генератора #1
    ExpRNGAuxiliarySeednt!WheapSelBuffer+0xC74XOR-маска для финального смешивания результата
    Extra Seed Poolnt!WheapSelBuffer+0x760Дополнительный пул seed-значений (DWORD массив)
    Instrumentation Flagsnt!PpmPolicyConfigTable+0xB04Флаги ETW instrumented spinlock (0x210000)
    Instrumentation Datant!PopStateTransitonBlameStack+0x930Указатель на ETW instrumentation контекст
    BugCheck Flagnt!PpmPolicyConfigTable+0xD60Флаг для retry при невалидном выравнивании
    Дамп AuxiliarySeed (текущее значение):
    Код (Text):
    1.  
    2. nt!WheapSelBuffer+0xC74 (ExpRNGAuxiliarySeed): 0x00000000
    3.  

    5. Обёртки: RtlRandom и RtlRandomEx
    Обе функции идентичны — они являются обёртками, вызывающими
    Код (Text):
    1. ExGenRandom(1)
    и маскирующими результат до 31 бита.
    nt!RtlRandom = 0xFFFFF801'B4B1BD90
    Код (Text):
    1.  
    2. nt!RtlRandom:
    3. fffff801`b4b1bd90  pacibsp
    4. fffff801`b4b1bd94  str   x19,[sp,#-0x10]!
    5. fffff801`b4b1bd98  stp   fp,lr,[sp,#-0x10]!
    6. fffff801`b4b1bd9c  mov   fp,sp
    7. fffff801`b4b1bda0  mov   x19,x0                      ; x19 = &Seed
    8. fffff801`b4b1bda4  mov   w0,#1                        ; GeneratorIndex = 1
    9. fffff801`b4b1bda8  bl    nt!ExGenRandom               ; Вызов LFG PRNG
    10. fffff801`b4b1bdac  and   w0,w0,#0x7FFFFFFF            ; result &= 0x7FFFFFFF (31 бит)
    11. fffff801`b4b1bdb0  str   w0,[x19]                     ; *Seed = result
    12. fffff801`b4b1bdb4  ldp   fp,lr,[sp],#0x10
    13. fffff801`b4b1bdb8  ldr   x19,[sp],#0x10
    14. fffff801`b4b1bdbc  autibsp
    15. fffff801`b4b1bdc0  ret
    16.  
    nt!RtlRandomEx = 0xFFFFF801'B450FBF0
    Код (Text):
    1.  
    2. nt!RtlRandomEx:
    3. fffff801`b450fbf0  pacibsp
    4. fffff801`b450fbf4  str   x19,[sp,#-0x10]!
    5. fffff801`b450fbf8  stp   fp,lr,[sp,#-0x10]!
    6. fffff801`b450fbfc  mov   fp,sp
    7. fffff801`b450fc00  mov   x19,x0                      ; x19 = &Seed
    8. fffff801`b450fc04  mov   w0,#1                        ; GeneratorIndex = 1
    9. fffff801`b450fc08  bl    nt!ExGenRandom               ; Вызов LFG PRNG
    10. fffff801`b450fc0c  and   w0,w0,#0x7FFFFFFF            ; result &= 0x7FFFFFFF (31 бит)
    11. fffff801`b450fc10  str   w0,[x19]                     ; *Seed = result
    12. fffff801`b450fc14  ldp   fp,lr,[sp],#0x10
    13. fffff801`b450fc18  ldr   x19,[sp],#0x10
    14. fffff801`b450fc1c  autibsp
    15. fffff801`b450fc20  ret
    16.  
    Ключевое наблюдение: Дизассембликация RtlRandom и RtlRandomEx полностью идентична — это одни и те же инструкции по разным адресам. Обе вызывают
    Код (Text):
    1. ExGenRandom(1)
    и маскируют результат до 31 бита
    Код (Text):
    1. & 0x7FFFFFFF
    . Это означает, что RtlRandomEx не предоставляет криптографически более стойкий результат по сравнению с RtlRandom — это просто второй экземпляр той же функции.

    6. BCrypt Pipeline и SmCrGenRandom
    nt!BCryptGenRandom = 0xFFFFF801'B4760B40
    Код (Text):
    1.  
    2. nt!BCryptGenRandom:
    3. fffff801`b4760b40  pacibsp
    4. fffff801`b4760b44  stp   x19,x20,[sp,#-0x20]!
    5. fffff801`b4760b48  stp   x21,x22,[sp,#0x10]
    6. fffff801`b4760b4c  stp   fp,lr,[sp,#-0x10]!
    7. fffff801`b4760b50  mov   fp,sp
    8. fffff801`b4760b54  adrp  x19,nt!SepTokenPolicyCounter+0xe0
    9. fffff801`b4760b58  ldr   x0,[x19,#0xD0]              ; CNG Extension Table
    10. fffff801`b4760b5c  mov   x22,x1                       ; Buffer
    11. fffff801`b4760b60  mov   w21,w2                       ; Size
    12. fffff801`b4760b64  ldr   w20,[pc+0x58]                ; Tag
    13. fffff801`b4760b68  bl    nt!ExGetExtensionTable       ; Получить CNG provider
    14. fffff801`b4760b6c  mov   x8,x0
    15. fffff801`b4760b70  cbz   x8,+0x34                     ; Если NULL → fallback
    16. ; Вызов CNG provider через CFG
    17. fffff801`b4760b74  ldr   x8,[x8,#0xA0]               ; Генератор random
    18. fffff801`b4760b78  mov   w3,#2                        ; Flags
    19. fffff801`b4760b7c  mov   w2,w21                       ; Size
    20. fffff801`b4760b80  mov   x1,x22                       ; Buffer
    21. fffff801`b4760b84  mov   x0,#0                        ; hAlgorithm = NULL
    22. fffff801`b4760b88  mov   x15,x8                       ; Target function
    23. fffff801`b4760b8c  bl    nt!KscpCfgCheckUserCallTargetEs ; CFG validation
    24. fffff801`b4760b90  blr   x15                          ; Вызов CNG random generator
    25. ; Cleanup
    26. fffff801`b4760b94  ldr   x8,[x19,#0xD0]
    27. fffff801`b4760b98  mov   w20,w0
    28. fffff801`b4760b9c  add   x0,x8,#0x58
    29. fffff801`b4760ba0  bl    nt!ExReleaseRundownProtection
    30. fffff801`b4760ba4  mov   w0,w20                       ; Return NTSTATUS
    31. ...
    32. fffff801`b4760bb8  ret
    33.  
    nt!SmCrGenRandom = 0xFFFFF801'B476A2C0
    Код (Text):
    1.  
    2. nt!SmCrGenRandom:
    3. fffff801`b476a2c0  mov   w2,w1                        ; Size
    4. fffff801`b476a2c4  mov   x1,x0                        ; Buffer
    5. fffff801`b476a2c8  b     nt!BCryptGenRandom           ; Tail call
    6.  
    Важное различие:
    - ExGenRandom → Быстрый, некриптографический PRNG (LFG). Не подходит для криптографии.
    - BCryptGenRandom → Криптографический PRNG через CNG (Cryptographic Next Generation) provider. Использует проверенный CSPRNG.
    - SmCrGenRandom → Просто tail-call обёртка над BCryptGenRandom.

    7. Глобальные seed-переменные
    ПеременнаяАдресЗначениеНазначение
    ExpRNGAuxiliarySeednt!WheapSelBuffer+0xC740x00000000XOR-маска финального смешивания ExGenRandom
    KiProcessNodeSeednt!KiProcessNodeSeed0x00000000'00000000Seed для NUMA node процессора
    CcRandomSeednt!CcRandomSeed0x00000003'0000ADADSeed для Cache Manager рандомизации
    ViRandomSeednt!ViRandomSeed0x00000000'0035CA79Seed для Driver Verifier
    CarEtwRandomSeednt!CarEtwRandomSeed0x00000000'00000000ETW random seed
    HvSymcryptSeednt!HvSymcryptSeedSymCrypt seed для Hyper-V
    RtlpLowFragHeapRandomDatant!RtlpLowFragHeapRandomData60874C69'1B747204...Seed для Low Fragmentation Heap
    RtlpSeedGlfsr (GLFSR seed function) — инициализирует seed через аппаратный счётчик:
    Код (Text):
    1.  
    2. nt!RtlpSeedGlfsr:
    3. fffff801`b4827478  mrs   x8,PMCCNTR_EL0              ; Аппаратный performance counter
    4. fffff801`b482747c  uxtw  x11,w8                       ; Младшие 32 бита
    5. fffff801`b4827480  mov   x8,#0                        ; bit = 0
    6. fffff801`b4827484  mov   w10,#0x20                    ; 32 итерации
    7. loop:
    8. fffff801`b4827488  mov   x9,#1
    9. fffff801`b482748c  lsl   x9,x9,x8                     ; mask = 1 << bit
    10. fffff801`b4827490  and   x9,x9,x11                    ; test = counter & mask
    11. fffff801`b4827494  lsl   x9,x9,x8                     ; test <<= bit
    12. fffff801`b4827498  eor   x0,x9,x0                     ; seed ^= test
    13. fffff801`b482749c  add   x8,x8,#1                     ; bit++
    14. fffff801`b48274a0  sub   w10,w10,#1                   ; remaining--
    15. fffff801`b48274a4  cbnz  w10,loop                     ; Пока remaining != 0
    16. fffff801`b48274a8  ret
    17.  
    Этот код извлекает энтропию из аппаратного performance counter процессора (PMCCNTR_EL0), обрабатывая каждый бит через XOR. Используется при инициализации PRNG для создания начального seed.

    8. Спинлок и синхронизация
    ExGenRandom использует два механизма синхронизации для потокобезопасности:
    Механизм 1: IRQL elevation
    Код (Text):
    1.  
    2. KfRaiseIrql(DISPATCH_LEVEL = 2)    ; Запретить переключение потоков
    3. ... PRNG operation ...
    4. KfLowerIrql(oldIrql)                ; Восстановить
    5.  
    Механизм 2: SpinLock
    Код (Text):
    1.  
    2. nt!WheapSelBuffer+0xC68 — 8-байтовый спинлок
    3.  
    Два пути захвата спинлока:
    ПутьУсловиеМеханизм
    БыстрыйФлаг 0x210000 сброшенSWPA (Store Word Pair Atomic) — direct atomic swap
    InstrumentedФлаг 0x210000 установленKiAcquireSpinLockInstrumented / KiReleaseSpinLockInstrumented — с ETW трассировкой
    Атомарный захват (SWPA):
    Код (Text):
    1.  
    2. mov   x8,#1
    3. swpa  x8,x8,[x20]           ; Atomic: if lock==0, set to 1 and return old=0 (acquired)
    4. cbz   x8,acquired           ; Если old==0 → успешно
    5. bl    KxWaitForSpinLockAndAcquire  ; Иначе → spin-wait
    6.  
    Освобождение (STLR):
    Код (Text):
    1.  
    2. stlr  xzr,[x20]             ; Store-release: SpinLock = 0
    3.  

    9. Ветвь KeBugCheckEx
    Если адрес спинлока не выровнен на 8 байт (
    Код (Text):
    1. tst x20, #7
    ≠ 0), ядро вызывает BSOD:
    Код (Text):
    1.  
    2. KeBugCheckEx(
    3.     BugCheckCode = 0x1F6,           // INVALID_CALLBACK
    4.     P1 = 0,                         // Reserved
    5.     P2 = SpinLockAddress,           // Неaligned адрес
    6.     P3 = 8,                         // Требуемое выравнивание
    7.     P4 = 0                          // Reserved
    8. );
    9.  
    BugCheck 0x1F6 в контексте ExGenRandom указывает на повреждение глобальной переменной спинлока — это может произойти при pool corruption или kernel-mode exploit.

    10. Сводные таблицы
    Ключевые адреса функций:
    ФункцияАдресОписание
    nt!ExGenRandom0xFFFFF801'B4582828Основной PRNG ядра (LFG)
    nt!RtlRandom0xFFFFF801'B4B1BD90Обёртка ExGenRandom(1) → & 0x7FFFFFFF
    nt!RtlRandomEx0xFFFFF801'B450FBF0Идентична RtlRandom
    nt!BCryptGenRandom0xFFFFF801'B4760B40Криптографический PRNG через CNG
    nt!SmCrGenRandom0xFFFFF801'B476A2C0Tail-call → BCryptGenRandom
    nt!KfRaiseIrql0xFFFFF801'B4406730Повышение IRQL
    nt!KfLowerIrql0xFFFFF801'B44065F0Понижение IRQL
    nt!KiAcquireSpinLockInstrumented0xFFFFF801'B446D420Instrumented spinlock acquire
    nt!KiReleaseSpinLockInstrumented0xFFFFF801'B4709668Instrumented spinlock release
    nt!KxWaitForSpinLockAndAcquire0xFFFFF801'B446D5E8Spinlock wait-loop
    nt!RtlpSeedGlfsr0xFFFFF801'B4827470GLFSR seed из performance counter
    nt!KeBugCheckEx0xFFFFF801'B445D770BSOD handler
    nt!ExGetExtensionTable0xFFFFF801'B457F580CNG extension table loader
    nt!KscpCfgCheckUserCallTargetEs0xFFFFF801'B4CF4040CFG call target validation
    nt!ExReleaseRundownProtection0xFFFFF801'B4579210Rundown protection release
    nt!SymCryptModSetRandom0xFFFFF801'B466E8C0SymCrypt modular random
    nt!SymCryptFdefModSetRandomGeneric0xFFFFF801'B467A440Generic FDEF random
    Глобальные переменные PRNG:
    ПеременнаяАдресРазмерНазначение
    PRNG Table (Gen #0)WheapSelBuffer+0xAA00xE4 байтаState array + индексы для генератора 0
    PRNG Table (Gen #1)WheapSelBuffer+0xB840xE4 байтаState array + индексы для генератора 1
    SpinLockWheapSelBuffer+0xC688 байтГлобальный спинлок PRNG
    PendingReseedWheapSelBuffer+0xC704 байтаСчётчик отложенных reseed
    AuxiliarySeedWheapSelBuffer+0xC744 байтаXOR-маска результата
    Extra Seed PoolWheapSelBuffer+0x760~0x340 байтПул seed-значений для reseed

    11. Сравнение PRNG функций Windows
    КритерийExGenRandomRtlRandom/RtlRandomExBCryptGenRandom
    АлгоритмLFG (Lagged Fibonacci)ExGenRandom(1)CNG CSPRNG (AES-CTR DRBG)
    Криптографическая стойкостьНЕТНЕТДА
    РежимKernel-mode onlyKernel-mode onlyKernel + User mode
    Размер результата32 бита (DWORD)31 бит (& 0x7FFFFFFF)Произвольный (буфер)
    СинхронизацияSpinLock + IRQL↑Наследует от ExGenRandomRundown Protection
    ПроизводительностьВысокая (~20 инструкций)Высокая (~15 инструкций)Ниже (CNG overhead)
    XOR маскаExpRNGAuxiliarySeedНаследует + & 0x7FFFFFFFN/A (CNG provider)
    CFG защитаPACIBSP/AUTIBSPPACIBSP/AUTIBSPPAC + KscpCfgCheckUserCallTargetEs
    Reseed поддержкаДа (PendingReseedCounter)НаследуетДа (CNG internal)
    ПрименениеASLR, hash рандомизация, pool tag randomizationСовместимость с legacy APIГенерация ключей, токенов, nonce

    12. Практические выводы
    1. ExGenRandom — НЕ криптографический PRNG. Алгоритм LFG (Lagged Fibonacci Generator) с lag=55 предсказуем при достаточном количестве наблюдений. Для криптографии использовать BCryptGenRandom.
    2. Два генератора = два контекста. Генератор #0 (w0=0) используется ядром для внутренних нужд (ASLR, рандомизация pool tag и т.д.). Генератор #1 (w0=1) — через RtlRandom/RtlRandomEx — для legacy API.
    3. RtlRandom == RtlRandomEx. Полностью идентичные функции. Ex-суффикс не даёт никакого улучшения качества случайности — это просто второй экземпляр того же кода.
    4. 31-битный результат RtlRandom. Маска
      Код (Text):
      1. & 0x7FFFFFFF
      гарантированно делает результат положительным signed LONG — это ограничение совместимости с legacy кодом.
    5. SpinLock + DISPATCH_LEVEL = полный запрет вытеснения на текущном процессоре. Это гарантирует атомарность операции с PRNG state, но создаёт latency для всех процессоров, ожидающих спинлок.
    6. XOR с AuxiliarySeed добавляет дополнительный уровень энтропии поверх LFG. Этот seed обновляется периодически из Extra Seed Pool.
    7. Reseed через PendingReseedCounter позволяет отложенно «подмешивать» новые seed-значения в генератор #1 при каждом следующем вызове, если счётчик отличен от нуля.
    8. Seed из аппаратного счётчика (PMCCNTR_EL0). RtlpSeedGlfsr извлекает энтропию из performance counter — это 32 цикла XOR, по одному на каждый бит.
    9. PAC (Pointer Authentication) на всех функциях. PACIBSP/AUTIBSP защищают от ROP-атак на return address.
    10. KeBugCheckEx при pool corruption. Если спинлок (WheapSelBuffer+0xC68) повреждён и его адрес не выровнен на 8 байт — BSOD 0x1F6.
    11. BCryptGenRandom использует CFG (Control Flow Guard) через KscpCfgCheckUserCallTargetEs — это предотвращает атаки на indirect call к CNG provider.
    12. Нет Nt/Zw API для ExGenRandom. Функция доступна только в kernel-mode. User-mode получает доступ к PRNG только через BCryptGenRandom или RtlRandom (через ntdll syscall).
    13. Один спинлок на оба генератора. Это означает, что вызов ExGenRandom(0) и ExGenRandom(1) на разных процессорах будут конкурировать за один и тот же спинлок — это потенциальное bottleneck на высоконагруженных системах.

    Сводка адресов (Build 26100 ARM64):
    Код (Text):
    1.  
    2. nt!ExGenRandom                     0xFFFFF801'B4582828
    3. nt!RtlRandom                       0xFFFFF801'B4B1BD90
    4. nt!RtlRandomEx                     0xFFFFF801'B450FBF0
    5. nt!BCryptGenRandom                 0xFFFFF801'B4760B40
    6. nt!SmCrGenRandom                   0xFFFFF801'B476A2C0
    7. nt!KfRaiseIrql                     0xFFFFF801'B4406730
    8. nt!KfLowerIrql                     0xFFFFF801'B44065F0
    9. nt!KiAcquireSpinLockInstrumented   0xFFFFF801'B446D420
    10. nt!KiReleaseSpinLockInstrumented   0xFFFFF801'B4709668
    11. nt!KxWaitForSpinLockAndAcquire     0xFFFFF801'B446D5E8
    12. nt!RtlpSeedGlfsr                   0xFFFFF801'B4827470
    13. nt!KeBugCheckEx                    0xFFFFF801'B445D770
    14. nt!ExGetExtensionTable             0xFFFFF801'B457F580
    15. nt!KscpCfgCheckUserCallTargetEs    0xFFFFF801'B4CF4040
    16. nt!ExReleaseRundownProtection      0xFFFFF801'B4579210
    17. nt!SymCryptModSetRandom            0xFFFFF801'B466E8C0
    18. nt!SymCryptFdefModSetRandomGeneric 0xFFFFF801'B467A440
    19.  
     
    Research и Mikl___ нравится это.
  2. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    353
    Раз уж разговор про криптографию, вашему ии нужно было упоменуть и других провайдеров BCrypt кроме дефолтного "RNG" - это "FIPS186DSARNG" и "DUALECRNG". Оба они являются примитивами для крипто-алгоритмов цифровых ключей DSA/ECDSA, а последний берёт полином от эллиптической кривой "Elliptic Curve".

    Функцией BCryptEnumAlgorithms() можно перечислить всех поддерживаемых системой крипто-провайдеров - она возвращает длину ключей, шаг их инкремента, а так-же размеры блоков для симметричных (не потоковых) алгоритмов типа AES\DES\RC2.
    Код (ASM):
    1. format pe console
    2. entry  start
    3. include 'win32ax.inc'
    4. include 'equates\bcrypt.inc'
    5. ;//------------
    6.  
    7. .data
    8. algCount     dd  0
    9. operation    dd  1   ; начинаем с "BCRYPT_CIPHER_OPERATION = 1"
    10. algHndl      dd  0
    11. pLen         dd  0
    12. objLen       dd  0
    13. pcbResult    dd  0
    14.  
    15. align 16
    16. algList      BCRYPT_ALGORITHM_IDENTIFIER
    17. keyLen       BCRYPT_KEY_LENGTHS_STRUCT
    18.  
    19. buff         db  0
    20. ;//------------
    21. .code
    22. start:   invoke  SetConsoleTitle,<'*** CNG Enum algo ***',0>
    23.         cinvoke  printf,<10,' Enum CNG Algorithm',\
    24.                          10,' ***************************',\
    25.                          10,'   Symmetric cipher....:  ',0>
    26.  
    27.          invoke  BCryptEnumAlgorithms,[operation],algCount,algList,0
    28.          call    GetAlgoName
    29.  
    30.          shl     [operation],1
    31.         cinvoke  printf,<10,'   Hash algorithm......:  ',0>
    32.          invoke  BCryptEnumAlgorithms,[operation],algCount,algList,0
    33.          call    GetAlgoName
    34.  
    35.          shl     [operation],1
    36.         cinvoke  printf,<10,'   Asymmetric cipher...:  ',0>
    37.          invoke  BCryptEnumAlgorithms,[operation],algCount,algList,0
    38.          call    GetAlgoName
    39.  
    40.          shl     [operation],1
    41.         cinvoke  printf,<10,'   Secret agreement....:  ',0>
    42.          invoke  BCryptEnumAlgorithms,[operation],algCount,algList,0
    43.          call    GetAlgoName
    44.  
    45.          shl     [operation],1
    46.         cinvoke  printf,<10,'   Signature...........:  ',0>
    47.          invoke  BCryptEnumAlgorithms,[operation],algCount,algList,0
    48.          call    GetAlgoName
    49.  
    50.          shl     [operation],1
    51.         cinvoke  printf,<10,'   Random generator....:  ',0>
    52.          invoke  BCryptEnumAlgorithms,[operation],algCount,algList,0
    53.          call    GetAlgoName
    54. ;// *********************************************
    55.  
    56.         cinvoke  printf,<10,10,10,\
    57.                          10,' Signature algo info',\    ;<---- детали алго подписей
    58.                          10,' ***************************',0>
    59.  
    60. ;         invoke  BCryptEnumAlgorithms,BCRYPT_ASYMMETRIC_ENCRYPTION_OPERATION,algCount,algList,0
    61. ;         invoke  BCryptEnumAlgorithms,BCRYPT_CIPHER_OPERATION,algCount,algList,0
    62.  
    63.          invoke  BCryptEnumAlgorithms,BCRYPT_SIGNATURE_OPERATION,algCount,algList,0
    64.          call    GetAlgoProperty
    65.  
    66. @exit:  cinvoke  _getch
    67.         cinvoke  exit,0
    68. ;------------
    69.  
    70. ;//----- ВСПОМОГАТЕЛЬНЫЕ ПРОЦЕДУРЫ ------------//
    71. proc GetAlgoName                      ;<---- выводит массив имён алгоритмов
    72.          mov     ecx,[algCount]
    73.          mov     esi,[algList.pszName]
    74.          mov     esi,[esi]
    75.  
    76. @@:      push    esi ecx
    77.         cinvoke  printf,<'%ls, ',0>,esi
    78.          pop     ecx esi
    79. @01:     lodsw
    80.          cmp     ax,0
    81.          jne     @01
    82.          loop    @b
    83.          ret
    84. endp
    85. ;//------------
    86. proc GetAlgoProperty                  ;<---- запрашивает свойства по имени
    87.          mov     ecx,[algCount]
    88.          mov     esi,[algList.pszName]
    89.          mov     esi,[esi]
    90.  
    91. @cycle:  push    esi ecx esi
    92.         cinvoke  printf,<10,10,' %ls *********',0>,esi
    93. ; Открыть алгоритм по имени (указатель на имя лежит в ESI)
    94.          pop     esi
    95.          invoke  BCryptOpenAlgorithmProvider,algHndl,esi,0,0
    96.  
    97. ; Размер блока шифрования
    98.          invoke  BCryptGetProperty,[algHndl],BCRYPT_BLOCK_LENGTH,pLen,4,pcbResult,0
    99.         cinvoke  printf,<10,'    Block size...:  %d byte',0>,[pLen]
    100.  
    101. ; Диапазон размеров ключей (и их шаг)
    102.          invoke  BCryptGetProperty,[algHndl],BCRYPT_KEY_LENGTHS,keyLen,12,pcbResult,0
    103.          mov     eax,[keyLen.dwMinLen]
    104.          mov     ebx,[keyLen.dwMaxLen]
    105.          mov     ecx,[keyLen.dwIncrement]
    106.         cinvoke  printf,<10,'    Key length...:  %03d...%03d bit, increment = %d bit',0>,\
    107.                                  eax,ebx,ecx
    108.  
    109. ; Размер временного буфера под данные
    110.          invoke  BCryptGetProperty,[algHndl],BCRYPT_OBJECT_LENGTH,objLen,4,pcbResult,0
    111.         cinvoke  printf,<10,'    Temp object..:  %d byte',0>,[objLen]
    112.          pop     ecx esi
    113. @@:      lodsw
    114.          cmp     ax,0
    115.          jne     @b
    116.          dec     ecx
    117.          jnz     @f
    118.          jmp     @stop
    119. @@:      jmp     @cycle
    120. @stop:   ret
    121. endp
    122. ;------------
    123. section '.idata' import data readable
    124. library  kernel32,'kernel32.dll',msvcrt,'msvcrt.dll',bcrypt,'bcrypt.dll'
    125. include  'api\kernel32.inc'
    126. include  'api\msvcrt.inc'
    127. include  'api\bcrypt.inc'
    128.  
    RngProv.png
     
    Последнее редактирование: 7 июн 2026 в 03:45
    Mikl___ нравится это.
  3. Entropy

    Entropy Member

    Публикаций:
    0
    Регистрация:
    23 авг 2020
    Сообщения:
    280
    этот форум примущественно направлен на архитектуру x86,я не знаю уместны ли тут публикации на тему архитектуры ARM