Windows 使用MASM32在汇编中随机化数字
如何使用带Masm32的汇编随机化一个数字?我可以使用什么来创建随机数生成器 多谢各位 您需要实现一个,如下所示:Windows 使用MASM32在汇编中随机化数字,windows,assembly,random,masm,masm32,Windows,Assembly,Random,Masm,Masm32,如何使用带Masm32的汇编随机化一个数字?我可以使用什么来创建随机数生成器 多谢各位 您需要实现一个,如下所示: 如果您想在汇编中获得随机数,我想有两种方法: 如果允许在程序集中调用C函数,则可以使用 我们在大学里用过,有一个命令 ()在NASM中读取CPU时钟并将其放入 登记册。你可以把这个数除以,得到一个随机数 我不知道MASM,但保罗·卡特的很棒。使用MASM32获取随机数 附带了一些实现随机生成器的示例。将它们用于自己的目的并不是最糟糕的想法。下面的示例只是示例,缺少错误处理。这
如果您想在汇编中获得随机数,我想有两种方法:
- 如果允许在程序集中调用C函数,则可以使用
- 我们在大学里用过,有一个命令 ()在NASM中读取CPU时钟并将其放入 登记册。你可以把这个数除以,得到一个随机数
nrandom
。源代码位于\masm32\m32lib\nrand.asm中。这与上面的Park-Miller算法相同
.686
.MODEL flat, STDCALL
OPTION casemap:none
INCLUDE kernel32.inc ; GetStdHandle, WriteFile, ExitProcess
INCLUDELIB kernel32.lib
INCLUDE user32.inc ; wsprintf
INCLUDELIB user32.lib
INCLUDE masm32.inc ; nseed, nrandom
INCLUDELIB masm32.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.CODE
main PROC
rdtsc
invoke nseed, eax ; Initialize nrandom_seed
mov ecx, NumberOfNumbers ; Loop counter - show ECX random numbers
LL1:
push ecx ; Preserve loop counter
invoke nrandom, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
call write_number ; printf ("%u ", EAX)
pop ecx ; Restore loop counter
loop LL1
invoke ExitProcess, 0
main ENDP
write_number PROC STDCALL USES ebx ; printf ("%u ", EAX)
LOCAL numstring[12]:BYTE, NumberOfBytesWritten:DWORD
.CONST
fmt db "%u ",0
.CODE
invoke wsprintf, ADDR numstring, ADDR fmt, eax
mov ebx, eax ; Preserve result - count of written bytes
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
mov edx, eax ; EAX will be used by the following INVOKE
invoke WriteFile, edx, ADDR numstring, ebx, ADDR NumberOfBytesWritten, 0
ret
write_number ENDP
END main
有许多.lib
文件可以访问Windows系统。Microsoft建议使用CryptGenRandom
:
.686
.MODEL flat, STDCALL
OPTION casemap:none
INCLUDE kernel32.inc ; GetStdHandle, WriteFile, ExitProcess
INCLUDELIB kernel32.lib
INCLUDE user32.inc ; wsprintf
INCLUDELIB user32.lib
INCLUDE advapi32.inc ; CryptAcquireContext, CryptGenRandom, CryptReleaseContext
INCLUDELIB advapi32.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.DATA
random_bytes dd 30 DUP (?)
hProvider dd ?
.CODE
main PROC
; https://msdn.microsoft.com/library/windows/desktop/aa379886.aspx
CRYPT_VERIFYCONTEXT = 0F0000000h
PROV_RSA_FULL = 1
invoke CryptAcquireContext, ADDR hProvider, 0, 0, PROV_RSA_FULL,CRYPT_VERIFYCONTEXT
; https://msdn.microsoft.com/library/windows/desktop/aa379942.aspx
invoke CryptGenRandom, hProvider, 30*4, ADDR random_bytes ; Generate 30 random DWORD (30*4)
; https://msdn.microsoft.com/library/windows/desktop/aa380268.aspx
invoke CryptReleaseContext, hProvider, 0
lea esi, random_bytes
mov ecx, NumberOfNumbers ; Loop counter - show ECX random numbers
@@:
push ecx ; Preserve loop counter
lodsd ; [ESI] -> EAX, ADD ESI, 4
; Adjust EAX to the range
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
call write_number ; printf ("%u ", EAX)
pop ecx ; Restore loop counter
loop @B ; Loop the next @@ above
invoke ExitProcess, 0 ; Exit (0) = return 0
main ENDP
write_number PROC STDCALL USES ebx ; printf ("%u ", EAX)
LOCAL numstring[12]:BYTE, NumberOfBytesWritten:DWORD
.CONST
fmt db "%u ",0
.CODE
invoke wsprintf, ADDR numstring, ADDR fmt, eax
mov ebx, eax ; Preserve result - count of written bytes
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
mov edx, eax ; EAX will be used by the following INVOKE
invoke WriteFile, edx, ADDR numstring, ebx, ADDR NumberOfBytesWritten, 0
ret
write_number ENDP
END main
我在dnsapi.lib
中找到了一个未记录的函数Dns\u GetRandomXid
。它使用CryptGenRandom
,有时使用C函数rand()
,看起来是线程安全的
.686
.MODEL flat, STDCALL
OPTION casemap:none
INCLUDE kernel32.inc ; GetStdHandle, WriteFile, ExitProcess
INCLUDELIB kernel32.lib
INCLUDE user32.inc ; wsprintf
INCLUDELIB user32.lib
INCLUDE dnsapi.inc ; Dns_GetRandomXid
INCLUDELIB dnsapi.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.CODE
main PROC
mov ecx, NumberOfNumbers ; Loop counter - show ECX random numbers
LL1:
push ecx ; Preserve loop counter
invoke Dns_GetRandomXid, 0 ; Argument not used -> AX = random WORD
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
call write_number ; printf ("%u ", EAX)
pop ecx ; Restore loop counter
loop LL1
invoke ExitProcess, 0
main ENDP
write_number PROC STDCALL USES ebx ; printf ("%u ", EAX)
LOCAL numstring[12]:BYTE, NumberOfBytesWritten:DWORD
.CONST
fmt db "%u ",0
.CODE
invoke wsprintf, ADDR numstring, ADDR fmt, eax
mov ebx, eax ; Preserve result - count of written bytes
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
mov edx, eax ; EAX will be used by the following INVOKE
invoke WriteFile, edx, ADDR numstring, ebx, ADDR NumberOfBytesWritten, 0
ret
write_number ENDP
END main
另一个未记录的函数是cryptdll.lib
中的CDGenerateRandomBits
.686
.MODEL flat, STDCALL
OPTION casemap:none
INCLUDE kernel32.inc ; GetStdHandle, WriteFile, ExitProcess
INCLUDELIB kernel32.lib
INCLUDE user32.inc ; wsprintf
INCLUDELIB user32.lib
INCLUDE cryptdll.inc ; CDGenerateRandomBits
INCLUDELIB cryptdll.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.DATA
random_bytes dd 30 DUP (?)
.CODE
main PROC
invoke CDGenerateRandomBits, Addr random_bytes, (NumberOfNumbers*4) ; Generate 120 random bytes (30 DWORD à 4 BYTE)
lea esi, random_bytes
mov ecx, 30 ; Show 30 random numbers
LL1:
push ecx ; Preserve loop counter
lodsd ; [ESI] -> EAX; ESI += 4
; Adjust EAX to range
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
call write_number ; printf ("%u ", EAX)
pop ecx ; Restore loop counter
loop LL1
invoke ExitProcess, 0
main ENDP
write_number PROC STDCALL USES ebx ; printf ("%u ", EAX)
LOCAL numstring[12]:BYTE, NumberOfBytesWritten:DWORD
.CONST
fmt db "%u ",0
.CODE
invoke wsprintf, ADDR numstring, ADDR fmt, eax
mov ebx, eax ; Preserve result - count of written bytes
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
mov edx, eax ; EAX will be used by the follwing INVOKE
invoke WriteFile, edx, ADDR numstring, ebx, ADDR NumberOfBytesWritten, 0
ret
write_number ENDP
END main
C库中良好的旧rand()
不应该丢失
.686
.MODEL flat, C
INCLUDE msvcrt.inc ; crt_time, crt_srand, crt_rand, crt_printf,crt_exit
INCLUDELIB msvcrt.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.DATA
fmt db "%u ", 0
.CODE
main PROC
sub esp, 8 ; Reserve place for the C arguments
; srand( time (NULL) )
mov DWORD PTR [esp], 0
call crt_time ; EAX = time(0)
mov [esp], eax
call crt_srand ; srand (EAX)
mov ebx, NumberOfNumbers ; Loop counter - show ECX random numbers
LL1:
call crt_rand ; EAX = rand()
; Adjust EAX to the range
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
; printf ("%d\n", EAX )
mov [esp], OFFSET fmt
mov [esp+4], eax
call crt_printf ; printf (fmt,eax)
dec ebx
jne LL1
; exit (0) = return 0
mov DWORD PTR [esp], 0
call crt_exit ; exit (0) = return 0
main ENDP
END main
在现代处理器上(至少从2012年起)实现了该指令。它符合标准。MASM32 SDK中的MASM汇编程序无法汇编此指令。解决方法是将指令作为一系列十六进制字节插入代码中。MASM将按给定方式存储它,处理器将按需要执行它
.686
.MODEL flat, STDCALL
INCLUDE kernel32.inc ; GetStdHandle, WriteFile, ExitProcess
INCLUDELIB kernel32.lib
INCLUDE user32.inc ; wsprintf
INCLUDELIB user32.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.CONST
err_text db "ERR: RDRAND not supported.",10,0
.CODE
main PROC
mov eax, 01h ; Check for availability (EAX=1) -> ECX.30
cpuid
bt ecx, 30 ; CPUID.01H:ECX.RDRAND[bit 30] = 1 ?
jnc err_exit ; No (RDRAND not supported) -> err_exit
mov ecx, NumberOfNumbers ; Loop counter - generate and show ECX random numbers
LL1:
push ecx ; Preserve loop counter
@@:
db 0Fh, 0C7h, 0F0h ; rdrand eax
jnc @B ; Invalid number - try again
; Adjust EAX to the range
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
call write_number
pop ecx ; Restore loop counter
loop LL1
invoke ExitProcess, 0 ; Returncode = 0
err_exit:
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
push eax ; Place for WriteFile.NumberOfBytesWritten
invoke WriteFile, eax, ADDR err_text, LENGTHOF err_text, esp, 0
invoke ExitProcess, 1 ; Returncode = 1
main ENDP
write_number PROC STDCALL USES ebx ; printf ("%u ", EAX)
LOCAL numstring[20]:BYTE, NumberOfBytesWritten:DWORD
.CONST
fmt db "%u ",0
.CODE
invoke wsprintf, ADDR numstring, ADDR fmt, eax
mov ebx, eax ; Preserve count of written bytes
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
mov edx, eax ; EAX will be used by the following INVOKE
invoke WriteFile, edx, ADDR numstring, ebx, ADDR NumberOfBytesWritten, 0
ret
write_number ENDP
END main
“全新”是处理器指令RDSEED
(至少从2014年开始)。它符合NIST SP 800-90B/C标准
.686
.MODEL flat, STDCALL
INCLUDE kernel32.inc ; GetStdHandle, WriteFile, ExitProcess
INCLUDELIB kernel32.lib
INCLUDE user32.inc ; wsprintf
INCLUDELIB user32.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.CONST
err_text db "ERR: RDSEED not supported.",10,0
.CODE
main PROC
mov eax, 07h ; Check for availability (EAX=7, ECX=0) -> EBX.18
xor ecx, ecx
cpuid
bt ebx, 18 ; CPUID (EAX=07H, ECX=0H):EBX.RDSEED[bit 18] = 1 ?
jnc err_exit ; No (RDSEED not supported) -> err_exit
mov ecx, NumberOfNumbers ; Loop counter - generate and show ECX random numbers
LL1:
push ecx ; Preserve loop counter
@@:
db 0Fh, 0C7h, 0F8h ; rdseed eax
jnc @B ; Invalid number - try again
; Adjust EAX to the range
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
call write_number
pop ecx ; Restore loop counter
loop LL1
invoke ExitProcess, 0 ; Returncode = 0
err_exit:
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
push eax ; Place for WriteFile.NumberOfBytesWritten
invoke WriteFile, eax, ADDR err_text, LENGTHOF err_text, esp, 0
invoke ExitProcess, 1 ; Returncode = 1
main ENDP
write_number PROC STDCALL USES ebx ; printf ("%u ", EAX)
LOCAL numstring[20]:BYTE, NumberOfBytesWritten:DWORD
.CONST
fmt db "%u ",0
.CODE
invoke wsprintf, ADDR numstring, ADDR fmt, eax
mov ebx, eax ; Preserve count of written bytes
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
mov edx, eax ; EAX will be used by the following INVOKE
invoke WriteFile, edx, ADDR numstring, ebx, ADDR NumberOfBytesWritten, 0
ret
write_number ENDP
END main
您是想实现自己的伪随机函数,还是只想知道如何从asm调用
rand()
?我想知道如何从asm调用rand()。我使用了这个解决方案,它是有效的!调用GetTickCount invoke nseed、eax invoke nrandom、10 invoke dwtoa、eax、offset lpszNumber invoke StdOut、offset lpszNumbercrc32%eax
可能是SSE4.2上可用的最简单的PRNG。
.686
.MODEL flat, C
INCLUDE msvcrt.inc ; crt_time, crt_srand, crt_rand, crt_printf,crt_exit
INCLUDELIB msvcrt.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.DATA
fmt db "%u ", 0
.CODE
main PROC
sub esp, 8 ; Reserve place for the C arguments
; srand( time (NULL) )
mov DWORD PTR [esp], 0
call crt_time ; EAX = time(0)
mov [esp], eax
call crt_srand ; srand (EAX)
mov ebx, NumberOfNumbers ; Loop counter - show ECX random numbers
LL1:
call crt_rand ; EAX = rand()
; Adjust EAX to the range
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
; printf ("%d\n", EAX )
mov [esp], OFFSET fmt
mov [esp+4], eax
call crt_printf ; printf (fmt,eax)
dec ebx
jne LL1
; exit (0) = return 0
mov DWORD PTR [esp], 0
call crt_exit ; exit (0) = return 0
main ENDP
END main
.686
.MODEL flat, STDCALL
INCLUDE kernel32.inc ; GetStdHandle, WriteFile, ExitProcess
INCLUDELIB kernel32.lib
INCLUDE user32.inc ; wsprintf
INCLUDELIB user32.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.CONST
err_text db "ERR: RDRAND not supported.",10,0
.CODE
main PROC
mov eax, 01h ; Check for availability (EAX=1) -> ECX.30
cpuid
bt ecx, 30 ; CPUID.01H:ECX.RDRAND[bit 30] = 1 ?
jnc err_exit ; No (RDRAND not supported) -> err_exit
mov ecx, NumberOfNumbers ; Loop counter - generate and show ECX random numbers
LL1:
push ecx ; Preserve loop counter
@@:
db 0Fh, 0C7h, 0F0h ; rdrand eax
jnc @B ; Invalid number - try again
; Adjust EAX to the range
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
call write_number
pop ecx ; Restore loop counter
loop LL1
invoke ExitProcess, 0 ; Returncode = 0
err_exit:
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
push eax ; Place for WriteFile.NumberOfBytesWritten
invoke WriteFile, eax, ADDR err_text, LENGTHOF err_text, esp, 0
invoke ExitProcess, 1 ; Returncode = 1
main ENDP
write_number PROC STDCALL USES ebx ; printf ("%u ", EAX)
LOCAL numstring[20]:BYTE, NumberOfBytesWritten:DWORD
.CONST
fmt db "%u ",0
.CODE
invoke wsprintf, ADDR numstring, ADDR fmt, eax
mov ebx, eax ; Preserve count of written bytes
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
mov edx, eax ; EAX will be used by the following INVOKE
invoke WriteFile, edx, ADDR numstring, ebx, ADDR NumberOfBytesWritten, 0
ret
write_number ENDP
END main
.686
.MODEL flat, STDCALL
INCLUDE kernel32.inc ; GetStdHandle, WriteFile, ExitProcess
INCLUDELIB kernel32.lib
INCLUDE user32.inc ; wsprintf
INCLUDELIB user32.lib
NumberOfNumbers = 30 ; Number of random numbers to be generated and shown
RangeOfNumbers = 12 ; Range of the random numbers (0..RangeOfNumbers-1)
.CONST
err_text db "ERR: RDSEED not supported.",10,0
.CODE
main PROC
mov eax, 07h ; Check for availability (EAX=7, ECX=0) -> EBX.18
xor ecx, ecx
cpuid
bt ebx, 18 ; CPUID (EAX=07H, ECX=0H):EBX.RDSEED[bit 18] = 1 ?
jnc err_exit ; No (RDSEED not supported) -> err_exit
mov ecx, NumberOfNumbers ; Loop counter - generate and show ECX random numbers
LL1:
push ecx ; Preserve loop counter
@@:
db 0Fh, 0C7h, 0F8h ; rdseed eax
jnc @B ; Invalid number - try again
; Adjust EAX to the range
mov ecx, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
xor edx, edx ; Needed for DIV
div ecx ; EDX:EAX/ECX -> EAX remainder EDX
mov eax, edx ; Get the remainder
call write_number
pop ecx ; Restore loop counter
loop LL1
invoke ExitProcess, 0 ; Returncode = 0
err_exit:
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
push eax ; Place for WriteFile.NumberOfBytesWritten
invoke WriteFile, eax, ADDR err_text, LENGTHOF err_text, esp, 0
invoke ExitProcess, 1 ; Returncode = 1
main ENDP
write_number PROC STDCALL USES ebx ; printf ("%u ", EAX)
LOCAL numstring[20]:BYTE, NumberOfBytesWritten:DWORD
.CONST
fmt db "%u ",0
.CODE
invoke wsprintf, ADDR numstring, ADDR fmt, eax
mov ebx, eax ; Preserve count of written bytes
invoke GetStdHandle, -11 ; Get STD_OUTPUT_HANDLE
mov edx, eax ; EAX will be used by the following INVOKE
invoke WriteFile, edx, ADDR numstring, ebx, ADDR NumberOfBytesWritten, 0
ret
write_number ENDP
END main