PerlでWindowsAPIをコールする(DynaLoader編)
昨日、『Perl で Win32::API プログラミング入門』リンクメモでのお約束(暇な時にソース解析)の前半部だけをソース解析してみました。
今日は後半部のソース解析をしてみます。
しかし、実力不足で10%ぐらいしか分からなかったです。
#!/usr/bin/perl use DynaLoader; sub GetProcAddress { my ($DLL, $API) = @_; my $path = "$ENV{SystemRoot}\\system32\\$DLL"; my $libref = DynaLoader::dl_load_file($path); pack "L", DynaLoader::dl_find_symbol($libref, $API); } my $x86 = "" . "h\0\0\0\0" . "h" . pack("P", "Message") . "h" . pack("P", "Hello, World!\n") . "h\0\0\0\0" . "\xb8" . GetProcAddress("user32.dll", "MessageBoxA") . "\xff\xd0" # call eax . "\xc3" # ret ; DynaLoader::dl_install_xsub("X",unpack"L",pack"P",$x86);&X;http://d.hatena.ne.jp/TAKESAKO/20090324/1237879559
なので、以下のソース解析のコメントには大部憶測で書いています。
- GetProcAddressサブルーチンは、引数にライブラリ名とAPI名を指定してAPIのアドレスをゲットして返します。
- 文字列『$x86』は、アセンブライメージ(?)を展開しているようです。
- "h\0\0\0\0"は、API(MessageBoxA)の第4引数(OKボタン等)に対応している感じです。
- "h" . pack("P", "Message")は、API(MessageBoxA)の第3引数(キャプションタイトル)に対応している感じです。
- "h" . pack("P", "Hello, World!\n")は、API(MessageBoxA)の第2引数(メッセージ)に対応している感じです。
- "h\0\0\0\0"は、API(MessageBoxA)の第1引数(親ハンドル)に対応している感じです。
- "\xb8" . GetProcAddress("user32.dll", "MessageBoxA")は、API(MessageBoxA)のアドレスを展開している感じです。
- "\xff\xd0"は、APIを実行する命令が書かれている感じです。
- "\xc3"は、APIのリターンになにか関係がある感じです。
- DynaLoader::dl_install_xsub("X",unpack"L",pack"P",$x86);は、"X"で示す名前の新しいPerlの外部サブルーチンを関数へのポインタを使って生成します
- &X;は、生成したサブルーチンの実行です。
しかし、以下の記述には悩まされました。
dl_install_xsub("X",unpack"L",pack"P",$x86);
普通、dl_install_xsubの引数は2つまたは3つなのですが、上記は4つあります。
しかし、実はよく見ると2つなのです。
第一引数は、"X"で外部サブルーチン名になります。
第二引数は、『unpack"L",pack"P",$x86』なのです。
そう、『"P",$x86』はpackの引数で、『"L",pack"P",$x86』はunpackの引数なのです。
ちなみに、処理は、文字列($x86)のポインタ指定でバイナリ構造体にして、これを符号なしlong値にしています。
えーと、分かったような説明をしていますが、私自身10%も分かっていませんのでご了承ください。