腳本類語言做爲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\tmp$$$.vbs
:: Run it with Microsoft Windows Script Host Version 5.6
cscript //nologo c:\mytemp\tmp$$$.vbs
:: Call the command line script the script host built
call c:\mytemp\tmp$$$.cmd
:: Clean up
for %%f in (c:\mytemp\tmp$$$.vbs c:\mytemp\tmp$$$.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\tmp$$$.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.readlinejavascript
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 跳過。而後在 六、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:\Windows\Microsoft.NET\Framework\v*\下,咱們能夠在批處理中輸出代碼而後調用這些編譯器來現場生成exe讓批處理調用。這些編譯器有,C# 的 csc.exe,VB.NET的vbc.exe,JScript.NET的jsc.exe,VJ#的vjc.exe,這裏給出 C# 的例子,因爲 C# 是一種語法嚴格的語言,因此推薦用more直接生成源代碼而且編譯
@echo off
set "dnfpath=C:\Windows\Microsoft.NET\Framework"
set "est=DO_NOT_ZT_WITHOUT_PERMISSION"
for /f "delims=" %%v in ('dir /ad /b %dnfpath%\v?.*') do (
if exist "%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.exe C:\Windows\System32\acwizard.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"刪除就好java
歡迎加入QQ技術羣聊:70539804算法