浅谈 PHP 神盾的解密过程
前些日子一个朋友丢了个shell给我,让我帮忙解密,打开源码看了下写着是 “神盾加密” , 牛逼闪闪的样子、
百度下发现神盾是个很古老的东西,最后一次更新是在 2012-10-09。和他相似的另一款是phpjm,有人说是神盾抄袭phpjm的,这些都不是我们所要关心的问题、
phpjm一直在更新,而神盾貌似不搞了,我们分析下神盾,顺便写成工具,方便大家使用(因为他不更新,所以就不用担心解密工具失效问题了)。
其实网上早就有人分析过这个了,而且写成了工具、但是我测试了很多个,没一个能用,所以决定自己从头分析一遍。
打开神盾加密过后的源码,可以看到这样的代码
上面写着广告注释,而且不能删除,因为文件末尾有个md5效验码,以验证代码是否被修改过,如图、
再仔细看代码部分,发现里面都是乱码,其实这都是障眼法,
它利用了php变量扩充到 latin1 字符范围,其变量匹配正则是 \$[a-zA-Z_\x7f-\xff][\w\x7f-\xff]* 这样的格式。
这个昨天已经分析过了,最终也在官网找到了答案,请看《浅谈 PHP 变量可用字符》
有点扯远了,我们来做第一步解密处理吧。
PS: 这只是我的解密思路,与大家分享一下,也许你有更好的方法还望分享。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?php $str = file_get_contents ( "1.php" ); // 第一步 替换所有变量 // 正则 \$[a-zA-Z_\x7f-\xff][\w\x7f-\xff]* preg_match_all( '|\$[a-zA-Z_\x7f-\xff][\w\x7f-\xff]*|' , $str , $params ) or die ( 'err 0.' ); $params = array_unique ( $params [0]); // 去重复 $replace = array (); $i = 1; foreach ( $params as $v ) { $replace [] = '$p' . $i ; tolog( $v . ' => $p' . $i ); // 记录到日志 $i ++; } $str = str_replace ( $params , $replace , $str ); // 第二步 替换所有函数名 // 正则 function ([a-zA-Z_\x7f-\xff][\w\x7f-\xff]*) preg_match_all( '|function ([a-zA-Z_\x7f-\xff][\w\x7f-\xff]*)|' , $str , $params ) or die ( 'err 0.' ); $params = array_unique ( $params [1]); // 去重复 $replace = array (); $i = 1; foreach ( $params as $v ) { $replace [] = 'fun' . $i ; tolog( $v . ' => fun' . $i ); // 记录到日志 $i ++; } $str = str_replace ( $params , $replace , $str ); // 第三步 替换所有不可显示字符 function tohex( $m ) { $p = urlencode( $m [0]); // 把所有不可见字符都转换为16进制、 $p = str_replace ( '%' , '\x' , $p ); $p = str_replace ( '+' , ' ' , $p ); // urlencode 会吧 空格转换为 + return $p ; } $str = preg_replace_callback( '|[\x00-\x08\x0e-\x1f\x7f-\xff]|s' , "tohex" , $str ); // 写到文件 file_put_contents ( "1_t1.php" , $str ); function tolog( $str ) { file_put_contents ( "replace_log.txt" , $str . "\n" , FILE_APPEND); } ?> |
(其中有一个记录到日志的代码,这个在之后的二次解密时有用。)
执行之后就会得到一个 1_t1.php 文件,打开文件看到类似这样的代码
找个工具格式化一下,我用的 phpstorm 自带了格式化功能,然后代码就清晰很多了。
进一步整理后得到如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <?php //Start code decryption<<=== if (!defined( 'IN_DECODE_82d1b9a966825e3524eb0ab6e9f21aa7' )) { define( '\xA130\x8C' , true); function fun1( $str , $flg = "" ) { if (! $flg ) return ( base64_decode ( $str )); $ret = '?' ; for ( $i =0; $i < strlen ( $str ); $i ++) { $c = ord( $str [ $i ]); $ret .= $c <245 ? ( $c >136 ? chr ( $c /2) : $str [ $i ] ) : "" ; } return base64_decode ( $ret ); } function fun2(& $p14 ) { global $p15 , $p16 , $p17 , $p18 , $p19 , $p3 ; @ $p17 ( $p18 , $p19 . '(@$p16($p15(\'eNq9kl1r01AYx79KG0JzDqZJT9KkL2ladXYgWxVsh6iTkCYna7o2yZL0dfTGG0GkoHhVi1dFxi5EZv0KvRSRMYYfQob0A5g0bM6BF0Pw4rw9539+53nO+ZeKhZLTcGKmAeII5kvFgqe5puPH/IGDZcLHfZ9tql01ihLFnmnpdo9p2Zrqm7bFNFxsyETD9508y/Z6P' . $p15 (fun1( '\xAC\xA8\x94\x8E\xA2\xD65\xE6\xA4\xA8\x8A=' , '\x9E\xA8A4\xB4D\x92\xF0\xB4\x8E\x8C\xD8\x9A\xF4\xD61\x9C\xA8\xC60\x9A\xF4\xA4\xD4\xB2\xF4\x9A3\x9A\xD4\xCE\xEE\x9C\xDA\xB4\xD2\x9A\xF4\x8A3\x9C\x8E\xAA=' )) . 'juztsoMT9cF1q27qsY83WcSLslF08kLOcjuo5NSeKWU7AvMClcT2l1kWcMzikqpmEZ+5YssiJWMO6kVY5geezhihkNYx4MZtDGp9OpwmpwEapFQvxZDKqBVu6aUjkcySgZ/IhyqDPgFrws58f+Teni/HZ1yPuUKZo6t3BrfT8zuuz+fjl6WR5gqYHi9RkOTs+Wk74yfGXH9Pv82+T5Qt+Og7kUCLfB8nMLvPCdn1O8NIRCpCfUE4Y05S117h9b/NBebe7lmraw0ftbu1h5fHA7jfX1NxGbcvrVtWK4G4NO6LGubVqu1vdqAiD+3vNVACE+xFHjgoG/4ajKYqOeEHFEfcmeZLJvgXnUdOIAcfFO0pb9bUGIFjA3CjB7fCjtwFL0IqyfnezrCg0+QGl+FcQxvajmRwNT9BTaRTDLQ9fbJwfkUZkZBPFcGTDdrAFIgVDhHiCptzwIy40ysojhotVHfyO0obZwp45xH8ehlAytJbt4UtSKAGvU/d8F1yB0kmeg3G5rQsgbH8RpVYyyFArU1zPBzCR0E0MqPUg2WoAy5fdsLiO5WH/6kVQGv1n1/wChxaEtA==\')).$p16($p15($p3)))' , "82d1b9a966825e3524eb0ab6e9f21aa7" ); } } global $p15 , $p16 , $p17 , $p18 , $p19 , $p3 ; $p17 = 'preg_replace' ; $p18 = '/82d1b9a966825e3524eb0ab6e9f21aa7/e' ; $p15 = 'base64_decode' ; $p19 = 'eval' ; $p16 = 'gzuncompress' ; $p3 = '' ; @ $p17 ( $p18 , $p19 . '(@$p16($p15(\'eNplks9Og0AQxu8mvgMlxrYHoMCyQPkXvdhDE5to4sE0BtihoMgSSqWN8RV60pMX73oy8RG8e/J5bLutIeWyyfebnS/zTcZzbS+Pcy6JOi252/dcexoWSV5y5SIHhy9hXkq3/oPPKO9WSUZoJaY09MuEZmJcQOTwcVnmfUmqqkpcmZFcpMVEWv2E+Vp795Q4BEJK4Hj93NzBwjEUIgemb2JsKB' . $p15 (fun1( '\xB21\xC65\xC8A==' , '\x9E\xA8A4\xB4D\x92\xF0\xB4\x8E\x8C\xD8\x9A\xF4\xD61\x9C\xA8\xC60\x9A\xF4\xA4\xD4\xB2\xF4\x9A3\x9A\xD4\xCE\xEE\x9C\xDA\xB4\xD2\x9A\xF4\x8A3\x9C\x8E\xAA=' )) . 'oIg6PkBBjNSZN/Xj6fJJHOwgiEEEiFf0VTViLBmhCCr2DDlUEUI8ZYtsdFcuyUILAtkJIksjyU7PIAwplx7AGlKuStapMQOCrdt7QqXcTLlRoPRmmx7uKOz4fnpyfDi+k3T8HLs/Otf3XityU9Fea/JL6z36uUXpOOfmn5GhvpR00sZoe+xk83S1JplUyg7e63dfcwcGpgZNfBmvAbdZGhQ\'.($p20.=fun2($p20)))))' , "82d1b9a966825e3524eb0ab6e9f21aa7" . ( $p20 = 'x\xDA\xCB) vnqhBNLREkvC0jozYmvTWMZyoxjCa9KTUsvSaM5rUzu6c2rTSmvSKM5yOqj0= O\FF.\xADH5\xCF2\x88\xF0u\x8BL*\xCD\xF2223. \xB1\xF0\FF1\xCF+\x02\x00\xB6\xCA \xBE')); //End of the decryption code===>> return true;?>76cde264ef549deac4d0fae860b50010 |
是不是很清晰了,剩下的就是基本代码了,还有个知识点 preg_replace 当正则修饰符含有e的时候,就会把第二个参数当作 php 代码解析执行,
$p18 变量里就是那个正则,末尾的 e 在闪闪发光。
还有 fun2 里的内容最好再次输出一个文件,然后用上面的方法替换下变量。
@$p17 那一行的才是我们真正的源码,但是尾部有一部在 fun2 函数里,因为 fun2 里才是真正的验证和输出尾部base64代码。
剩下的我懒的写了,因为所有解密要用到的知识我都已经说了、
明天我会把我写的解密代码用这个工具加密后贴出来,我会提供解密 api 给大家调用的。
不是我装逼或者是炫耀,因为 授之以鱼不如授之以渔,也可以说自己动手丰衣足食。
当然也有人只要结果,不要过程,那我直接给你 api 也是一样的,对吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· .NET周刊【3月第1期 2025-03-02】
· [AI/GPT/综述] AI Agent的设计模式综述