16

PHP 代码混淆处理思路

 3 years ago
source link: https://mp.weixin.qq.com/s/It9Thtz20rSQ3Z4u_3rl6g
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

昨天在一个 PHP 的群里看到一个图片,图片如下:

ZJRjym6.png!web

        看到这个图片,我觉得这应该是某个收费项目的源码,收费的项目为什么还要提供源码,这就是 PHP 的问题之一吧。

很多人也许想要修改这样的源码,但是无奈源码又是这样的让人看不懂。 拿到这样的源码,我估计很多想要修改源码的一部分人就被卡住了。在这种情况下,我想说的是,作者既然这么做了,就是不希望被别人修改。如果真的觉得项目好的话,其实可以去付费的,毕竟软件是每个软件工程师的汗水。

虽然话是这么说,但是如果只是单纯的想要学习,也不产生什么利益的话,遇到这样的问题有什么办法呢?虽然我对 PHP 不怎么懂,但是我知道对于 PHP 这种源代码层面的处理想要还原问题不大(我自己的臆想,毕竟各种的处理方法可能很多,只是我不知罢了),关键在于还原一下值不值。当然了,PHP 的加密还存在引擎级别的,我觉得引擎级别还是有难度的。但是如果只是源码级别的处理,我觉得发挥想象其实每个人都是可以去尝试还原的,因为还原的可能性还是很大的。

这类代码我没怎么见过,针对上面那个图片,我没有拿到源文件,只有这个图片。针对这个图片,我给出一个处理的思路,和大家进行交流。

说说我的思路

说说如果是我处理的话,我处理的思路吧。

  • 首先将代码格式化,用很多工具都可以进行格式化,比如 PHPStorm;

  • 这样的代码格式化后显然是没有太大的用处的,格式化的目的在于要把整个源码规范一下,然后尝试把整个代码中的 goto 语句去掉;因为代码的执行是顺序的,也就是从文件的开头到结尾这么进行执行,如果能把 goto 去掉的话,你就得到了一份真正的执行顺序的代码,其实 goto 就是无条件的跳转,我们将离散的用 goto 连接的代码,变成线性的就可以了;

  • 除了满屏的 goto 语句以外,剩下的就是一些看不懂的字符了,可能有人会说是加密了之类的,其实是看的不够仔细。仔细观察的话,其实只是被编码了。我们可以从代码中有明显特征的位置开始还原,什么是明显特征?看下图。

ayMNJbJ.png!web

        图中是一个 date() 函数,这个函数我们每个人都会用,它的参数是字符串。PHP 中用来限定字符串的符号分两种,分别是 单引号 双引号 ,在平时为了代码的运行速度,我们写代码通常会使用单引号,而字符串当中有转义字符时,我们就要去使用双引号。而这里 date() 函数中的字符串其实就是转义字符。这些看起来被加密的东西其实 就是一些 ASCII 码,说白了就是考验大家的基础。 “\”开头的是 8 进制,“x”开头的是 16 进制,"\131" 是大写字母“Y”,“\55”是字符“-”,剩下的还要我说吗?还不会?找一份 ASCII 码表对着看看不行么?

        有了第三步的基础,还原剩下的部分难吗?

尝试

我去网上找了类似的一个文件,然后自己尝试用代码去还原它的结构,也就是我上面思路的第二步。毕竟文件有点大,还是写代码还原靠谱。代码写了不到 200 行,还原差不多 20 多行的代码。可以说是有进展的,为什么没有全部还原呢?其实是有原因的,因为在格式化以后,我用代码进行处理的时候,没有逐个的去处理各种可能(因为这部分花时间比较多),我只是处理了部分的情况。有些格式化后的代码,和我想要的预期也不太相同,比如多行连续标签,标签后面接 goto 之类的情况,我没有去一一处理,因为我为的不是还原源码,而是验证我的思路。给出关键代码的结构,完整的源码就不提供了 (具体的处理我删掉了 ,我自己都没有写完,而且也不算复杂。

<?php


class decode

{

private $f;

private $arr = [];

private $lineNo = 0;


public function openfile()

{

$this->f = fopen('./test.php', 'r');

}


public function closefile()

{

fclose($this->f);

}


public function de()

{

$this->openfile();

while (!feof($this->f)) {

$line = fgets($this->f);

$this->lineNo ++;

$this->parse($line);

}


$this->closefile();

$this->output();

$this->outputcode();

}


public function delrn($str)

{

}


public function parse($line)

{

// 处理 goto 的

if (strpos($line, 'goto') !== false) {


}


// 处理标号后的代码

if (strpos($line, ':') !== false) {


// 标号后面是单行代码

if (strpos($line, ';') !== false) {


}


if (strpos($line, ':') !== false) {


}


if (strpos($line, 'goto') !== false) {

}


// 标号后面是多行代码

if (strpos($line, '{') !== false) {

$code = $this->delrn($line);

$i = 1; // 记录左括号{的数量

while ($line = fgets($this->f)) {

$this->lineNo ++;

if (strpos($line, '{') !== false) {

}


if (strpos($line, '}') !== false) {


}


$code = $code . ' ' . $this->delrn($line);

}

}


// 标号后面是个function

if (strpos($line, 'function') !== false) {

$code = $line;

$i = 0; // 记录左括号{的数量

while ($line = fgets($this->f)) {

$this->lineNo ++;

if (strpos($line, '{') !== false) {


}


if (strpos($line, '}') !== false) {


}


$code = $code . ' ' . $line;

}

}


return ;

}

}


// 中间文件

public function output()

{

$f = fopen('./output.php', 'w');


foreach ($this->arr as $k => $v) {

}


fclose($f);

}


// 最终文件

public function outputcode()

{

$f = fopen('./code.php', 'w');


while (true) {

}


fclose($f);

}


public function next($key, $arr)

{

$bret = false;


foreach($arr as $k => $v) {

if ($bret == true) {

return $k;

}

if ($k === $key) {

$bret = true;

}

}


return false;

}

}


$decode = new decode();

$decode->de();

总结

这种对代码的处理一般应该被称为“ 代码混淆 ”,而这种代码混淆的方式算是简单的。这种工具其实可以自己实现一个,按行读取每一行的 PHP 代码,然后给每行代码随机生成一个行号,然后用 goto 连接,最后进行乱序。然后可以把“字符串”处理成“转义字符”。当然了,其实还有很多可以处理的方法,只要把能想到的处理方法定义成规则,你的代码混淆工具处理后的 PHP 代码会比这个要复杂。

知道了混淆的思路,那么反混淆的话,其实也是这种思路,可以人肉进行处理,如果量大就不合适人肉了。量大就需要写工具去自动化完成了。

最后,我想再次和大家说,我们都是做软件开发的,请珍惜每一位软件工程师的汗水。盗取别人的成果,其实是在破坏这个行业,也是在违法。我们面对各种问题时,还是抱着学习和提高自身能力出发。

AJ77FvR.jpg!web

喜欢就点在看哦~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK