
前幾天在網上看到一份代碼,打開來看,裡面都是類似下面的十六進制字元串。一臉懵逼,啥情況,我萬能的sublime text 打開居然是十六進制檔案,而且檔案居然還能運作?
3c3f 7068 700d 0a6e 616d 6573 7061 6365
2061 7070 3b24 5f53 4552 5645 525b 5048
505f 454f 4c5d 203d 2065 7870 6c6f 6465
複制
使用萬能的記事本打開一看裡面一段可見的部分引起注意
$_SERVER[PHP_EOL] = explode(
",",
gzinflate('? ?N?I-.袸+退-N K扮? ',10,-8)
);
複制
于是仔細研究了一下。
常見的幾種PHP代碼加密方式
1.opecode 方式
将PHP代碼直接編譯為opcode代碼,有點類似于java種的class檔案。采用這種方式避免源碼暴露出來。因為Zend引擎最終執行的是opcode,隻要保證能解密出opcode就能保證程式正常運作,隻要簡單的将opcode進行簡單的序列化或者像Zend Guard那樣進行混淆,在運作之前将opcode還原,那麼源代碼的資訊就不存在了,這樣我們就能保證源代碼的安全, 而不至于洩露。
通過擴充的方式對加密檔案進行解密
因為php程式運作前都會執行擴充的方法,是以通過擴充的方式對php源碼進行保護可以有很多形式。
- 源碼許可驗證。通過擴充在程式執行前驗證代碼的licence可以避免盜版使用的情況。
- 通過hash驗證,驗證源碼是否被修改
- 對核心代碼進行加密,甚至放在擴充中運作,避免被破解。
直接對PHP代碼進行混淆,加到源碼閱讀難度
這種方式不是真正意義上的加密,隻是對代碼進行混淆。将PHP代碼中的變量,方法名稱等換成毫無意義的表示符号。代碼混淆有多種處理方式。
- 将代碼檔案作為字元串進行base64編碼,然後使用evel的方式在執行的過程中對檔案進行base64解碼運作。這種方式對原來的代碼内部變化比較小。隻是換了一種現實方式而已。
- 通過正則方式替換變量符号,函數名稱等。這種方式替換會有很大的不确定性。因為已經在實質上修改了原有的代碼,容易造成變量沖突,類屬性不存在等錯誤。特别對于通過魔術方式等設定的類屬性,或者通過依賴注入方式,回調方式建立的對象,這種替換會使得代碼無法運作。
- 建立一個全局數組作為替換碼表。将所有字元串進行替換。這種方式不改變類屬性的名稱,方法的名稱等。隻是将所有的變量名稱,方法名稱替換成碼表種的值。将碼表進行加密存,在程式入口進行解密,保證後續代碼能正常運作。這種方式隻要替換正确都能保證代碼可運作。
目前網上的代碼基本上都是使用混淆的方式。因為這些代碼都不能要求使用者使用特定的擴充,同時為了保證代碼客運作,基本上都是在一些核心檔案才會使用混淆,對代碼進行混淆。
對于文章開始混淆前代碼
<?phpnamespace app;class Test{ public $msg; public function setMsg($msg){ $this->msg = $msg;
} public function getMsg(){
$hex = 'haha';
$tys = '8'; return $this->msg;
}
}
$t = new Test();
$t->setMsg('hahahahah');
var_dump($t->getMsg());
複制
混淆後的代碼
<?phpnamespace app;
$_SERVER[PHP_EOL] = explode(
",",
gzdecode(? 薍)?? Wc? ));
class Test {
public $msg;
public function test(${$_SERVER[PHP_EOL][0]}) { $this->msg = ${$_SERVER[PHP_EOL][0]}; } public function {$_SErVer[php_eol][2]}() { goto {$_SERVER[PHP_EOL][55]}; {$_SERVER[PHP_EOL][57]}: return $this->msg; goto {$_SERVER[PHP_EOL][58]}; {$_SERVER[PHP_EOL][56]}: ${$_SERVER[PHP_EOL][17]} = "\70"; goto {$_SERVER[PHP_EOL][57]}; {$_SERVER[PHP_EOL][55]}: ${$_SERVER[PHP_EOL][16]} = "\150\x61\x68\141"; goto {$_SERVER[PHP_EOL][56]}; {$_SERVER[PHP_EOL][58]}: } } ${$_SERVER[PHP_EOL][18]} = new Test(); ${$_SERVER[PHP_EOL][18]}->{$_SERVER[PHP_EOL][1]}("\150\141\x68\x61\x68\141\150\x61\x68"); var_dump(${$_SERVER[PHP_EOL][18]}->{$_SERVER[PHP_EOL][2]}());
複制
編輯器打開是十六進制,其實是一個障眼法。主要是目前編輯器在檢測到檔案前有特殊字元就會當做十六進制檔案進行顯示!!是以當我們把碼表轉換成字元串,進行gz壓縮之後肯定會有特殊字元,然後把它放在檔案開始的地方,編輯器打開就是十六進制顯示方式。