/* 时间:2022-1-9? 作者:aweii 内容:关于"给PHP源代码加密"的代码分析[原创] */ 网上看到一则"给PHP源代码加密"的代码,饶有兴趣研究了下(https://www.jb51.net/article/134506.htm)。代码如下:?? ??? ??? ?
<?php
??
?function RandAbc($length = "") { // 返回随机字符串?
? $str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";?
? return str_shuffle($str);?
?}?
??
?$filename = 'index.php'; //要加密的文件?
?$T_k1 = RandAbc(); //随机密匙1?
?$T_k2 = RandAbc(); //随机密匙2?
?$vstr = file_get_contents($filename);?
?$v1 = base64_encode($vstr);?
?$c = strtr($v1, $T_k1, $T_k2); //根据密匙替换对应字符。?
?$c = $T_k1.$T_k2.$c;?
?$q1 = "O00O0O";?
?$q2 = "O0O000";?
?$q3 = "O0OO00";?
?$q4 = "OO0O00";?
?$q5 = "OO0000";?
?$q6 = "O00OO0";?
?$s = '$'.$q6.'=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");$'.$q1.'=$'.$q6.'{3}.$'.$q6.'{6}.$'.$q6.'{33}.$'.$q6.'{30};$'.$q3.'=$'.$q6.'{33}.$'.$q6.'{10}.$'.$q6.'{24}.$'.$q6.'{10}.$'.$q6.'{24};$'.$q4.'=$'.$q3.'{0}.$'.$q6.'{18}.$'.$q6.'{3}.$'.$q3.'{0}.$'.$q3.'{1}.$'.$q6.'{24};$'.$q5.'=$'.$q6.'{7}.$'.$q6.'{13};$'.$q1.'.=$'.$q6.'{22}.$'.$q6.'{36}.$'.$q6.'{29}.$'.$q6.'{26}.$'.$q6.'{30}.$'.$q6.'{32}.$'.$q6.'{35}.$'.$q6.'{26}.$'.$q6.'{30};eval($'.$q1.'("'.base64_encode('$'.$q2.'="'.$c.'";eval(\'?>\'.$'.$q1.'($'.$q3.'($'.$q4.'($'.$q2.',$'.$q5.'*2),$'.$q4.'($'.$q2.',$'.$q5.',$'.$q5.'),$'.$q4.'($'.$q2.',0,$'.$q5.'))));').'"));'; ?
??
?$s = '<?php '."\n".$s."\n".' ?>';?
?//echo $s;?
?// 生成 加密后的PHP文件?
?$fpp1 = fopen('temp_'.$filename, 'w');?
?fwrite($fpp1, $s) or die('写文件错误');?
??
??>?
以上代码极尽代码加密、混淆之能事,目的只有一个,让阅读者云里雾里,从而无法窥见真实的源码。但其实,对php程序员而言,根据上述算法, 是可以还原出源码的,就是稍费些功夫而已。下面,就一步步分析还原上述代码的逻辑。 $filename中存放源码文件名,'temp_'.$filename是目标文件名存放加密后的代码。首先生成$T_k1、$T_k2两个随机密钥, 源码读入变量$vstr中,对源码先进行base64_encode编码,然后用密钥做加密后放入$c变量(简单的凯撒密码,就是用密码本做字符替换的那种,不过这个密码本是随机生成的而已)。最后的$c还要在首部把两个密钥加上,后续运行时解密要用到。 $q1~$6存放6个临时变量名,这在加密文件运行过程中使用。最后把解密代码、加密字符串$c合成处理后(存放于临时变量$s中)放入目标文件。 那么奥秘主要在于$s中的内容及运行时的解密步骤了。 ? 下面是$s的内容,是不是看着眼花,莫急,待我慢慢道来。?? ??? ??? ?
$s = '$'.$q6.'=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");$'.$q1.'=$'.$q6.'{3}.$'.$q6.'{6}.$'.$q6.'{33}.$'.$q6.'{30};$'.$q3.'=$'.$q6.'{33}.$'.$q6.'{10}.$'.$q6.'{24}.$'.$q6.'{10}.$'.$q6.'{24};$'.$q4.'=$'.$q3.'{0}.$'.$q6.'{18}.$'.$q6.'{3}.$'.$q3.'{0}.$'.$q3.'{1}.$'.$q6.'{24};$'.$q5.'=$'.$q6.'{7}.$'.$q6.'{13};$'.$q1.'.=$'.$q6.'{22}.$'.$q6.'{36}.$'.$q6.'{29}.$'.$q6.'{26}.$'.$q6.'{30}.$'.$q6.'{32}.$'.$q6.'{35}.$'.$q6.'{26}.$'.$q6.'{30};eval($'.$q1.'("'.base64_encode('$'.$q2.'="'.$c.'";eval(\'?>\'.$'.$q1.'($'.$q3.'($'.$q4.'($'.$q2.',$'.$q5.'*2),$'.$q4.'($'.$q2.',$'.$q5.',$'.$q5.'),$'.$q4.'($'.$q2.',0,$'.$q5.'))));').'"));';?? ?
首先,echo $s; 看看到底最后是什么东东。原始代码都在一行,为便于阅读,我加了回车。
以第一个eval为界可分两部分来看,前半部分代入变量值为:
$O00OO0=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
$O00O0O=$O00OO0{3}.$O00OO0{6}.$O00OO0{33}.$O00OO0{30};
$O0OO00=$O00OO0{33}.$O00OO0{10}.$O00OO0{24}.$O00OO0{10}.$O00OO0{24};
$OO0O00=$O0OO00{0}.$O00OO0{18}.$O00OO0{3}.$O0OO00{0}.$O0OO00{1}.$O00OO0{24};
$OO0000=$O00OO0{7}.$O00OO0{13};
$O00O0O.=$O00OO0{22}.$O00OO0{36}.$O00OO0{29}.$O00OO0{26}.$O00OO0{30}.$O00OO0{32}.$O00OO0{35}.$O00OO0{26}.$O00OO0{30};
后半部分为:
'eval($'.$q1.'("'.base64_encode('$'.$q2.'="'.$c.'";eval(\'?>\'.$'.$q1.'($'.$q3.'($'.$q4.'($'.$q2.',$'.$q5.'*2),$'.$q4.'($'.$q2.',$'.$q5.',$'.$q5.'),$'.$q4.'($'.$q2.',0,$'.$q5.'))));').'"))';
变量代入后($c是加密的代码,没做替换)得到
eval($O00O0O(base64_encode('$O0O000="'.$c.'";eval(\'?>\'$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000))));')));
上面代码依然不直观,通过echo 可以进一步得到各变量的值,本质上是下面的结果:
$O00OO0="n1zb/ma5\vt0i28-pxuqy*6lrkdg9_ehcswo4+f37j";
$O00O0O="base";
$O0OO00="strtr";
$OO0O00="substr";
$OO0000="52";
$O00O0O.="64_decode"; //$O00O0O="base64_decode";
所以后半部分为:化为:
eval(base64_decode(
base64_encode('$O0O000="'.$c.'";
?? ??? ??? ??? ?eval(\'?>\'.base64_decode(
?? ??? ??? ??? ??? ??? ??? ?strtr(
?? ??? ??? ??? ??? ??? ??? ??? ??? ?substr($O0O000,52*2), ?//去掉$T_k1.$T_k2后的$c
?? ??? ??? ??? ??? ??? ??? ??? ??? ?substr($O0O000,52,52), //$T_k2
?? ??? ??? ??? ??? ??? ??? ??? ??? ?substr($O0O000,0,52) //$T_k1
?? ??? ??? ??? ??? ??? ??? ??? ?)
?? ??? ??? ??? ??? ??? ??? ?)
?? ??? ??? ? ? ??? ?);'
?? ??? ??? ? )
? ? ? ? ? ? ? ? ?)
?? ?);?? ?
首先,$O0O000赋值为加密代码$c,然后再执行内嵌的eval,上述代码等价于 eval('eval(\'?>\'.base64_decode( strtr(substr(加密代码串,52*2),substr(加密代码串,52,52),substr(加密代码串,0,52)) );'); 这相当于在php环境中运行 eval('?>'.base64_decode(strtr(substr($c,52*2),substr($c,52,52),substr($c,0,52))));//$c代表加密代码串
注意,外层eval负责base64_decode、strtr、substr函数的执行(解密、解码过程)以及执行内嵌eval函数, 内嵌eval执行的是解密、解码后的原始代码。这里边引号的使用极见技巧,决定着代码是由外层eval还是内层eval执行。
strtr(……)这部分是上述加密的逆过程,因为是字符还原过程,所以两个密钥参数$T_k1,$T_k2调换了位置,解密后再用base64_decode解码 就得到了源代码。用'?>'和解密解码后的源代码串连接是因为源代码都是<?php开始的,所以要先结束上段php代码,再开始另一段php代码, 如果不这么处理,运行时会出现"eval()’d code"错误。
以下为补充: 其中base64_decode(strtr(substr($c,52*2),substr($c,52,52),substr($c,0,52)))是上述加密的逆过程(解密),再回顾下上述加密过程: ?
$v1 = base64_encode($vstr);?
?$c = strtr($v1, $T_k1, $T_k2); //根据密匙替换对应字符。?
?$c = $T_k1.$T_k2.$c;?
所以最后就是 eval('?>'.你的原始代码); 比如你的代码:
<?php
echo "Hello world!\n";
?>
运行加密后,再运行加密的文件,进行上述解密转换,最后运行的代码为: ?? ?
eval('?>'."<?php
echo "Hello world!\n";
?>");
|