我的编程空间,编程开发者的网络收藏夹
学习永远不晚

phpjiami加密原理详解及解密

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

phpjiami加密原理详解及解密

零、引言

最近工作中遇到一些使用phpjiami进行加密的php代码,所以对这个加密进行了详细的分析。
本文包括如下内容:

  1. phpjiami的加密原理
  2. 详细的phpjiami的解密方法
  3. 略带一些Php-parser使用方法

一、管中窥豹-了解phpjiami使用

phpjiami的官方网站为:https://www.phpjiami.com/phpjiami.html
使用phpjiami有几个关键的参数:

  1. 独立加密后,解密的代码会在原本的代码中。如果使用_lib库会生成一个单独的_lib.php,enc.php会通过include(’_lib.php’)进行解密,实际的解密代码和独立加密相同,后面不做单独分析。
  2. 控制参数,免费用户只能锁定ip、文件名和过期时间。
    在这里插入图片描述
    为了测试加密解密的效果创建一个包含类、函数的测试代码
function info($a,$b){    return $a.':'.$b;}class people{    protected $a;    protected $b;    public function __construct($a,$b)    {        $this->a = $a;        $this->b = $b;    }    public function info()    {        return $this->a.':'.$this->b;    }    public static function phpinfo()    {        phpinfo();    }}$name = $_GET['name'];$age = $_GET['age'];echo info($name,$age);$p = new people($name,$age);echo $p->info();people::phpinfo();

加密后代码如下,可以发现如下特点

  1. 函数名、变量名都被替换为了不可见字符,所有代码都缩到了一行,干扰正常分析。
  2. 代码中有3个函数,如果多加密几个文件会发现都是3个函数,因此3个函数就是解密代码运行的关键。
  3. 在代码?>后面还有一坨乱码,猜测保存了原始的加密代码。
    在这里插入图片描述

二、磨刀霍霍-Php-parser美化phpjiami代码

乱码太严重,而且格式不规范,是时候祭出神器PHP-Parser对代码美化一下。(百科:PHP Parser 是由 nikic 开发的一款 php 抽象语法树(AST)解析工具。PHP Parser 同时兼顾接口易用,结构简洁,工具链完善等诸多优点。在工程上,普遍使用 PHP Paser 生成模板代码,或使用其生成的抽象语法树进行静态分析,https://github.com/nikic/PHP-Parser),挖个坑之后有机会再详细研究研究怎么使用,在enphp mzphp2的解密中就需要大量使用。

  1. 安装PHP-Parser
安装PHP-Parser
  1. 使用PhpParser解析加密后的代码获取AST树
$code = file_get_contents('./test_enc.php');$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);try {    $ast = $parser->parse($code);} catch (Error $error) {    echo "Parse error: {$error->getMessage()}\n";    return;}
  1. 使用NodeFinder获取所有的函数,并将乱码函数名替换为func1,func2
$nodeFinder = new NodeFinder;$Funcs = $nodeFinder->findInstanceOf($ast, PhpParser\Node\Stmt\Function_::class);$map = [];$v = 0;foreach ($Funcs as $func) {    $funcname = $func->name->name;    if (!isset($map[$funcname])) {        if (!preg_match('/^[a-z0-9A-Z_]+$/', $funcname)) {            $code = str_replace($funcname, "func" . $v, $code);            $v++;            $map[$funcname] = $v;        }    }}
  1. 使用token_get_all获取php代码中的基本令牌,并将乱码变量名替换为v1,v2
//将乱码变量名,替换变量为$v1,$v2$v = 0;$map = [];$tokens = token_get_all($code);foreach ($tokens as $token) {    if ($token[0] === T_VARIABLE) {        if (!isset($map[$token[1]])) {            if (!preg_match('/^\$[a-zA-Z0-9_]+$/', $token[1])) {                $code = str_replace($token[1], '$v' . $v++, $code);                $map[$token[1]] = $v;            }        }    }}
  1. 美化格式并保存
