VBScript と JScript でこんにちは!(その1)
VBScript と JScript を交配させるたったひとつの方法 - 葉っぱ日記 のパクリです。
VBScript と JScript はとっても仲がいいので、かんたんに交配させることができます。
rem=[1,2,3] ["Hello, JScript!"] = "Hello, VBScript!" WScript.Echo(["Hello, JScript!"])
例えば、これを hello1.txt などというファイル名で保存しておいて、コマンドラインから
C:\>cscript //E:VBScript hello1.txt
のように実行すると「Hello, VBScript!」と表示され
C:\>cscript //E:JScript hello1.txt
のように実行すると「Hello, JScript!」と表示されます。
Enjoy!
defined &func の不思議
Ubuntu8.10(x86_64) な環境で perl -e "require 'syscall.ph'" すると
Prototype mismatch: sub main::__LONG_MAX__ () vs none at /usr/lib/perl/5.10/_h2ph_pre.ph line 309. Constant subroutine __LONG_MAX__ redefined at /usr/lib/perl/5.10/_h2ph_pre.ph line 309.
という警告メッセージが出てしまう問題を深追いしていたんですけど、、、
該当コード /usr/lib/perl/5.10/_h2ph_pre.ph はこんな感じ:
... 192 unless (defined &__LONG_MAX__) { sub __LONG_MAX__() { 9223372036854775807 } } ... 308 # gross hack 309 unless (defined &__LONG_MAX__) { sub __LONG_MAX__ { 2147483647 } }
Prototype mismatch と Constant subroutine redefined の問題を切り分けるためにサンプルプログラムを書いてみたんですが、
unless (defined &PPP) { sub PPP() { 1 } } warn unless ( PPP() == 2);# Warning: something's wrong at - line 1. unless (defined &PPP) { sub PPP() { 2 } } warn unless ( PPP() == 2); unless (defined &PPS) { sub PPS() { 1 } } warn unless (&PPS == 2); unless (defined &PPS) { sub PPS() { 2 } } warn unless (&PPS == 2); unless (defined &PSP) { sub PSP() { 1 } } warn unless ( PSP() == 2);# Warning: something's wrong at - line 5. unless (defined &PSP) { sub PSP { 2 } } warn unless ( PSP() == 2); unless (defined &PSS) { sub PSS() { 1 } } warn unless (&PSS == 2); unless (defined &PSS) { sub PSS { 2 } } warn unless (&PSS == 2); unless (defined &SPP) { sub SPP { 1 } } warn unless ( SPP() == 2); unless (defined &SPP) { sub SPP() { 2 } } warn unless ( SPP() == 2); unless (defined &SPS) { sub SPS { 1 } } warn unless (&SPS == 2); unless (defined &SPS) { sub SPS() { 2 } } warn unless (&SPS == 2); unless (defined &SSP) { sub SSP { 1 } } warn unless ( SSP() == 2); unless (defined &SSP) { sub SSP { 2 } } warn unless ( SSP() == 2); unless (defined &SSS) { sub SSS { 1 } } warn unless (&SSS == 2); unless (defined &SSS) { sub SSS { 2 } } warn unless (&SSS == 2);
これを実行すると
Warning: something's wrong at - line 1. Warning: something's wrong at - line 3.
となっちゃいます。。。
コンパイルフェーズと実行フェーズの違いなんでしょうけど、、、意味がわかりません(><)
元々の意図からすると # gross hack は意味をなしてないってことなんですかね。
Perl で Win32::API プログラミング入門
ActivePerl (Windows版) には Win32::API - Perl Win32 API Import Facility - metacpan.org が付属しているので、今日からすぐに Win32::API を利用したプログラミングが出来ます。
簡単なメッセージボックスを表示するPerlプログラムは以下になります。
#!/usr/bin/perl use Win32::API; my $MessageBox = Win32::API->new("user32", "MessageBoxA", "NPPN", "N"); $MessageBox->Call(0, "Hello, World!\n", "Message", 0);
このプログラム実行すると、「Hello, World!」と書かれたWindowsメッセージボックスが表示されます。
これを Win32::API を使わない形に書き直すと以下のようになります。
#!/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;
DynaLoader はとっても便利なモジュールですね。
Perl 5.10.0 / 日本語 Windows XP SP2 (x86) の環境で試しました。
(もしかしたら Vista や 64bit Windows 環境では動かないかもしれませんが、手元に環境がないので)→追記の動作報告があり、動いたみたいです。
■追記:
Twitter/ワッサーで以下の方々から動作報告をいただきました。Vistaやstrawberry perlでも動作するようです。
- "Win32::APIを使わない方" WinXP pro, Strawberry Perl v5.10.0でも実行可能なことを確認しますた by likkさん
- ちなむと、便利なDynaLoaderはVista上のActivePerlでもちゃんと動いてますよ。 by printf("hsegawa\n"); //DEBUG さん
- x64版Vistaでも動きました! (Perlは5.10 x86) by kaorunさん
ありがとうございます!
Perl で動的 x86_64 プログラミング
相対ジャンプのcall命令を動的に生成できるようにしておくとx86実行コード中に任意の文字列を埋め込めるので大変便利です。
● Linux/x86_64 で /usr/bin/perl -e 'print "Hello, world!\n"' を実行するサンプル
#!/usr/bin/perl -w sub P{"\xe8".pack('L',1+length$_[0]).$_[0]."\x00"}; use DynaLoader;DynaLoader::dl_install_xsub('X',unpack'L',pack'P', $_=P($^X)."_h-e\x00\x00H\x89\xe1".P('print "Hello, world!\n"') ."[1\xd2RSQWH\x89\xe6j;X\x0f\x05j\x01_j<\x0f\x05");&X
CentOS 4.4/x86_64 + AMD Opteron 240 EE + Perl 5.8.5 で動作確認
Hello, world!
上記プログラムは AMD64 ABI(*1) を利用した syscall で Linux のシステムコールを呼び出しているため、i386 環境では動作しません。uname -i が x86_64 な環境で動作可能です。
● 参考文献
はじめての x86_64/Linux プログラミング
$ vi amd64linux.pl
#!/usr/bin/perl use DynaLoader; my $x="" . "\x48\xb8Hello64!" # mov 'Hello64!',%rax . "\x50" # push %rax . "\x48\x89\xe6" # mov %rsp,%rsi . "\x48\xc7\xc7\x01\x00\x00\x00" # mov $0x1,%rdi . "\x48\xc7\xc2\x08\x00\x00\x00" # mov $0x8,%rdx . "\x48\xc7\xc0\x01\x00\x00\x00" # mov $0x1,%rax . "\x0f\x05" # syscall . "\x48\x89\xf8" # mov %rdi,%rax . "\x0f\x05" # syscall . "\x58" # pop %rax . "\xc3" # ret ; DynaLoader::dl_install_xsub("X",unpack("L",pack("P*",$x)));X(); print "ok\n";
$ perl amd64linux.pl
Hello64!Hello64!ok