随机数生成器在装配中崩溃
Random number generator crashing in assembly
在 Whosebug 上找到这段代码,我了解它的工作原理并尝试实现它。它在 INT 1AH 指令处崩溃,我不知道为什么。
当我 运行 它在 ollydbg 时,它停在同一行。
我还尝试了随机数生成器函数 rand(void),但每当我重新运行 代码时,它总是给我相同的数字。 (如果我连续调用它 3 次,则有 3 个不同的数字,但每次调用仍然相同 运行)
.386
.model flat, stdcall
includelib msvcrt.lib
extern exit: proc
extern printf: proc
extern rand: proc
public start
.data
decimal_format DB "%d",0ah
.code
start:
mov ah, 00h
int 1ah
mov ax,dx
mov dx,0
mov cx,10
div cx
mov ah,2h
int 21h
push edx
push offset decimal_format
call printf
add esp,8
push 0
call exit
end start
如果您正在编写 Win32 程序,则不能调用 BIOS 和 DOS 服务,例如 Int 1ah
、Int 10h
、Int 21h
等。这会使您的应用程序崩溃,因为 Win32 程序不会可以访问这些服务。
WindowsC库(MSVCRT.LIB)中的基本rand
和srand
是基于线性全等的生成器 (LCG) pseudo-random 数字生成器 (PRNG)。此公式依赖于种子值来设置 PRNG 的初始状态。每次程序重新启动时,程序执行时的初始状态将始终相同。每次调用 rand
都会重新生成一个 pseudo-random 数字,但是每次程序 运行.
时数字的序列都是相同的
srand
can be used to change the seed value of the PRNG. Changing the seed value will alter the numbers rand
will produce but they will always be the same sequence of numbers given the same seed. What you need is a mechanism to set the seed value to a different value each time the program is run. You can use the C library time
带有 NULL(0) 参数的函数获取自 1970 年 1 月 1 日午夜以来的秒数。只要您的程序不是 运行 快速,这个值应该不同以这种方式它在同一秒内执行。这通常就足够了。
然后您可以将 return 由 time(0)
在 EAX 中编辑的值传递给 srand
以设置种子值。程序启动时只调用 srand
一次。从那时起,您应该可以调用 rand
来获得一个新的随机数。 rand
return0 和 RAND_MAX 和 RAND_MAX 之间的值是 32767。
此示例代码 srand(time(0))
初始化种子,然后循环 10 次打印出通过调用 rand
检索到的不同随机数。每次 运行 程序的输出都应该不同。
.386
.model flat, C
includelib msvcrt.lib
extern exit: proc
extern printf: proc
extern rand: proc
extern srand: proc
extern time: proc
.data
decimal_format DB "%d", 0ah, 0
; Ensure string is NUL(0) terminated
.code
main PROC
push ebx ; Save callee saved (non-volatile) registers that we use.
; EBX, EBP, ESI, EDI, ESP are non-volatile. For each
; one we clobber we must save it and restore it before
; returning from `main`
push 0
call time ; EAX=time(0)
add esp, 4
push eax ; Use time as seed
call srand ; srand(time(0))
add esp, 4
mov ebx, 10 ; Loop 10 times
loopit:
call rand ; Get a random number between 0 and 32767 into EAX
push eax
push offset decimal_format
call printf ; Print the random number
add esp,8
dec ebx
jnz loopit ; Loop until the counter EBX reaches 0
pop ebx ; Restore callee saved registers
xor eax, eax ; Return 0 from our program
ret
main ENDP
END
其他一些重要的变化。我使用 C (CDECL) 调用约定(通过 .model flat, C
)自动处理在 32 位代码中使用下划线装饰 main PROC
。我还将 start
更改为 main
,并将 end start
更改为 end
。我们也不想使用 end main
,因为该指令将使 main
成为我们代码的入口点,并将跳过 C 运行 时间通常必须在调用 main
之前完成的初始化。未能调用 C 运行time 初始化可能会使 C 库函数意外工作或完全崩溃。
代码完成后,我对 C 启动代码执行 ret
到 return,这将为我们退出。该代码还保留了 non-volatile(被调用方已保存)寄存器。有关详细信息,请参阅 Microsoft 32-bit CDECL calling convention。
在 Whosebug 上找到这段代码,我了解它的工作原理并尝试实现它。它在 INT 1AH 指令处崩溃,我不知道为什么。 当我 运行 它在 ollydbg 时,它停在同一行。
我还尝试了随机数生成器函数 rand(void),但每当我重新运行 代码时,它总是给我相同的数字。 (如果我连续调用它 3 次,则有 3 个不同的数字,但每次调用仍然相同 运行)
.386
.model flat, stdcall
includelib msvcrt.lib
extern exit: proc
extern printf: proc
extern rand: proc
public start
.data
decimal_format DB "%d",0ah
.code
start:
mov ah, 00h
int 1ah
mov ax,dx
mov dx,0
mov cx,10
div cx
mov ah,2h
int 21h
push edx
push offset decimal_format
call printf
add esp,8
push 0
call exit
end start
如果您正在编写 Win32 程序,则不能调用 BIOS 和 DOS 服务,例如 Int 1ah
、Int 10h
、Int 21h
等。这会使您的应用程序崩溃,因为 Win32 程序不会可以访问这些服务。
WindowsC库(MSVCRT.LIB)中的基本rand
和srand
是基于线性全等的生成器 (LCG) pseudo-random 数字生成器 (PRNG)。此公式依赖于种子值来设置 PRNG 的初始状态。每次程序重新启动时,程序执行时的初始状态将始终相同。每次调用 rand
都会重新生成一个 pseudo-random 数字,但是每次程序 运行.
srand
can be used to change the seed value of the PRNG. Changing the seed value will alter the numbers rand
will produce but they will always be the same sequence of numbers given the same seed. What you need is a mechanism to set the seed value to a different value each time the program is run. You can use the C library time
带有 NULL(0) 参数的函数获取自 1970 年 1 月 1 日午夜以来的秒数。只要您的程序不是 运行 快速,这个值应该不同以这种方式它在同一秒内执行。这通常就足够了。
然后您可以将 return 由 time(0)
在 EAX 中编辑的值传递给 srand
以设置种子值。程序启动时只调用 srand
一次。从那时起,您应该可以调用 rand
来获得一个新的随机数。 rand
return0 和 RAND_MAX 和 RAND_MAX 之间的值是 32767。
此示例代码 srand(time(0))
初始化种子,然后循环 10 次打印出通过调用 rand
检索到的不同随机数。每次 运行 程序的输出都应该不同。
.386
.model flat, C
includelib msvcrt.lib
extern exit: proc
extern printf: proc
extern rand: proc
extern srand: proc
extern time: proc
.data
decimal_format DB "%d", 0ah, 0
; Ensure string is NUL(0) terminated
.code
main PROC
push ebx ; Save callee saved (non-volatile) registers that we use.
; EBX, EBP, ESI, EDI, ESP are non-volatile. For each
; one we clobber we must save it and restore it before
; returning from `main`
push 0
call time ; EAX=time(0)
add esp, 4
push eax ; Use time as seed
call srand ; srand(time(0))
add esp, 4
mov ebx, 10 ; Loop 10 times
loopit:
call rand ; Get a random number between 0 and 32767 into EAX
push eax
push offset decimal_format
call printf ; Print the random number
add esp,8
dec ebx
jnz loopit ; Loop until the counter EBX reaches 0
pop ebx ; Restore callee saved registers
xor eax, eax ; Return 0 from our program
ret
main ENDP
END
其他一些重要的变化。我使用 C (CDECL) 调用约定(通过 .model flat, C
)自动处理在 32 位代码中使用下划线装饰 main PROC
。我还将 start
更改为 main
,并将 end start
更改为 end
。我们也不想使用 end main
,因为该指令将使 main
成为我们代码的入口点,并将跳过 C 运行 时间通常必须在调用 main
之前完成的初始化。未能调用 C 运行time 初始化可能会使 C 库函数意外工作或完全崩溃。
代码完成后,我对 C 启动代码执行 ret
到 return,这将为我们退出。该代码还保留了 non-volatile(被调用方已保存)寄存器。有关详细信息,请参阅 Microsoft 32-bit CDECL calling convention。