PHPをハックしよう(第二回)
2014-10-22
PHP嫌いのハッカーがPHPをハックする連載の第二回目です。 前回はこちら。
前回見つけた、opdumperというPHP拡張でopcodeをdumpしてみましょう。
foo.php
として以下の内容のファイルを作成します。
<?php
function f($a, $b) {
return $a + $b;
}
echo f(1,2);
このファイルのopcodeをdumpしてみましょう。
$ php -d opdumper.active=1 foo.php
line: 3
opcode: ZEND_NOP
op1_type: UNUSED
op2_type: UNUSED
result_type: UNUSED
op1: UNUSED
op2: UNUSED
result: UNUSED
==============================
line: 7
opcode: ZEND_SEND_VAL
op1_type: CONST
op2_type: UNUSED
result_type: UNUSED
op1: 1
op2: UNUSED
result: UNUSED
==============================
line: 7
opcode: ZEND_SEND_VAL
op1_type: CONST
op2_type: UNUSED
result_type: UNUSED
op1: 2
op2: UNUSED
result: UNUSED
==============================
line: 7
opcode: ZEND_DO_FCALL
op1_type: CONST
op2_type: UNUSED
result_type: VAR
op1: f
op2: UNUSED
result: $4294967264
==============================
line: 7
opcode: ZEND_ECHO
op1_type: VAR
op2_type: UNUSED
result_type: UNUSED
op1: $4294967264
op2: UNUSED
result: UNUSED
==============================
line: 8
opcode: ZEND_RETURN
op1_type: CONST
op2_type: UNUSED
result_type: UNUSED
op1: 1
op2: UNUSED
result: UNUSED
$
ちなみに、失敗する場合にはPHP拡張が読み込めていない可能性があります。
その場合にはphp.ini
にextension=opdumper.so
を追加するなどしてみてください。
opcodeとソースを見比べるとなんとなくわかりますね。
ZEND_SEND_VAL
で関数の引数をスタックに積んで、ZEND_DO_FCALL
で関数を呼び出しているのがわかります。
で、その結果をZEND_ECHO
で出力しています。
しかしですね、関数f
の定義のopcodeが見当たらない。。。
調べてみると、PHPのコンパイラはtwo-passのコンパイラ、つまり2回ソースをスキャンするタイプのコンパイラなんです。
1回目で関数の宣言とかそういうのをスキャンして、2回目で実際の関数の呼び出しのopcodeを生成しているようです。
つまり、この出力されているのは2回目のスキャンの結果のようです。
1回目のスキャン結果のopcodeはどうやって取得すればよいのやら。。。
どうやらPHPのソースをハックする必要がありそうです。
なんか深みにはまりそうな予感。。。
続きは次回。