phpjm混淆解密浅谈
字数 814 2025-08-07 08:22:39

PHPJM混淆解密技术详解

0x00 前言

PHPJM是一种常见的PHP代码混淆工具,通过对变量名、函数名进行随机化处理,并在代码中插入大量无意义的字符和操作来增加代码分析的难度。本文将全面介绍PHPJM混淆的解密技术,包括手动解混淆、调试解混淆和自动化脚本解混淆三种方法。

0x01 PHPJM混淆特征分析

PHPJM混淆后的代码通常具有以下特征:

  1. 变量名被替换为随机字符串,如$O00OO0$O00O0O
  2. 使用字符串拼接方式构造关键函数名,如$O00O0O=$O00OO0{3}.$O00OO0{6}...
  3. 最终通过eval()函数执行动态生成的代码
  4. 代码中包含大量无意义的字符和操作

0x02 手动解混淆方法

手动解混淆是最基础的方法,适用于简单的混淆代码:

  1. 替换eval为echo:将eval()替换为echo可以直接输出动态生成的代码
  2. 逐层解密:将输出的代码替换原eval语句,重复这个过程直到获得清晰代码
  3. 执行流程
    • 修改eval()echo
    • 执行PHP文件
    • 复制输出结果替换原eval语句
    • 重复上述步骤直到代码完全清晰

0x03 调试解混淆方法

使用调试工具可以更高效地解混淆:

工具准备

  • VSCode + Xdebug + PHP Debug插件

调试步骤

  1. 格式化混淆代码
  2. 在关键位置设置断点
  3. 使用"Launch currently open script"模式启动调试
  4. 按F11进行单步调试
  5. 观察变量赋值过程
  6. 跟踪到最终执行的清晰代码

0x04 自动化脚本解混淆

对于复杂的混淆代码,可以编写自动化解密脚本:

脚本设计思路

  1. 识别PHP代码块
  2. 循环处理每个代码块:
    • 替换evalecho
    • 执行PHP代码并捕获输出
    • 用输出替换原eval语句
  3. 使用正则判断是否完成解密

关键正则表达式

# 识别混淆变量
r'(\$[a-zA-Z0-9]+{[0-9]\d{0,1}})'

# 识别eval语句
r'(eval$.*?$;)'

完整Python脚本

import shutil
import os
import re
import sys

def decode(fileName):
    tempFile = "temp.php"
    originContent = open(fileName,'r').read()
    dataList = re.findall('(\<\?php.*?\>)',originContent.replace('\n', ' ').replace('\r', ' '))
    fileResult = ""
    for data in dataList:
        flag = 0
        while(1):
            Content = open(fileName,'r').read()
            if(flag == 0):
                Content = data
                flag = 1
            if len(Content) <= 10:
                Content = data
            if 'eval' in Content:
                tempContent = Content.replace("eval","echo")
                open(fileName,'w').write(tempContent)
                os.system("php {fileName} > {tempFile}".format(fileName=fileName,tempFile=tempFile))
                shutil.copyfile(tempFile, fileName)
            else:
                try:
                    result = re.findall('(eval$.*?$;)',data)[0]
                    result = data.replace(result,"echo('<?php ');"+Content)
                    open(fileName,'w').write(result)
                    shutil.copyfile(fileName, tempFile)
                    os.system("php {tempFile} > {fileName}".format(tempFile=tempFile,fileName=fileName))
                    os.unlink(tempFile)
                    break
                except:
                    open(fileName,'w').write(data)
                    shutil.copyfile(fileName, tempFile)
                    os.system("php {tempFile} > {fileName}".format(tempFile=tempFile,fileName=fileName))
                    os.unlink(tempFile)
                    break
        fileContent = open(fileName,'r').read()
        fileResult += fileContent
    open(fileName,'w').write(fileResult)

def main():
    originFileName = sys.argv[1]
    TempFileName = originFileName.split('.')[0]
    fileName = TempFileName+".de.php"
    shutil.copyfile(originFileName, fileName)
    while(1):
        result = open(fileName,'r').read()
        flag = re.findall(r'(\$[a-zA-Z0-9]+{[0-9]\d{0,1}})',result)
        if flag:
            decode(fileName)
        else:
            print("Decryption complete! save as {0}.de.php".format(TempFileName))
            break

if __name__ == '__main__':
    main()

0x05 实战案例解析

案例1:基础混淆

