PHP-Parser 用于代码混淆的代码
learn from
http://j0k3r.top/2020/03/24/php-Deobfuscator/#0x01-php-parser
https://github.com/nikic/PHP-Parser/tree/master/doc
下载
curl -s http://getcomposer.org/installer | php
遇到权限问题时,可以输入一下命令
sudo chown -R 'user-name' /home/'user-name'/.composer
之后再在所需项目中php composer.phar require nikic/php-parser
为了更方便调用composer
,可以输入一下命令
mv composer.phar /usr/local/bin/composer
如果composer require nikic/php-parse
遇到长时间卡住,可以尝试更新源
composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
项目: https://github.com/nikic/PHP-Parser
runoob 再次好用
生成AST
首先介绍一下PHP-Parser中定义的一些节点类型:
(1)PhpParser\Node\Stmt是语句节点,不带任何返回信息(return)的结构,如赋值语句”$a = $b” ;
(2)PhpParser\Node\Expr是表达式节点,可以返回一个值的语言结构,如$var和func()。
(3)PhpParser\Node\Scalar是常量节点,可以用来表示任何常量值。如’string’,0,以及常量表达式。
(4)还有一些节点没有包括进去,如参数节点(PhpParser\Node\Arg)。
一些节点类的名称使用了下划线,这是为了避免和PHP关键字冲突。
PHP-parser的test.php下,该代码片段会生成AST
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php use PhpParser\Error; use PhpParser\ParserFactory; require dirname(__FILE__).'/vendor/autoload.php'; $code = <<<'CODE' <?php
echo 'Hello PHP'; CODE;
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
try { $stmts = $parser->parse($code); var_dump($stmts); } catch (Error $e) { echo 'Parse Error: ', $e->getMessage(); }
|
output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| /home/fe1w0/babyshop/ttt.php:15: array(1) { [0] => class PhpParser\Node\Stmt\Echo_#1131 (2) { public $exprs => array(1) { [0] => class PhpParser\Node\Scalar\String_#1130 (2) { ... } } protected $attributes => array(2) { 'startLine' => int(3) 'endLine' => int(3) } } }
|
使用 NodeDumper
来查看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php use PhpParser\Error; use PhpParser\ParserFactory; use PhpParser\NodeDumper; require dirname(__FILE__).'/vendor/autoload.php'; $code = <<<'CODE' <?php
echo 'Hello PHP'; CODE;
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
try { $stmts = $parser->parse($code); $nodeDumper = new NodeDumper; echo $nodeDumper->dump($stmts), "\n"; } catch (Error $e) { echo 'Parse Error: ', $e->getMessage(); }
|
output:
1 2 3 4 5 6 7 8 9
| array( 0: Stmt_Echo( exprs: array( 0: Scalar_String( value: Hello PHP ) ) ) )
|
修改节点值 将Hello PHP
改为Hello world
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <?php use PhpParser\Error; use PhpParser\ParserFactory; use PhpParser\NodeDumper; use PhpParser\NodeTraverser; use PhpParser\Node; use PhpParser\NodeVisitorAbstract; use PhpParser\PrettyPrinter;
require dirname(__FILE__).'/vendor/autoload.php';
$code = <<<'CODE' <?php
echo 'Hello PHP';
CODE;
class MyNodeVisitor extends NodeVisitorAbstract { public function leaveNode(Node $node) { if ($node instanceof Node\Scalar\String_) { $node->value = 'Hello Word'; } } }
class PrintNodeVisitor extends NodeVisitorAbstract { public function leaveNode(Node $node) { if ($node instanceof Node\Stmt\Echo_) { return new PhpParser\Node\Stmt\Expression( new Node\Expr\Print_(new Node\Scalar\String_(($node->exprs)[0]->value)) ); } } }
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
try { $stmts = $parser->parse($code); $traverser = new NodeTraverser; $traverser->addVisitor(new MyNodeVisitor); $traverser->addVisitor(new PrintNodeVisitor); $new_stmts = $traverser->traverse($stmts); $prettyPrinter = new PrettyPrinter\Standard; $new_code = $prettyPrinter->prettyPrintFile($new_stmts); echo $code.PHP_EOL; echo "--After parser:--\n\n".$new_code;
} catch (Error $e) { echo 'Parse Error: ', $e->getMessage(); }
|
解混淆[缺失ing]