批处理技术内幕:随机数%RANDOM%

标签: , , , , , ,

在批处理中,如果命令扩展被启用,那么有几个动态环境变量可以被扩展,其中之一就是随机数%RANDOM%,%RANDOM%会被扩展到0和32767之间的任意十进制数字。这是常识,地球人都知道,我们讲点一般人不知道的。

说到随机数,学过C语言的朋友马上会想到rand函数,rand是C标准库函数,用来生成伪随机数,而%RANDOM%恰好也是用rand函数来实现的,也许CMD本身就是用C语言写的吧。

rand

在调用rand函数之前,一般要先调用srand函数,用来初始化随机数种子,为了防止随机数每次重复常常使用系统时间来初始化,即使用time函数来获得系统时间,这在C程序中可以说是固定写法了。

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i;
    srand(time(NULL));
    for (i = 0; i < 10; i++) {
        printf("%d\n", rand());
    }
    return 0;
}

CMD在初始化时也是这么做的,以time函数的返回值来调用srand函数初始化种子。

srand

rand函数生成的是伪随机数,而不是真正的随机数,其算法可以在Visual C++中找到。

void __cdecl srand (
        unsigned int seed
        )
{

        _getptd()->_holdrand = (unsigned long)seed;

}
int __cdecl rand (
        void
        )
{

        _ptiddata ptd = _getptd();

        return( ((ptd->_holdrand = ptd->_holdrand * 214013L
            + 2531011L) >> 16) & 0x7fff );

}

分析上面的代码可知,如果知道调用srand函数的时间,那么就可以知道每次调用rand函数生成的随机数是多少。也就是说,如果知道CMD的启动时间(从CMD启动到CMD调用srand的时间通常不会超过1秒),那么就可以推算出%RANDOM%的值是多少。

写一个批处理来演示一下:

::By Demon
::https://demon.tw
@echo off
setlocal enabledelayedexpansion
set /a x = !random!
echo !x! & echo;
call :time t
for /l %%i in (%t%, -1, 0) do (
    set /a "y = ((%%i * 214013 + 2531011) >> 16) & 0x7fff"
    if !y! equ !x! (
        echo %%i
        call :srand %%i
        call :rand z
        echo !z! & echo;
        for /l %%j in (1, 1, 10) do (
            call :rand z
            echo !z! !random!
        )
    )
    echo;
    pause & exit
)

:time
setlocal
for /f "skip=1 tokens=1-9" %%a in ('wmic path win32_utctime ^| findstr .') do set /a m=%%e+9,m%%=12,y=%%i-m/10,t=365*y+y/4-y/100+y/400+(m*306+5)/10+%%a-719469,t=t*86400+%%c*3600+%%d*60+%%g
endlocal & set %1=%t% & goto :eof

:srand
set /a _holdrand = %1
goto :eof

:rand
set /a _holdrand = _holdrand * 214013 + 2531011
set /a "%1 = (_holdrand >> 16) & 0x7fff"
goto :eof
赞赏

微信赞赏支付宝赞赏

随机文章:

  1. MAX_PATH 还是 MAX_PATH + 1 ?
  2. OpenWrt中的Hotplug脚本
  3. VBS模拟POST上传文件
  4. VBScript编译器(VBS也疯狂)
  5. OpenWrt SSH远程端口转发

留下回复