<?php 
$O00OO0=urldecode("n1zb/ma5\vt0i28-pxuqy*6lrkdg9_ehcswo4+f37j");
$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($O00O0O("JE8wTzAwMD0iZ0pqUU5IUkx5RGJoU0luTXF0R29LbHB3eG16QlhUdk9rc2VpYWZQWmRyY0FWVUNFRnVZV2VtWmtpbkVhVXh5c0FkcVdMSXZ1T0hnVEpOekdvYmZjU2p3aHB0ckJSRE1QUVZYWUtGQ2xyeDlUcG5QaVhONXN5bFF6TXZLWkJBR1p5M21Ib3ZKZ0NaamVDMkpzTTNXZUV2ZGV3VUdUTU5IMkNvRUhkWEV6Qm9tMkJvZDdkbkdVcG9Cc1J2VmVtbkdVQmJqZU1ubWdSTkswQkFHelJ2SzBwbFdlbXZIRk0zRXN5TmlIY1VHVFJsbWpwbFdlTTNFc1J2SFpkdkIxeU5pMHBsOUZkdlJIUllIRk0zRXN5TmlIT1hIN2R2SE5PdlFJTW5FNU9uaUh5dkM2Y2hFZ3lxaTBDbDVaQkFTZ3dVR3pCbEpOY1p1U3BsNXpSdktGQzJWOXlOUTNkbmlIeXZDdU9iamV0QUdVQm9FMU1ONGVNMlFqQlp1Nm12SEZNM0VzeU5pSGNVRzlkbkdVcG9Cc1J2VmVCcVFGQzNFZ3kyNGVvMTlaeXY5RkJBZWd3MzBlTW5tZ1JOSzBCQUdOUmw1WlJ2SGZ5aEd0bzJpZnlxaTBNcVFaUlhlZ2RuamVSbm01ZG5qZW1uRXVwb1dlYWI0ZU0yUVVSTlFVZHgwZXlOUTNkS0prRVk4dW0yMTVNM0tqY05zZk0zazltVVBGZFlpZnlOQmdCenU2QjJRME9YUlNDaDV1eTNpMG1VU2VhaFBxYzNHZk1xazltVVBGZFlpZnlOQmdCenU2QjJRME9YUlNDaDVUeTNtMG1VU2VhaFBxYzJFaHlOS0lCYjBxZFg0ZWsyOUZCTkhxY1pncUJva3VtMkVoYU41c3lsVnFPQVRlazI5RkJOSHFjWmdxQm9rdW0yRWhhcVF6Qm9kcU9BVGVrMjlGQk5IcWNaZ3FCb2t1bTJFaGFxRzNtVVNnY1VQU1J2c2dNVVBJcmhHekJvbTJCb2RlYWI0ZU0yUTBrb0UwTU5IaFJvRUhPS0prRVk4NmNTS1ZRS210RVFtQWJWOVlFQVRlb0tHWWJ6dTZFUW1BYlY5WUVROUtsWWlLVktFbWIwNGdjVVBTUnZzZ01VUElyaEd6Qm9tMkJvZGVhYjRlQm9zSENVZWhNMlEwZHY1c3lsUXpkblEwQlplaE9iamVtbkV1cG9XZWFiNGVNbm1IZHgwZWsyOUZCTkhxY1pncUJva3VtMkVoYXFFc0NOSkhNbm1IbVVTN2RuMGVDMkswQzJldW9LR1liMFE0QzJRVFJ2SGZ5aFBTQkFTZXdVR0h3dkgwT1hFSGRYMCtkdlJIUlkxSE0zaXNCMlZ1T0FTN2RuMGV0QUdUUmxtanBsV2VCcVFGQzNFZ3kyNGVNM0tqT1hFSlJsUVV3QVNld1VHME1xU2V3VVBTYmw5U0JsVGVyQVBTUnZzZ01VUElyaEd6Qm9tMkJvZGVhYjRlTW5tSE12S1VCQWVTTW9RSE1xU2djVVBTYmw5U0JsVGVhYjRlQm9zSEMzUTBCQWVnY1VQU3lROVNDb0VzZHgwZW1ZMWZCdlFqZFgwK2R2QkhSdml1a2xKak9LSmtFWTg2Y1NCS1FZaWRvMEtiVjA5eE9iamVNTlEwUm9tRmRYRUlvMkVzUnZZN2RuMGVDMkswQzJldW9LR1liMFE0QzJRVFJ2SGZ5aFBTQkFTZXdVR0h3dkgwT1hFSGRYMCtkdlJIUlkxSE0zaXNCMlZ1T0FTN2RuMGV0QUdUUmxtanBsV2VCcVFGQzNFZ3kyNGVwbDV6Qm9tME9YRTBDbG1qQkFUZW12S1VNTks1YVhFZ00xOWpDb2kwQWw1ekJvbTBBbGs5RVNLV1YwVmdkbmplUm5tNWRuamVtdkhGUnY4ZXJBUGhkWmplbW5Cc3lYUDlkdktVTU5LNU9YUzdkWEVneXFpSE1xRXR5cVFJZHgwZVd4amVtdmlVQmxLMEJROUlCb0V1eTJrZXJBUHFtemplQk45VUJsS1pwWFB1bXZLVU1OSzVkdkt6ZFhFREJvU2VyYjRlbW5Cc3luUUhPQUc3ZFhFZ3lxRWZkWDQ5ZFhtN212SUh3bzBqZFpqZW1uQnN5S0lSZHgwZW1uQnN5blFIY1VQU3BsNXpCb20wbzI1MXlBakRjVUc5ZHZCZk1oUHVtdlNlckFQVGNVUFNwQVA4ZFhFZ3lxaUhNcUV0eXFRSWNVUFNwQWpET0FHN2RYRVpNTlFzUnZRdHlsUTBwdjlTZFg0OWRYTS9hWE03ZG4wZW12aVVCbEswQlE5SUJvRXV5MmtlckFHVVJubWd5QWVTQzNtSENvRUhvMjFIUnZzZkJYVGVkaFRoT2JqZW12SEZSdjhlckFHVVJubWd5QWVTcGw1MHlVVGVkaFRoT2JqZW1ZMWZCdlFqZHgwZW1uRXVwb1dlYWI0ZU0yUVVSTlFVZFgwK2RuR1VCb0dzTU5WdWROSEZNMlFVUlhHZ3lxRWZkbmpTUnZzZ01VUElyaEdUTU5ROXdVRTBDbG1qQm8wZU9ualNwbDUweTMwZ2RuQnN5blFITVVQdXdVRVpNTlFzUnZRdHlsUTBwdjlTdEFTaE9iamVtdlE0QkFQOWRYRWl5MkVIeVhQSXJoR0h3dlFaUm9FSE9YRTJDbFRnY1VHZ0JoUHVkQUVnTTE5akNvaTBBbDV6Qm9tMEFsa2dkbmplTU5RMFJvbUZkWEVId3ZWN2RuMGVCbEp6QkFHN2RYRUlCb0V1eTJFdHBsa2VyQVBTUnZzZ01VUElyaEd6Qm9tMkJvZGVhYjRleXZLelJZSEZNMlFVUllIU09YUzdkbm1IUm5RVXloUFN5bFEwcHY5U28ySFNjVUc5ZG4wZUMySzBDMmVlT0tKa0VZOUt3dmlITW5FZ3kyNGVtdlZnZG5qZUJvc2dSWGVTQkFQSXJoR3FCb0VpQm9pekNsUkhPWFNnY1VHOWRuMGVNblFoeXZIWmR2QjF5TmkwcGw5RmRuaUh5dlFaUlhlU1J2S2h5dlZqbW5SdUJvbUhkeDBlbVVNamRYRUx5MkhGZHgwZW1VTWpkWEVTQm9pWmR4MGVtVU1qZFhFanBsMWdSWFA5ZFhNcWFYRU5wbFFqQlhQOWRYTXFPb2plUm5tNWRuamVtdkhOUjJzSE1OVmVyQVBxbXpqZW12OVVCdlFVZHgwZW1VTTdkWEVTQm9pWm8ySmd5bEgwZHgwZW1VTTdkdkhOZFhlc2R2UUlNbkU1T1hFM3B2UVVCQVNnZG5qZW12SE5SMnNITU5WZXJBUGhSMnNITU5WZXdVRTNwdlFVQm8waGNVRzlkdkhOZFhlc2R2UUlNbkU1T1hFU0JvaVpPQVNld1VQU3kzbVNCb2RlckFQaHkzbVNCb2RlQ3FTZXdVRVNCb2ladEFHU0JvaVpkWmpldEFHZ0JoUHVkQUdIeW9HMHdBZVN5dkhJcG9rZ09BRzdkWEVTQm9pWm8ySmd5bEgwZHgwZWROSmd5bEgwZG5qU3l2SElwb0U5ZFpqZXRBR0h5b0cwd0FlU0JOSEh5dmtnZHg4ZW12QmdCbEpTZHgwZWRodWhkeHVlRVNLV1YwVjdkWEV6TWxUZXJBUGhWMFFXRVZpVmRualNCTkhIeXZFOWRZQkFiMDBld1VFMHB2SHpkWDArZG5HVUJvMTdtbkVzQ05KSHRBRzdtdmdmcGw1OWRualNwbEIzcHZRVUJvMGV3VUVmTU5FSE1xMGV3VUVTQm9pWm8ySmd5bEgwdEFkN2RYRXpNbFRlckFHelJubXRNTlFUeXZLWkJBZXFNbm1Ib1VNam1uRXVwb1dlYWI0ZU1ubUhhWFBTTTNLak9iamVtWTFmQnZRamR4MGVtbkV1cG9XSXJxaUhNcUJITWgwK01ubUhNdktVQkFlU00zS2pPYmplbVkxZkJ2UWphYjVId3ZRWlJvRUhPWFM3ZFhFSW8yRXNSdlllckFQU2JsOVNCbFRJck5CSFJ2aXVrbEpqT0tKa0VZODZjU0JLUVlpZG8wS2JWMDl4T2JqZU1OUTBSb21GZFhFSW8yRXNSdlk3ZG4wZUMySzBDMmVlT0tKa0VZOUt3dmlITW5FZ3kyNGVtdlZnZG5qZUJvc2dSWGVTQkFQSXJoR3FCb0VpQm9pekNsUkhPWFNnY1VHOWRuMGVNblFoeXZIWmR2QjF5TmkwcGw5RmRuUVRCdkswQkFlU1J2S2h5dlZqbXZLVU1OSzVhWFBTUjJzSE1OVmVyQVBxbVVIN2RuRVV3QUNnZ1JYZWd3VVBTUnZzZ01VMCtNMlFVUk5RVWFiNVp5MjFJcG9rdU9iamV0QUdUUmxtanBsV2VCcVFGQzNFZ3kyNGVNTjlqeVltc0MyanVPb2plbW5FdXBvV0lycWlITXFCSE1oMCtNTjlqeVltc0MyanVPYmpldEFHVFJsbWpwbFdlQnFRRkMzRWd5MjRlbzE5U0JvaTBNcVFaUlhlZ2RuamVtbkV1cG9XZWFiNGVNMlFVUk5RVWR4MGV5cVFqeXhqZXRBRzlkeDgrIjtldmFsKCc/PicuJE8wME8wTygkTzBPTzAwKCRPTzBPMDAoJE8wTzAwMCwkT08wMDAwKjIpLCRPTzBPMDAoJE8wTzAwMCwkT08wMDAwLCRPTzAwMDApLCRPTzBPMDAoJE8wTzAwMCwwLCRPTzAwMDApKSkpOw=="));
?>

