解密cocos2dx游戏资源照片

#逆向

简介

接到取证任务,提取违法游戏中的图片资源文件。

操作

分析

该游戏为apk安装包,使用apktool和jadx-gui进行简单的反编译,找到res目录中的图片打开,提示已损坏。
Pasted image 20240717122356.png

逆向

使用记事本打开该照片,发现文件头存在可疑字符串 shiyuegame
Pasted image 20240717122508.png

分析逆向后的apk文件结构,得知此游戏使用cocos2dx开发。每张加密图片下方均存在plist文件,末尾存在texturepacker标识,表明该图片资源使用了texturepacker加密:这就有了

IDA pro

在源码\app\src\main\lib\armeabi找到了libcocos2dlua.so

通过IDA打开,搜索字符串,找到了解密key
Pasted image 20240717133835.png

编写解密脚本

  • 安装python虚拟环境,以便安装xxtea
python3 -m venv lua #开启虚拟python环境,以便安装xxtea。Mac默认python3环境无法安装xxtea
source lua/bin/activate
pip install xxtea
  • 选择一个图片目录进行单张图片调试。先编写脚本:
import xxtea

def lua_decrypt(infile, outfile, sign, key):
    try:
        with open(infile, 'rb') as f:
            buf = f.read()

        signlen = len(sign)
        keylen = len(key)

        # Verify that the file starts with the given sign
        if not buf.startswith(sign.encode()):
            print(f"File does not start with the expected sign: {sign}")
            print(f"First 32 bytes of the file: {buf[:32]}")
            return

        # Remove the sign from the buffer
        buf = buf[signlen:]

        # Decrypt the remaining data using XXTEA
        decrypted_data = xxtea.decrypt(buf, key.encode())

        # Check the decrypted data length and print the first 32 bytes for debugging
        print(f"Decrypted data length: {len(decrypted_data)}")
        print(f"Decrypted first 32 bytes: {decrypted_data[:32]}")

        # Save the decrypted data to the output file
        with open(outfile, 'wb') as f:
            f.write(decrypted_data)

        print(f"{infile} decrypt successful")
    except Exception as e:
        print(f"{infile} decrypt fail: {e}")
        if 'decrypted_data' in locals():
            print(f"Decrypted data length: {len(decrypted_data)}")
            print(f"Decrypted first 32 bytes: {decrypted_data[:32]}")
        print(f"First 32 bytes of the original file: {buf[:32]}")

if __name__ == '__main__':
    if len(sys.argv) < 5:
        print("usage: lua_decrypt infile outfile sign key")
        sys.exit(1)

    infile = sys.argv[1]
    outfile = sys.argv[2]
    sign = sys.argv[3]
    key = sys.argv[4]

    lua_decrypt(infile, outfile, sign, key)

在resource/set目录下执行:

python3 lua.py set.png out.png shiyuegame JYDYdpyRecDuHQc8

发现图片已成功解密
Pasted image 20240717134600.png

解密所有图片

如果把所有.png图片取出再解密,会出现文件名冲突等问题。于是遍历各个文件夹,如果存在png图片则解密,替换原图片


        signlen = len(sign)
        keylen = len(key)

        # Verify that the file starts with the given sign
        if not buf.startswith(sign.encode()):
            print(f"File does not start with the expected sign: {sign}")
            print(f"First 32 bytes of the file: {buf[:32]}")
            return

        # Remove the sign from the buffer
        buf = buf[signlen:]

        # Decrypt the remaining data using XXTEA
        decrypted_data = xxtea.decrypt(buf, key.encode())

        # Check the decrypted data length and print the first 32 bytes for debugging
        print(f"Decrypted data length: {len(decrypted_data)}")
        print(f"Decrypted first 32 bytes: {decrypted_data[:32]}")

        # Save the decrypted data to the output file
        with open(outfile, 'wb') as f:
            f.write(decrypted_data)

        print(f"{infile} decrypt successful")
    except Exception as e:
        print(f"{infile} decrypt fail: {e}")
        if 'decrypted_data' in locals():
            print(f"Decrypted data length: {len(decrypted_data)}")
            print(f"Decrypted first 32 bytes: {decrypted_data[:32]}")
        print(f"First 32 bytes of the original file: {buf[:32]}")

def decrypt_images_in_folder(folder, sign, key):
    for root, _, files in os.walk(folder):
        for file in files:
            if file.endswith('.png'):
                filepath = os.path.join(root, file)
                lua_decrypt(filepath, filepath, sign, key)

if __name__ == '__main__':
    if len(sys.argv) < 4:
        print("usage: python script.py folder sign key")
        sys.exit(1)

    folder = sys.argv[1]
    sign = sys.argv[2]
    key = sys.argv[3]

    decrypt_images_in_folder(folder, sign, key)

其他方案

组员使用C编写的解密脚本:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"xxtea.h"
int main(int argc,char*argv[]){
	FILE*fp;
	char*key;
	char*sign;
	char*infile;
	char*outfile;
	char*buf,*data;
	unsigned long size;
	int keylen,signlen,retlen;
	if(argc<5){
		printf("usage:lua_decrypt infile outfile sign key\n");
		return -1;
	}
	else{
		infile=argv[1];
		outfile=argv[2];
		sign=argv[3];
		key=argv[4];
		keylen=strlen(key);
		signlen=strlen(sign);
	}

	if((fp=fopen(infile,"rb"))==NULL){
			perror("can't open the input file");
			return -1;
	}
	fseek(fp, 0L, SEEK_END);
	size=ftell(fp);
	rewind(fp);
	buf=(char*)malloc(size);
	fread(buf,size,1,fp);
	fclose(fp);
	data=xxtea_decrypt(buf+signlen,size-signlen,key,keylen,&retlen);
	if(data==NULL){
		printf("%s decrypt fail\n",infile);
		return -1;
	}
	if((fp=fopen(outfile,"wb+"))==NULL){
		    perror("can't open the output file");
			return -1;
	}
	fwrite(data,retlen,1,fp);
	fclose(fp);
	free(data);
	printf("%s decrypt successful\n",infile);
	return 0;

}

遍历破解:

#!/bin/bash

# 父目录路径
parent_dir="/home/kali/xxtea/png/FGOBT_YNBT_v1.2.7_0514/"

# 加密解密工具路径和参数
decrypt_tool="./lua_decrypt"
key="shiyuegame"
iv="JYDYdpyRecDuHQc8"

# 查找所有包含 PNG 图片的目录
find "$parent_dir" -type d -exec sh -c '
    for dir do
        # 检查目录中是否有 PNG 图片
        if ls "$dir"/*.xml 1> /dev/null 2>&1; then
            echo "处理目录: $dir"
            # 迭代目录中的所有 PNG 图片
            for file in "$dir"/*.xml; do
                # 获取文件名(不包含路径部分)
                filename=$(basename -- "$file")
                # 解密并覆盖原文件
                '"$decrypt_tool"' "$file" "$file" "'"$key"'" "'"$iv"'"
                echo "文件 $filename 解密完成"
            done
        fi
    done' sh {} +

echo "解密完成"
© 版权声明
THE END
喜欢就支持一下吧
点赞8 分享