miau's blog?

patch for PerlScript 5.8.7.813

(2006/09/24 追記)
タイトルの通り、このパッチは ActivePerl 5.8.7.813 以外には使えません。他のバージョンの PerlSE.dll でも有効そうな方法を書いてみましたので、こちらをお試しください。

patch for PerlScript 5.8.x.xxx - miau's blog?

以降は初稿のままです。


ほんのちょっと胡散臭いんですが、作ってみました。

PerlSE_5.8.7.813_patch.EXE

ActivePerl 5.8.7.813 付属の PerlSE.dll を変更して、2バイト文字等を使用してもエラーが出ないようにします。
使い方は、PerlSE.dll と同階層(C:\Perl\bin とか)に放り込んで実行するだけです。

よく考えるとファイル末尾に詰め物する方法は確実とはいえない気がしてきた(調べないとわからないけど、クリーンアップのときに Perl がスクリプト領域外も参照してしまう可能性がある?)ので、日本語を含むファイルは外部に切り出して require() するか、このパッチ当てるかしたほうがいい気もします。

以下、作ったときの苦労話(?)とか。




現在配布されている PerlScript で日本語を使うとエラーが出るのは、以前のアイテムで書いたとおり。
「バイト数をカウントすべきところで文字数をカウントしてるんじゃないか?」という疑惑はあったわけですが、もう少し深く追ってみました。

WideChar(Unicode)で渡された文字列を ShiftJIS に変換してるのは、PerlSE.dll のこの辺りらしい。
(「この辺り」といっても先頭のアドレスは実行時のアドレスなので意味ないんですが・・・)

281C736B 53 PUSH EBX
281C736C 56 PUSH ESI
281C736D 57 PUSH EDI
281C736E 8BD9 MOV EBX,ECX
281C7370 FF7424 18 PUSH DWORD PTR SS:[ESP+18] ; |s = "# aaあああ.."
281C7374 FF15 E8901C28 CALL DWORD PTR DS:[<&MSVCRT.wcslen>] ; msvcrt.wcslen …(1)
281C737A 59 POP ECX
281C737B 8BF0 MOV ESI,EAX
281C737D FF7424 10 PUSH DWORD PTR SS:[ESP+10]
281C7381 8BCB MOV ECX,EBX
281C7383 8D46 02 LEA EAX,DWORD PTR DS:[ESI+2]
281C7386 50 PUSH EAX
281C7387 E8 64FFFFFF CALL PerlSE.281C72F0 …(2)
281C738C 8BF8 MOV EDI,EAX
281C738E 85FF TEST EDI,EDI
281C7390 74 14 JE SHORT PerlSE.281C73A6
281C7392 56 PUSH ESI
281C7393 8BCB MOV ECX,EBX
281C7395 FF7424 1C PUSH DWORD PTR SS:[ESP+1C]
281C7399 57 PUSH EDI
281C739A E8 06FFFFFF CALL PerlSE.281C72A5 …(3)

やっぱり予想通り、
・(1) で wcslen を使って(バイト数でなく)文字数を取得
・(2) の中でその長さ分(+2 byte)の領域を確保
・(3) の中で WideCharToMultiByte を使って文字コード変換
 (このとき、(1) で取得した文字数と、(2) で確保した領域を使用)
という処理になっているようで。

