Системные генераторы случайных чисел
Системные генераторы случайных чисел
На сайте уже выложено несколько различных алгоритмов генераторов псевдослучайных чисел. Какие-то генераторы лучше, какие-то похуже. Но когда надо сгенерировать всего пару-тройку чисел или результаты генерации не используются в критических участках кода, можно воспользоваться системными источниками псевдослучайных чисел.
Первые две функции - это RtlRandom и ее улучшенная версия RtlRandomEx. К сожалению, в MSDN ничего не сказано относительно того, какие алгоритмы используются для генерации в этих функциях. А использование очень простое, что-то типа:
Code (Assembler) : Убрать нумерацию
- ; Инициализация генератора
- invoke GetTickCount
- mov [random_seed],eax
- ...
- ; Сгенерировать псевдослучайное число
- invoke RtlRandom,random_seed
- ; EAX - число
- ...
- ; Сгенерировать псевдослучайное число
- invoke RtlRandomEx,random_seed
- ; EAX - число
Code (Assembler) : Убрать нумерацию
- dllname db 'advapi32.dll',0
- fname db 'SystemFunction036',0
- RtlGenRandom dd ?
- ...
- ; Получить адрес функции RtlGenRandom
- invoke LoadLibrary,dllname
- invoke GetProcAddress,eax,fname
- mov [RtlGenRandom],eax
- ; Сгенерировать псевдослучайное число размером 4 байта
- stdcall [RtlGenRandom],random,4
- ; [random] -> псевдослучайное число
Code (Assembler) : Убрать нумерацию
- ; Инициализация генератора
- invoke GetTickCount
- invoke srand,eax
- ; Сгенерировать псевдослучайное число
- invoke rand
- ; ECX -> псевдослучайное число DWORD
- ; EAX -> псевдослучайное число WORD
Code (Assembler) : Убрать нумерацию
- ...
- ; Инициализация генератора
- invoke CryptAcquireContext,hProv,NULL,NULL,PROV_RSA_FULL,\
- CRYPT_VERIFYCONTEXT or CRYPT_SILENT
- ...
- ; Сгенерировать псевдослучайное число размером 4 байта
- invoke CryptGenRandom,[hProv],4,rnd
- ; [rnd] -> псевдослучайное число
- ...
- ; Освободить хэндл
- invoke CryptReleaseContext,[hProv],0
Code (Assembler) : Убрать нумерацию
- szAlgId du 'RNG',0
- ...
- ; Инициализация генератора
- invoke BCryptOpenAlgorithmProvider,hAlgorithm,szAlgId,NULL,NULL
- ...
- ; Сгенерировать псевдослучайное число размером 4 байта
- invoke BCryptGenRandom,[hAlgorithm],rnd,4,NULL
- ; [rnd] -> псевдослучайное число
- ...
- ; Освободить хэндл
- invoke BCryptCloseAlgorithmProvider,[hAlgorithm]
Code (Assembler) : Убрать нумерацию
- ; Проверить доступность команды RDRAND
- mov eax,1
- cpuid
- test ecx,0x40000000
- jz loc_exit
- ...
- rdrand eax
- ; EAX -> случайное число
Code (Assembler) : Убрать нумерацию
- ; Проверить доступность команды RDSEED
- xor ecx,ecx
- mov eax,7
- cpuid
- test ebx,0x40000
- jz loc_exit
- ...
- rdseed eax
- ; EAX -> случайное число
Code (Assembler) : Убрать нумерацию
- rdtsc
- ; EDX:EAX -> случайное число
Просмотров: 2066 | Комментариев: 26
Метки: Assembler, генератор ПСЧ
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
Petya
(02.02.2024 в 15:37):
Сунул нос в исходники XP, там сказано так:
RtlRandom:
RtlRandomEx:
Но это лютая недокументирщина и никто не обещает детерминизм относительно Seed, так что может зависеть от версии.
АндрейК
(21.10.2021 в 10:13):
Прошу заранее простить за вопрос.
Скажите, чем можно нагенерировать (псевдо-)случайников со скоростью ~500 МБ/сек (в объёме 500 Гб), под windows, x64 и/или x86, и какое минимальное железо для этого требуется.
PS. Хотелось бы чтобы архиватором с огромным словарём не сжималось, т.е. чтобы массив был с высокой энтропией.
Скажите, чем можно нагенерировать (псевдо-)случайников со скоростью ~500 МБ/сек (в объёме 500 Гб), под windows, x64 и/или x86, и какое минимальное железо для этого требуется.
PS. Хотелось бы чтобы архиватором с огромным словарём не сжималось, т.е. чтобы массив был с высокой энтропией.
Petya
(17.08.2021 в 17:00):
1. Чего-т я не вкуриваю из интеловского мана, RDRAND от RDSEED чем отличается, кроме одного байта опкода?
2. Из старых заблуждений...
2. Из старых заблуждений...
ManHunter
(22.07.2021 в 10:05):
rndgen, а какое отношение это имеет к системным генераторам?
rdtsc меняет регистр EDX, а тут сохраняются и восстанавливаются только esi и ecx. edx вернется с непредсказуемым значением.
xor ecx,ecx
mov cl,al
xor eax,eax
mov al,byte [esi+ecx]
преобразуется в человеческое
movzx eax,al
mov al,byte [esi+eax]
test al,al
je @1
То есть первый символ строки в принципе никогда не выпадет?
symbols db 'qwertyuiopasdfghjklzxcvbnm0123456789',0
symlen dd ($ - symbols - 1)
Смысл завершающего нуля, если он все равно вычеркивается при расчете длины?
Смысл резервировать DWORD для symlen, если он станет константой и будет использоваться в вызове?
symbols db 'qwertyuiopasdfghjklzxcvbnm0123456789'
symlen = $-symbols
stdcall RndNameGen,symbols,symlen
Садись, двойка.
rdtsc меняет регистр EDX, а тут сохраняются и восстанавливаются только esi и ecx. edx вернется с непредсказуемым значением.
xor ecx,ecx
mov cl,al
xor eax,eax
mov al,byte [esi+ecx]
преобразуется в человеческое
movzx eax,al
mov al,byte [esi+eax]
test al,al
je @1
То есть первый символ строки в принципе никогда не выпадет?
symbols db 'qwertyuiopasdfghjklzxcvbnm0123456789',0
symlen dd ($ - symbols - 1)
Смысл завершающего нуля, если он все равно вычеркивается при расчете длины?
Смысл резервировать DWORD для symlen, если он станет константой и будет использоваться в вызове?
symbols db 'qwertyuiopasdfghjklzxcvbnm0123456789'
symlen = $-symbols
stdcall RndNameGen,symbols,symlen
Садись, двойка.
rndgen
(22.07.2021 в 10:03):
еще один вариант
symbols db 'qwertyuiopasdfghjklzxcvbnm0123456789',0
symlen dd ($ - symbols - 1)
;stdcall RndNameGen,symbols,[symlen]
proc RndNameGen pSym:DWORD, pLen:DWORD
push ecx esi
mov esi,[pSym]
mov ecx,[pLen]
@1:
rdtsc
@3:
cmp al,cl
jb @2
cmp al,ah
ja @4
shr al,1
jmp @3
@4:
test ah,ah
je @1
sub al,ah
jmp @3
@2:
test al,al
je @1
xor ecx,ecx
mov cl,al
xor eax,eax
mov al,byte [esi+ecx]
pop esi ecx
ret
endp
symbols db 'qwertyuiopasdfghjklzxcvbnm0123456789',0
symlen dd ($ - symbols - 1)
;stdcall RndNameGen,symbols,[symlen]
proc RndNameGen pSym:DWORD, pLen:DWORD
push ecx esi
mov esi,[pSym]
mov ecx,[pLen]
@1:
rdtsc
@3:
cmp al,cl
jb @2
cmp al,ah
ja @4
shr al,1
jmp @3
@4:
test ah,ah
je @1
sub al,ah
jmp @3
@2:
test al,al
je @1
xor ecx,ecx
mov cl,al
xor eax,eax
mov al,byte [esi+ecx]
pop esi ecx
ret
endp
Petya
(19.07.2021 в 13:03):
voffka, слова "EXE" в предыдущем сообщении не было. а "DLL" было.
Ладно, кончаю спорить, пока хозяину не надоело.
Ладно, кончаю спорить, пока хозяину не надоело.
voffka
(19.07.2021 в 12:37):
Petya, DEF - он же Export Definition File, при компиляции exe нахрен не упал ни на одном языке программирования. Он нужен при компиляции dll, чтоб указать какие процедуры должны экспортироваться.
Petya
(19.07.2021 в 11:02):
voffka, Всё ещё не понимаю. И создать, и импортировать DLL FASM может и без этого, см. прилагающиеся к нему примеры.
voffka
(16.07.2021 в 20:49):
Petya, def-ы нужны при создании dll, чтоб ты смог в FASM сделать
Petya
(16.07.2021 в 14:47):
А теперь внимание, вопрос - зачем вообще нужны эти def-файлы, если FASM и без них даже лучше работает?
Функции, вообще-то, крошечные. Выдрать и носить с собой оптимальнее и по скорости, и по размеру, чем лишнюю библиотеку грузить.
Единственный бонус - некоторые версии msvcrt делают его потокобезопасным - каждой твари по ячейке памяти.
voffka
(14.07.2021 в 23:17):
В msvcrt в eax оказывается ограничение не 0xFFFF, а 0x7FFF
SHR EAX,010h
AND EAX,07FFFh
MOV ESP,EBP
POP EBP
RETN
SHR EAX,010h
AND EAX,07FFFh
MOV ESP,EBP
POP EBP
RETN
SMaSm-94
(14.07.2021 в 01:53):
ManHunter, да всё так, за исключением того, что я не удостоверился в наличии данной функции в "Окнах" версии ниже 8.1. На данный момент семёрки под рукой не имею, но вот в 8.1 и 10 функция "ProcessPrng" присутствует. Думаю, она была реализована в Win8; хотя не факт - чекнуть нужно. Использовать, или нет - дело каждого.
ManHunter
(13.07.2021 в 23:19):
Да я вообще был удивлен, что мой стационарный рабочий комп внезапно не вывез RDSEED по железу. Что уж тут говорить про поддержку всего этого паноптикума на уровне операционки.
voffka
(13.07.2021 в 23:10):
ManHunter, В 7 нет, в 10 уже есть. Так что длл не постоянная и лучше ее не юзать.
ManHunter
(13.07.2021 в 23:08):
Добавил srand/rand, архив обновлен.
ManHunter
(13.07.2021 в 22:47):
SMaSm-94, не то, чтоб я сомневался, но факты - упрямая штука. У bcryptprimitives.dll экспорт не содержит ProcessPrng, соответственно, код типа
dllname db 'bcryptprimitives.dll',0
fname db 'ProcessPrng',0
ProcessPrng dd ?
invoke LoadLibrary,dllname
invoke GetProcAddress,eax,fname
mov [ProcessPrng],eax
возвращает ошибку (Win7 x86).
Пруф: https://ibb.co/kqxPkZ8
ЧЯДНТ?
dllname db 'bcryptprimitives.dll',0
fname db 'ProcessPrng',0
ProcessPrng dd ?
invoke LoadLibrary,dllname
invoke GetProcAddress,eax,fname
mov [ProcessPrng],eax
возвращает ошибку (Win7 x86).
Пруф: https://ibb.co/kqxPkZ8
ЧЯДНТ?
SMaSm-94
(13.07.2021 в 20:59):
ADVAPI32.DLL:SystemFunction036(RtlGenRandom) вызывает CRYPTBASE.DLL:SystemFunction036, которая в свою очередь вызывает BCryptPrimitives.DLL:ProcessPrng, поэтому лучше в целях экономии процессорного времени использовать напрямую последнюю. Вот пример:
...
szBCryptPrimitivesLibrary TCHAR 'BCryptPrimitives.dll',0
align 4
szProcessPrng db 'ProcessPrng',0
pProcessPrng dd ?
bRandBuffer rb 4
sizeof.bRandBuffer = $ - bRandBuffer
...
invoke LoadLibrary, szBCryptPrimitivesLibrary
invoke GetProcAddress, eax, szProcessPrng
mov [pProcessPrng], eax
...
stdcall [pProcessPrng], bRandBuffer, sizeof.bRandBuffer
...
Ещё для генерации псевдослучайных чисел можно воспользоваться функцией CPGenRandom из RSAENH.DLL. Но она по сути является лишь "надстройкой" над ProcessPrng.
...
szBCryptPrimitivesLibrary TCHAR 'BCryptPrimitives.dll',0
align 4
szProcessPrng db 'ProcessPrng',0
pProcessPrng dd ?
bRandBuffer rb 4
sizeof.bRandBuffer = $ - bRandBuffer
...
invoke LoadLibrary, szBCryptPrimitivesLibrary
invoke GetProcAddress, eax, szProcessPrng
mov [pProcessPrng], eax
...
stdcall [pProcessPrng], bRandBuffer, sizeof.bRandBuffer
...
Ещё для генерации псевдослучайных чисел можно воспользоваться функцией CPGenRandom из RSAENH.DLL. Но она по сути является лишь "надстройкой" над ProcessPrng.
voffka
(13.07.2021 в 19:50):
В msvcrt
srand(seed) идет как init
rand() возвращает радомные числа в eax число до 0xFFFF, в ecx до 0xFFFFFFFF
srand(seed) идет как init
rand() возвращает радомные числа в eax число до 0xFFFF, в ecx до 0xFFFFFFFF
ManHunter
(13.07.2021 в 16:48):
Добавил примеры из камментов в статью, архив обновлен. Всем большое спасибо за подсказки!
ManHunter
(13.07.2021 в 16:02):
В FASM работает конструкция:
section '.idata' import data readable writeable
library advapi32,'advapi32.dll'
import advapi32,RtlGenRandom,'SystemFunction036'
и вызывается invoke RtlGenRandom,buf,[cnt]
section '.idata' import data readable writeable
library advapi32,'advapi32.dll'
import advapi32,RtlGenRandom,'SystemFunction036'
и вызывается invoke RtlGenRandom,buf,[cnt]
voffka
(13.07.2021 в 15:57):
Это я знаю. Просто как в песенке - Жопа есть, а слова нет. Есть api, у него есть название, а прилинковать невозможно т.к. в dll оно под кодовым названием SystemFunction036.
ManHunter
(13.07.2021 в 15:42):
voffka, это RtlGenRandom
https://docs.microsoft.com/en-...rtlgenrandom
https://docs.microsoft.com/en-...rtlgenrandom
voffka
(13.07.2021 в 15:39):
Еще один не очевидный виндовый генератор
invoke LoadLibrary,SADD("Advapi32.dll")
invoke GetProcAddress,eax,SADD("SystemFunction036")
push 100
push offset buffer
call eax
invoke LoadLibrary,SADD("Advapi32.dll")
invoke GetProcAddress,eax,SADD("SystemFunction036")
push 100
push offset buffer
call eax
voffka
(13.07.2021 в 15:17):
SMaSm, Тоже самое, что и BCrypt, только BCrypt появился в висте, а wincrypt в Advapi32.dll намного раньше еще в win2000 вроде.
SMaSm
(13.07.2021 в 13:58):
; вот ещё, как вариант :
; --------------------
RAND_BUFFER_LENGTH = MAX_PATH ; длинна буфера
...
hProv rd 1 ; хэндл CSP
bRandBuffer rb RAND_BUFFER_LENGTH ; буфер
...
invoke CryptAcquireContext, hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_SILENT
test al, al
jz .cryptapi_context_acquirement_error
invoke CryptGenRandom, [hProv], RAND_BUFFER_LENGTH, bRandBuffer
test al, al
jz .cryptapi_random_data_generation_error
...
invoke CryptReleaseContext, [hProv], 0
; --------------------
RAND_BUFFER_LENGTH = MAX_PATH ; длинна буфера
...
hProv rd 1 ; хэндл CSP
bRandBuffer rb RAND_BUFFER_LENGTH ; буфер
...
invoke CryptAcquireContext, hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT or CRYPT_SILENT
test al, al
jz .cryptapi_context_acquirement_error
invoke CryptGenRandom, [hProv], RAND_BUFFER_LENGTH, bRandBuffer
test al, al
jz .cryptapi_random_data_generation_error
...
invoke CryptReleaseContext, [hProv], 0
Добавить комментарий
Заполните форму для добавления комментария
RtlRandom[Ex] не детерминистичны! Замечено по исходнику, проверено экспериментально - Seed изменяется примитивным LCG (Random дважды, RandomEx единожды), идентичным RtlUniform (про него в статье молчок, и поделом), но для возврата в EAX у них монструозные потихоньку обновляемые массивы, и явного способа их задать не замечено.