//美化格式输出$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);try {    $ast = $parser->parse($code);} catch (Error $error) {    echo "Parse error: {$error->getMessage()}\n";    return;}$prettyPrinter = new PrettyPrinter\Standard;$prettyCode = $prettyPrinter->prettyPrintFile($ast);echo $prettyCode;file_put_contents('./test_enc_format.php', $prettyCode);

解密完成后,代码基本可读。
在这里插入图片描述
完整代码如下

use PhpParser\Error;use PhpParser\ParserFactory;use PhpParser\PrettyPrinter;use PhpParser\NodeFinder;require 'vendor/autoload.php';//1. 读取代码并解析$code = file_get_contents('./test_enc.php');$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);try {    $ast = $parser->parse($code);} catch (Error $error) {    echo "Parse error: {$error->getMessage()}\n";    return;}//将乱码函数名,替换函数为func1,fun2$nodeFinder = new NodeFinder;$Funcs = $nodeFinder->findInstanceOf($ast, PhpParser\Node\Stmt\Function_::class);$map = [];$v = 0;foreach ($Funcs as $func) {    $funcname = $func->name->name;    if (!isset($map[$funcname])) {        if (!preg_match('/^[a-z0-9A-Z_]+$/', $funcname)) {            $code = str_replace($funcname, "func" . $v, $code);            $v++;            $map[$funcname] = $v;        }    }}//将乱码变量名,替换变量为$v1,$v2$v = 0;$map = [];$tokens = token_get_all($code);foreach ($tokens as $token) {    if ($token[0] === T_VARIABLE) {        if (!isset($map[$token[1]])) {            if (!preg_match('/^\$[a-zA-Z0-9_]+$/', $token[1])) {                $code = str_replace($token[1], '$v' . $v++, $code);                $map[$token[1]] = $v;            }        }    }}//美化格式输出$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);try {    $ast = $parser->parse($code);} catch (Error $error) {    echo "Parse error: {$error->getMessage()}\n";    return;}$prettyPrinter = new PrettyPrinter\Standard;$prettyCode = $prettyPrinter->prettyPrintFile($ast);echo $prettyCode;file_put_contents('./test_enc_format.php', $prettyCode);

三、一探究竟-phpjiami加密原理

先给出整个加密代码的结构,后面再各个击破

function func0($v0)//反调试,解密代码function func1(&$v1, $v2)//全局函数名恢复function func2($v1, $v2 = '')//输入$v1需要解密的字符串,返回解密后的字符串if(!$v1){n个func1解密函数名并赋值全局变量}$v46=func0(_f_);//读取解密代码set_include_path(dirname('当前文件名'));$v90 = base64_encode($v46);//base64编码代码eval(func2('乱码字符串'));//真正执行的地方,乱码字符串解密后:eval(base64_decode($��ƻ��));//真正执行代码的地方,因为修改了变量名导致最终无法正常执行。set_include_path(dirname('当前文件名'));return null;?>加密压缩的代码+1个随机字符+32字节加密代码的md5值

phpjiami核心就是3个函数,每次加密3个函数的顺序会不一样,可以通过参数进行区分。

func2函数分析(解密函数)

