首页
社区
课程
招聘
[原创]从0到1的某Cocos2dlua手游解包笔记
发表于: 2023-3-31 17:26 6997

[原创]从0到1的某Cocos2dlua手游解包笔记

2023-3-31 17:26
6997

本文研究的apk基于2023/03/31的国际服版本。lua文件和图像文件都进行了加密。

简单看一下,java层基本没上加密。文件加密估计放在native层。打开ida分析libcocos2dlua.so文件,根据https://bbs.kanxue.com/thread-268574.htm#msg_header_h1_6的指导,定位到cocos2d::Image::initWithImageData(),直接就看到cocos2d::FileUtils::decryptUF(),分析后应该是所有加密文件都由这个函数解密。解密函数就是简单的异或固定的密钥。从ida拉出函数并稍加改写就得到了可用的解密器

(由于是直接复制ida的函数,不大好看)

参数1是要解密的文件,参数2是输出的文件名,处理多个文件可以再写个批处理。解密后至少有3类,png图片,用于生成spine的.pvr.ccz,lua脚本(LuaJit)。

想要获取动态立绘,可以用spite软件加载。以应用数据下upgrade\res\common\knight_spine\40008001对应的角色动态立绘为例。首先,同目录下的.png文件替换成用解密器解出来的.pvr.ccz再用texturePackerGUI解出来的同名png。打开spine点左上角的"spine"再选导入数据选40008001.atlas,再点开左上角再选纹理解包器,选同目录对应的.skel解到某个目录。之后右侧的图片选中刚刚解包纹理的目录,不出意外的话就可以看到合成出来cg图片了。

右侧的动画可以切换动作,左上角“设置”可以切换为“动画”来预览效果。

附:spine是旧版本的v3.8.99,正版的免费试用版不支持旧版,请自行寻找旧的破解版或考虑自行破解

解包出来的luajit可以自行反编译。

 
 
#include<iostream>
#include <cinttypes>
#include <fstream>
#define _BYTE unsigned char
#define _DWORD unsigned int
 
unsigned char key[] =
{
   19911213, 1022234431725,
   88643616146649875644,
   532811,   5, 1163758, 1052015,
   77,   729,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   01991,
   1213, 10222344317258864,
   36161466498756445328,
   11,   5, 1163758, 105201577,   7,
   29,   0,   0,   0,   0,   0,   0,   0,   0,   0,
};
 
unsigned int decryptFile(_BYTE* a1, int a2, _DWORD* a3, _DWORD* a4, _BYTE* a5)
{
    __int64 v5; // x8
    __int64 v6; // x5
    __int64 v7; // x3
    int v8; // w9
    int v9; // w11
    int v10; // w7
    __int64 v11; // x2
    int v12; // w5
    int v13; // w1
    int v15; // w5
    _BYTE* v16; // x8
    int v17; // w12
    int v18; // w11
    int v19; // w3
    char v20; // w6
    unsigned int v21; // w8
    unsigned int v22; // w2
    int v23; // w7
    unsigned int v24; // w7
    int v25; // w3
    _BYTE* v26; // x0
    int v27; // w8
    int v28; // w2
 
    if (a2 <= 3)
        return 0xFFFFFFFFLL;
    if (*a1 != 0x55 || a1[1] != 0x46)
        return 0xFFFFFFFELL;
    if (a1[2] == 0x4F)
    {
        v5 = 4LL;
        *a4 = (unsigned __int8)a1[3];
        v8 = 1;
        v6 = 5LL;
        v7 = 6LL;
        v9 = 4;
    }
    else
    {
        v5 = 2LL;
        v6 = 3LL;
        v7 = 4LL;
        v8 = 0;
        v9 = 2;
    }
    *a3 = (unsigned __int8)a1[v5];
    v10 = (unsigned __int8)a1[v6];
    if (v10 == 1)
    {
        v13 = a2 - 3 - v9;
        if (v13 <= 0)
        {
        LABEL_13:
            *a5 = v13;
            return 0LL;
        }
        v15 = v9 + 3;
        v16 = a1;
        v17 = v13 + v9 + 3;
        v18 = (unsigned __int8)a1[(unsigned int)v7] - v9 - 3;
        do
        {
            v19 = v18 + v15;
            v20 = a1[v15++];
            *v16++ = key[v19 % 33] ^ v20;
        } while (v15 != v17);
        *a5 = v13;
        return 0LL;
    }
    else
    {
        if (v10 != 2)
        {
            v11 = 0LL;
            if (v8)
                v12 = 7;
            else
                v12 = 5;
            v13 = a2 - v12;
            if (v13 > 0)
            {
                do
                {
                    a1[v11] = a1[(unsigned int)(v12 + v11)];
                    ++v11;
                } while (v13 > (int)v11);
            }
            goto LABEL_13;
        }
        v21 = (unsigned __int8)a1[v7];
        v22 = v9 + 3;
        v13 = a2 - (v9 + 3);
        *a1 = a1[v13] ^ key[v21 % 0x21 + 48];
        a1[1] = a1[v13 + 1] ^ key[(v21 + 1) % 0x21 + 48 ];
        a1[2] = a1[v13 + 2] ^ key[(v21 + 2) % 0x21 + 48 ];
        a1[3] = a1[v13 + 3] ^ key[(v21 + 3) % 0x21 + 48 ];
        a1[4] = a1[v13 + 4] ^ key[(v21 + 4) % 0x21 + 48 ];
        if (v9 != 2)
        {
            a1[6] = a1[v13 + 6] ^ key[(v21 + 6) % 0x21 + 48];
            a1[5] = a1[v13 + 5] ^ key[(v21 + 5) % 0x21 + 48];
        }
        if ((int)(v13 - v22) > 95)
            v23 = 95;
        else
            v23 = v13 - v22;
        v24 = v23 + v22;
        if (v22 >= v24)
            goto LABEL_13;
        v25 = v21 + v22;
        v26 = &a1[v22];
        v27 = v21 + v24;
        do
        {
            v28 = v25 % 33;
            ++v25;
            *v26++ ^= key[v28 + 48];
        } while (v25 != v27);
        *a5 = v13;
        return 0LL;
    }
}
unsigned char mydata[1000000] = { 0 };
unsigned char outdata[1000000] = { 0 };
int main(int argc, char* argv[]) {
 
 
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " input_file output_file\n";
        return 1;
    }
 
    std::ifstream infile(argv[1], std::ios::binary);
 
    if (!infile) {
        std::cerr << "Error opening input file.\n";
        return 1;
    }
 
    std::ofstream outfile(argv[2], std::ios::binary);
 
    if (!outfile) {
        std::cerr << "Error opening output file.\n";
        return 1;
    }
 
    if (infile && outfile) {
        infile.seekg(0, std::ios::end);
        std::streamsize size = infile.tellg();
        infile.seekg(0, std::ios::beg);
 
        char* buffer = new char[size];
        if (infile.read(buffer, size)) {
            decryptFile((unsigned char*)buffer, size, (_DWORD*)&outdata[100000], (_DWORD*)&outdata[200000], outdata);
            outfile.write(buffer, size);
        }
        delete[] buffer;
    }
 
    infile.close();
    outfile.close();
    return 0;
}
#include<iostream>
#include <cinttypes>
#include <fstream>
#define _BYTE unsigned char
#define _DWORD unsigned int
 
