分析某「神盾加密」混淆代碼時發現,變數名大量使用不可見、非字母數字底線的字元。PHP 官方文件僅說明「以字母或底線開頭,後接字母數字底線」,實際上 PHP 引擎允許的字元範圍遠大於此。
編寫測試腳本,遍歷 0x00~0xFF 每個位元組作為變數名首字元/次字元,嘗試 eval('$' . chr($i) . '=1;'),若不拋出 Parse Error 則判定為合法。
<?php
// 測試首字元
if ($_POST) {
$chr = chr($_POST['chr']);
eval('$' . $chr . '=1;');
echo 'ok'; exit;
}
?>
0x41-0x5A (A-Z), 0x5F (_), 0x61-0x7A (a-z), 0x7F-0xFF (擴展 Latin-1 字元)
即正則:[a-zA-Z_\x7f-\xff]。PHP 將變數首字元擴充至 Latin-1 (ISO-8859-1) 範圍。
在首字元固定為 a 後,測試第二字元:
新增:0x30-0x39 (0-9)、0x09(\t)、0x0A(\n)、0x0D(\r)、0x20(space)
去除空白字元(PHP 語法允許的分隔符)後,次字元實際為 [\w\x7f-\xff](\w = [0-9a-zA-Z_])。
| 位置 | 合法字元集 | 正則表示 |
|---|---|---|
| 首字元 | 字母、底線、Latin-1 擴展字元 (0x7F-0xFF) | [a-zA-Z_\x7f-\xff] |
| 後續字元 | 首字元集合 + 數字 0-9 | [\w\x7f-\xff] |
$ = 1;(中間含零寬空格)。[a-zA-Z_][a-zA-Z0-9_]*,避免維護噩夢。屬於執行期解析,脫離「命名規則」範疇,不在本文討論範圍內。