Hatena::ブログ(Diary)

葉っぱ日記 このページをアンテナに追加

2009-03-31

[] Windowsユーザのための初めてのPerlプログラミング  Windowsユーザのための初めてのPerlプログラミングを含むブックマーク

ActivePerl (Windows版) には DynaLoader が付属しているので、今日からすぐに DynaLoader::dl_install_xsub を利用したプログラミングが出来ます。

簡単なメッセージボックスを表示するPerlプログラムは以下になります。

#!/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;

このプログラム実行すると、「Hello, World!」と書かれたWindowsメッセージボックスが表示されます。

これを DynaLoader を使わない形に書き直すと以下のようになります。

#!/usr/bin/perl
use strict;
use warnings;
use Win32::API;

my $EnumWindows = Win32::API->new( "user32", "EnumWindows", "NN", "N" );
my $GetModuleHandle = Win32::API->new( "kernel32", "GetModuleHandleA", "P", "N" );
my $GetProcAddress = Win32::API->new( "kernel32", "GetProcAddress", "NP", "N" );
my $VirtualAlloc = Win32::API->new( "kernel32", "VirtualAlloc", "NNNN", "N" );
my $VirtualFree = Win32::API->new( "kernel32", "VirtualFree", "NNN", "N" );
my $RtlCopyMemory = Win32::API->new( "kernel32", "RtlMoveMemory", "NNN", "V" );

my $hUser32 = $GetModuleHandle->Call( "user32" );
my $MessageBox = $GetProcAddress->Call( $hUser32, "MessageBoxA" );

my $x86 = ""
.  "\x6a\0"                         # push 0 as MB_OK
.  "\x68" . pack( "P", "Message" )  # push caption
.  "\x68" .                         # push text
     pack( "p", "\x48\x65\x6c\x6c\x6f\x2c\x20\x8f\xba\x98\x61\x20\x57\x6f\x72\x6c\x64\x21" )
.  "\x6a\0"                         # push 0 for HWND
.  "\xb8" . pack( "L", $MessageBox )# mov eax, func
.  "\xff\xd0"                       # call eax
.  "\x33\xc0"                       # xor eax, eax
.  "\xc2\x08\x00"                   # ret
;

my $px86 = $VirtualAlloc->Call( 0, length( $x86 ), 0x1000, 0x40 );
$RtlCopyMemory->Call( $px86, unpack( 'L', pack( 'P', $x86 ) ), length( $x86 ) );
$EnumWindows->Call( $px86, 0 );
$VirtualFree->Call( $px86, 0, 0x8000 );

Win32::API はとっても便利なモジュールですね。

Perl 5.8.9 / 日本語 Windows Vista SP1 (x86) の環境で試しました。