Get random numbers with MASM32
The MASM32 SDK comes with some examples which implement random generators. It isn't the worst idea to use them for own purposes. The following examples are just examples and lack - among others - in an error handling. The examples generate and produce 30 random numbers in the range [0..11].
A linear congruential generator with a=134775813 and b=c (like Delphi) is in masm32examplesexampl03lcdlcd.asm.
.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)
.DATA
RandSeed dd ?
.CODE
PseudoRandom PROC ; Deliver EAX: Range (0..EAX-1)
push edx ; Preserve EDX
imul edx,RandSeed,08088405H ; EDX = RandSeed * 0x08088405 (decimal 134775813)
inc edx
mov RandSeed, edx ; New RandSeed
mul edx ; EDX:EAX = EAX * EDX
mov eax, edx ; Return the EDX from the multiplication
pop edx ; Restore EDX
ret
ret
PseudoRandom ENDP ; Return EAX: Random number in range
main PROC
rdtsc
mov RandSeed, eax ; Initialize random generator
mov ecx, NumberOfNumbers ; Loop counter - show ECX random numbers
LL1:
push ecx ; Preserve loop counter
mov eax, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
call PseudoRandom
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
A XORshifter can be found in masm32examplesexampl04pascalpascal.asm.
.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)
.CODE
Rnd3Bit Proc ; This procedure generates up to 20 random bits (EAX=0..20).
.DATA
RndInit dd 0A2F59C2Eh
.CODE
mov edx,RndInit
rl: rol edx, 1
jnc rs
xor edx, 0Ah
rs: dec eax
jne rl
mov eax, edx
rcr edx, 1
mov RndInit, edx
ret
Rnd3Bit EndP
main PROC
rdtsc ; Any number for the first seed
test eax, eax ; EAX == 0?
setz dl ; DL=1 if EAX==0, DL=0 if EAX>0
or eax, edx ; Not 0 under any circumstances
mov RndInit, eax ; Reinitialize random generator
mov ecx, NumberOfNumbers ; Loop counter - show ECX random numbers
LL1:
push ecx ; Preserve loop counter
mov eax, 20 ; Amount of bits
call Rnd3Bit
and eax, 11111111111111111111b ; 20 bits set = 1048575
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 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
The Park-Miller-Algorithm is used in masm32examplesexampl05
pg
pg.asm
.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)
.DATA
rseed dd 0
range dd 0
.CODE
nrandom PROC
; ------------------
; NaN's nrandom algo (Park Miller random algorithm)
; ------------------
lpstart:
mov eax, rseed
test eax, 80000000h
jz @F
add eax, 7FFFFFFFh
@@:
xor edx, edx
mov ecx, 127773
div ecx
mov ecx, eax
mov eax, 16807
mul edx
mov edx, ecx
mov ecx, eax
mov eax, 2836
mul edx
sub ecx, eax
xor edx, edx
mov eax, ecx
mov rseed, ecx
div range
mov eax, edx ; Write DWORD result to return register
add rseed, 1 ; New value to rseed
ret
nrandom ENDP
main PROC
rdtsc
mov rseed, eax ; Reinitialize random generator
mov ecx, NumberOfNumbers ; Loop counter - show ECX random numbers
LL1:
push ecx ; Preserve loop counter
mov range, RangeOfNumbers ; Range (0..RangeOfNumbers-1)
call nrandom
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 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
masm32examplesexampl07shuflarrsa.asm uses the MASM32 built in nrandom
. The source code is located in masm32m32lib
rand.asm. It's the same Park-Miller-Algorithm as above.
.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
There are a lot of .lib
files to acces the Windows system. Microsoft suggests to use 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
I found an undocumented functio