|
|
|
@ -70,6 +70,28 @@ function value($value) // {{{
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
// }}}
|
|
|
|
|
function unquoteProperty($str, $indent = '') // {{{
|
|
|
|
|
{
|
|
|
|
|
$str = str($str, $indent);
|
|
|
|
|
if (preg_match("!^'[\\w_][\\w\\d_]*'\$!", $str)) {
|
|
|
|
|
return substr($str, 1, -1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return "{" . $str . "}";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// }}}
|
|
|
|
|
function unquoteName($str, $indent = '') // {{{
|
|
|
|
|
{
|
|
|
|
|
$str = str($str, $indent);
|
|
|
|
|
if (preg_match("!^'[\\w_][\\w\\d_]*'\$!", $str)) {
|
|
|
|
|
return substr($str, 1, -1);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return $str;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// }}}
|
|
|
|
|
class Decompiler_Object // {{{
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
@ -153,6 +175,10 @@ class Decompiler_Fetch extends Decompiler_Code // {{{
|
|
|
|
|
case ZEND_FETCH_LOCAL:
|
|
|
|
|
return '$' . substr($this->src, 1, -1);
|
|
|
|
|
case ZEND_FETCH_STATIC:
|
|
|
|
|
if (ZEND_ENGINE_2_3) {
|
|
|
|
|
// closure local variable?
|
|
|
|
|
return str($this->src);
|
|
|
|
|
}
|
|
|
|
|
die('static fetch cant to string');
|
|
|
|
|
case ZEND_FETCH_GLOBAL:
|
|
|
|
|
case ZEND_FETCH_GLOBAL_LOCK:
|
|
|
|
@ -183,18 +209,25 @@ class Decompiler_Dim extends Decompiler_Value // {{{
|
|
|
|
|
{
|
|
|
|
|
var $offsets = array();
|
|
|
|
|
var $isLast = false;
|
|
|
|
|
var $isObject = false;
|
|
|
|
|
var $assign = null;
|
|
|
|
|
|
|
|
|
|
function toCode($indent)
|
|
|
|
|
{
|
|
|
|
|
if (is_a($this->value, 'Decompiler_ListBox')) {
|
|
|
|
|
$exp = foldToCode($this->value->obj->src, $indent);
|
|
|
|
|
$exp = str($this->value->obj->src, $indent);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$exp = foldToCode($this->value, $indent);
|
|
|
|
|
$exp = str($this->value, $indent);
|
|
|
|
|
}
|
|
|
|
|
foreach ($this->offsets as $dim) {
|
|
|
|
|
$exp .= '[' . foldToCode($dim, $indent) . ']';
|
|
|
|
|
$last = count($this->offsets) - 1;
|
|
|
|
|
foreach ($this->offsets as $i => $dim) {
|
|
|
|
|
if ($this->isObject && $i == $last) {
|
|
|
|
|
$exp .= '->' . unquoteProperty($dim, $indent);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$exp .= '[' . str($dim, $indent) . ']';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $exp;
|
|
|
|
|
}
|
|
|
|
@ -219,7 +252,7 @@ class Decompiler_List extends Decompiler_Code // {{{
|
|
|
|
|
if (!isset($dim->assign)) {
|
|
|
|
|
return foldToCode($dim, $indent);
|
|
|
|
|
}
|
|
|
|
|
return foldToCode($this->dims[0]->assign, $indent) . ' = ' . foldToCode($dim, $indent);
|
|
|
|
|
return foldToCode($this->dims[0]->assign, $indent) . ' = ' . str($dim, $indent);
|
|
|
|
|
}
|
|
|
|
|
/* flatten dims */
|
|
|
|
|
$assigns = array();
|
|
|
|
@ -230,7 +263,7 @@ class Decompiler_List extends Decompiler_Code // {{{
|
|
|
|
|
}
|
|
|
|
|
$assign = foldToCode($dim->assign, $indent);
|
|
|
|
|
}
|
|
|
|
|
return $this->toList($assigns) . ' = ' . foldToCode($this->src, $indent);
|
|
|
|
|
return $this->toList($assigns) . ' = ' . str($this->src, $indent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function toList($assigns)
|
|
|
|
@ -376,7 +409,6 @@ class Decompiler_ForeachBox extends Decompiler_Box // {{{
|
|
|
|
|
class Decompiler
|
|
|
|
|
{
|
|
|
|
|
var $rName = '!^[\\w_][\\w\\d_]*$!';
|
|
|
|
|
var $rQuotedName = "!^'[\\w_][\\w\\d_]*'\$!";
|
|
|
|
|
|
|
|
|
|
function Decompiler()
|
|
|
|
|
{
|
|
|
|
@ -438,12 +470,12 @@ class Decompiler
|
|
|
|
|
$oldticks = $curticks;
|
|
|
|
|
$curticks = $toticks;
|
|
|
|
|
if (!$curticks) {
|
|
|
|
|
echo $origindent, "}\n";
|
|
|
|
|
echo $origindent, "}\n\n";
|
|
|
|
|
$indent = $origindent;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if ($oldticks) {
|
|
|
|
|
echo $origindent, "}\n";
|
|
|
|
|
echo $origindent, "}\n\n";
|
|
|
|
|
}
|
|
|
|
|
else if (!$oldticks) {
|
|
|
|
|
$indent .= INDENT;
|
|
|
|
@ -568,6 +600,7 @@ class Decompiler
|
|
|
|
|
*/
|
|
|
|
|
$op['line'] = $i;
|
|
|
|
|
switch ($op['opcode']) {
|
|
|
|
|
case XC_GOTO:
|
|
|
|
|
case XC_JMP:
|
|
|
|
|
$target = $op['op1']['var'];
|
|
|
|
|
$op['jmpouts'] = array($target);
|
|
|
|
@ -586,6 +619,7 @@ class Decompiler
|
|
|
|
|
case XC_JMPNZ:
|
|
|
|
|
case XC_JMPZ_EX:
|
|
|
|
|
case XC_JMPNZ_EX:
|
|
|
|
|
case XC_JMP_SET:
|
|
|
|
|
// case XC_FE_RESET:
|
|
|
|
|
case XC_FE_FETCH:
|
|
|
|
|
// case XC_JMP_NO_CTOR:
|
|
|
|
@ -771,15 +805,6 @@ class Decompiler
|
|
|
|
|
$this->outputCode($EX, $next, $last, $indent);
|
|
|
|
|
}
|
|
|
|
|
// }}}
|
|
|
|
|
function unquoteName($str) // {{{
|
|
|
|
|
{
|
|
|
|
|
$str = str($str);
|
|
|
|
|
if (preg_match($this->rQuotedName, $str)) {
|
|
|
|
|
$str = substr($str, 1, -1);
|
|
|
|
|
}
|
|
|
|
|
return $str;
|
|
|
|
|
}
|
|
|
|
|
// }}}
|
|
|
|
|
function dasmBasicBlock(&$EX, $opline, $last) // {{{
|
|
|
|
|
{
|
|
|
|
|
$T = &$EX['Ts'];
|
|
|
|
@ -842,12 +867,28 @@ class Decompiler
|
|
|
|
|
array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
|
|
|
|
|
$EX['object'] = (int) $res['var'];
|
|
|
|
|
$EX['called_scope'] = null;
|
|
|
|
|
$EX['fbc'] = 'new ' . $this->unquoteName($this->getOpVal($op1, $EX));
|
|
|
|
|
$EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
|
|
|
|
|
if (!ZEND_ENGINE_2) {
|
|
|
|
|
$resvar = '$new object$';
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_THROW: // {{{
|
|
|
|
|
$resvar = 'throw ' . str($this->getOpVal($op1, $EX));
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_CLONE: // {{{
|
|
|
|
|
$resvar = 'clone ' . str($this->getOpVal($op1, $EX));
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_CATCH: // {{{
|
|
|
|
|
$resvar = 'catch (' . str($this->getOpVal($op1, $EX)) . ' ' . str($this->getOpVal($op2, $EX)) . ')';
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_INSTANCEOF: // {{{
|
|
|
|
|
$resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_FETCH_CLASS: // {{{
|
|
|
|
|
if ($op2['op_type'] == XC_IS_UNUSED) {
|
|
|
|
|
switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
|
|
|
|
@ -864,26 +905,28 @@ class Decompiler
|
|
|
|
|
$istmpres = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$class = $op2['constant'];
|
|
|
|
|
if (is_object($class)) {
|
|
|
|
|
$class = get_class($class);
|
|
|
|
|
$class = $this->getOpVal($op2, $EX);
|
|
|
|
|
if (isset($op2['constant'])) {
|
|
|
|
|
$class = unquoteName($class);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$resvar = $class;
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_FETCH_CONSTANT: // {{{
|
|
|
|
|
if ($op1['op_type'] == XC_IS_UNUSED) {
|
|
|
|
|
$resvar = $op2['constant'];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($op1['op_type'] == XC_IS_CONST) {
|
|
|
|
|
$resvar = $op1['constant'];
|
|
|
|
|
}
|
|
|
|
|
else if ($op1['op_type'] == XC_IS_UNUSED) {
|
|
|
|
|
$resvar = $op2['constant'];
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$class = $T[$op1['var']];
|
|
|
|
|
assert($class[0] == 'class');
|
|
|
|
|
$resvar = $class[1] . '::' . $op2['constant'];
|
|
|
|
|
$resvar = $this->getOpVal($op1, $EX);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
// {{{ case XC_FETCH_*
|
|
|
|
@ -904,11 +947,11 @@ class Decompiler
|
|
|
|
|
switch ($fetchtype) {
|
|
|
|
|
case ZEND_FETCH_STATIC_MEMBER:
|
|
|
|
|
$class = $this->getOpVal($op2, $EX);
|
|
|
|
|
$rvalue = $class . '::$' . $this->unquoteName($rvalue);
|
|
|
|
|
$rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
$name = $this->unquoteName($rvalue);
|
|
|
|
|
$globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[$rvalue]";
|
|
|
|
|
$name = unquoteName($rvalue, $EX);
|
|
|
|
|
$globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
|
|
|
|
|
$rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
@ -930,20 +973,23 @@ class Decompiler
|
|
|
|
|
case XC_FETCH_DIM_UNSET:
|
|
|
|
|
case XC_FETCH_DIM_IS:
|
|
|
|
|
case XC_ASSIGN_DIM:
|
|
|
|
|
case XC_UNSET_DIM_OBJ: // PHP 4 only
|
|
|
|
|
case XC_UNSET_DIM:
|
|
|
|
|
case XC_UNSET_DIM_OBJ:
|
|
|
|
|
case XC_UNSET_OBJ:
|
|
|
|
|
$src = $this->getOpVal($op1, $EX, false);
|
|
|
|
|
if (is_a($src, "Decompiler_ForeachBox")) {
|
|
|
|
|
$src->iskey = $this->getOpVal($op2, $EX);
|
|
|
|
|
$resvar = $src;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else if (is_a($src, "Decompiler_DimBox")) {
|
|
|
|
|
|
|
|
|
|
if (is_a($src, "Decompiler_DimBox")) {
|
|
|
|
|
$dimbox = $src;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (!is_a($src, "Decompiler_ListBox")) {
|
|
|
|
|
$list = new Decompiler_List($this->getOpVal($op1, $EX, false));
|
|
|
|
|
$op1val = $this->getOpVal($op1, $EX, false);
|
|
|
|
|
$list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
|
|
|
|
|
|
|
|
|
|
$src = new Decompiler_ListBox($list);
|
|
|
|
|
if (!isset($op1['var'])) {
|
|
|
|
@ -967,16 +1013,20 @@ class Decompiler
|
|
|
|
|
else if ($ext == ZEND_FETCH_STANDARD) {
|
|
|
|
|
$dim->isLast = true;
|
|
|
|
|
}
|
|
|
|
|
if ($opc == XC_UNSET_OBJ) {
|
|
|
|
|
$dim->isObject = true;
|
|
|
|
|
}
|
|
|
|
|
unset($dim);
|
|
|
|
|
$rvalue = $dimbox;
|
|
|
|
|
unset($dimbox);
|
|
|
|
|
|
|
|
|
|
if ($opc == XC_ASSIGN_DIM) {
|
|
|
|
|
$lvalue = $rvalue;
|
|
|
|
|
++ $i;
|
|
|
|
|
$rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
|
|
|
|
|
$resvar = str($lvalue, $EX) . ' = ' . $rvalue;
|
|
|
|
|
$resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
|
|
|
|
|
}
|
|
|
|
|
else if ($opc == XC_UNSET_DIM) {
|
|
|
|
|
else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
|
|
|
|
|
$op['php'] = "unset(" . str($rvalue, $EX) . ")";
|
|
|
|
|
$lastphpop = &$op;
|
|
|
|
|
}
|
|
|
|
@ -1010,7 +1060,7 @@ class Decompiler
|
|
|
|
|
$lvalue = $this->getOpVal($op1, $EX);
|
|
|
|
|
$rvalue = $this->getOpVal($op2, $EX, false);
|
|
|
|
|
if (is_a($rvalue, 'Decompiler_Fetch')) {
|
|
|
|
|
$src = foldToCode($rvalue->src, $EX);
|
|
|
|
|
$src = str($rvalue->src, $EX);
|
|
|
|
|
if (substr($src, 1, -1) == substr($lvalue, 1)) {
|
|
|
|
|
switch ($rvalue->fetchType) {
|
|
|
|
|
case ZEND_FETCH_GLOBAL:
|
|
|
|
@ -1049,14 +1099,7 @@ class Decompiler
|
|
|
|
|
if (!isset($obj)) {
|
|
|
|
|
$obj = '$this';
|
|
|
|
|
}
|
|
|
|
|
$prop = $this->getOpVal($op2, $EX);
|
|
|
|
|
if (preg_match($this->rQuotedName, $prop)) {
|
|
|
|
|
$prop = substr($prop, 1, -1);;
|
|
|
|
|
$rvalue = "{$obj}->$prop";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$rvalue = "{$obj}->{" . "$prop}";
|
|
|
|
|
}
|
|
|
|
|
$rvalue = str($obj) . "->" . unquoteProperty($this->getOpVal($op2, $EX), $EX);
|
|
|
|
|
if ($res['op_type'] != XC_IS_UNUSED) {
|
|
|
|
|
$resvar = $rvalue;
|
|
|
|
|
}
|
|
|
|
@ -1064,7 +1107,7 @@ class Decompiler
|
|
|
|
|
++ $i;
|
|
|
|
|
$lvalue = $rvalue;
|
|
|
|
|
$rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
|
|
|
|
|
$resvar = "$lvalue = $rvalue";
|
|
|
|
|
$resvar = "$lvalue = " . str($rvalue);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
@ -1124,12 +1167,7 @@ class Decompiler
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_INIT_STATIC_METHOD_CALL:
|
|
|
|
|
case XC_INIT_METHOD_CALL:
|
|
|
|
|
case XC_INIT_FCALL_BY_FUNC:
|
|
|
|
|
case XC_INIT_FCALL_BY_NAME: // {{{
|
|
|
|
|
if (($ext & ZEND_CTOR_CALL)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case XC_INIT_METHOD_CALL: // {{{
|
|
|
|
|
array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
|
|
|
|
|
if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
|
|
|
|
|
$obj = $this->getOpVal($op1, $EX);
|
|
|
|
@ -1138,7 +1176,7 @@ class Decompiler
|
|
|
|
|
}
|
|
|
|
|
if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
|
|
|
|
|
$EX['object'] = null;
|
|
|
|
|
$EX['called_scope'] = $this->unquoteName($obj);
|
|
|
|
|
$EX['called_scope'] = unquoteName($obj, $EX);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$EX['object'] = $obj;
|
|
|
|
@ -1153,13 +1191,26 @@ class Decompiler
|
|
|
|
|
$EX['called_scope'] = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($opc == XC_INIT_FCALL_BY_FUNC) {
|
|
|
|
|
$which = $op1['var'];
|
|
|
|
|
$EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
|
|
|
|
|
$EX['fbc'] = $this->getOpVal($op2, $EX, false);
|
|
|
|
|
if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
|
|
|
|
|
$EX['fbc'] = '__construct';
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$EX['fbc'] = $this->getOpVal($op2, $EX, false);
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_INIT_FCALL_BY_NAME: // {{{
|
|
|
|
|
if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
$EX['object'] = null;
|
|
|
|
|
$EX['called_scope'] = null;
|
|
|
|
|
$EX['fbc'] = $this->getOpVal($op2, $EX);
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
|
|
|
|
|
$EX['object'] = null;
|
|
|
|
|
$EX['called_scope'] = null;
|
|
|
|
|
$which = $op1['var'];
|
|
|
|
|
$EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_DO_FCALL_BY_FUNC:
|
|
|
|
@ -1169,14 +1220,14 @@ class Decompiler
|
|
|
|
|
$resvar = $fname . "($args)";
|
|
|
|
|
break;
|
|
|
|
|
case XC_DO_FCALL:
|
|
|
|
|
$fname = $this->unquoteName($this->getOpVal($op1, $EX, false));
|
|
|
|
|
$fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
|
|
|
|
|
$args = $this->popargs($EX, $ext);
|
|
|
|
|
$resvar = $fname . "($args)";
|
|
|
|
|
break;
|
|
|
|
|
case XC_DO_FCALL_BY_NAME: // {{{
|
|
|
|
|
$object = null;
|
|
|
|
|
|
|
|
|
|
$fname = $this->unquoteName($EX['fbc']);
|
|
|
|
|
$fname = unquoteName($EX['fbc'], $EX);
|
|
|
|
|
if (!is_int($EX['object'])) {
|
|
|
|
|
$object = $EX['object'];
|
|
|
|
|
}
|
|
|
|
@ -1210,7 +1261,7 @@ class Decompiler
|
|
|
|
|
exit;
|
|
|
|
|
}
|
|
|
|
|
$class = &$this->dc['class_table'][$key];
|
|
|
|
|
$class['name'] = $this->unquoteName($this->getOpVal($op2, $EX));
|
|
|
|
|
$class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
|
|
|
|
|
if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
|
|
|
|
|
$ext /= XC_SIZEOF_TEMP_VARIABLE;
|
|
|
|
|
$class['parent'] = $T[$ext];
|
|
|
|
@ -1220,18 +1271,31 @@ class Decompiler
|
|
|
|
|
$class['parent'] = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while ($i + 2 < $ic
|
|
|
|
|
&& $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
|
|
|
|
|
&& $opcodes[$i + 2]['op1']['var'] == $res['var']
|
|
|
|
|
&& $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
|
|
|
|
|
for (;;) {
|
|
|
|
|
if ($i + 1 < $ic
|
|
|
|
|
&& $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
|
|
|
|
|
&& $opcodes[$i + 1]['op1']['var'] == $res['var']) {
|
|
|
|
|
// continue
|
|
|
|
|
}
|
|
|
|
|
else if ($i + 2 < $ic
|
|
|
|
|
&& $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
|
|
|
|
|
&& $opcodes[$i + 2]['op1']['var'] == $res['var']
|
|
|
|
|
&& $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
|
|
|
|
|
// continue
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$fetchop = &$opcodes[$i + 1];
|
|
|
|
|
$impl = $this->unquoteName($this->getOpVal($fetchop['op2'], $EX));
|
|
|
|
|
$impl = unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX);
|
|
|
|
|
$addop = &$opcodes[$i + 2];
|
|
|
|
|
$class['interfaces'][$addop['extended_value']] = $impl;
|
|
|
|
|
unset($fetchop, $addop);
|
|
|
|
|
$i += 2;
|
|
|
|
|
}
|
|
|
|
|
$this->dclass($class);
|
|
|
|
|
echo "\n";
|
|
|
|
|
unset($class);
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
@ -1246,18 +1310,17 @@ class Decompiler
|
|
|
|
|
$op2val = $this->getOpVal($op2, $EX);
|
|
|
|
|
switch ($opc) {
|
|
|
|
|
case XC_ADD_CHAR:
|
|
|
|
|
$op2val = foldToCode(chr($op2val), $EX);
|
|
|
|
|
$op2val = value(chr(str($op2val)));
|
|
|
|
|
break;
|
|
|
|
|
case XC_ADD_STRING:
|
|
|
|
|
$op2val = foldToCode($op2val, $EX);
|
|
|
|
|
break;
|
|
|
|
|
case XC_ADD_VAR:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if ($op1val == "''") {
|
|
|
|
|
if (str($op1val) == "''") {
|
|
|
|
|
$rvalue = $op2val;
|
|
|
|
|
}
|
|
|
|
|
else if ($op2val == "''") {
|
|
|
|
|
else if (str($op2val) == "''") {
|
|
|
|
|
$rvalue = $op1val;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
@ -1327,7 +1390,7 @@ class Decompiler
|
|
|
|
|
case XC_INCLUDE_OR_EVAL: // {{{
|
|
|
|
|
$type = $op2['var']; // hack
|
|
|
|
|
$keyword = $this->includeTypes[$type];
|
|
|
|
|
$resvar = "$keyword(" . str($this->getOpVal($op1, $EX)) . ")";
|
|
|
|
|
$resvar = "$keyword " . str($this->getOpVal($op1, $EX));
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_FE_RESET: // {{{
|
|
|
|
@ -1365,6 +1428,7 @@ class Decompiler
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_JMP_NO_CTOR:
|
|
|
|
|
break;
|
|
|
|
|
case XC_JMP_SET: // ?:
|
|
|
|
|
case XC_JMPNZ: // while
|
|
|
|
|
case XC_JMPZNZ: // for
|
|
|
|
|
case XC_JMPZ_EX: // and
|
|
|
|
@ -1402,6 +1466,7 @@ class Decompiler
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
|
case XC_GOTO:
|
|
|
|
|
case XC_JMP: // {{{
|
|
|
|
|
$op['cond'] = null;
|
|
|
|
|
$op['isjmp'] = true;
|
|
|
|
@ -1436,24 +1501,17 @@ class Decompiler
|
|
|
|
|
case XC_PRE_INC_OBJ: // {{{
|
|
|
|
|
$flags = array_flip(explode('_', $opname));
|
|
|
|
|
if (isset($flags['OBJ'])) {
|
|
|
|
|
$resvar = $this->getOpVal($op1, $EX);
|
|
|
|
|
$prop = $this->unquoteName($this->getOpVal($op2, $EX));
|
|
|
|
|
if ($prop{0} == '$') {
|
|
|
|
|
$resvar = $resvar . "{" . $prop . "}";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$resvar = $resvar . "->" . $prop;
|
|
|
|
|
}
|
|
|
|
|
$resvar = $this->getOpVal($op1, $EX) . '->' . unquoteProperty($this->getOpVal($op2, $EX), $EX);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$resvar = $this->getOpVal($op1, $EX);
|
|
|
|
|
}
|
|
|
|
|
$opstr = isset($flags['DEC']) ? '--' : '++';
|
|
|
|
|
if (isset($flags['POST'])) {
|
|
|
|
|
$resvar .= ' ' . $opstr;
|
|
|
|
|
$resvar .= $opstr;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$resvar = "$opstr $resvar";
|
|
|
|
|
$resvar = "$opstr$resvar";
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
// }}}
|
|
|
|
@ -1491,6 +1549,12 @@ class Decompiler
|
|
|
|
|
case XC_EXT_FCALL_END:
|
|
|
|
|
case XC_EXT_NOP:
|
|
|
|
|
break;
|
|
|
|
|
case XC_DECLARE_LAMBDA_FUNCTION:
|
|
|
|
|
ob_start();
|
|
|
|
|
$this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
|
|
|
|
|
$resvar = ob_get_clean();
|
|
|
|
|
$istmpres = true;
|
|
|
|
|
break;
|
|
|
|
|
case XC_DECLARE_FUNCTION_OR_CLASS:
|
|
|
|
|
/* always removed by compiler */
|
|
|
|
|
break;
|
|
|
|
@ -1498,6 +1562,14 @@ class Decompiler
|
|
|
|
|
$lastphpop['ticks'] = $this->getOpVal($op1, $EX);
|
|
|
|
|
// $EX['tickschanged'] = true;
|
|
|
|
|
break;
|
|
|
|
|
case XC_RAISE_ABSTRACT_ERROR:
|
|
|
|
|
// abstract function body is empty, don't need this code
|
|
|
|
|
break;
|
|
|
|
|
case XC_USER_OPCODE:
|
|
|
|
|
echo '// ZEND_USER_OPCODE, impossible to decompile';
|
|
|
|
|
break;
|
|
|
|
|
case XC_OP_DATA:
|
|
|
|
|
break;
|
|
|
|
|
default: // {{{
|
|
|
|
|
echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
|
|
|
|
|
// }}}
|
|
|
|
@ -1558,14 +1630,14 @@ class Decompiler
|
|
|
|
|
case XC_IS_VAR:
|
|
|
|
|
$d[$kk] = '$' . $op[$k]['var'];
|
|
|
|
|
if ($kk != 'res') {
|
|
|
|
|
$d[$kk] .= ':' . $this->getOpVal($op[$k], $EX);
|
|
|
|
|
$d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case XC_IS_TMP_VAR:
|
|
|
|
|
$d[$kk] = '#' . $op[$k]['var'];
|
|
|
|
|
if ($kk != 'res') {
|
|
|
|
|
$d[$kk] .= ':' . $this->getOpVal($op[$k], $EX);
|
|
|
|
|
$d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -1660,7 +1732,6 @@ class Decompiler
|
|
|
|
|
function dfunction($func, $indent = '', $nobody = false) // {{{
|
|
|
|
|
{
|
|
|
|
|
if ($nobody) {
|
|
|
|
|
$body = ";\n";
|
|
|
|
|
$EX = array();
|
|
|
|
|
$EX['op_array'] = &$func['op_array'];
|
|
|
|
|
$EX['recvs'] = array();
|
|
|
|
@ -1675,12 +1746,31 @@ class Decompiler
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo 'function ', $func['op_array']['function_name'], '(';
|
|
|
|
|
$functionName = $func['op_array']['function_name'];
|
|
|
|
|
if ($functionName == '{closure}') {
|
|
|
|
|
$functionName = '';
|
|
|
|
|
}
|
|
|
|
|
echo 'function ', $functionName, '(';
|
|
|
|
|
$this->dargs($EX, $indent);
|
|
|
|
|
echo ")\n";
|
|
|
|
|
echo $indent, "{\n";
|
|
|
|
|
echo $body;
|
|
|
|
|
echo "$indent}\n";
|
|
|
|
|
echo ")";
|
|
|
|
|
if ($nobody) {
|
|
|
|
|
echo ";\n";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if ($functionName !== '') {
|
|
|
|
|
echo "\n";
|
|
|
|
|
echo $indent, "{\n";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
echo " {\n";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo $body;
|
|
|
|
|
echo "$indent}";
|
|
|
|
|
if ($functionName !== '') {
|
|
|
|
|
echo "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// }}}
|
|
|
|
|
function dclass($class, $indent = '') // {{{
|
|
|
|
@ -1694,19 +1784,18 @@ class Decompiler
|
|
|
|
|
$isinterface = false;
|
|
|
|
|
if (!empty($class['ce_flags'])) {
|
|
|
|
|
if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
|
|
|
|
|
echo 'interface ';
|
|
|
|
|
$isinterface = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT) {
|
|
|
|
|
if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
|
|
|
|
|
echo "abstract ";
|
|
|
|
|
}
|
|
|
|
|
if ($class['ce_flags'] & ZEND_ACC_FINAL) {
|
|
|
|
|
if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
|
|
|
|
|
echo "final ";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
echo 'class ', $class['name'];
|
|
|
|
|
echo $isinterface ? 'interface ' : 'class ', $class['name'];
|
|
|
|
|
if ($class['parent']) {
|
|
|
|
|
echo ' extends ', $class['parent'];
|
|
|
|
|
}
|
|
|
|
@ -1821,9 +1910,11 @@ class Decompiler
|
|
|
|
|
echo "\n";
|
|
|
|
|
}
|
|
|
|
|
echo $newindent;
|
|
|
|
|
$isAbstractMethod = false;
|
|
|
|
|
if (isset($opa['fn_flags'])) {
|
|
|
|
|
if ($opa['fn_flags'] & ZEND_ACC_ABSTRACT) {
|
|
|
|
|
if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
|
|
|
|
|
echo "abstract ";
|
|
|
|
|
$isAbstractMethod = true;
|
|
|
|
|
}
|
|
|
|
|
if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
|
|
|
|
|
echo "final ";
|
|
|
|
@ -1847,7 +1938,7 @@ class Decompiler
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$this->dfunction($func, $newindent, $isinterface);
|
|
|
|
|
$this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
|
|
|
|
|
if ($opa['function_name'] == 'Decompiler') {
|
|
|
|
|
//exit;
|
|
|
|
|
}
|
|
|
|
@ -1878,22 +1969,21 @@ class Decompiler
|
|
|
|
|
// }}}
|
|
|
|
|
function output() // {{{
|
|
|
|
|
{
|
|
|
|
|
echo "<?". "php\n";
|
|
|
|
|
echo "<?". "php\n\n";
|
|
|
|
|
foreach ($this->dc['class_table'] as $key => $class) {
|
|
|
|
|
if ($key{0} != "\0") {
|
|
|
|
|
echo "\n";
|
|
|
|
|
$this->dclass($class);
|
|
|
|
|
echo "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($this->dc['function_table'] as $key => $func) {
|
|
|
|
|
if ($key{0} != "\0") {
|
|
|
|
|
echo "\n";
|
|
|
|
|
$this->dfunction($func);
|
|
|
|
|
echo "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo "\n";
|
|
|
|
|
$this->dop_array($this->dc['op_array']);
|
|
|
|
|
echo "\n?" . ">\n";
|
|
|
|
|
return true;
|
|
|
|
@ -1902,6 +1992,12 @@ class Decompiler
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// {{{ defines
|
|
|
|
|
define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
|
|
|
|
|
define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
|
|
|
|
|
define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
|
|
|
|
|
define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
|
|
|
|
|
define('ZEND_ENGINE_2', ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
|
|
|
|
|
|
|
|
|
|
define('ZEND_ACC_STATIC', 0x01);
|
|
|
|
|
define('ZEND_ACC_ABSTRACT', 0x02);
|
|
|
|
|
define('ZEND_ACC_FINAL', 0x04);
|
|
|
|
@ -1911,6 +2007,9 @@ define('ZEND_ACC_IMPLICIT_ABSTRACT_CLASS', 0x10);
|
|
|
|
|
define('ZEND_ACC_EXPLICIT_ABSTRACT_CLASS', 0x20);
|
|
|
|
|
define('ZEND_ACC_FINAL_CLASS', 0x40);
|
|
|
|
|
define('ZEND_ACC_INTERFACE', 0x80);
|
|
|
|
|
if (ZEND_ENGINE_2_4) {
|
|
|
|
|
define('ZEND_ACC_TRAIT', 0x120);
|
|
|
|
|
}
|
|
|
|
|
define('ZEND_ACC_PUBLIC', 0x100);
|
|
|
|
|
define('ZEND_ACC_PROTECTED', 0x200);
|
|
|
|
|
define('ZEND_ACC_PRIVATE', 0x400);
|
|
|
|
@ -1927,12 +2026,6 @@ define('ZEND_ACC_ALLOW_STATIC', 0x10000);
|
|
|
|
|
|
|
|
|
|
define('ZEND_ACC_SHADOW', 0x2000);
|
|
|
|
|
|
|
|
|
|
define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
|
|
|
|
|
define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
|
|
|
|
|
define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
|
|
|
|
|
define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
|
|
|
|
|
define('ZEND_ENGINE_2', ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
|
|
|
|
|
|
|
|
|
|
if (ZEND_ENGINE_2_4) {
|
|
|
|
|
define('ZEND_FETCH_GLOBAL', 0x00000000);
|
|
|
|
|
define('ZEND_FETCH_LOCAL', 0x10000000);
|
|
|
|
@ -2030,7 +2123,7 @@ foreach (array (
|
|
|
|
|
'XC_FETCH_DIM_' => -1,
|
|
|
|
|
'XC_ASSIGN_DIM' => -1,
|
|
|
|
|
'XC_UNSET_DIM' => -1,
|
|
|
|
|
'XC_FETCH_OBJ_' => -1,
|
|
|
|
|
'XC_UNSET_OBJ' => -1,
|
|
|
|
|
'XC_ASSIGN_OBJ' => -1,
|
|
|
|
|
'XC_ISSET_ISEMPTY_DIM_OBJ' => -1,
|
|
|
|
|
'XC_ISSET_ISEMPTY_PROP_OBJ' => -1,
|
|
|
|
@ -2051,18 +2144,28 @@ foreach (array (
|
|
|
|
|
'XC_FETCH_' => -1,
|
|
|
|
|
'XC_FETCH_DIM_' => -1,
|
|
|
|
|
'XC_UNSET_DIM_OBJ' => -1,
|
|
|
|
|
'XC_FETCH_OBJ_' => -1,
|
|
|
|
|
'XC_ISSET_ISEMPTY' => -1,
|
|
|
|
|
'XC_INIT_FCALL_BY_FUNC' => -1,
|
|
|
|
|
'XC_DO_FCALL_BY_FUNC' => -1,
|
|
|
|
|
'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
|
|
|
|
|
'XC_INIT_NS_FCALL_BY_NAME' => -1,
|
|
|
|
|
'XC_GOTO' => -1,
|
|
|
|
|
'XC_CATCH' => -1,
|
|
|
|
|
'XC_THROW' => -1,
|
|
|
|
|
'XC_INSTANCEOF' => -1,
|
|
|
|
|
'XC_DECLARE_FUNCTION' => -1,
|
|
|
|
|
'XC_RAISE_ABSTRACT_ERROR' => -1,
|
|
|
|
|
'XC_DECLARE_CONST' => -1,
|
|
|
|
|
'XC_USER_OPCODE' => -1,
|
|
|
|
|
'XC_JMP_SET' => -1,
|
|
|
|
|
'XC_DECLARE_LAMBDA_FUNCTION' => -1,
|
|
|
|
|
) as $k => $v) {
|
|
|
|
|
if (!defined($k)) {
|
|
|
|
|
define($k, $v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* XC_UNDEF XC_OP_DATA
|
|
|
|
|
//* XC_UNDEF XC_OP_DATA
|
|
|
|
|
$content = file_get_contents(__FILE__);
|
|
|
|
|
for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
|
|
|
|
|
if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
|
|
|
|
|