Skip to content

Commit 324bacd

Browse files
committed
Add new match pattern
$GLOBALS[FOO] $GLOBALS['FOO'] explode('DELIMITER', gzinflate(substr('DATA', 0x0a, -8)) explode('DELIMITER', 'DATA')
1 parent 4765444 commit 324bacd

7 files changed

+163
-83
lines changed

src/AutoDecoder.php

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
use Ganlv\EnphpDecoder\NodeVisitors\GlobalStringNodeVisitor;
3131
use Ganlv\EnphpDecoder\NodeVisitors\RemoveDefineGlobalVariableNameNodeVisitor;
3232
use Ganlv\EnphpDecoder\NodeVisitors\RemoveUnusedConstFetchNodeVisitor;
33-
use PhpParser\Error;
3433
use PhpParser\NodeTraverser;
3534
use PhpParser\ParserFactory;
3635
use PhpParser\PrettyPrinter\Standard;
@@ -40,11 +39,14 @@ class AutoDecoder
4039
protected $ast;
4140
protected $globalVarName;
4241
protected $globalVarKey;
42+
protected $globalVarKeyExpr;
4343
protected $delimiter;
4444
protected $data;
4545
protected $start;
4646
protected $length;
4747
protected $stringArray;
48+
protected $dataType;
49+
protected $globalVarKeyType;
4850

4951
public function __construct($ast)
5052
{
@@ -66,20 +68,36 @@ public function findAndRemoveGlobalVariableName()
6668
$this->ast = $traverser->traverse($this->ast);
6769
$this->globalVarName = $nodeVisitor->globalVarName;
6870
$this->globalVarKey = $nodeVisitor->globalVarKey;
71+
$this->globalVarKeyExpr = $nodeVisitor->globalVarKeyExpr;
6972
$this->delimiter = $nodeVisitor->delimiter;
7073
$this->data = $nodeVisitor->data;
7174
$this->start = $nodeVisitor->start;
7275
$this->length = $nodeVisitor->length;
76+
$this->dataType = $nodeVisitor->dataType;
77+
$this->globalVarKeyType = $nodeVisitor->globalVarKeyType;
7378
return $this->ast;
7479
}
7580

81+
public function decodeStringArray()
82+
{
83+
switch ($this->dataType) {
84+
case 0:
85+
break;
86+
case FindAndRemoveGlobalVariableNameNodeVisitor::DATA_TYPE_EXPLODE_GZINFLATE_SUBSTR:
87+
$this->stringArray = explode($this->delimiter, gzinflate(substr($this->data, $this->start, $this->length)));
88+
break;
89+
case FindAndRemoveGlobalVariableNameNodeVisitor::DATA_TYPE_EXPLODE:
90+
$this->stringArray = explode($this->delimiter, $this->data);
91+
break;
92+
}
93+
}
94+
7695
public function removeDefineGlobalVariableName()
7796
{
7897
$nodeVisitor = new RemoveDefineGlobalVariableNameNodeVisitor($this->globalVarKey);
7998
$traverser = new NodeTraverser();
8099
$traverser->addVisitor($nodeVisitor);
81100
$this->ast = $traverser->traverse($this->ast);
82-
$this->stringArray = explode($this->delimiter, gzinflate(substr($this->data, $this->start, $this->length)));
83101
return $this->ast;
84102
}
85103

@@ -94,7 +112,7 @@ public function removeUnusedConstFetchNodeVisitor()
94112

95113
public function replaceGlobalString()
96114
{
97-
$nodeVisitor = new GlobalStringNodeVisitor($this->globalVarName, $this->globalVarKey, $this->stringArray);
115+
$nodeVisitor = new GlobalStringNodeVisitor($this->globalVarName, $this->globalVarKeyExpr, $this->stringArray);
98116
$traverser = new NodeTraverser();
99117
$traverser->addVisitor($nodeVisitor);
100118
$this->ast = $traverser->traverse($this->ast);
@@ -104,11 +122,11 @@ public function replaceGlobalString()
104122
public function replaceFunctionLikeGlobalString()
105123
{
106124
$globalVarName = $this->globalVarName;
107-
$globalVarKey = $this->globalVarKey;
125+
$globalVarKeyExpr = $this->globalVarKeyExpr;
108126
$stringArray = $this->stringArray;
109-
$nodeVisitor = new FunctionLikeNodeVisitor(function ($node) use ($globalVarName, $globalVarKey, $stringArray) {
127+
$nodeVisitor = new FunctionLikeNodeVisitor(function ($node) use ($globalVarName, $globalVarKeyExpr, $stringArray) {
110128
/** @var $node \PhpParser\Node\Stmt\Function_ */
111-
$nodeVisitor = new FunctionGlobalStringNodeVisitor($globalVarName, $globalVarKey, $stringArray);
129+
$nodeVisitor = new FunctionGlobalStringNodeVisitor($globalVarName, $globalVarKeyExpr, $stringArray);
112130
$traverser = new NodeTraverser();
113131
$traverser->addVisitor($nodeVisitor);
114132
$node->stmts = $traverser->traverse($node->stmts);
@@ -155,13 +173,19 @@ public static function decode($code)
155173
{
156174
$ast = self::parseFile($code);
157175
$decoder = new self($ast);
158-
$decoder->findAndRemoveGlobalVariableName();
159-
$decoder->removeDefineGlobalVariableName();
160-
$decoder->removeUnusedConstFetchNodeVisitor();
161-
$decoder->replaceGlobalString();
162-
$decoder->replaceFunctionLikeGlobalString();
163-
$decoder->renameFunctionLikeLocalVariable();
164-
$decoder->beautify();
176+
for ($i = 0; $i < 10; $i++) { // avoid too many loops
177+
$decoder->findAndRemoveGlobalVariableName();
178+
if ($decoder->dataType === 0) {
179+
break;
180+
}
181+
$decoder->decodeStringArray();
182+
$decoder->removeDefineGlobalVariableName();
183+
$decoder->removeUnusedConstFetchNodeVisitor();
184+
$decoder->replaceGlobalString();
185+
$decoder->replaceFunctionLikeGlobalString();
186+
$decoder->renameFunctionLikeLocalVariable();
187+
$decoder->beautify();
188+
}
165189
return $decoder->prettyPrintFile();
166190
}
167191
}

src/NodeVisitors/FindAndRemoveGlobalVariableNameNodeVisitor.php

Lines changed: 93 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,118 @@
22

33
namespace Ganlv\EnphpDecoder\NodeVisitors;
44

5+
use Ganlv\EnphpDecoder\PrettyPrinter\StandardPrettyPrinter;
56
use PhpParser\Node;
67
use PhpParser\NodeTraverser;
78
use PhpParser\NodeVisitorAbstract;
89

910
class FindAndRemoveGlobalVariableNameNodeVisitor extends NodeVisitorAbstract
1011
{
12+
const GLOBAL_VAR_KEY_TYPE_CONST_FETCH = 1;
13+
const GLOBAL_VAR_KEY_TYPE_STRING = 2;
14+
const DATA_TYPE_EXPLODE_GZINFLATE_SUBSTR = 1;
15+
const DATA_TYPE_EXPLODE = 2;
16+
1117
public $globalVarName;
1218
public $globalVarKey;
19+
public $globalVarKeyType = 0;
20+
public $globalVarKeyExpr;
1321
public $delimiter;
1422
public $data;
1523
public $start;
1624
public $length;
25+
public $dataType = 0;
26+
27+
public function enterNode(Node $node)
28+
{
29+
if ($this->dataType !== 0) {
30+
return NodeTraverser::STOP_TRAVERSAL;
31+
}
32+
}
1733

1834
public function leaveNode(Node $node)
1935
{
2036
if ($node instanceof \PhpParser\Node\Stmt\Expression
2137
&& $node->expr instanceof \PhpParser\Node\Expr\Assign
2238
&& $node->expr->var instanceof \PhpParser\Node\Expr\ArrayDimFetch
2339
&& $node->expr->var->var instanceof \PhpParser\Node\Expr\Variable
24-
&& $node->expr->var->dim instanceof \PhpParser\Node\Expr\ConstFetch
25-
&& $node->expr->var->dim->name instanceof \PhpParser\Node\Name
26-
&& count($node->expr->var->dim->name->parts) === 1
27-
&& $node->expr->expr instanceof \PhpParser\Node\Expr\FuncCall
28-
&& $node->expr->expr->name instanceof \PhpParser\Node\Name
29-
&& count($node->expr->expr->name->parts) === 1
30-
&& $node->expr->expr->name->parts[0] === 'explode'
31-
&& count($node->expr->expr->args) === 2
32-
&& $node->expr->expr->args[0] instanceof \PhpParser\Node\Arg
33-
&& $node->expr->expr->args[0]->value instanceof \PhpParser\Node\Scalar\String_
34-
&& $node->expr->expr->args[0]->byRef === false
35-
&& $node->expr->expr->args[0]->unpack === false
36-
&& $node->expr->expr->args[1] instanceof \PhpParser\Node\Arg
37-
&& $node->expr->expr->args[1]->value instanceof \PhpParser\Node\Expr\FuncCall
38-
&& $node->expr->expr->args[1]->value->name instanceof \PhpParser\Node\Name
39-
&& count($node->expr->expr->args[1]->value->name->parts) === 1
40-
&& $node->expr->expr->args[1]->value->name->parts[0] === 'gzinflate'
41-
&& count($node->expr->expr->args[1]->value->args) === 1
42-
&& $node->expr->expr->args[1]->value->args[0] instanceof \PhpParser\Node\Arg
43-
&& $node->expr->expr->args[1]->value->args[0]->value instanceof \PhpParser\Node\Expr\FuncCall
44-
&& $node->expr->expr->args[1]->value->args[0]->value->name instanceof \PhpParser\Node\Name
45-
&& count($node->expr->expr->args[1]->value->args[0]->value->name->parts) === 1
46-
&& $node->expr->expr->args[1]->value->args[0]->value->name->parts[0] === 'substr'
47-
&& count($node->expr->expr->args[1]->value->args[0]->value->args) === 3
48-
&& $node->expr->expr->args[1]->value->args[0]->value->args[0] instanceof \PhpParser\Node\Arg
49-
&& $node->expr->expr->args[1]->value->args[0]->value->args[0]->value instanceof \PhpParser\Node\Scalar\String_
50-
&& $node->expr->expr->args[1]->value->args[0]->value->args[0]->byRef === false
51-
&& $node->expr->expr->args[1]->value->args[0]->value->args[0]->unpack === false
52-
&& $node->expr->expr->args[1]->value->args[0]->value->args[1] instanceof \PhpParser\Node\Arg
53-
&& $node->expr->expr->args[1]->value->args[0]->value->args[1]->value instanceof \PhpParser\Node\Scalar\LNumber
54-
&& $node->expr->expr->args[1]->value->args[0]->value->args[1]->byRef === false
55-
&& $node->expr->expr->args[1]->value->args[0]->value->args[1]->unpack === false
56-
&& $node->expr->expr->args[1]->value->args[0]->value->args[2] instanceof \PhpParser\Node\Arg
57-
&& $node->expr->expr->args[1]->value->args[0]->value->args[2]->value instanceof \PhpParser\Node\Expr\UnaryMinus
58-
&& $node->expr->expr->args[1]->value->args[0]->value->args[2]->value->expr instanceof \PhpParser\Node\Scalar\LNumber
59-
&& $node->expr->expr->args[1]->value->args[0]->value->args[2]->byRef === false
60-
&& $node->expr->expr->args[1]->value->args[0]->value->args[2]->unpack === false
61-
&& $node->expr->expr->args[1]->value->args[0]->byRef === false
62-
&& $node->expr->expr->args[1]->value->args[0]->unpack === false
63-
&& $node->expr->expr->args[1]->byRef === false
64-
&& $node->expr->expr->args[1]->unpack === false
65-
) {
66-
$this->globalVarName = $node->expr->var->var->name;
67-
$this->globalVarKey = $node->expr->var->dim->name->parts[0];
68-
$this->delimiter = $node->expr->expr->args[0]->value->value;
69-
$this->data = $node->expr->expr->args[1]->value->args[0]->value->args[0]->value->value;
70-
$this->start = $node->expr->expr->args[1]->value->args[0]->value->args[1]->value->value;
71-
$this->length = -$node->expr->expr->args[1]->value->args[0]->value->args[2]->value->expr->value;
72-
return NodeTraverser::REMOVE_NODE;
40+
&& $node->expr->var->dim !== null) {
41+
42+
// $GLOBALS[FOO]
43+
// $GLOBALS['FOO']
44+
if ($node->expr->var->dim instanceof \PhpParser\Node\Expr\ConstFetch
45+
&& $node->expr->var->dim->name instanceof \PhpParser\Node\Name
46+
&& count($node->expr->var->dim->name->parts) === 1) {
47+
$this->globalVarKeyType = self::GLOBAL_VAR_KEY_TYPE_CONST_FETCH;
48+
$this->globalVarKey = $node->expr->var->dim->name->parts[0];
49+
} elseif ($node->expr->var->dim instanceof \PhpParser\Node\Scalar\String_) {
50+
$this->globalVarKeyType = self::GLOBAL_VAR_KEY_TYPE_STRING;
51+
$this->globalVarKey = $node->expr->var->dim->value;
52+
} else {
53+
return null;
54+
}
55+
56+
if ($node->expr->expr instanceof \PhpParser\Node\Expr\FuncCall
57+
&& $node->expr->expr->name instanceof \PhpParser\Node\Name
58+
&& count($node->expr->expr->name->parts) === 1
59+
&& $node->expr->expr->name->parts[0] === 'explode'
60+
&& count($node->expr->expr->args) === 2
61+
&& $node->expr->expr->args[0] instanceof \PhpParser\Node\Arg
62+
&& $node->expr->expr->args[0]->value instanceof \PhpParser\Node\Scalar\String_
63+
&& $node->expr->expr->args[0]->byRef === false
64+
&& $node->expr->expr->args[0]->unpack === false) {
65+
66+
// explode('DELIMITER', gzinflate(substr('DATA', 0x0a, -8))
67+
// explode('DELIMITER', 'DATA')
68+
if ($node->expr->expr->args[1] instanceof \PhpParser\Node\Arg
69+
&& $node->expr->expr->args[1]->value instanceof \PhpParser\Node\Expr\FuncCall
70+
&& $node->expr->expr->args[1]->value->name instanceof \PhpParser\Node\Name
71+
&& count($node->expr->expr->args[1]->value->name->parts) === 1
72+
&& $node->expr->expr->args[1]->value->name->parts[0] === 'gzinflate'
73+
&& count($node->expr->expr->args[1]->value->args) === 1
74+
&& $node->expr->expr->args[1]->value->args[0] instanceof \PhpParser\Node\Arg
75+
&& $node->expr->expr->args[1]->value->args[0]->value instanceof \PhpParser\Node\Expr\FuncCall
76+
&& $node->expr->expr->args[1]->value->args[0]->value->name instanceof \PhpParser\Node\Name
77+
&& count($node->expr->expr->args[1]->value->args[0]->value->name->parts) === 1
78+
&& $node->expr->expr->args[1]->value->args[0]->value->name->parts[0] === 'substr'
79+
&& count($node->expr->expr->args[1]->value->args[0]->value->args) === 3
80+
&& $node->expr->expr->args[1]->value->args[0]->value->args[0] instanceof \PhpParser\Node\Arg
81+
&& $node->expr->expr->args[1]->value->args[0]->value->args[0]->value instanceof \PhpParser\Node\Scalar\String_
82+
&& $node->expr->expr->args[1]->value->args[0]->value->args[0]->byRef === false
83+
&& $node->expr->expr->args[1]->value->args[0]->value->args[0]->unpack === false
84+
&& $node->expr->expr->args[1]->value->args[0]->value->args[1] instanceof \PhpParser\Node\Arg
85+
&& $node->expr->expr->args[1]->value->args[0]->value->args[1]->value instanceof \PhpParser\Node\Scalar\LNumber
86+
&& $node->expr->expr->args[1]->value->args[0]->value->args[1]->byRef === false
87+
&& $node->expr->expr->args[1]->value->args[0]->value->args[1]->unpack === false
88+
&& $node->expr->expr->args[1]->value->args[0]->value->args[2] instanceof \PhpParser\Node\Arg
89+
&& $node->expr->expr->args[1]->value->args[0]->value->args[2]->value instanceof \PhpParser\Node\Expr\UnaryMinus
90+
&& $node->expr->expr->args[1]->value->args[0]->value->args[2]->value->expr instanceof \PhpParser\Node\Scalar\LNumber
91+
&& $node->expr->expr->args[1]->value->args[0]->value->args[2]->byRef === false
92+
&& $node->expr->expr->args[1]->value->args[0]->value->args[2]->unpack === false
93+
&& $node->expr->expr->args[1]->value->args[0]->byRef === false
94+
&& $node->expr->expr->args[1]->value->args[0]->unpack === false
95+
&& $node->expr->expr->args[1]->byRef === false
96+
&& $node->expr->expr->args[1]->unpack === false) {
97+
$this->dataType = self::DATA_TYPE_EXPLODE_GZINFLATE_SUBSTR;
98+
$this->data = $node->expr->expr->args[1]->value->args[0]->value->args[0]->value->value;
99+
$this->start = $node->expr->expr->args[1]->value->args[0]->value->args[1]->value->value;
100+
$this->length = -$node->expr->expr->args[1]->value->args[0]->value->args[2]->value->expr->value;
101+
} elseif ($node->expr->expr->args[1] instanceof \PhpParser\Node\Arg
102+
&& $node->expr->expr->args[1]->value instanceof \PhpParser\Node\Scalar\String_
103+
&& $node->expr->expr->args[1]->byRef === false
104+
&& $node->expr->expr->args[1]->unpack === false) {
105+
$this->dataType = self::DATA_TYPE_EXPLODE;
106+
$this->data = $node->expr->expr->args[1]->value->value;
107+
} else {
108+
return null;
109+
}
110+
111+
$this->globalVarName = $node->expr->var->var->name;
112+
$this->globalVarKeyExpr = StandardPrettyPrinter::prettyPrinter()->prettyPrintExpr($node->expr->var->dim);
113+
$this->delimiter = $node->expr->expr->args[0]->value->value;
114+
return NodeTraverser::REMOVE_NODE;
115+
}
73116
}
117+
return null;
74118
}
75119
}

src/NodeVisitors/FunctionGlobalStringNodeVisitor.php

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Ganlv\EnphpDecoder\NodeVisitors;
44

5+
use Ganlv\EnphpDecoder\PrettyPrinter\StandardPrettyPrinter;
56
use PhpParser\Node;
67
use PhpParser\NodeTraverser;
78
use PhpParser\NodeVisitorAbstract;
@@ -10,13 +11,13 @@ class FunctionGlobalStringNodeVisitor extends NodeVisitorAbstract
1011
{
1112
public $localVarName;
1213
public $globalVarName;
13-
public $globalVarKey;
14+
public $globalVarKeyExpr;
1415
public $stringArray;
1516

16-
public function __construct($globalVarName, $globalVarKey, $stringArray)
17+
public function __construct($globalVarName, $globalVarKeyExpr, $stringArray)
1718
{
1819
$this->globalVarName = $globalVarName;
19-
$this->globalVarKey = $globalVarKey;
20+
$this->globalVarKeyExpr = $globalVarKeyExpr;
2021
$this->stringArray = $stringArray;
2122
}
2223

@@ -28,17 +29,14 @@ public function leaveNode(Node $node)
2829
&& $node->expr->expr instanceof Node\Expr\ArrayDimFetch
2930
&& $node->expr->expr->var instanceof Node\Expr\Variable
3031
&& $node->expr->expr->var->name === $this->globalVarName
31-
&& $node->expr->expr->dim instanceof Node\Expr\ConstFetch
32-
&& $node->expr->expr->dim->name instanceof Node\Name
33-
&& $node->expr->expr->dim->name->parts[0] === $this->globalVarKey
34-
) {
32+
&& $node->expr->expr->dim !== null
33+
&& StandardPrettyPrinter::prettyPrinter()->prettyPrintExpr($node->expr->expr->dim) === $this->globalVarKeyExpr) {
3534
$this->localVarName = $node->expr->var->name;
3635
return NodeTraverser::REMOVE_NODE;
3736
} elseif ($node instanceof Node\Expr\ArrayDimFetch
3837
&& $node->var instanceof Node\Expr\Variable
3938
&& $node->var->name === $this->localVarName
40-
&& $node->dim instanceof Node\Scalar\LNumber
41-
) {
39+
&& $node->dim instanceof Node\Scalar\LNumber) {
4240
return new Node\Scalar\String_($this->stringArray[$node->dim->value]);
4341
}
4442
return null;

src/NodeVisitors/GlobalStringNodeVisitor.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22

33
namespace Ganlv\EnphpDecoder\NodeVisitors;
44

5+
use Ganlv\EnphpDecoder\PrettyPrinter\StandardPrettyPrinter;
56
use PhpParser\Node;
67
use PhpParser\NodeVisitorAbstract;
78

89
class GlobalStringNodeVisitor extends NodeVisitorAbstract
910
{
1011
public $globalVarName;
11-
public $globalVarKey;
12+
public $globalVarKeyExpr;
1213
public $stringArray;
1314

14-
public function __construct($globalVarName, $globalVarKey, $stringArray)
15+
public function __construct($globalVarName, $globalVarKeyExpr, $stringArray)
1516
{
1617
$this->globalVarName = $globalVarName;
17-
$this->globalVarKey = $globalVarKey;
18+
$this->globalVarKeyExpr = $globalVarKeyExpr;
1819
$this->stringArray = $stringArray;
1920
}
2021

@@ -24,11 +25,9 @@ public function leaveNode(Node $node)
2425
&& $node->var instanceof Node\Expr\ArrayDimFetch
2526
&& $node->var->var instanceof Node\Expr\Variable
2627
&& $node->var->var->name === $this->globalVarName
27-
&& $node->var->dim instanceof Node\Expr\ConstFetch
28-
&& $node->var->dim->name instanceof Node\Name
29-
&& $node->var->dim->name->parts[0] === $this->globalVarKey
30-
&& $node->dim instanceof Node\Scalar\LNumber
31-
) {
28+
&& $node->var->dim !== null
29+
&& StandardPrettyPrinter::prettyPrinter()->prettyPrintExpr($node->var->dim) === $this->globalVarKeyExpr
30+
&& $node->dim instanceof Node\Scalar\LNumber) {
3231
return new Node\Scalar\String_($this->stringArray[$node->dim->value]);
3332
}
3433
return null;

src/NodeVisitors/RemoveDefineGlobalVariableNameNodeVisitor.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,7 @@ public function leaveNode(Node $node)
3131
&& $node->expr->args[1] instanceof \PhpParser\Node\Arg
3232
&& $node->expr->args[1]->value instanceof \PhpParser\Node\Scalar\String_
3333
&& $node->expr->args[1]->byRef === false
34-
&& $node->expr->args[1]->unpack === false
35-
) {
34+
&& $node->expr->args[1]->unpack === false) {
3635
return NodeTraverser::REMOVE_NODE;
3736
}
3837
}

0 commit comments

Comments
 (0)