(ちなみに (2) の中で msvcrt.dll 内の「??2@YAPAXI@Z」っていう関数を読んでいて謎だったんだけど、new() に相当する処理らしいです。
 wine-patches mailing list: Msvcrt Undocumented functions

(1) の部分でちゃんとバイト数取得しちゃえばいいんだけど・・・どうするべきなんだろう?
と、調べてみると・・・WideCharToMultiByte() で MultiByteCount に 0 を渡せばいいらしい。

WideCharToMultiByte

でも引数多いから処理入れるスペース足りないなー・・・。
と思ったんですが、ちょっと頭を捻った結果、こんな感じになりました。
(変更前→青、変更後→赤)

281C736B 53 PUSH EBX
281C736C 56 PUSH ESI
281C736D 57 PUSH EDI
281C736E 8BD9 MOV EBX,ECX
281C7370 FF7424 18 PUSH DWORD PTR SS:[ESP+18] ; |s = "# aaあああ.."
281C7374 FF15 E8901C28 CALL DWORD PTR DS:[<&MSVCRT.wcslen>] ; msvcrt.wcslen …(1)
281C737A 59 POP ECX
281C737B 8BF0 MOV ESI,EAX
281C737D FF7424 10 PUSH DWORD PTR SS:[ESP+10]
281C7381 8BCB MOV ECX,EBX
281C7383 8D46 02 LEA EAX,DWORD PTR DS:[ESI+2]
281C7386 50 PUSH EAX
281C7387 E8 64FFFFFF CALL PerlSE.281C72F0 …(2)
281C738C 8BF8 MOV EDI,EAX
281C738E 85FF TEST EDI,EDI
281C7390 74 14 JE SHORT PerlSE.281C73A6

281C7370 57 PUSH EDI ; |DefaultCharUsed = NULL
281C7371 57 PUSH EDI ; |pDefaultChar = NULL
281C7372 57 PUSH EDI ; |MultiByteCount = 0
281C7373 57 PUSH EDI ; |MultiByteStr = NULL
281C7374 6A FF PUSH -1 ; |WideCharCount = FFFFFFFF (-1.)
281C7376 FF7424 2C PUSH DWORD PTR SS:[ESP+2C] ; |WideCharStr = "# aaあああ.."
281C737A 57 PUSH EDI ; |Options = 0
281C737B 57 PUSH EDI ; |CodePage = CP_ACP
281C737C FF15 74901C28 CALL DWORD PTR DS:[<&KERNEL32.WideCharToM>; KERNEL32.WideCharToMultiByte
281C7382 8BF0 MOV ESI,EAX
281C7384 57 PUSH EDI
281C7385 8BCB MOV ECX,EBX
281C7387 40 INC EAX
281C7388 50 PUSH EAX
281C7389 E8 62FFFFFF CALL PerlSE.281C72F0 …(2)
281C738E 8BF8 MOV EDI,EAX
281C7390 90 NOP
281C7391 90 NOP

281C7392 56 PUSH ESI
281C7393 8BCB MOV ECX,EBX
281C7395 FF7424 1C PUSH DWORD PTR SS:[ESP+1C]
281C7399 57 PUSH EDI
281C739A E8 06FFFFFF CALL PerlSE.281C72A5 …(3)

この関数のコール元のほうで、XOR EDI, EDI なんて処理が入ってたから(EDI を 0 として使えたので)、なんとか詰め込めました。

領域足りなかったので (2) の処理のエラー判定部分潰しちゃったけど、まあ通常の環境で new() で失敗することはないし・・・とりあえず無視で。
もっとうまいやり方あれば教えてください。>こういうの得意な方


ちなみにこういう解析は、美咲本読むだけで結構できるようになっちゃいます。たぶん。

OllyDbg の細かい使い方忘れてたので今回読みなおしたんですが、やっぱりいい本ですね。
二周目ともなると各章のまとめとかがあったほうが親切かな、という気はしましたが。それでも。


(2006/01/02 追記)

ActivePerl 5.8.7.815 付属の PerlSE.dll も変更箇所は同じなんだけど、CRC が違うからこのパッチは使えないみたい。

とりあえず、バイナリエディタで

FF742418FF15E8901C28598BF0FF7424108BCB8D460250E864FFFFFF8BF885FF7414

575757576AFFFF74242C5757FF1574901C288BF0578BCB4050E862FFFFFF8BF89090

こんな感じの置換すれば OK。

毎回やるのは面倒そうだから、気が向いたらまたパッチ作ろう・・・。
posted at 22:31:06 on 2005-09-23 by miau - Category: Perl No Trackbacks - Permalink

TrackBack

このエントリにトラックバックはありません
現在トラックバックは受け付けていません。

Comments

No comments yet

Add Comments

現在コメントは受け付けていません。
お手数ですが、 こちら のコメント欄にでも記載していただければと思います。