func2函数输入两个参数,解密参数1得到对应的字符串。

  1. base64_decode解密需要用到的函数md5、ord、strlen、chr函数
  2. 计算特定不可见字符串的md5,用于后续异或解密
  3. 小于0xF5设置为 v1[ v1[ v1[i],大于0xF5设置为’’
  4. 异或解密字符串
    在这里插入图片描述
    手动实现类似的代码
function func2($v1, $v2 = ''){    //base64_decode解密使用到的函数,    $md5 = md5(pack("H*", 'EDE5E0E5ECEA'));    $v2 = !$v2 ? 0xf5 : $v2;    $i = 0;    $str = '';    for (; $i < strlen($v1);$i++) {        $str .= ord($v1[$i]) < 0xf5 ? ord($v1[$i]) > $v2 && ord($v1[$i]) < 0xF5 ? chr(ord($v1[$i]) / 2) : $v1[$i] : '';        //v2并未设置,因此小于0xF5设置为$v1[$i],大于0xF5设置为''    }    $str = base64_decode($str);    $i = 0;    $result = '';    $j = $md5_len = strlen($md5);    for(;$i<strlen($str);$i++)//循环和md5值进行异或    {        $j = $j?$j:$md5_len;        $j--;        $result .= $str[$i]^$md5[$j];    }    return $result;}

func1函数分析(全局函数名恢复)

func1通过str_rot13、gzuncompress、stripcslashes、func2对字符串进行解密,并赋值给传入的全局变量。
在这里插入图片描述

手动恢复代码**(ps:因为编码格式不同,直接将加密字符串复制出来会解密失败,这也是为什么在phpstorm里面修改了加密代码保存之后无法正常运行的原因)(pps:可以在010editor里面进行修改,或者phpstorm里面有什么地方进行设置,知道的大佬可以交流一下)**

function func1(&$v1,$v2){    $funcs = str_rot13(gzuncompress(stripcslashes(func2("一串不可见字符"))));    $arrays_func = explode(',',$funcs);    $v1 = $arrays_func[$v2];}

func0函数分析(核心函数)

func0主要用于反调试和最后文件解密。
在这里插入图片描述

反调试1—启动方式反调试:如果是cli启动,则退出程序。

php_sapi_name() == cli ? die():''

反调试2—服务端信息反调试:如果没有设置相关的服务器变量,则退出程序。

if (!isset($_SERVER['HTTP_HOST']) && !isset($_SERVER['SERVER_ADDR']) && !isset($_SERVER['REMOTE_ADDR'])) {    die();}

反调试3—时间反调试:两个语句运行时间超过100毫秒,则退出程序。

$time1 = microtime(true) * 1000;if (microtime(true) * 100 - $time1 > 100) {die();}

反调试4—文件完整性反调试:先读取最后44个字节并调用func2进行解密得到33个字节内容,再读取除了后44个字节的文件内容并计算md5,最后查看md5是非在前面解密内容中。

可以知道加密后文件结构=解密代码+加密压缩后的代码+1字节随机字节+32字节md5(加密代码)

!strpos(func2(substr($file,func2(pack('H*','54ee5947')),func2(pack('H*','\x54\xee\x4d\x3d')))),md5(substr($file,func2(pack('H*','55ce3d3d')),func2('H*','54ee5946'))))?$nothisfunc():$nothisvar;

反反调试最简单的方法就是将所有的反调试注释掉。

最后的代码:计算了需要解密的代码偏移,使用str_rot13、@gzuncompress、func2、substr解密得到最终的代码。
在这里插入图片描述

四、直捣黄龙-完整解密

通过前面的分析可以知道

加密后的文件=解密代码+加密压缩后的代码+1字节随机字节+32字节md5(加密代码)

只需要获取到加密压缩后的代码进行解密就好了(ps:func2中用于计算md5值的不可见字符会变化,需要手动获取)

function func2($v1, $v2 = ''){    //base64_decode解密使用到的函数,    $md5 = md5(pack("H*", 'EDE5E0E5ECEA'));    $v2 = !$v2 ? 0xf5 : $v2;    $i = 0;    $str = '';    for (; $i < strlen($v1);$i++) {        $str .= ord($v1[$i]) < 0xf5 ? ord($v1[$i]) > $v2 && ord($v1[$i]) < 0xF5 ? chr(ord($v1[$i]) / 2) : $v1[$i] : '';        //v2并未设置,因此小于0xF5设置为$v1[$i],大于0xF5设置为''    }    $str = base64_decode($str);    $i = 0;    $result = '';    $j = $md5_len = strlen($md5);    for(;$i<strlen($str);$i++)//循环和md5值进行异或    {        $j = $j?$j:$md5_len;        $j--;        $result .= $str[$i]^$md5[$j];    }    return $result;}$file = file_get_contents('test_enc.php');$enc_code = explode('?>',$file);//try {    $dec_code = str_rot13(@gzuncompress(func2(substr($enc_code[1], 0, -44))));//解密代码    print_r($dec_code);    file_put_contents('test_dec.php',$dec_code);}catch (Error $error){    echo "Parse error: {$error->getMessage()}\n";    return;}

成功解密
在这里插入图片描述

五、总结

phpjiami有点像最早的android加固的感觉。其实获取到的代码还使用了enphp、mzphp2进行了加密,和phpjiami也有点类似,挖个坑后续有空补上解密过程。

参考:

  1. 《PHP解密:zym加密 带乱码调试过程 》https://www.52pojie.cn/thread-693641-1-1.html
  2. 《初探PHP-Parser和PHP代码混淆》https://www.redteaming.top/2020/05/07/%E5%88%9D%E6%8E%A2PHP-Parser%E5%92%8CPHP%E4%BB%A3%E7%A0%81%E6%B7%B7%E6%B7%86/
  3. 《PHPJiaMi 免扩展加密分析及解密》

来源地址:https://blog.csdn.net/abel_big_xu/article/details/127827902

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

phpjiami加密原理详解及解密

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

HTTPS 的加解密原理

这篇文章主要介绍“HTTPS 的加解密原理”,在日常操作中,相信很多人在HTTPS 的加解密原理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”HTTPS 的加解密原理”的疑惑有所帮助!接下来,请跟着小编一起来
2023-06-17

数据加密和解密原理以及实现方法

  随着Internet的普及,大量的数据、文件在Internet传送,因此在客观上就需要一种强有力的安全措施来保护机密数据不被窃取或篡改。不管是安全手段或是安全措施,它们都需要加密算法和相应的解密算法,不了解与此相关的加密原理和算法,就很难深刻认识到各种安全传输协议,以及实现网络安全所采用的数字凭证、数字签名等技术,
数据加密和解密原理以及实现方法
2024-04-18

Android 加密解密字符串详解

加密和解密的字符串: 代码如下:package eoe.demo; import java.security.SecureRandom; import javax.crypto.Cipher; import javax.crypto.Key
2022-06-06

Android 安全加密:对称加密详解

Android安全加密专题文章索引Android安全加密:对称加密Android安全加密:非对称加密Android安全加密:消息摘要Message DigestAndroid安全加密:数字签名和数字证书Android安全加密:Https编程
2022-06-06

Android数据加密之Des加密详解

Android DES加密的相关实现,简单的实现了一下,今天来总结一下:DES加密介绍: DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。DES加密算法出自IBM的研究, 后来被美国政府正式采用,之后开始广泛流传
2022-06-06

详解RSA加密算法的原理与Java实现

这篇文章主要和大家分享非对称加密中的一种算法,那就是RSA加密算法。本文介绍了RSA算法的原理与Java实现,感兴趣的小伙伴可以尝试一下
2022-11-13

详解DES加密算法的原理与Java实现

DES加密,是对称加密。对称加密,顾名思义,加密和解密的运算全都是使用的同样的秘钥。这篇文章主要为大家讲讲DES加密算法的原理与Java实现,需要的可以参考一下
2022-11-13

详解ASP.NET中加密和解密的方法

本文详细讲解了ASP.NET中加密和解密的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2022-11-13

PHP加密函数与解密函数详解

这篇文章主要为大家详细介绍了PHP中的加密函数与解密函数的相关资料,文中的示例代码讲解详细,对我们学习了解PHP有一定的帮助,需要的可以参考一下
2022-11-13

详解PHPlaravel中的加密与解密函数

Laravel为我们提供了完整的加密方法及加密模式。这篇文章主要带大家具体看下laravel为我们提供的加密及解密方法,感兴趣的小伙伴可以了解一下
2022-11-13

详解C#如何加密解密RAR文件

这篇文章主要为大家详细介绍了C#如何实现加密解密RAR文件的功能,文中的示例代码讲解详细,对我们学习C#有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
2022-12-31

Android 安全加密:非对称加密详解

Android安全加密专题文章索引Android安全加密:对称加密Android安全加密:非对称加密Android安全加密:消息摘要Message DigestAndroid安全加密:数字签名和数字证书Android安全加密:Https编程
2022-06-06

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录