• 超级经典的与其他语言混合编程的批处理代码


    脚本类语言作为21世纪的一种先进的高级语言,其特征是整合,批处理有极强的其他语言整合能力,目前比较成熟的方案有下面所述几种,通过和其他计算机语言的整合,极大的扩展批处理的功能,使得原本用批处理不可能实现的工作,通过整合汇编/VBS/.NET可以轻松达到惊人的效果。
    与汇编集成
    传统的DOS和经典的CMD都支持一个外部命令debug所以使得批处理有了汇编方面的扩展能力,debug命令支持重定向输入代码,所以给了代码极大的灵活性
    早期方法
    早期的批处理功能十分弱,甚至嵌用汇编也不是那么直接,比如自嵌后直接重定向的例子
    下面这个代码是屏幕闪屏
    @echo off
    goto start
    e 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 C3
    r cx
    1c
    n mini_ani.com
    w
    q
    :start
    debug < %0 >nul
    mini_ani.com
    del mini_ani.com
    pause
    find反过滤的例子
    它的优势在于可以通过find过滤嵌入多个脚本
    @echo off
    e 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 C3
    r cx
    1c
    n mini_ani.com
    w
    q
    @find "@" /v < %0 | debug >nul
    @mini_ani.com
    @del mini_ani.com
    @pause
    传统的echo大法
    通过echo命令重定向标准输出到临时文件,然后用debug执行这个临时文件里的命令,这个方法比较通用,批处理输出文件都是用的这个方法,不足是需要产生临时文件
    echo D C000:000> v.dat
    echo D>>v.dat
    echo D>>v.dat
    echo Q>>v.dat
    Debug.exe < v.dat >info.txt
    @echo off
    echo o 70 17 >tmp.txt
    echo o 71 ff >>tmp.txt
    echo Q >>tmp.txt
    debug <tmp.txt
    del 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.com
    goto:eof
    e100 B0 13 CD 10 C4 2F AA 11 F8 64 13 06 6C 04 EB F6
    rbx
    0
    rcx
    10
    n 0.com
    w
    q
    强悍的ASCode
    @echo off
    chcp 437>nul&graftabl 936>nul
    echo hP1X500P[PZBBBfh#b##fXf-V@`$fPf]f3/f1/5++u5x>in.com
    set /p password=请输入密码:<nul
    for /f "tokens=*" %%i in ('in.com') do set password=%%i
    del in.com
    echo.
    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 OFF
    COPY %0 /B C:BATVIR.COM /B /Y
    C:BATVIR.COM
    DEL 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.vbs
    cscript v.vbs
    国外的find大法
    利用find命令过滤出VBS代码的一个特定 'VBS,这样可以嵌入多段VBS代码到bat里,例如:
    @echo off & setlocal enableextensions
    :: Make a temporary folder
    if not exist c:mytemp mkdir c:mytemp
    :: Build a Visual Basic Script
    findstr "'%skip%VBS" "%~f0" > c:mytemp mp$$$.vbs
    :: Run it with Microsoft Windows Script Host Version 5.6
    cscript //nologo c:mytemp mp$$$.vbs
    :: Call the command line script the script host built
    call c:mytemp mp$$$.cmd
    :: Clean up
    for %%f in (c:mytemp mp$$$.vbs c:mytemp mp$$$.cmd) do if exist %%f del %%f
    rmdir c:mytemp
    :: Show the result
    echo Day Number dn_=%dn_%
    endlocal & goto :EOF
    '
    'The Visual Basic Script
    Const ForReading = 1, ForWriting = 2, ForAppending = 8 'VBS
    Dim DateNow, fso, f 'VBS
    DateNow = Date 'VBS
    Set fso = CreateObject("Scripting.FileSystemObject") 'VBS
    Set f = fso.OpenTextFile("c:mytemp mp$$$.cmd", ForWriting, True) 'VBS
    f.Write "@set dn_=" & DatePart("y", DateNow) 'VBS
    f.Close 'VBS
    经典的more大法
    同上面的more大法,优点是不需要考虑特殊字符的问题,缺点是代码灵活性不高,添加了代码就需要修改 +n 的值
    < "%~f0" more +3 >v.vbs
    cscript //nologo v.vbs
    goto:eof
    msgbox now
    wscript.echo ">>>CN-DOS<<<"
    wscript.stdin.readline

    Vacum 的方法
    最近在写几个Bat,在Google 上找到这里,顺便把我的方法也贴到这里来,和上面的Find 、more 方法原理差不多。但感觉灵活方便许多。代码如下,不是很复杂,就不多说明了。
    :: Make all the code into one bat file
    @echo OFF
    IF "%1"==":_GET_LINES_" GOTO :_GET_LINES_
    REM Your code here
    REM Example
    ( CALL %0 :_GET_LINES_ ############ ) | MORE
    ( CALL %0 :_GET_LINES_ __SQLPLUS__ ) | MORE
    REM 这一部分用来取数据。
    goto :EOF
    :_GET_LINES_
    SETLOCAL ENABLEDELAYEDEXPANSION
    SET LINE_TAG=%2
    SET BEGIN_LINE=0
    SET TOTAL_LINE=0
    SET CURLINE=0
    for /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_OK
    for /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_OK
    for /f "skip=%BEGIN_LINE% tokens=*" %%i IN (%0) DO ( ( SET /A CURLINE+=1 ) & ( if !CURLINE! LSS %TOTAL_LINE% (if not "A%%i"=="A" @echo %%i ) ) )
    ENDLOCAL
    GOTO :EOF
    REM 下面是数据部分的内容
    ############
    Hello This Just a Test
    限制,前导空格、空行会被过滤掉,可以在上面的for 语句中增加 delims= 选项来解决,但同时会带来新的问题
    ############
    __SQLPLUS__
    SELECT * FROM DUAL;
    select * from dual;
    __SQLPLUS__
    方便的mshta大法
    该方法由est首创,巧妙利用了Windows系统里自带的javascript:和vbscript:协议使得在批处理中能够在一行的狭小空间里插入简短的VBS/JS代码
    mshta "javascript:new ActiveXObject('SAPI.SpVoice').Speak('Hi, CN-DOS guys!');window.close();"
    事实上使用 iexplore.exe 和 Helpctr.exe 也可以,不过mshta.exe的权限相对要高一点
    让WSH直接解析bat
    :On Error Resume Next
    Sub bat
    echo off & cls
    echo Batching_codez_here_following_vbs_rules & pause
    start wscript -e:vbs "%~f0"
    Exit Sub
    End Sub
    MsgBox "This is vbs"
    代码解释
    :On Error Resume Next
    cmd.exe 识别成一段注释
    wscript.exe 这样识别, : 在vbs语法里代表分行,然后 On Error Resume Next,也就是让WSH忽略一些错误
    start wscript -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,但是 goto call exit 在vbs又是一个关键词,所以我们只能用符合 vbs 语法的 exit sub,所以我们在第二句加一个 sub bat,其实 cmd.exe 寻找了一个叫 sub.exe 的命令,但是这个命令是不存在的,cmd.exe 跳过。然后在 6、7 句加一个 exit sub 以及 end sub,让 批处理结束,同时又符合 vbs 的语法
    那个 echo off & cls ,批处理的意思就是相当于 @echo off ,但是 vbs 不认 @ 符号,所以改成 echo off & cls , vbs 可以解析为,调用一个叫 echo() 的函数,参数为 off & cls ,也就是两个字符串 off 和 cls 相加
    这段代码的好处是:不用生成临时文件。其实用 echo 或者 more 或者 find 来生成临时vbs很浪费系统资源的,用我写的这段代码,就完全免去了这些麻烦。直接混合编程,以 start wscript -e:vbs "%~f0" 为界限,上面写 批处理,下面写 vbs,并行不悖!
    与.NET语言集成
    安装了 .NET Framework 之后,系统就多了一个强势语言的编译工具,在 C:WindowsMicrosoft.NETFrameworkv*下,我们可以在批处理中输出代码然后调用这些编译器来现场生成exe让批处理调用。这些编译器有,C# 的 csc.exe,VB.NET的vbc.exe,JScript.NET的jsc.exe,VJ#的vjc.exe,这里给出 C# 的例子,由于 C# 是一种语法严格的语言,所以推荐用more直接生成源代码并且编译
    @echo off
    set "dnfpath=C:WindowsMicrosoft.NETFramework"
    set "est=DO_NOT_ZT_WITHOUT_PERMISSION"
    for /f "delims=" %%v in ('dir /ad /b %dnfpath%v?.*') do (
    if exist "%dnfpath%\%%vcsc.exe" set "cscpath=%dnfpath%\%%vcsc.exe"
    )
    < "%~f0" more +17 > "%temp%estTrayTip.cs"
    %cscpath% "/out:%cd%estTrayTip.exe" "%temp%estTrayTip.cs"
    estTrayTip.exe C:WindowsSystem32acwizard.ico 看什么看 没见过批处理啊?没见过任务栏的汽泡信息啊?见过了吧?见过了顶electronixtar的帖子。 2
    :exe的参数解释:estTrayTip.exe 图标路径 标题 内容 提示图标类型Error、Info、None、Warning,这里取2=Info。每个参数都必须正确填写
    >nul ping 127.1 -n 1
    del estTrayTip.exe
    goto:eof
    :estTrayTip
    using System;
    using System.Windows.Forms;
    using System.Drawing;
    namespace estTrayTip
    {
    class Program
    {
    static void Main(string[] args)
    {
    NotifyIcon estIcon = new NotifyIcon();
    estIcon.Icon = new Icon(args[0]);
    estIcon.Visible = true;
    ToolTipIcon estToolTipIcon = new ToolTipIcon();
    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 = <<CMDSHELL
    @echo off & cls
    for %%? in (ruby.exe) do if not *%%~$PATH:?==* ruby.exe "%~f0" %*
    exit/b
    CMDSHELL
    #ruby code
    print "ruby run in shell bash/cmd , 参数:" ; $*.each {|i| print '"'+i+'" '}
    __END__
    *注释*
    可运行在 win/unix shell
    让同一个文件,被 cmd.exe 识别成批处理,让 ruby.exe 识别成ruby脚本
    可以直接在cmd中编写ruby脚本
    如只想运行在win 可以把第一行 "#!/usr/bin/ruby" 删除,再把" & cls"删除就好

     欢迎加入QQ技术群聊:70539804

  • 相关阅读:
    css3 文本超出后出现省略号
    Bootstrap 开关(switch)控件需要注意的问题
    angularJs 使用中遇到的问题小结【一:关于传参】
    ctrl+enter提交留言
    div a块状布局
    模态框 快速选定合适的布局
    ionic 项目分享No.2——简化版【转】
    jquery判断div是否显示或者隐藏
    phpsotrm 设置命名空间
    win10 cmd 替换 powershell
  • 原文地址:https://www.cnblogs.com/boltkiller/p/4791730.html
Copyright © 2020-2023  润新知