脚本类语言作为21世纪的一种先进的高级语言,其特征是整合,批处理有极强的其他语言整合能力,目前比较成熟的方案有下面所述几种,通过和其他计算机语言的整合,极大的扩展批处理的功能,使得原本用批处理不可能实现的工作,通过整合汇编/VBS/.NET可以轻松达到惊人的效果。 与汇编集成传统的DOS和经典的CMD都支持一个外部命令debug所以使得批处理有了汇编方面的扩展能力,debug命令支持重定向输入代码,所以给了代码极大的灵活性 早期方法早期的批处理功能十分弱,甚至嵌用汇编也不是那么直接,比如自嵌后直接重定向的例子 下面这个代码是屏幕闪屏@echo offgoto starte 100 B0 13 CD 10 C4 2F AA 13 C7 64 13 06 6C 04 50 B4 01 CD 16 58 74 F0 B8 03 00 CD 10 C3r cx1cn mini_ani.comwq:startdebug < %0 >nulmini_ani.comdel mini_ani.compausefind反过滤的例子 它的优势在于可以通过find过滤嵌入多个脚本 @echo offe 100 B0 13 CD 10 C4 2F AA 13 C7 64 13 06 6C 04 50 B4 01 CD 16 58 74 F0 B8 03 00 CD 10 C3r cx1cn mini_ani.comwq@find "@" /v < %0 | debug >nul@mini_ani.com@del mini_ani.com@pause传统的echo大法通过echo命令重定向标准输出到临时文件,然后用debug执行这个临时文件里的命令,这个方法比较通用,批处理输出文件都是用的这个方法,不足是需要产生临时文件echo D C000:000> v.datecho D>>v.datecho D>>v.datecho Q>>v.datDebug.exe < v.dat >info.txt@echo offecho o 70 17 >tmp.txtecho o 71 ff >>tmp.txtecho Q >>tmp.txtdebug <tmp.txtdel tmp.txt方便的prompt大法prompt命令支持一个特殊的参数 $_ ,改参数表示换行,所以在批处理中灵活应用可以写出紧凑的汇编代码echo exit|%ComSpec% /k prompt e 100 B4 00 B0 12 CD 10 B0 03 CD 10 CD 20 $_g$_q$_|debug>nul经典的more大法more支持一个 +n 参数,表示从文件的指定行开始输出,我们利用这个参数把批处理本身尾部的一些汇编代码直接通过 | 管道直接输出到debug命令<"%~f0" more +2 |debug & 0.comgoto:eofe100 B0 13 CD 10 C4 2F AA 11 F8 64 13 06 6C 04 EB F6rbx0rcx10n 0.comwq强悍的ASCode@echo offchcp 437>nul&graftabl 936>nulecho hP1X500P[PZBBBfh#b##fXf-V@`$fPf]f3/f1/5++u5x>in.comset /p password=请输入密码:<nulfor /f "tokens=*" %%i in ('in.com') do set password=%%idel in.comecho.echo The Password is:"%password%"pause这类汇编程序的特殊性在于,所有的代码全部分布于ASCII码表的可显示字符范围中,当然这样的程序不是碰巧得到的,而是人为的构造出来的,其中需要用到许多技巧。比如最常见的中断调用代码int 21(CD 21),因为不在ASCII可显示字符范围内,所以用到许多压栈、出栈、增减代码来构造,所以它的代码段是动态变化的。这样的代码被叫做 ASCODE,这样的技术被称作 ASCII Assemble,一门即将消失的技术,可想而知,这样的代码构造起来是困难的,在网上流传的ASCODE只有很少量的是人为构造的,因为已经有成熟的技术可以将任何二进制文件转变为ASCODE,这样的过程叫encode。而ASCODE执行的过程需要decode,合称codec,codec 的算法已知的超过4种,比较有名的应该是Herbert Kleebauer的算法,不过它要求原程序必须有org 170H的类似标记,因为前面的文件头被用来存放decode代码。 巧妙的.com文件头据说这个是袁哥写的病毒天极网的分析资料:0jeX4e-005POP]hWeX5ddP^1,FFFFF1,FFF1,4rP^P_jeX4aPY-x-AAR`0`*=00uPBOIAAAAFKAOBPIDMCBALEAJMNCBJALIAAEMMNCBFEGIGFCAENGBGDHCGPHGGJHCHFHDCAGJHDCAGDGPGNGJGOGHCACOCOCOCOCOCOANAKCEAAqqqq@ECHO OFFCOPY %0 /B C:\BATVIR.COM /B /YC:\BATVIR.COMDEL C:\BATVIR.COM这段代码有什么巧妙指出呢?第一句的开头, : 冒号告诉 cmd.exe ,这句是个GOTO语句的标识符,cmd.exe会直接跳过这一句,也就是当作注释了,但是,后面的批处理把自身copy为batvir.com,这就很讲究了, .com文件是以 : 开头的一段ASCode代码!所以这种ASCode比上一种更加高级,因为必须以 : 作为ASCode的开头。 与VBS集成在命令行下调用VBS/JS用cscript命令,由于cscript只能读取文件,不接受重定向和管道的输入,所以只能用echo或者more来生成一个临时脚本文件 传统的echo大法与批处理不同的是,VBS有很多特殊字符,例如>在批处理中代表重定向输出,在VBS语法里代表 大于,所以使用 echo需要用 ^ 来转义特殊符号 echo msgbox 3^>2 >v.vbscscript v.vbs国外的find大法利用find命令过滤出VBS代码的一个特定 'VBS,这样可以嵌入多段VBS代码到bat里,例如: @echo off & setlocal enableextensions:: Make a temporary folderif not exist c:\mytemp mkdir c:\mytemp:: Build a Visual Basic Scriptfindstr "'%skip%VBS" "%~f0" > c:\mytemp\tmp$$$.vbs:: Run it with Microsoft Windows Script Host Version 5.6cscript //nologo c:\mytemp\tmp$$$.vbs:: Call the command line script the script host builtcall c:\mytemp\tmp$$$.cmd:: Clean upfor %%f in (c:\mytemp\tmp$$$.vbs c:\mytemp\tmp$$$.cmd) do if exist %%f del %%frmdir c:\mytemp:: Show the resultecho Day Number dn_=%dn_%endlocal & goto :EOF''The Visual Basic ScriptConst ForReading = 1, ForWriting = 2, ForAppending = 8 'VBSDim DateNow, fso, f 'VBSDateNow = Date 'VBSSet fso = CreateObject("Scripting.FileSystemObject") 'VBSSet f = fso.OpenTextFile("c:\mytemp\tmp$$$.cmd", ForWriting, True) 'VBSf.Write "@set dn_=" & DatePart("y", DateNow) 'VBSf.Close 'VBS经典的more大法同上面的more大法,优点是不需要考虑特殊字符的问题,缺点是代码灵活性不高,添加了代码就需要修改 +n 的值 < "%~f0" more +3 >v.vbscscript //nologo v.vbsgoto:eofmsgbox nowwscript.echo ">>>CN-DOS<<<"wscript.stdin.readline
Vacum 的方法 最近在写几个Bat,在Google 上找到这里,顺便把我的方法也贴到这里来,和上面的Find 、more 方法原理差不多。但感觉灵活方便许多。代码如下,不是很复杂,就不多说明了。 :: Make all the code into one bat file@echo OFFIF "%1"==":_GET_LINES_" GOTO :_GET_LINES_REM Your code hereREM Example( CALL %0 :_GET_LINES_ ############ ) | MORE( CALL %0 :_GET_LINES_ __SQLPLUS__ ) | MOREREM 这一部分用来取数据。goto :EOF:_GET_LINES_SETLOCAL ENABLEDELAYEDEXPANSIONSET LINE_TAG=%2SET BEGIN_LINE=0SET TOTAL_LINE=0SET CURLINE=0for /f "usebackq delims=: tokens=1 " %%i in ( ` findstr /N /R /C:^^^^%LINE_TAG% %0 `) DO set BEGIN_LINE=%%i & goto __GET_BEGIN_LINE_OK:__GET_BEGIN_LINE_OKfor /f "usebackq delims=: tokens=1 " %%i in ( ` (for /f "skip=!BEGIN_LINE! tokens=*" %%j in (%0^) do @echo %%j ^) ^| findstr /N /R /C:^^^^%LINE_TAG% `) DO set TOTAL_LINE=%%i& goto __GET_END_LINE_OK:__GET_END_LINE_OKfor /f "skip=
