昨天在一個(gè) PHP 的群里看到一個(gè)圖片,圖片如下:
看到這個(gè)圖片,我覺得這應(yīng)該是某個(gè)收費(fèi)項(xiàng)目的源碼,收費(fèi)的項(xiàng)目為什么還要提供源碼,這就是 PHP 的問題之一吧。
很多人也許想要修改這樣的源碼,但是無(wú)奈源碼又是這樣的讓人看不懂。拿到這樣的源碼,我估計(jì)很多想要修改源碼的一部分人就被卡住了。在這種情況下,我想說(shuō)的是,作者既然這么做了,就是不希望被別人修改。如果真的覺得項(xiàng)目好的話,其實(shí)可以去付費(fèi)的,畢竟軟件是每個(gè)軟件工程師的汗水。
雖然話是這么說(shuō),但是如果只是單純的想要學(xué)習(xí),也不產(chǎn)生什么利益的話,遇到這樣的問題有什么辦法呢?雖然我對(duì) PHP 不怎么懂,但是我知道對(duì)于 PHP 這種源代碼層面的處理想要還原問題不大(我自己的臆想,畢竟各種的處理方法可能很多,只是我不知罷了),關(guān)鍵在于還原一下值不值。當(dāng)然了,PHP 的加密還存在引擎級(jí)別的,我覺得引擎級(jí)別還是有難度的。但是如果只是源碼級(jí)別的處理,我覺得發(fā)揮想象其實(shí)每個(gè)人都是可以去嘗試還原的,因?yàn)檫€原的可能性還是很大的。
這類代碼我沒怎么見過,針對(duì)上面那個(gè)圖片,我沒有拿到源文件,只有這個(gè)圖片。針對(duì)這個(gè)圖片,我給出一個(gè)處理的思路,和大家進(jìn)行交流。
說(shuō)說(shuō)我的思路
說(shuō)說(shuō)如果是我處理的話,我處理的思路吧。
首先將代碼格式化,用很多工具都可以進(jìn)行格式化,比如 PHPStorm;
這樣的代碼格式化后顯然是沒有太大的用處的,格式化的目的在于要把整個(gè)源碼規(guī)范一下,然后嘗試把整個(gè)代碼中的 goto 語(yǔ)句去掉;因?yàn)榇a的執(zhí)行是順序的,也就是從文件的開頭到結(jié)尾這么進(jìn)行執(zhí)行,如果能把 goto 去掉的話,你就得到了一份真正的執(zhí)行順序的代碼,其實(shí) goto 就是無(wú)條件的跳轉(zhuǎn),我們將離散的用 goto 連接的代碼,變成線性的就可以了;
除了滿屏的 goto 語(yǔ)句以外,剩下的就是一些看不懂的字符了,可能有人會(huì)說(shuō)是加密了之類的,其實(shí)是看的不夠仔細(xì)。仔細(xì)觀察的話,其實(shí)只是被編碼了。我們可以從代碼中有明顯特征的位置開始還原,什么是明顯特征?看下圖。
圖中是一個(gè) date() 函數(shù),這個(gè)函數(shù)我們每個(gè)人都會(huì)用,它的參數(shù)是字符串。PHP 中用來(lái)限定字符串的符號(hào)分兩種,分別是 單引號(hào) 和 雙引號(hào),在平時(shí)為了代碼的運(yùn)行速度,我們寫代碼通常會(huì)使用單引號(hào),而字符串當(dāng)中有轉(zhuǎn)義字符時(shí),我們就要去使用雙引號(hào)。而這里 date() 函數(shù)中的字符串其實(shí)就是轉(zhuǎn)義字符。這些看起來(lái)被加密的東西其實(shí)就是一些 ASCII 碼,說(shuō)白了就是考驗(yàn)大家的基礎(chǔ)?!癨”開頭的是 8 進(jìn)制,“x”開頭的是 16 進(jìn)制,"\131" 是大寫字母“Y”,“\55”是字符“-”,剩下的還要我說(shuō)嗎?還不會(huì)?找一份 ASCII 碼表對(duì)著看看不行么?
有了第三步的基礎(chǔ),還原剩下的部分難嗎?
嘗試
我去網(wǎng)上找了類似的一個(gè)文件,然后自己嘗試用代碼去還原它的結(jié)構(gòu),也就是我上面思路的第二步。畢竟文件有點(diǎn)大,還是寫代碼還原靠譜。代碼寫了不到 200 行,還原差不多 20 多行的代碼??梢哉f(shuō)是有進(jìn)展的,為什么沒有全部還原呢?其實(shí)是有原因的,因?yàn)樵诟袷交院?,我用代碼進(jìn)行處理的時(shí)候,沒有逐個(gè)的去處理各種可能(因?yàn)檫@部分花時(shí)間比較多),我只是處理了部分的情況。有些格式化后的代碼,和我想要的預(yù)期也不太相同,比如多行連續(xù)標(biāo)簽,標(biāo)簽后面接 goto 之類的情況,我沒有去一一處理,因?yàn)槲覟榈牟皇沁€原源碼,而是驗(yàn)證我的思路。給出關(guān)鍵代碼的結(jié)構(gòu),完整的源碼就不提供了(具體的處理完刪掉了),我自己都沒有寫完,而且也不算復(fù)雜。
<?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) {
}
// 處理標(biāo)號(hào)后的代碼
if (strpos($line, ':') !== false) {
// 標(biāo)號(hào)后面是單行代碼
if (strpos($line, ';') !== false) {
}
if (strpos($line, ':') !== false) {
}
if (strpos($line, 'goto') !== false) {
}
// 標(biāo)號(hào)后面是多行代碼
if (strpos($line, '{') !== false) {
$code = $this->delrn($line);
$i = 1; // 記錄左括號(hào){的數(shù)量
while ($line = fgets($this->f)) {
$this->lineNo ++;
if (strpos($line, '{') !== false) {
}
if (strpos($line, '}') !== false) {
}
$code = $code . ' ' . $this->delrn($line);
}
}
// 標(biāo)號(hào)后面是個(gè)function
if (strpos($line, 'function') !== false) {
$code = $line;
$i = 0; // 記錄左括號(hào){的數(shù)量
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();
總結(jié)
這種對(duì)代碼的處理一般應(yīng)該被稱為“代碼混淆”,而這種代碼混淆的方式算是簡(jiǎn)單的。這種工具其實(shí)可以自己實(shí)現(xiàn)一個(gè),按行讀取每一行的 PHP 代碼,然后給每行代碼隨機(jī)生成一個(gè)行號(hào),然后用 goto 連接,最后進(jìn)行亂序。然后可以把“字符串”處理成“轉(zhuǎn)義字符”。當(dāng)然了,其實(shí)還有很多可以處理的方法,只要把能想到的處理方法定義成規(guī)則,你的代碼混淆工具處理后的 PHP 代碼會(huì)比這個(gè)要復(fù)雜。
知道了混淆的思路,那么反混淆的話,其實(shí)也是這種思路,可以人肉進(jìn)行處理,如果量大就不合適人肉了。量大就需要寫工具去自動(dòng)化完成了。
最后,我想再次和大家說(shuō),我們都是做軟件開發(fā)的,請(qǐng)珍惜每一位軟件工程師的汗水。盜取別人的成果,其實(shí)是在破壞這個(gè)行業(yè),也是在違法。我們面對(duì)各種問題時(shí),還是抱著學(xué)習(xí)和提高自身能力出發(fā)。