游客发表
一个下午,加解我盯着屏幕上那行eval(gzinflate(base64_decode(...)))足足看了二十分钟。密破那串乱码一样的加解PHP代码,像一张揉皱的密破纸团,里面藏着某个“加密”过的加解业务逻辑。说真的密破,这种加密与其叫加密,加解不如叫“糊弄”——把代码压缩、密破base64编码,加解再套一层eval,密破就敢自称商业授权保护了。加解
破解这玩意儿,密破第一步不是加解写脚本,是密破认清本质。PHP是加解解释型语言,服务器最终要执行的是明文opcode。你加密得再花哨,只要eval能跑,那它执行前必然在内存里还原成可读源码。所以最笨也最有效的办法,就是让PHP自己把底裤露出来——把那个eval改成echo,或者干脆在eval前加个file_put_contents('dump.php', $decoded)。一次命中,源码直接躺硬盘里。
去年接了个活儿,客户网站被后门搞瘫了。我扫出个“加密”文件,后缀是php,打开一看全乱码。当时没急着破解,先看文件头部——好家伙,直接写着Zend Guard的标识。这种商业级加密麻烦点,因为Zend会把opcode也编码了,纯eval替换没用。但别慌,PHP版本和Zend版本总有匹配漏洞,老版本Zend Optimizer在PHP 5.3上有个已知的缓存溢出,能拿到解密后的zend_execute返回值。不过那是2012年的事了,现在谁还用PHP5?现实点,直接找内存dump——跑个脚本触发执行,同时用gdb抓进程内存,搜function关键字节,照样能拼出源码。
最让我觉得讽刺的是,有些“加密”根本不需要技术破解。有回接了个外包维护,对方丢来一堆ionCube加密的文件,说解密费另算。我本地装上ionCube loader,跑起来一看报错——加密时用的版本太老,新版loader直接拒绝执行。然后我仔细读了文件头,发现ionCube的格式里居然留着原始文件名和行号映射表。顺着那个表,用十六进制编辑器把loader的decode函数入口patch掉,强制让它跳过验证,结果文件直接以明文形式被加载到内存。那次没写一行PHP代码,光改二进制就搞定了。
不过话说回来,真遇到硬茬——比如用swoole扩展配合opcache加密的,破解成本就高了。但那种场景少,多数所谓“加密”,防的是小白,不是程序员。你拿个十六进制编辑器,搜eval、搜assert、搜create_function,基本能定位到执行点。再配合PHP的token_get_all()函数,写个50行的小脚本自动解码,半小时出活。
说句得罪人的话,PHP加密破解这行当,七成时间花在识别加密方式上,三成时间才是动手。你看见eval开头,先试base64+gzinflate;看见乱码里有$_GET字样,那是变量覆盖混淆;看见文件末尾多了一段注释,八成是Zend的签名。破解不是炫技,是耐心活——就像拆锁,好锁匠不是拿电钻,而是拿根铁丝慢慢探。
最后提个醒,别拿这套去搞别人的商业代码。我破解的都是自己买的、或者客户授权的系统。技术本身中性,但用在哪,心里得有杆秤。真遇到恶意加密——比如后门藏了加密webshell——那破解就是正当防卫了。那下午那串乱码,最后被我dump出来,发现是个定时发包的僵尸程序。删掉文件,清掉计划任务,收工。加密破了,但心里没爽感,只有一种“果然如此”的疲惫。
友情链接