【内容已更新】
%random% 是个CMD(bat)中的一个系统变量用途就如他的名字一样返回给出一个随机数,比如 echo %random%,就是显示一个随机数.
见batman的探讨(http://bbs.bathome.net/thread-10141-1-1.html),于是也好奇就大致跟踪了一下CMD的处理过程。
前边不说,当CMD识别 random 这个关键字之后,直接调用位于 msvcrt.lib 中的 函数 rand();
;--------------------------------------------------------------
49E82D20 > \68 3C2DE849 PUSH cmd.49E82D3C ; UNICODE "RANDOM"
49E82D25 . FF75 08 PUSH DWORD PTR SS:[EBP+8] ; 这里是我们的关键字"random"
49E82D28 . FFD3 CALL EBX ;一个比较字符串的函数
49E82D2A . 59 POP ECX
49E82D2B . 59 POP ECX
49E82D2C . 85C0 TEST EAX,EAX
49E82D2E . 0F84 AF250100 JE cmd.49E952E3 ;若返回值为0 则跳转,跳转后就是到了下面这条
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
49E952E3 > \FF15 AC10E849 CALL DWORD PTR DS:[<&msvcrt.rand>] ; 这里就是调用msvcrt.dll里的rand函数,看的出这个函数无参数
;--------------------------------------------------------------
下面我们到msvcrt.dll里看看这个rand函数到底做了什么. 下面这个就是rand函数
msvcrt&rand()函数 ;以下就是msvcrt&rand函数,简化下给大家看- push 1
- call FlsGetValue ;返回值eax 是一个结构的指针(这个结构与纤程有关,我们不管其具体含义)
- mov ecx,[eax + 14h] ;[eax + 14h]对我们的随机数 至关重要 !从计算过程可以看出,它直接影响随机数的计算!
- imul ecx,ecx,343FDh ;ecx里就是从[eax + 14h]取出来的值,看它在计算了
- add ecx,269EC3h
- mov [eax + 14h],ecx ;这里更新了 [eax + 14h],这样下次我们再取随机数,再用到[eax + 14h],那么他已经不是原来的值了
- mov eax,ecx ;这样每一次的数值才可能不同
- shr eax,10h
- and eax,7FFFh ;与运算保证了随机数的范围0~32767。此时的eax中的值就是 我们最后 得到的%random%的值
复制代码 上哪个面说了 [eax + 14h] 里的内容对我们随机数至关重要,那么它的初始值是多少呢? 也就是说 一个随机数没取呢,rand函数
没有改变过它呢
cmd.exe把它置为多少呢?? 其实它就是我们的 随机数种子 ,产生伪随机数的原因就是种子未与时间关联。
那么我们的cmd.exe最初把[eax + 14h]置为了与时间有关的量了吗???
答案是:是的。(原谅我上次轻率地说与时间无关)
经过又一轮苦苦的跟踪调试,终于找到了以下两个函数,大家一看函数名字就明白了 ~~~哈哈
这两个函数的执行时在 系统初始化完后,cmd.exe进程自身初始化时主动调用的:
他们就是:
;===============================================================
49F457E0 . 56 PUSH ESI ; /timer
49F457E1 . FF15 8410F449 CALL DWORD PTR DS:[<&msvcrt.time>] ; \time
49F457E7 . 50 PUSH EAX ; /seed
49F457E8 . FF15 8810F449 CALL DWORD PTR DS:[<&msvcrt.srand>] ; \srand
;===============================================================
看哪! 是 time 函数 和 srand 函数,一个是内部调用API GetSystemTimeAsFileTime(获取当前的系统时间和日期)
并进行一系列运算返回一个值
一个是把刚刚返回的值作为参数,并修改 [eax + 14h]。综合起来就是以时间作为随机数种子!
好了,到这里我们认识到了,cmd.exe初始化时调用msvcrt.dll里的time和srand函数作为随机数种子
之后若用户使用 %random% 则调用msvcrt.dll 里的 rand 函数。
这与C里的rand()函数就很类似了!因此
若真要比就是 大同小异。
我们的 %random% 很不错啊!
;/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
总结:
1。当多次双击时实质是打开多个CMD.EXE进程,这些进程之间是不相关的,无联系,但是为什么它们的随机数这么接近?
原因可能就是 打开时间接近 随机数种子 接近,导致随机数接近
2。在同一个进程中,多次调用%random%结果可以说肯定是随机的,因为MOV DWORD PTR DS:[EAX+14],ECX 改变了随机数种子,
每一次都将它变化.
3。对于for语句内部的确是与预处理有关,就如这个- @echo off
- for /l %%a in (1,1,10) do echo %random%
- pause>nul
复制代码 它的执行是,执行时处理%random%然后就echo random的值10次,其间不再调用 msvcrt.dll 里的 rand 函数,大家知道,这就意味着,
它只负责把变量处理一次,然后自己找个地方存起来,以后for里面do后的命令都用它自己存起来的这个值,不再重新获得变量的值!
而开启了 变量延迟 的是:每次 都重新 调用 msvcrt.dll 里的 rand 函数,即每次系统都主动更新变量,不自己存储。
【内容 已更新,找到了随机数种子 ~~~ 就是 时间 】
[ 本帖最后由 vsbat 于 2010-12-2 00:12 编辑 ] |