標題: 批處理技術內(nèi)幕:Unicode CMD在內(nèi)部是以Unicode來運作的,這點無須置疑。你可能要問,如果是Unicode的話,那么Unicode編碼保存的腳本怎么不能執(zhí)行?
讓我們一起來看一下CMD是怎么解析批處理腳本的吧。 echo http:// 用OllyDbg載入,bp ReadFile后運行,就會斷在讀取腳本的地方。 可以看到每次讀取0x1FFF(8191)個字節(jié)(注意不是字符)到緩沖區(qū)。 F8單步,不一會就到了MultiByteToWideChar函數(shù),將剛才讀取的字節(jié)以當前代碼頁轉(zhuǎn)換成Unicode儲存在另一個緩沖區(qū),之后的處理都是建立在轉(zhuǎn)換后的Unicode之上的。 也就是說,CMD在讀取腳本時并不會預先判斷腳本的編碼(實際上,要準確判斷文件編碼幾乎是不可能的),而是調(diào)用ReadFile函數(shù)讀取文件后以當前代碼頁調(diào)用MultiByteToWideChar函數(shù)將其轉(zhuǎn)成Unicode編碼。如果你的是簡體中文系統(tǒng),而你沒有修改默認的區(qū)域設置,并且你沒有在批處理中使用chcp命令的話,那么默認的當前代碼頁就是936,即GBK編碼。 就算你的批處理是使用Unicode保存的,CMD也不會知道,CMD仍然傻傻的把它當成GBK,Unicode被當成GBK轉(zhuǎn)換成Unicode,結果當然是不能運行的。 到這里還沒有結束,我們都知道CMD有一個/U開關,幫助文檔對/U的描述是: Causes the output of internal commands to a pipe or file to be Unicode 對應的還有一個/A開關: Causes the output of internal commands to a pipe or file to be ANSI 默認是開關是/A,也就是說CMD命令輸出的默認編碼是ANSI。 等一下,好像哪里不對吧?是的,只有在輸出被重定向到管道或者文件的時候才是ANSI(默認,不加/U的話),換句話說,如果直接在CMD輸出,那么仍然是Unicode編碼。 echo 你好,世界 echo 你好,世界>1.txt CMD對這兩行代碼的處理是不一樣的。 如果標準輸出STDOUT沒有被重定向(第一行代碼),那么直接調(diào)用WriteConsoleW函數(shù)輸出Unicode。 如果標準輸出STDOUT被重定向了(第二行代碼),那么會先以當前代碼頁為參數(shù)調(diào)用WideCharToMultiByte函數(shù)將Unicode轉(zhuǎn)成相應的編碼,再調(diào)用WriteFile寫入文件。 請注意我一直強調(diào)當前代碼頁,因為代碼頁是可以通過chcp命令改變的,所以從MultiByteToWideChar到WideCharToMultiByte這段時間里,當前的代碼頁很可能被改變了。 猜猜看下面這段批處理會輸出什么? @echo off setlocal enabledelayedexpansion chcp 437>nul set c=個 chcp 1252>nul echo !c!>1.txt pause 為了減低難度,給出兩個鏈接: 如果你不用運行就能知道答案,那么恭喜你已經(jīng)理解本文了;如果你就算實際運行了還是想不明白為什么,那也不用灰心,我會告訴你答案。 前兩行大家都懂,我就不說了,第三行chcp將當前活動的代碼頁改為437,CMD就會把之后的代碼當成437編碼(請允許我這么稱呼,因為我實在不知道它叫什么編碼)。 好在437編碼是部分兼容ASCII的,所以"set c="并不會有什么問題,它仍然是"set c=";但是437里面是沒有"個"這個中文字符的,它會把"個"當成0x82和0x80兩個字符,而437中的0x82和0x80對應Unicode中的0x00E9和0x00C7(上面的鏈接里有映射表),于是 set c=個 這行代碼運行之后c在內(nèi)存中的值是0x00E9 0x00C7。 接下來chcp將代碼頁改成了1252,而下一行echo是把c的值重定向輸出到1.txt,所以要把Unicode轉(zhuǎn)成1252編碼。0x00E9對應1252中的0xE9,0x00C7對應1252中的0xC7(參考上面的鏈接),所以轉(zhuǎn)換以后的值是0xE9 0xC7,即1.txt的內(nèi)容為0xE9 0xC7(當然,還有echo附加上去的0x0D 0x0A)。 用記事本打開1.txt時當前的代碼頁仍然是936不變,所以將按照GBK編碼來解釋0xE9 0xC7,這正好是"榍"字的GBK碼,怎么樣,是不是繞暈了? 如果你還是搞不明白,那也沒關系,你只要知道CMD會先把批處理腳本轉(zhuǎn)成Unicode再進行解析的就行了;如果你搞懂了,那可以考慮一下下面的代碼會生成什么: chcp 37 in[ 可以參考http://en./wiki/EBCDIC_037 相關文章: 隨機文章:
這篇文章發(fā)布于 2012年07月25日,星期三,13:52,歸類于 逆向調(diào)試。 您可以跟蹤這篇文章的評論通過 RSS 2.0 feed。 您可以留下評論,或者從您的站點trackback。 |
|