美文网首页
破解cocos2dx-lua脚本加密资源加密

破解cocos2dx-lua脚本加密资源加密

作者: 小云锅 | 来源:发表于2019-01-03 18:34 被阅读0次

    工具篇:

    IDA Pro (32-bit)7.0 神器不多说 百度网盘 提取码6666

    ApkToolBox 功能很强大的拆包工具 爱盘 - 最新的在线破解工具包

    Visual Studio 随便什么版本可以执行c/c++就行,用于解密脚本,好处是伪代码能直接用.

    notepad++ 自行百度很好用的文本工具

    Demo 百度网盘 提取码6666

    开始:

    解密图片:

    反编译apk 发现图片被加密了 发现代码也被加密了文件头不是lua开始的... ida打开libgame.so 在导出表中搜索getFileData看安卓的实现 经过一番分析发现fopen之后对文件进行了funck!的前缀解析... 资源和配置文件都被弄成了这样.. 这是上面对应的解密数组

    // gamecenter_decrypt.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

    //

    #include <iostream>

    #include <fstream>

    #include <cstring>        // for strcat()

    #include <io.h>

    #include <vector>

    #include <Windows.h>

    using namespace std;

    #define _BYTE unsigned char;

    #define _DWORD unsigned int;

    const char *res_path = "D:\\tmp\\gamecenter-release-android-huakai-6162\\assets";

    const char *des_path = "D:\\tmp\\gamecenter-release-android-huakai-6162\\assets_des";

    void listFiles(const char * dir, vector<string> &file_list);

    void decrypt_(const char *name);

    bool exist(const char * lpPath);

    void decrypt_data(const char *name, const void *buffer, const size_t &len);

    int main()

    {

    vector<string> dirList;

    char dir[300] = { 0 };

    strcpy(dir, res_path);

        std::cout << "Hello World!\n";

    listFiles(dir, dirList);

    for (size_t i = 0; i < dirList.size(); i++)

    {

    //printf("%s\n", dirList[i].c_str());

    decrypt_(dirList[i].c_str());

    }

    system("pause");

    }

    //是否是文件夹 #include <Windows.h>

    bool isDir(const char *lpPath)

    {

    return GetFileAttributesA(lpPath)&FILE_ATTRIBUTE_DIRECTORY;

    }

    void listFiles(const char * dir, vector<string> &file_list)

    {

    char dirNew[200];

    strcpy(dirNew, dir);

    strcat(dirNew, "\\*.*");    // 在目录后面加上"\\*.*"进行第一次搜索

    intptr_t handle;

    _finddata_t findData;

    handle = _findfirst(dirNew, &findData);

    if (handle == -1)        // 检查是否成功

    return;

    do

    {

    if (findData.attrib & _A_SUBDIR)

    {

    if (strcmp(findData.name, ".") == 0 || strcmp(findData.name, "..") == 0)

    continue;

    //cout << findData.name << "\t<dir>\n";

    // 在目录后面加上"\\"和搜索到的目录名进行下一次搜索

    strcpy(dirNew, dir);

    strcat(dirNew, "\\");

    strcat(dirNew, findData.name);

    listFiles(dirNew, file_list);

    }

    else

    {

    //cout << findData.name << "\t" << findData.size << " bytes.\n";

    file_list.push_back(string(dir).append("\\").append(findData.name));

    }

    } while (_findnext(handle, &findData) == 0);

    _findclose(handle);    // 关闭搜索句柄

    }

    void decrypt_(const char *name)

    {

    unsigned char byte_A5DF0F[] = {

    0xA4, 0x11, 0x98, 0xD3, 0xB2, 0x41, 0x27, 0x8F, 0x56,

    0x14, 0xF1, 0x74, 0xF6, 0xCA, 0xE0, 0x7D, 0x32, 0xFF,

    0x92, 0xE2, 0x36, 0xA8, 0x94, 0x6E, 0xF0, 0x10, 0xDC,

    0xF7, 0xC6, 0x66, 0x81, 0x91, 0xE4, 0xA1, 0x12, 0x28,

    0xF5, 0x3B, 0xAE, 0x1B, 0xD9, 0x6E, 0x64, 0x19, 0xC4,

    0xD2, 0x19, 0x59, 0x93, 0x23, 0x2D, 0xA1, 0x92, 0x54,

    0xDD, 0xF2, 0xEF, 0x24, 0xD0, 0x9B, 0x3A, 0x20, 0xBE,

    0x7C, 0xF2, 0x6D, 0x3A, 0x66, 0x85, 0x77, 0x9B, 0x2B,

    0x1A, 0xC8, 0xC6, 0x64, 0xFA, 0x62, 0xCB, 0xCA, 0xAB,

    0xC1, 0xC9, 0x21, 0x71, 0x96, 0xA3, 0xA9, 0xC7, 0xB0,

    0x9A, 0xC2, 0x6B, 0x46, 0x9A, 0xBF, 0xFC, 0x6C, 0xFA,

    0x16, 0x5C, 0xEF, 0x90, 0xED, 0x9F, 0x6C, 0xAB, 0x25,

    0x94, 0x5A, 0x5C, 0xAF, 0x4E, 0x2A, 0xC4, 0xC6, 0xB0,

    0xD8, 0x71, 0x50, 0x38, 0x82, 0x1A, 0xF7, 0x2A, 0x45,

    0xE8, 0x2E, 0x64, 0x9E, 0x65, 0x32, 0x7A, 0x3C, 0x33,

    0x13, 0x51, 0x1F, 0xA7, 0x82, 0x67, 0x8D, 0xE9, 0x2C,

    0x4C, 0x7F, 0xA7, 0xCF, 0x9E, 0x2E, 0x79, 0x72, 0xB9,

    0x72, 0xBF, 0x4F, 0x14, 0x53, 0x9B, 0xFC, 0xD9, 0x3B,

    0xEE, 0x15, 0xF8, 0xB0, 0x4C, 0xF1, 0xCB, 0x79, 0x9B,

    0x5D, 0x42, 0xF7, 0xEB, 0xAE, 0xEB, 0x8F, 0xB9, 0xBC,

    0xBE, 0xA1, 0x7E, 0x9E, 0x38, 0xBE, 0xE9, 0x7D, 0xB2,

    0x8D, 0x3D, 0x82, 0x90, 0x39, 0xCD, 0x17, 0x49, 0xCF,

    0x4B, 0xF2, 0x1C, 0x59, 0x2A, 0xA3, 0x73, 0x72, 0x66,

    0xFE, 0x3E, 0x30, 0xD5, 0xE4, 0xB9, 0x19, 0xD7, 0xAC,

    0x72, 0x5F, 0x21, 0x37, 0x2E, 0x6B, 0x14, 0xA4, 0x8C,

    0x35, 0xC1, 0x16, 0xFF, 0xCC, 0xB3, 0x3F, 0x1D, 0x1A,

    0xA4, 0xA5, 0xF1, 0x83, 0xD1, 0x99, 0x29, 0x80, 0x25,

    0xBD, 0xD0, 0x4E, 0xD8, 0x9C, 0xBE, 0xE9, 0xB8, 0xDD,

    0xCB, 0x21, 0x94, 0x49, 0

    };

    unsigned __int8 *v8 = NULL;

    size_t file_len = 0;

    size_t *v6 = &file_len;

    //if (*name == 47)

    {

    FILE *v11 = fopen(name, "rb");

    FILE *v12 = v11;

    if (v11)

    {

    fseek(v11, 0, 2);

    long v13 = ftell(v12);

    fseek(v12, 0, 0);

    v8 = (unsigned __int8 *)operator new[](v13);

    size_t v14 = fread(v8, 1u, v13, v12);

    fclose(v12);

    //if (!v6)

    // __und(0xFDEEu);

    *v6 = v14;

    if (v14 > 7)

    {

    unsigned __int8 v15 = *v8;

    unsigned __int8 v16 = v15 == 102;

    if (v15 == 102)

    v16 = v8[1] == 117;

    if (v16)

    {

    unsigned __int8 v17 = v8[2];

    unsigned __int8 v18 = v17 == 99;

    if (v17 == 99)

    v18 = v8[3] == 107;

    if (v18)

    {

    unsigned __int8 v19 = v8[4];

    unsigned __int8 v20 = v19 == 121;

    if (v19 == 121)

    v20 = v8[5] == 111;

    if (v20)

    {

    unsigned __int8 v21 = v8[6];

    unsigned __int8 v22 = v21 == 117;

    if (v21 == 117)

    v22 = v8[7] == 33;

    if (v22)

    {

    unsigned int v23 = v14 - 8;

    *v6 = v23;

    //_aeabi_memmove(v8, v8 + 8);

    v8 += 8;

    if (v23)

    {

    unsigned int v24 = 0;

    do

    {

    v8[v24] ^= byte_A5DF0F[(signed int)v24 % 256];

    ++v24;

    } while (v24 < v23);

    //解密完成写入图片

    decrypt_data(name, v8, *v6);

    goto LABEL_60;

    }

    v8 -= 8;

    }

    }

    }

    }

    }

    //goto LABEL_60;

    }

    goto LABEL_58;

    }

    LABEL_60:

    //printf("%s\n", name);

    return;

    //声音没有加密, 加密的是luac

    LABEL_58:

    printf("%s\n", name);

    }

    void decrypt_data(const char *name, const void *buffer, const size_t &len)

    {

    string des(name);

    des.replace(des.find(res_path), strlen(res_path), des_path);

    string parent_dir = des.substr(0, des.rfind("\\"));

    if (!exist(parent_dir.c_str()))

    system(string("md ").append(parent_dir).c_str());

    //printf(des.c_str());

    FILE * fd = fopen(des.c_str(), "wb+");

    if (fd) {

    if (fwrite(buffer, len, 1, fd) > 0) {

    //printf("write success .");

    }

    fclose(fd);

    }

    }

    //是否存在

    bool exist(const char * lpPath)

    {

    /* Check for existence */

    if ((_access(lpPath, 0)) != -1)

    {

    return true;

    }

    else {

    return false;

    }

    }


    lua解密:

    上面是解密的代码分析好相应的变量之后直接拷贝伪代码,完成之后发现图片解密了代码还是原样...

    中间也踩了很多坑,找.lua xxtea aes之类的加密函数或者具有嫌疑的字符串都失败了.最后luaLoadBuffer看到了...

    接着搜索luaLoadBuffer函数

    看了下_byds_d_的解密逻辑比较复杂,解密完还要解压缩,索性就hook dump吧 hook luaL_loadbuffer函数

    hook工具很多都只停留在4.4版本,这点坑了我许久,nexus5x最低支持6.0无奈.

    经过各种论坛百度,最后找到注入解决方案 基于Xposed和Substrate的通用性SO注入 - 大星星的专栏 - CSDN博客 该应该适用于8.0

    不改变原包体,xposed入口注入substrate.so 和自己的so 进行hook dlopen函数  dlopen 检测到libgame.so打开之后得到符号直接hook其函数.

    打印日志,buffer len path都出来了... 接下来就是提取lua脚本到内存卡,这里有个坑 1.文件夹不能直接创建,2.开始写入到/data/local/tmp目录创建不了 以二进制写的方式打开文件,打开之后写入 写入完成之后用adb pull命令拷贝到解密文件夹内. 原以为luac还要在解密一次为lua打开一看多虑了,直接明文...


    交流可加qq99939534

    相关文章

      网友评论

          本文标题:破解cocos2dx-lua脚本加密资源加密

          本文链接:https://www.haomeiwen.com/subject/tmlqrqtx.html