for/f"tokens=*"%%iin('')dosetpassword=%%i
del
echo.
echoThePasswordis:
"%password%"
pause
这类汇编程序的特殊性在于,所有的代码全部分布于ASCII码表的可显示字符范围中,当然这样的程序不是碰巧得到的,而是人为的构造出来的,其中需要用到许多技巧。
比如最常见的中断调用代码int21(CD21),因为不在ASCII可显示字符范围内,所以用到许多压栈、出栈、增减代码来构造,所以它的代码段是动态变化的。
这样的代码被叫做ASCODE,这样的技术被称作ASCIIAssemble,一门即将消失的技术,可想而知,这样的代码构造起来是困难的,在网上流传的ASCODE只有很少量的是人为构造的,因为已经有成熟的技术可以将任何二进制文件转变为ASCODE,这样的过程叫encode。
而ASCODE执行的过程需要decode,合称codec,codec的算法已知的超过4种,比较有名的应该是HerbertKleebauer的算法,不过它要求原程序必须有org170H的类似标记,因为前面的文件头被用来存放decode代码。
巧妙的.com文件头
据说这个是袁哥写的病毒天极网的分析资料 (
:
0jeX4e-005POP]hWeX5ddP^1,FFFFF1,FFF1,4rP^P_jeX4aPY-x-AAR`0`*=00uPBOIAAAAFKAOBPIDMCBALEAJMNCBJALIAAEMMNCBFEGIGFCAENGBGDHCGPHGGJHCHFHDCAGJHDCAGDGPGNGJGOGHCACOCOCOCOCOCOANAKCEAAqqqq
@ECHOOFF
COPY%0/BC:
\BATVIR.COM/B/Y
C:
\BATVIR.COM
DELC:
\BATVIR.COM
这段代码有什么巧妙指出呢?
第一句的开头, :
冒号告诉cmd.exe,这句是个GOTO语句的标识符,cmd.exe会直接跳过这一句,也就是当作注释了,但是,后面的批处理把自身copy为,这就很讲究了,.com文件是以 :
开头的一段ASCode代码!
所以这种ASCode比上一种更加高级,因为必须以 :
作为ASCode的开头。
与VBS集成
在命令行下调用VBS/JS用cscript命令,由于cscript只能读取文件,不接受重定向和管道的输入,所以只能用echo或者more来生成一个临时脚本文件
传统的echo大法
与批处理不同的是,VBS有很多特殊字符,例如>在批处理中代表重定向输出,在VBS语法里代表大于,所以使用echo需要用^来转义特殊符号
echomsgbox3^>2>v.vbs
cscriptv.vbs
国外的find大法
利用find命令过滤出VBS代码的一个特定'VBS,这样可以嵌入多段VBS代码到bat里,例如:
@echooff&setlocalenableextensions
:
:
Makeatemporaryfolder
ifnotexistc:
\mytempmkdirc:
\mytemp
:
:
BuildaVisualBasicScript
findstr"'%skip%VBS""%~f0">c:
\mytemp\tmp$$$.vbs
:
:
RunitwithMicrosoftWindowsScriptHostVersion5.6
cscript//nologoc:
\mytemp\tmp$$$.vbs
:
:
Callthecommandlinescriptthescripthostbuilt
callc:
\mytemp\tmp$$$.cmd
:
:
Cleanup
for%%fin(c:
\mytemp\tmp$$$.vbsc:
\mytemp\tmp$$$.cmd)doifexist%%fdel%%f
rmdirc:
\mytemp
:
:
Showtheresult
echoDayNumberdn_=%dn_%
endlocal&goto :
EOF
'
'TheVisualBasicScript
ConstForReading=1,ForWriting=2,ForAppending=8'VBS
DimDateNow,fso,f'VBS
DateNow=Date'VBS
Setfso=CreateObject("Scripting.FileSystemObject")'VBS
Setf=fso.OpenTextFile("c:
\mytemp\tmp$$$.cmd",ForWriting,True)'VBS
f.Write"@setdn_="&DatePart("y",DateNow)'VBS
f.Close'VBS
经典的more大法
同上面的more大法,优点是不需要考虑特殊字符的问题,缺点是代码灵活性不高,添加了代码就需要修改+n的值
<"%~f0"more+3>v.vbs
cscript//nologov.vbs
goto:
eof
msgboxnow
wscript.echo">>>CN-DOS<<<"
wscript.stdin.readline
Vacum的方法
最近在写几个Bat,在Google上找到这里,顺便把我的方法也贴到这里来,和上面的Find、more方法原理差不多。
但感觉灵活方便许多。
代码如下,不是很复杂,就不多说明了。
:
:
Makeallthecodeintoonebatfile
@echoOFF
IF"%1"==":
_GET_LINES_"GOTO :
_GET_LINES_
REMYourcodehere
REMExample
(CALL%0 :
_GET_LINES_############)|MORE
(CALL%0 :
_GET_LINES___SQLPLUS__)|MORE
REM这一部分用来取数据。
goto :
EOF
:
_GET_LINES_
SETLOCALENABLEDELAYEDEXPANSION
SETLINE_TAG=%2
SETBEGIN_LINE=0
SETTOTAL_LINE=0
SETCURLINE=0
for/f"usebackqdelims=:
tokens=1"%%iin(`findstr/N/R/C:
^^^^%LINE_TAG%%0`)DOsetBEGIN_LINE=%%i&goto__GET_BEGIN_LINE_OK
:
__GET_BEGIN_LINE_OK
for/f"usebackqdelims=:
tokens=1"%%iin(`(for/f"skip=!
BEGIN_LINE!
tokens=*"%%jin(%0^)do@echo%%j^)^|findstr/N/R/C:
^^^^%LINE_TAG%`)DOsetTOTAL_LINE=%%i&goto__GET_END_LINE_OK
:
__GET_END_LINE_OK
for/f"skip=%BEGIN_LINE%tokens=*"%%iIN(%0)DO((SET/ACURLINE+=1)&(if !
CURLINE!
LSS%TOTAL_LINE%(ifnot"A%%i"=="A"@echo%%i)))
ENDLOCAL
GOTO :
EOF
REM下面是数据部分的内容
############
HelloThisJustaTest
限制,前导空格、空行会被过滤掉,可以在上面的for语句中增加delims=选项来解决,但同时会带来新的问题
############
__SQLPLUS__
SELECT*FROMDUAL;
select*fromdual;
__SQLPLUS__
方便的mshta大法
该方法由est首创,巧妙利用了Windows系统里自带的javascript:
和vbscript:
协议使得在批处理中能够在一行的狭小空间里插入简短的VBS/JS代码论坛讨论 (-
mshta"javascript:
newActiveXObject('SAPI.SpVoice').Speak('Hi,CN-DOSguys!
');window.close();"
事实上使用iexplore.exe和Helpctr.exe也可以,不过mshta.exe的权限相对要高一点
让WSH直接解析bat
这个方法也是est首创论坛讨论 (-
:
OnErrorResumeNext
Subbat
echooff&cls
echoBatching_codez_here_following_vbs_rules&pause
startwscript-e:
vbs"%~f0"
ExitSub
EndSub
MsgBox"Thisisvbs"
代码解释
:
OnErrorResumeNext
cmd.exe识别成一段注释
wscript.exe这样识别, :
在vbs语法里代表分行,然后OnErrorResumeNext,也就是让WSH忽略一些错误
startwscript-e:
vbs"%~f0"
cmd.exe识别成:
启动wscript.exe,其参数是:
①-e:
vbs设定以vbs解析文件自身②"%~f0"指这个批处理本身。
wscript.exe把这句识别成:
调用一个叫start的函数,函数参数是wscript这个变量,然后用这个函数的结果来减去e。
接下来是又是一个 :
,分行,然后又是调用一个名叫vbs的函数,参数是字符:
"%~f0"
这句是最为精巧的,因为它成功的让vbs引擎解释了一段批处理,而且没有错误!
当然这些start()、vbs()函数是不存在的,但是会被cmd.exe当成命令执行。
为什么不用wscript//e:
vbs"%~f0"来执行呢?
vbs解析会出错的
这段代码的核心思想已经介绍完毕了。
下面,为了让批处理以vbs调用其自身后,马上退出,我们需要exit或者goto :
eof,但是gotocallexit在vbs又是一个关键词,所以我们只能用符合vbs语法的exitsub,所以我们在第二句加一个subbat,其实cmd.exe寻找了一个叫sub.exe的命令,但是这个命令是不存在的,cmd.exe跳过。
然后在6、7句加一个exitsub以及endsub,让批处理结束,同时又符合vbs的语法
那个echooff&cls,批处理的意思就是相当于@echooff,但是vbs不认@符号,所以改成echooff&cls,vbs可以解析为,调用一个叫echo()的函数,参数为off&cls,也就是两个字符串off和cls相加
这段代码的好处是:
不用生成临时文件。
其实用echo或者more或者find来生成临时vbs很浪费系统资源的,用我写的这段代码,就完全免去了这些麻烦。
直接混合编程,以startwscript-e:
vbs"%~f0"为界限,上面写批处理,下面写vbs,并行不悖!
与.NET语言集成
安装了.NETFramework之后,系统就多了一个强势语言的编译工具,在C:
\Windows\Microsoft.NET\Framework\v*\下,我们可以在批处理中输出代码然后调用这些编译器来现场生成exe让批处理调用。
这些编译器有,C#的csc.exe,VB.NET的vbc.exe,JScript.NET的jsc.exe,VJ#的vjc.exe,这里给出C#的例子,由于C#是一种语法严格的语言,所以推荐用more直接生成源代码并且编译论坛讨论 (-
@echooff
set"dnfpath=C:
\Windows\Microsoft.NET\Framework"
set"est=DO_NOT_ZT_WITHOUT_PERMISSION"
for/f"delims="%%vin('dir/ad/b%dnfpath%\v?
.*')do(
ifexist"%dnfpath%\%%v\csc.exe"set"cscpath=%dnfpath%\%%v\csc.exe"
)
<"%~f0"more+17>"%temp%\estTrayTip.cs"
%cscpath%"/out:
%cd%\estTrayTip.exe""%temp%\estTrayTip.cs"
estTrayTip.exeC:
\Windows\System32\acwizard.ico看什么看没见过批处理啊?
没见过任务栏的汽泡信息啊?
见过了吧?
见过了顶electronixtar的帖子。
2
:
exe的参数解释:
estTrayTip.exe图标路径 标题 内容 提示图标类型Error、Info、None、Warning,这里取2=Info。
每个参数都必须正确填写
>nulping127.1-n1
delestTrayTip.exe
goto:
eof
:
estTrayTip
usingSystem;
usingSystem.Windows.Forms;
usingSystem.Drawing;
namespaceestTrayTip
{
classProgram
{
staticvoidMain(string[]args)
{
NotifyIconestIcon=newNotifyIcon();
estIcon.Icon=newIcon(args[0]);
estIcon.Visible=true;
ToolTipIconestToolTipIcon=newToolTipIcon();
switch(args[3])
{
case"1":
estToolTipIcon=ToolTipIcon.Error;break;
case"2":
estToolTipIcon=ToolTipIcon.Info;break;
case"3":
estToolTipIcon=ToolTipIcon.None;break;
case"4":
estToolTipIcon=ToolTipIcon.Warning;break;
}
estIcon.ShowBalloonTip(1,args[1],args[2],estToolTipIcon);
}
}
}
与其他语言集成
其他语言,例如Python,Perl等和批处理集成,方法和上面的都大同小异
ruby和CMD脚本的混杂编写示例
#!
/usr/bin/ruby
@rem=<@echooff&cls
for%%?
in(ruby.exe)doifnot*%%~$PATH:
?
==*ruby.exe"%~f0"%*
exit/b
CMDSHELL
#rubycode
print"rubyruninshellbash/cmd,参数:
" ;$*.each{|i|print'"'+i+'"'}
__END__
*注释*
可运行在win/unixshell
让同一个文件,被cmd.exe识别成批处理,让ruby.exe识别成ruby脚本
可以直接在cmd中编写ruby脚本
如只想运行在win可以把第一行"#!
/usr/bin/ruby"删除,再把"&cls"删除就好
附加信息
本wiki持续更新中,转载请注意版本更新,不要误人之弟
作者:
est,联系方式:
(Email&MSN)electronicstar@
最后更新:
2007-1-1717:
22感谢lxmxn的支持,感谢ccwan帮助测试代码
080807补充FORtokens和delims的应用
delims是指分割符,tokens是指选取分割后得到的字符串片断。
以下面这段代码为例:
FOR/F"eol=;tokens=2,3*delims=,"%iin("a,bc,def,ghij,jklmn")do@echo%i%j%k
其中Delims是“,”,所以"a,bc,def,ghij,klmn")被分隔成了abcdefghijklmn这5段。
tokens=2,3*表示取第2个片段、第3个片段以及第3个片段以后的所有片段,亦即:
%i=bc
%j=def
%k=ghij,klmn(此处“*”表示从第4个片段开始就不用再分割了,统统赋给%k)
所以如果你代码中用“tokens=*”的话,就表示不进行任何分割,直接把当前行赋给循环变量。
内容如下
helloworld
thankyouvery
youareverygood
这三行内容
for/f"tokens=*"%ain(a.txt)do@echo%a
helloworld
thankyouvery
youareverygood