使用MASM32随机化装配中的数字

时间:2013-04-23 13:40:21

标签: windows assembly random masm masm32

如何使用Masm32装配随机化数字?我可以用什么来创建随机数生成器?

非常感谢!

3 个答案:

答案 0 :(得分:4)

使用MASM32获取随机数

MASM32 SDK附带了一些实现随机生成器的示例。将它们用于自己的目的并不是最糟糕的想法。以下示例仅是示例,缺少 - 其中 - 在错误处理中。这些示例生成并生成[0..11]范围内的30个随机数。

a linear congruential generator,其中a = 134775813,b = c(如Delphi)位于 \ masm32 \ examples \ exampl03 \ lcd \ lcd.asm

{"random":84}

可以在 \ masm32 \ examples \ exampl04 \ pascal \ pascal.asm 中找到XORshifter

.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

\ masm32 \ examples \ exampl05 \ rpg \ rpg.asm

中使用Park-Miller-Algorithm
.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

\ masm32 \ examples \ exampl07 \ shuflarr \ sa.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 内置的MASM32。源代码位于 \ masm32 \ m32lib \ nrand.asm 中。它与上面的Park-Miller算法相同。

nrandom

有很多.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 个文件可以访问Windows系统。 Microsoft建议使用.lib

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 中找到了一个未记录的函数Dns_GetRandomXid。它使用dnsapi.lib,有时使用C函数CryptGenRandom,似乎是线程安全的。

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 中的CDGenerateRandomBits

cryptdll.lib

不应缺少C库中的旧.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

rand()

在现代处理器上(至少Ivy Bridge - 自2012年起),实施了指令RDRAND。它符合NIST SP 800-90A standard。 MASM32 SDK中的MASM汇编程序无法汇编此指令。解决方法是将指令作为一系列十六进制字节插入代码中。 MASM会将其存储为给定,处理器将根据需要执行它。

.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 (至少Broadwell - 自2014年起)。它符合NIST SP 800-90B / C标准。

RDSEED

答案 1 :(得分:1)

您需要实现Pseudorandom number generator,就像在这个答案中一样:

Pseudorandom generator in Assembly Language

答案 2 :(得分:0)

如果你想在Assembly中获得随机数,我猜有两种方法:

  • 如果允许您在程序集中调用C函数,则可以使用 rand()
  • 我们在大学里使用NASM并且有一个命令 (rdtsc)在NASM中读取CPU时钟并将其置于 寄存器。你可以将这个数字除以一个随机数。

我不知道MASM,但保罗卡特的NASM tutorial很棒。