unsigned char key[] =
{
   19911213, 1022234431725,
   88643616146649875644,
   532811,   5, 1163758, 1052015,
   77,   729,   0,   0,   0,   0,   0,   0,   0,
    0,   0,   0,   0,   0,   0,   0,   01991,
   1213, 10222344317258864,
   36161466498756445328,
   11,   5, 1163758, 105201577,   7,
   29,   0,   0,   0,   0,   0,   0,   0,   0,   0,
};
 
unsigned int decryptFile(_BYTE* a1, int a2, _DWORD* a3, _DWORD* a4, _BYTE* a5)
{
    __int64 v5; // x8
    __int64 v6; // x5
    __int64 v7; // x3
    int v8; // w9
    int v9; // w11
    int v10; // w7
    __int64 v11; // x2
    int v12; // w5
    int v13; // w1
    int v15; // w5
    _BYTE* v16; // x8
    int v17; // w12
    int v18; // w11
    int v19; // w3
    char v20; // w6
    unsigned int v21; // w8
    unsigned int v22; // w2
    int v23; // w7
    unsigned int v24; // w7
    int v25; // w3
    _BYTE* v26; // x0
    int v27; // w8
    int v28; // w2
 
    if (a2 <= 3)
        return 0xFFFFFFFFLL;
    if (*a1 != 0x55 || a1[1] != 0x46)
        return 0xFFFFFFFELL;
    if (a1[2] == 0x4F)
    {
        v5 = 4LL;
        *a4 = (unsigned __int8)a1[3];
        v8 = 1;
        v6 = 5LL;
        v7 = 6LL;
        v9 = 4;
    }
    else
    {
        v5 = 2LL;
        v6 = 3LL;
        v7 = 4LL;
        v8 = 0;
        v9 = 2;
    }
    *a3 = (unsigned __int8)a1[v5];
    v10 = (unsigned __int8)a1[v6];
    if (v10 == 1)
    {
        v13 = a2 - 3 - v9;
        if (v13 <= 0)
        {
        LABEL_13:
            *a5 = v13;
            return 0LL;
        }
        v15 = v9 + 3;
        v16 = a1;
        v17 = v13 + v9 + 3;
        v18 = (unsigned __int8)a1[(unsigned int)v7] - v9 - 3;
        do
        {
            v19 = v18 + v15;
            v20 = a1[v15++];
            *v16++ = key[v19 % 33] ^ v20;
        } while (v15 != v17);
        *a5 = v13;
        return 0LL;

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回
//