æ¨æ¥éå¬ããã Shibuya Perl Mongersãã¯ãã«ã«ãã¼ã¯#11ã§ãWindowsã¦ã¼ã¶ã®ããã®åãã¦ã®Perlããã°ã©ãã³ã°ãã¨ãããã¼ãã§LTãã¦ãã¾ããããªããªããã£ãã説æã¯ã§ããªãã£ãã®ã§ããã¢ã¨ãã¦ç¨æãã¦ãããã³ã¼ããè²¼ã£ã¦ããã¾ãã
(追è¨)ãã¬ã¼ã³ãã¼ã·ã§ã³è³æãã¢ãããã¼ããã¦ããã¾ãã
http://www.slideshare.net/hasegawayosuke/windowsperl-1330816
ã¡ãªã¿ã«ãããã®PPTã®ãã³ãã¬ããè¦ã¤ããããã¨è¨ããããã§ããã©ãæé ãªãã³ãã¬ããªãã£ãã®ã§èªåã§ãã¼ãã¨ã並ã¹ã¦ä½ã£ããã¤ã§ãã
Perlããx86ã³ã¼ããå¼ã³ããã¨ãã®ä¾ãWin32 APIã® SetConsoleCtrlHandler ã使ã£ã¦ãã¤ããªã³ã¼ããã·ã°ãã«ãã³ãã©ã«è¨å®ããGenerateConsoleCtrlEvent 㧠Ctrl+C (SIGINT) ãçºçããã¦ãã¤ããªã³ã¼ãã«ã¸ã£ã³ãããä¾ã§ããPerlå´ã®ã·ã°ãã«ãã³ãã©ãè¨å®ãã¦ãããªãã¨ãèªåèªèº«ã®Ctrl+Cã§çµäºãã¦ãã¾ãã¾ãã
#!/usr/bin/perl # call x86 code from Perl with signal use strict; use warnings; use Win32::API; #include <windows.h> my $GetModuleHandle = Win32::API->new( "kernel32", "GetModuleHandleA", "P", "N" ); my $GetProcAddress = Win32::API->new( "kernel32", "GetProcAddress", "NP", "N" ); my $GenerateConsoleCtrlEvent = Win32::API->new( "kernel32", "GenerateConsoleCtrlEvent", "NN", "N" ); my $SetConsoleCtrlHandler = Win32::API->new( "kernel32", "SetConsoleCtrlHandler", "NN", "N" ); use constant{ TRUE => 1, CTRL_C_EVENT => 0, }; sub catch_signal { } my $hUser32 = $GetModuleHandle->Call( "user32" ); my $hKernel32 = $GetModuleHandle->Call( "kernel32" ); my $MessageBox = pack( 'L', $GetProcAddress->Call( $hUser32, "MessageBoxA" ) ); #$SIG{INT} = \&catch_signal; my $x86 = "" . "\x90" # --- check signal type --- . "\x83\x7d\x08\x00" # cmp [dwCtrlEvent], 0 . "\x74\x05" # je ... if( not Ctrl+C ) return . "\x33\xc0" # xor eax, eax . "\xc2\x04\x00" # ret 4 . "\x90" # --- MessageBox --- . "\x6a\0" # push 0 MB_OK . "\x68" # push caption . pack( 'P', "Message" ) # . "\x68" # push text . pack( 'P', "Hello,World" ) . "\x6a\0" # push 0 hWnd . "\xb8" # mov eax, addr . $MessageBox . "\xff\xd0" # call eax . "\x33\xc0" # xor eax, eax . "\xc2\x04\x00" # ret 4 ; $SetConsoleCtrlHandler->Call( unpack( 'L', pack( 'P', $x86 ) ), TRUE ); $GenerateConsoleCtrlEvent->Call( CTRL_C_EVENT, 0 ); while( 1 ){};
x86ãã¤ããªã³ã¼ãããPerlã®ã³ã¼ããå¼ã¶ä¾ã§ããPerlä¸ã§ $SIG{INT} ã§ã·ã°ãã«ãã³ãã©ãè¨å®ãã¦ããããã¤ããªã³ã¼ãå ã§GenerateConsoleCtrlEvent ã使ã£ã¦ã·ã°ãã«ãçºçããããã¨ã§ Perl å´ã«ã³ã³ããã¹ãã移ãã¾ãããã¤ããªã³ã¼ãã®å®è¡ã¯ãæåã®ä¾ã¨åãã Perl å´ããã®ã·ã°ãã«ã使ãã¾ããPerlãããã¤ããªã³ã¼ãããã¤ããªã³ã¼ãããPerlã®ããããã§ä½¿ãã·ã°ãã«ãããã¦ãã¾ãã
#!/usr/bin/perl # call Perl code from x86 code with signal use strict; use warnings; use Win32::API; #include <windows.h> my $GetModuleHandle = Win32::API->new( "kernel32", "GetModuleHandleA", "P", "N" ); my $GetProcAddress = Win32::API->new( "kernel32", "GetProcAddress", "NP", "N" ); my $GenerateConsoleCtrlEvent = Win32::API->new( "kernel32", "GenerateConsoleCtrlEvent", "NN", "N" ); my $SetConsoleCtrlHandler = Win32::API->new( "kernel32", "SetConsoleCtrlHandler", "NN", "N" ); use constant{ TRUE => 1, CTRL_BREAK_EVENT => 1, }; sub catch_signal { print "Hello, Perl World!\n"; } $SIG{INT} = \&catch_signal; my $hUser32 = $GetModuleHandle->Call( "user32" ); my $hKernel32 = $GetModuleHandle->Call( "kernel32" ); my %addr = ( 'MessageBox' => pack( 'L', $GetProcAddress->Call( $hUser32, "MessageBoxA" ) ), 'GenerateConsoleCtrlEvent' => pack( 'L', $GetProcAddress->Call( $hKernel32, "GenerateConsoleCtrlEvent" ) ), ); my $x86 = "" . "\x90" # --- check signal type --- . "\x83\x7d\x08\x01" # cmp [dwCtrlEvent], 0 . "\x74\x05" # je ... if( not Ctrl+BREAK ) return . "\x33\xc0" # xor eax, eax . "\xc2\x04\x00" # ret 4 . "\x90" # --- GenerateConsoleCtrlEvent --- . "\x6a\0" # push 0 Process Group Id . "\x6a\0" # push 0 Ctrl-C Event . "\xb8" # mov eax, addr . $addr{'GenerateConsoleCtrlEvent'} . "\xff\xd0" # call eax . "\xB8\x01\x00\x00\x00" # mov eax, 1 return TRUE . "\xc2\x04\x00" # ret 4 ; $SetConsoleCtrlHandler->Call( unpack( 'L', pack( 'P', $x86 ) ), TRUE ); $GenerateConsoleCtrlEvent->Call( CTRL_BREAK_EVENT, 0 ); sleep( 1 );
Win32::API::Callback ãæ®éã«ä½¿ãä¾ã§ããEnumWindows ã使ã£ã¦ã¦ã£ã³ãã¦ã¿ã¤ãã«ãåæãããæç§æ¸éãã®ä¾ã§ãã
#!/usr/bin/perl # Win32::API::Callback sample use strict; use warnings; use Win32::API; use Win32::API::Callback; #include <windows.h> my $EnumWindows = Win32::API->new( "user32", "EnumWindows", "KN", "N" ); my $GetWindowText = Win32::API->new( "user32", "GetWindowTextA", "NPN", "N" ); my $callback = Win32::API::Callback->new( sub { my ( $hWnd, $param ) = @_; my $buf = "\0" x 1024; $GetWindowText->Call( $hWnd, $buf, length( $buf ) ); $buf =~ s/\0.*$//; if( length( $buf ) ){ print "$hWnd : $buf\n"; } return 1; }, "NN", "N", ); $EnumWindows->Call( $callback, 0 );
Win32::API::Callback ã使ã£ã¦ãx86ã³ã¼ãããPerlã®é¢æ°ãå¼ã³åºãä¾ã§ããEnumWindowsã®ã³ã¼ã«ããã¯é¢æ°ã¨ãã¦ãã¤ããªã³ã¼ããå¼ã³åºãããã®ãã¤ããªã³ã¼ãã¸ã®å¼æ°ã¨ãã¦Perlå´ã§ç¨æãã Callback ãªãã¸ã§ã¯ãã®ã¢ãã¬ã¹ã渡ãã¦ããã¾ãããã¤ããªã³ã¼ãå ã§ã¯ãåãåã£ãã¢ãã¬ã¹ãcallãã¾ããã·ã°ãã«ãã³ãã©ã«ããã³ã³ããã¹ãã®åãæ¿ãã¨ç°ãªããå¼æ°ãè¿ãå¤ã®åã渡ããã¹ã ã¼ãºã«è¡ãã¾ãã
#!/usr/bin/perl # Call Perl code from x86 code using Win32::API::Callback use strict; use warnings; use Win32::API; use Win32::API::Callback; #include <windows.h> #my $EnumWindows = Win32::API->new( "user32", "EnumWindows", "KN", "N" ); my $EnumWindows = Win32::API->new( "user32", "EnumWindows", "NK", "N" ); my $callback = Win32::API::Callback->new( sub { my $value = shift; print "Hello, Perl World! arg = $value\n"; return 0; }, "N", "N", ); my $x86 = "" . "\x8b\x44\x24\x08" # mov eax, dword ptr[ callback ] . "\x68\x4E\x61\xBC\x00" # push 12345678 . "\xff\xd0" # call eax . "\x33\xc0" # xor eax, eax . "\xc2\x08\x00" # ret ; $EnumWindows->Call( unpack( 'L', pack( 'P', $x86 ) ), $callback );
æå¾ã«ãPerlãããã¤ããªã³ã¼ããå¼ã³åºãå¿ç¨ã¨ãã¦å°ãã¯ä½¿ãåæã®ãããµã³ãã«ã¨ãã¦ãstdcallã§ã¯ãªãDLLé¢æ°ãå¼ã³åºãã³ã¼ãã§ããmsvcrt.dllã«å«ã¾ãã sprintf é¢æ°ã¯ãcdecl ã¨ããå¼ã³åºãè¦ç´ã«ãªã£ã¦ãã¾ãã®ã§ãæ®éã« Win32::API ã§ã¯å¼ã³åºãã¾ããããé¢æ°ãå¼ã³åºãé¨åãèªåã§æ¸ããã¨ã«ãã£ã¦ãstdcall ã§ã¯ãªãé¢æ°ã使ããã¨ãã§ãã¾ãã
#!/usr/bin/perl # calling non-stdcall function (sprintf) use strict; use warnings; use Win32::API; #include <windows.h> my $EnumWindows = Win32::API->new( "user32", "EnumWindows", "NN", "N" ); my $GetProcAddress = Win32::API->new( "kernel32", "GetProcAddress", "NP", "N" ); my $LoadLibrary = Win32::API->new( "kernel32", "LoadLibraryA", "P", "N" ); my $FreeLibrary = Win32::API->new( "kernel32", "FreeLibrary", "N" ); sub my_sprintf{ if( @_ < 1 ){ die "argument error"; } my $hDll = $LoadLibrary->Call( "msvcrt" ); my $sprintf = pack( 'L', $GetProcAddress->Call( $hDll, "sprintf" ) ); my $buf = "\0" x 1024; my $x86 =""; my $i = @_; while( $i-- > 0 ){ $x86 .= "\x68" . $_[ $i ]; # push args } $x86 .= "\x68" . pack( 'P', $buf ); # push $buf my $n = ( @_ + 1 ) * 4; $x86 .= "" . "\xb8" . $sprintf # mov eax, func . "\xff\xd0" # call eax . "\x81\xC4" # add esp, @_ * 4 . pack( 'L', $n ) . "\x33\xc0" # xor eax, eax . "\xc2\x08\x00" # ret ; # print unpack( 'H2 ' x length( $x86 ), $x86 ); # print "\n"; $EnumWindows->Call( unpack( 'L', pack( 'P', $x86 ) ), 0 ); $FreeLibrary->Call( $hDll ); # print unpack( 'H2 ' x 20, $buf ); # print "\n"; $buf =~s/\0.*$//; return $buf; } my $s = my_sprintf( pack( 'P', "%s,%s" ), pack( 'P', "Hello" ), pack( 'P', "World" ) ); print $s;