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

问题描述 投票:-2回答:3

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

非常感谢你!

windows assembly random masm masm32
3个回答
5
投票

使用MASM32获取随机数

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

a = 134775813和b = c(如Delphi)的linear congruential generator位于\ masm32 \ examples \ exampl03 \ lcd \ lcd.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

可以在\ 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)

.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

Park-Miller-Algorithm用于\ masm32 \ examples \ exampl05 \ rpg \ rpg.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 \ examples \ exampl07 \ shuflarr \ sa.asm使用内置nrandom的MASM32。源代码位于\ 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系统。微软建议使用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。它使用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

另一个未记载的函数是CDGenerateRandomBits中的cryptdll.lib

.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

在现代处理器(至少Ivy Bridge - 自2012年),实施指令RDRAND。它符合NIST SP 800-90A standard。 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(至少Broadwell - 自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

1
投票

你需要实现一个Pseudorandom number generator,就像这个答案:

Pseudorandom generator in Assembly Language


0
投票

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

  • 如果允许在Assembly中调用C函数,则可以使用rand()
  • 我们在大学里使用过NASM,在NASM中有一个命令(rdtsc)读取CPU时钟并将其放入寄存器中。您可以将此数字分开并获得一个随机数。

我不知道MASM,但Paul Carter的NASM tutorial很棒。

© www.soinside.com 2019 - 2024. All rights reserved.