案例2:复杂混淆

<?php
define('pfkzYUelxEGmVcdDNLTjXCSIgMBKOuHAFyRtaboqwJiQWvsZrPhn', __FILE__);
$cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ = urldecode("n1zb/ma5\vt0i28-pxuqy*6lrkdg9_ehcswo4+f37j");
$BwltqOYbHaQkRPNoxcfnFmzsIjhdMDAWUeKGgviVrJZpLuXETSyC = $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{3} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{6} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{33} . $cPIHjUYxDZVBvOTsuiEClpMXAfSqrdegyFtbnGzRhWNJKwLmaokQ{30};
[...省略...]
eval($BwltqOYbHaQkRPNoxcfnFmzsIjhdMDAWUeKGgviVrJZpLuXETSyC("JE52aXV5d0NlUFdFR2xhY0FtZmpyZ0JNVFlYekhacEl4RHFRbnNVS2tob3RGU09SZFZKTGI9IldBckllVEJFWFBaTlN0b3ppZ2hmcENPUlV2S0x5eFFubXdsR2NqYVZiRGtGdUpZZHNNSHF1d1dBZW1NVWhRb0NMYURma0Z4VEtsenRCWHJkT2liSEpqeU52WVNQcGNzSVpFR1JnblZxUWM5alNWd0ZvTlBKU3U1eXJsUjZTMkNzcHV5TlBJb3JMSUk1dnU5RFJVYU9wSHhmbVZSSmIwdGpQQnlvU3lFSXVzRUNQMmlidVU5MlJCNUhCMkV4b0JJVkVPaWpvSmE2dVBQeXBWeEl0MjF1RzJ0VW1zaUJTeXhjQjB5SG1CRWRtM1BBYkJvNUJIdHhHSjlpUjBLS0JQUjJ2MUtPQk54WnJtZ3NieW96R3NDWVNKOWlHdTUxdnlJeVNVeUh0QjlhbVVSU21QUDZlUHQ0QlZDMFMzUk1SSm9qQjBhTHVOaXJTdXRodFVvb0xjMTF2Smlzb3VDWG9OQkRBa0IydG1VeUMwVXlDWUF5bnNHeUNzYnlDWVUxRW1QY0VtdjJFbXYwbmxCMnptQTRFbUVVRW12akVtdjRFbXYxRW12aUVtdjVFbUVNQ2tCMmJPQjNua0IyYmtCMkNsQjJDZnN5Q0JHeUNZQnlDWUZ5Q1lueUNmbnlDZnZ5Q3NHMEVtRWxFbUcybmZ2eUNzVWtybWdzR2h5enZ1NXlwM0VVTFZ4TmJ5QzNHMGFEbU5LckJWdFFTQkNKdUJJSHVIb2twSXhQQnl0aFBKMWp0QjF0dDJhNkx1dGZSbTBzYnlvekdzQ1lTSjlpR3U1MXZ5SXlTVXlIdEI5YW1VUlNtUFA2ZVB0NEJWQzBTM1JNUkpvakIwYUx1TmlyU3V0aHRVb29MVmdmVEw0c2J5b3pHc0NZU0o5aUd1NTF2eUl5U1V5SHRCOWFtVVJTbVBQNmVQdDRCVkMwUzNSTVJKb2pCMGFMdU5pclN1dGh0VW9vTFZnMlRMNHNieW96R3NDWVNKOWlHdTUxdnlJeVNVeUh0QjlhbVVSU21QUDZlUHQ0QlZDMFMzUk1SSm9qQjBhTHVOaXJTdXRodFVvb0xWZ2ZuMzBaRVVFdW1KRWNHMktYdnVJWlJoRXRvdXhFbzBQUXBCaVZ1czFQZUh5QmVJTWZSTmEzYmhvSnZJQ2RCeXhnTEp5c1AwdE51Qng3bmZNOXpPdG90MUtBUkp5amIzUDZtMW9pdnlSQkJCb2dvSHlsTGh0YnYyeGtHM3h5THMxZEdCUEdwMjEzQkpSWlB1YW1vVUlubXN0cVFMdGxQczVrYjJDcXAzSXhwSFBPQnVQREx1UkltMjFudDFLQ1BoSzVQVnhidjN0V1IwSTJvSE1tTDFFR3BVS0tvSVJVdHl5QWVmbmZUTDRzYnlvekdzQ1lTSjlpR3U1MXZ5SXlTVXlIdEI5YW1VUlNtUFA2ZVB0NEJWQzBTM1JNUkpvakIwYUx1TmlyU3
PHPJM混淆解密技术详解 0x00 前言 PHPJM是一种常见的PHP代码混淆工具,通过对变量名、函数名进行随机化处理,并在代码中插入大量无意义的字符和操作来增加代码分析的难度。本文将全面介绍PHPJM混淆的解密技术,包括手动解混淆、调试解混淆和自动化脚本解混淆三种方法。 0x01 PHPJM混淆特征分析 PHPJM混淆后的代码通常具有以下特征: 变量名被替换为随机字符串,如 $O00OO0 、 $O00O0O 等 使用字符串拼接方式构造关键函数名,如 $O00O0O=$O00OO0{3}.$O00OO0{6}... 最终通过 eval() 函数执行动态生成的代码 代码中包含大量无意义的字符和操作 0x02 手动解混淆方法 手动解混淆是最基础的方法,适用于简单的混淆代码: 替换eval为echo :将 eval() 替换为 echo 可以直接输出动态生成的代码 逐层解密 :将输出的代码替换原eval语句,重复这个过程直到获得清晰代码 执行流程 : 修改 eval() 为 echo 执行PHP文件 复制输出结果替换原eval语句 重复上述步骤直到代码完全清晰 0x03 调试解混淆方法 使用调试工具可以更高效地解混淆: 工具准备 VSCode + Xdebug + PHP Debug插件 调试步骤 格式化混淆代码 在关键位置设置断点 使用"Launch currently open script"模式启动调试 按F11进行单步调试 观察变量赋值过程 跟踪到最终执行的清晰代码 0x04 自动化脚本解混淆 对于复杂的混淆代码,可以编写自动化解密脚本: 脚本设计思路 识别PHP代码块 循环处理每个代码块: 替换 eval 为 echo 执行PHP代码并捕获输出 用输出替换原eval语句 使用正则判断是否完成解密 关键正则表达式 完整Python脚本 0x05 实战案例解析 案例1:基础混淆 案例2:复杂混淆