标题: [原创]批处理学习帖⑤ —— if命令的运行机制初探
[打印本页]
作者: q8249014
时间: 2010-2-4 16:54
标题: [原创]批处理学习帖⑤ —— if命令的运行机制初探
作为三种基本结构之一的选择结构在程序编写中起着至关重要的作用。在批处理中选择结构
是由if命令来实现的,了解批处理中if命令的运行机制能够帮助我们更好的解决实际问题。
我们先来看两个例子
@echo off&setlocal enabledelayedexpansion
:: 代码1
set "var=if test==test echo.ok"
set var
<nul set/p"=%%var%% -- "&%var%
<nul set/p"=^!var^! -- "&!var!
pause
代码1执行结果
var=if test==test echo.ok
%var% -- ok
!var! -- 'if' 不是内部或外部命令,也不是可运行的程序
或批处理文件。
请按任意键继续. . .
从命令行打印的结果中可以看出“var”的值等于“if test==test echo.ok”,第二行打印出“%var% -- ok”
没有什么问题,然而第三行打印出“'if' 不是内部或外部命令……”,为什么呢?if不是内部命令吗?呵呵
@echo off&setlocal enabledelayedexpansion
:: 代码2
set "var=test "
echo.[^^!var^^!=!var!] [%%var%%=%var%]
if !var!==%var% (echo.相等) else (echo.不相等)
pause
代码2执行结果
[!var!=test ] [%var%=test ]
不相等
请按任意键继续. . .
从“echo”打印的结果中可以看出“!var!=%var%”,可为什么用“if”进行比较后却又“不相等”呢?
“原创文章,转帖请注明出处cn-dos&q8249014哦”
一、实例分析
看过学习贴①的同学可能还记得学习贴①中第二段所提到的“预处理工作”中“Rem (3)……”这些内容
___________________________________________________________________________________
“if”命令没有单独的命令分析处理模块,它和预处理共用一个命令处理模块。在“匹配处理”过后,如果命令语句
中存在“if”命令则对“if”命令语句进行格式匹配,然后待预处理中其他工作进行完毕后(如:延迟变量的扩展)进
行条件比较,将成立的命令语句提交给该命令主体执行。“if”命令嵌套“if”命令也是一样。
___________________________________________________________________________________
好,我们先来看一下代码1中的 “<nul set/p"=%%var%% -- "&%var%”
cmd读取完毕“<nul set/p"=%%var%% -- "&%var%”后,首先扩展其中的环境变量,“%%var%%”中两个“%”均被转义
变为“%var%”,“%var%”被替换为“if test==test echo.ok”,然后命令先后得到执行,没有问题
再来看一下“<nul set/p"=^!var^! -- "&!var!”
读取完毕“<nul set/p"=^!var^! -- "&!var!”后,在“匹配处理”阶段,由于代码中的“^”都在引号内,所以不被
解释,又因为开启了延迟环境变量扩展,所以在命令提交给“set”前会扩展使用“!”引用的变量,而这时由于“^”
的存在两个“!”均被转义变为“!var!”,然后提交给“set”执行;紧接着执行命令连接符后面的“!var!”,这时首先将
“!var!”替换为“if test==test echo.ok”,然后提交给“if”,可为什么显示“'if' 不是内部或外部命令……”,的错
误提示呢?如上面所说“if”命令的解释过程在延迟变量扩展之前进行,由于在这个时候没有匹配到“if”命令,所
以延迟变量扩展完毕后就直接将命令语句提交给命令主体,而“if”命令又没有单独的处理模块,cmd也找不到
外部主体,自然就提示错误了。
注:命令解释器会读取一条完整的命令语句然后对其进行处理,上文为了叙述方便所以分开来说。
根据上面的分析同学们自行解释一下代码2?
“原创文章,转帖请注明出处cn-dos&q8249014哦”
二、实例演示
密码验证程序
在我所见过的代码中,密码验证一般都是使用这种格式:
@echo off
set var=
set /p var=:
if %var%==test (echo 密码正确) else (echo 密码错误)
pause
如果你通过telnet得到了一个远程主机的shell,但是他在注册表的 autorun 键值中加入了上面的代码,你
该怎么办呢?
其实从预处理的角度来看以上代码是有严重漏洞的。你可以在命令行中输入“a==a call type %0 & pause”
这样我们就知道密码了
如果管理员在聪明一点儿,把以上代码加密,那么上面这种方法就没有用了,但是我们可以这样来做
1.“a==a call >test_.tmp echo ”
2.再次登陆远程主机输入:“a==a type test_.tmp & pause”
3.还可以使用reg命令来破解
还是有漏洞,[当然还有其他情况,破解方法大同小异]
我们现在知道了if的运行机制后就可以很容易的防止这种漏洞
以下这段代码你如何破解呢?
@echo off&endlocal&setlocal enabledelayedexpansion
set var=
set/p var=:&cls
if !var!==q8249014 (echo.密码正确) else (%0)
pause
对用户输入的文件路径进行精确验证
下面这段代码同学们可以使用任意字符进行测试
@echo off
set filename=
set error=
set /p filename=请输入文件名或者文件的绝(相)对路径:&cls
setlocal enabledelayedexpansion
set path=%cd%
for /f "eol=? delims=" %%i in ("!filename!") do (
if not exist %%~$path:i.\* (set error=0)
)
endlocal&if "%error%" equ "" echo.输入错误&%0
set filename
pause
其实沿用这个思路还可以解决很多问题,如:“批处理编程的异类 ”中所提到的防空字符的选择等。
三、总结
这里我们大致的写一下“if”命令的执行流程
1.扩展命令语句中使用“%”引用的环境变量
2.进行预处理匹配工作
3.if接管控制权,进行命令格式匹配
4.…………
5.扩展延迟环境变量“!”
6.if开始进行条件比较
7.将成立的命令语句提交给该命令主体执行
这仅是一个大致的执行过程。
@echo off&setlocal enabledelayedexpansion
call if test==test echo equ
set "var=if test==test echo equ"
!var!
pause
上面这两种调用if的方法都是错误的,学习了这节课后同学们就知道为什么不能使用call调用if和for命令了
这一节到这里就结束了。
“原创文章,转帖请注明出处cn-dos&q8249014哦”
[
Last edited by q8249014 on 2010-2-4 at 16:56 ]
作者: bat-zw
时间: 2010-2-5 17:46
好!很有见解,学习了。
作者: qinchun36
时间: 2010-2-6 07:37
你真适合去做科研,我还不知道能这么破密码呢。。。
作者: jarry0932
时间: 2010-2-8 00:59
好贴!!!见到楼主这句“a==a call type %0 & pause” 我感觉太经典了,换成我,打死都想不到这样就可以破解一般的批处理密码验证。。。强。。。牛。。。