Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows 使用MASM32在汇编中随机化数字_Windows_Assembly_Random_Masm_Masm32 - Fatal编程技术网

Windows 使用MASM32在汇编中随机化数字

Windows 使用MASM32在汇编中随机化数字,windows,assembly,random,masm,masm32,Windows,Assembly,Random,Masm,Masm32,如何使用带Masm32的汇编随机化一个数字?我可以使用什么来创建随机数生成器 多谢各位 您需要实现一个,如下所示: 如果您想在汇编中获得随机数,我想有两种方法: 如果允许在程序集中调用C函数,则可以使用 我们在大学里用过,有一个命令 ()在NASM中读取CPU时钟并将其放入 登记册。你可以把这个数除以,得到一个随机数 我不知道MASM,但保罗·卡特的很棒。使用MASM32获取随机数 附带了一些实现随机生成器的示例。将它们用于自己的目的并不是最糟糕的想法。下面的示例只是示例,缺少错误处理。这

如何使用带Masm32的汇编随机化一个数字?我可以使用什么来创建随机数生成器

多谢各位

您需要实现一个,如下所示:


如果您想在汇编中获得随机数,我想有两种方法:

  • 如果允许在程序集中调用C函数,则可以使用
  • 我们在大学里用过,有一个命令 ()在NASM中读取CPU时钟并将其放入 登记册。你可以把这个数除以,得到一个随机数
我不知道MASM,但保罗·卡特的很棒。

使用MASM32获取随机数 附带了一些实现随机生成器的示例。将它们用于自己的目的并不是最糟糕的想法。下面的示例只是示例,缺少错误处理。这些示例生成并生成范围为[0..11]的30个随机数

A=134775813和b=c的A(如Delphi)位于\masm32\examples\exampl03\lcd\lcd.asm中

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

在\masm32\examples\exampl05\rpg\rpg.asm中使用

\masm32\examples\exampl07\shufarr\sa.asm使用masm32内置的
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 lpszNumber
crc32%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