标题: 批处理技术内幕:随机数%RANDOM%
作者: Demon
链接: https://demon.tw/reverse/cmd-internal-random.html
版权: 本博客的所有文章,都遵守“署名-非商业性使用-相同方式共享 2.5 中国大陆”协议条款。
在批处理中,如果命令扩展被启用,那么有几个动态环境变量可以被扩展,其中之一就是随机数%RANDOM%,%RANDOM%会被扩展到0和32767之间的任意十进制数字。这是常识,地球人都知道,我们讲点一般人不知道的。
说到随机数,学过C语言的朋友马上会想到rand函数,rand是C标准库函数,用来生成伪随机数,而%RANDOM%恰好也是用rand函数来实现的,也许CMD本身就是用C语言写的吧。
在调用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函数初始化种子。
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
微信赞赏支付宝赞赏
随机文章: