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

工具篇:


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

#include

#include         // for strcat()

#include

#include

#include

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 &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 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

bool isDir(const char *lpPath)

{

return GetFileAttributesA(lpPath)&FILE_ATTRIBUTE_DIRECTORY;

}

void listFiles(const char * dir, vector &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

\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脚本加密资源加密)