MENU

PHPJiaMi 加密分析及手工解密过程

• December 2, 2017 • Read: 3135 • 瞎折腾,PHP

解密准备

首先我们来了解一下PHPJiami原理:

加密流程:源码 -> 加密处理(压缩,替换,BASE64,转义)-> 安全处理(验证文件 MD5 值,限制 IP、限域名、限时间、防破解、防命令行调试)-> 加密程序成品,再简单的说:源码 + 加密外壳 == 加密程序

这里做演示,我写了 phpinfo() 然后去
http://www.phpjiami.com/ 生成加密文件,打开之后,果然都是一片乱码。
使用代码修复工具 http://zhaoyuanma.com/phpcodefix.html 将 ascii 不可见字符的变量修复成正常的变量名,再 PHP 代码美化,方便下一步分析。

0x02 函数分析

代码内有三个函数,由于每次加密这三个函数的顺序都不一样,这个以传参方式区分这三个函数
fun1 = ($var1, $var2 = '') = 核心函数,将乱码转成正常字符串
fun2 = (&$var1, $var2) = 校验 IP、域名,防止被破解。最后一句是解密整个 php 文件
fun3 = ($var1) = 将需要用到的函数赋值给 N 个全局变量

先从 fun1 开始逆起,在编辑器中双击变量名,该变量高亮之后,可以看到它怎么变化,在哪里被使用。
一句句语句逆下去,发现有语法错误,其实是代码修复后的 bug,用 winhex 打开定位到这句代码,发现是三元运算符

$var2 = !$var2 ? ord('乱码') : $var2;

接下来是一句很奇怪很无用的代码,再下一句是 for 循环,我猜测是给 $i 赋值

for($i=0; $i<strlen($var1); $i++)

下个 for 循环里又是一个三元运算符,手动修复后,基本 fun1 的代码就出来。
接下来就是运行 fun1 函数,但是碰到个坑点,fun1 有很多处用到乱码做运算,而乱码不能直接拷到编辑器中。
用 winhex 将 16 进制的乱码字符复制出来,在运算的时候 pack("H*","乱码") 将它还原回乱码即可。

function fun1($var1, $var2 = '')
{
    $md5 = md5(pack("H*",'FBE3FCFAF9E0'));//乱码随机字符串1
    $var2 = !$var2?ord(pack("H*",'8C')):$var2;//乱码随机字符串2
    
    $str = '';
    for($i=0; $i<strlen($var1); $i++)
    {
        $str .= ord($var1{$i}) < ord(pack("H*",'F5')) ? ((ord($var1{$i}) > $var2 && ord($var1{$i}) < ord(pack("H*",'F5'))) ? chr(ord($var1{$i}) / 2) : $var1{$i}) : '';
    }
    $de1 =  base64_decode($str);
    $len = $len2 = strlen($md5);
    $str2 = '';
    for($i=0; $i<strlen($de1); $i++)
    {
        $len = $len ? $len : $len2;
        $len--;
        $str2 .= $de1[$i] ^ $md5[$len];
    }
    return $str2;
}

接着开始还原 fun2 代码,fun2 中前面都调用了 fun1 解密字符串,解密可得到 fun2 后面需要用到的函数名。有了 fun1,后面解密都非常顺利

function fun2(&$var1, $var2)
{
    $de = str_rot13(strrev(gzuncompress(stripslashes(fun1(pack('H*','8ECA349A37A639E43946ACE4B242F4EED8E8A0CC4444E639E894C2C69CB0384134EEEEC6CA3233B433ECD89CC6D435A437CE98B0D2A092909E96D030EE8EA2A4D044CADCA2DC32CCE02BAADCEEEA4537D8ACB43298F238E0428EC29646A0CAA2EECA43D2B2C442F4C4358E46429434AE44B0DACAF0AE4190C845EE32AE34C82BC49494E22BCAA49CD6D2E8CA94D2D4A6329C929A3596F2CC36CCD6CCAAF0C646D0A69EC8F02FA2A03938D234C2D2E0DCCCCAC4A8A631AC4238C4A490ECD4CCF0DAF4CAB2'))))));
    $exp = explode(',', $de);
    $var1 = $exp[$var2];
}

$de 解出来是一堆函数名,然后赋值给全局变量,后面解密都需要用到。fun2 解出来是固定的字符串

,chr,addslashes,rand,gzuncompress,assert_options,assert,file_exists,file_get_contents,substr,unpack,constant,strpos,create_function,str_rot13,md5,set_include_path,dirname,preg_replace,base64_encode,base64_decode,

接着暂且先不看 fun3,回到主代码中。
2265835617.png
这里创建了一堆全局变量,通过 fun2 赋值,每个变量都代表一个函数名
1848056089.png
接着还原 fun3 函数,步骤一样。

function fun3()
{
    php_sapi_name() == 'cli' ? die():'';
    $file = file_get_contents(__FILE__);
    if(!isset($_SERVER['HTTP_HOST']) && !isset($_SERVER['SERVER_ADDR']) && !isset($_SERVER['REMOTE_ADDR']))
    {
        die();
    }
    $time = microtime(true) * 1000;
    if(microtime(true) * 1000 - $time > 100)
    {
        die();
    }
    if(strpos(__FILE__, gtmclaei) !== 0){$exitfunc();}
    !strpos(de1(substr($file, de1('A8414145'), de1('A841AA3D'))), md5(substr($file, de1('AAA23D3D'), de1('A8414190')))) ? unkonw1() : unkonw2();
    $loc1 = fun1('A841AA45ACEE3D3D');
    $loc1 = fun1('A8414190');
    $de = str_rot13(gzuncompress(fun1(substr($file, $loc1, $loc2))));//核心解密
    return $de;
}

后面的代码已经不用再看了,fun2 解出来的就是解密后的原代码。
3757017134.png

最后

附上自动化脚本,下载地址:

此处内容需要评论回复后方可阅读。

Tags: None
Archives QR Code
QR Code for this page
Tipping QR Code
Leave a Comment

已有 59 条评论
  1. 不错啊!

  2. wady wady

    方式发顺丰

  3. 現在還可不可以使用?

  4. 唏噓一世 唏噓一世

    現在還可不可以使用?

  5. PHP PHP

    解密试下

  6. 学习下 不错的哈 多谢分享

  7. uglyer uglyer

    学习学习

  8. 小小班 小小班

    这个加密搞的眼花缭乱

  9. 小白 小白

    来学习一下

  10. 学习学习