原理是修改cocos2dx引擎的原有的ScriptEngine::setFileOperationDelegate函数, 然后对onGetStringFromFile进行包装,加此基础上一个保存文件功能。
此破解法虽复杂,但是通用。 之所以进行此实战,因为有的游戏不按套路出牌(xxtea方式), 有自己的加密方式 压缩方式。
保存文件功能,保存到可写目录de中。
void ScriptEngine::setFileOperationDelegate(const FileOperationDelegate& delegate) { auto onGetStringFromFile = delegate.onGetStringFromFile; const_cast<FileOperationDelegate&>(delegate).onGetStringFromFile = [onGetStringFromFile](const std::string& path) -> std::string{ char de[] = {'/','d','e',0}; auto fUtils = cocos2d::FileUtils::getInstance(); std::string writePath = fUtils->getWritablePath(); writePath.append(de); std::string data = onGetStringFromFile(path); std::string fileName; if(fUtils->isAbsolutePath(path)){ size_t pos = path.rfind('/'); if(pos!=std::string::npos){ fileName = writePath+path.substr(pos); } } if(fileName.empty()){ fileName = writePath + '/' + path; } // mkdir -p size_t pos = fileName.rfind('/'); fUtils->createDirectory(fileName.substr(0,pos)); auto ok = fUtils->writeStringToFile(data, fileName); // CCLOG("path == %s, %s", fileName.c_str(), ok?"true":"false"); return data; }; _fileOperationDelegate = delegate; }
保存效果:/data/user/0/com.xxxx.xxx/files/de/jsb-adapter/jsb-engine.js
拷贝函数的二进制数据:(打一个release.apk包,解压出so文件,找到setFileOperationDelegate函数地址)
反编译效果:
函数起始地址:00566F48 函数结束地址:00567298 长度:848. 长度很重要, 因为这个数据要插入到破解的游戏so文件中,如果间隙不够,就虾米了。
F0 4B 2D E9 18 B0 8D E2 68 D0 4D E2 00 80 A0 E1 2C 03 9F E5 01 40 A0 E1 18 70 84 E2 00 00 9F E7 00 00 90 E5 1C 00 0B E5 28 00 94 E5 00 00 50 E3 0A 00 00 0A 00 00 57 E1 0E 00 00 0A 00 10 90 E5 08 10 91 E5 31 FF 2F E1 18 10 8D E2 28 00 8D E5 10 90 81 E2 00 00 50 E3 10 00 00 1A 03 00 00 EA 00 00 A0 E3 28 00 8D E5 18 00 8D E2 10 90 80 E2 00 00 A0 E3 0F 00 00 EA 18 50 8D E2 28 50 8D E5 00 10 90 E5 0C 20 91 E5 05 10 A0 E1 32 FF 2F E1 28 00 9D E5 10 90 85 E2 00 00 50 E3 F3 FF FF 0A 18 10 8D E2 00 00 51 E1 12 00 00 0A 00 10 90 E5 08 10 91 E5 31 FF 2F E1 0D 60 A0 E1 10 00 8D E5 00 00 50 E3 15 00 00 0A 00 00 56 E1 03 00 00 0A 40 00 8D E5 00 00 A0 E3 10 00 8D E5 11 00 00 EA 30 10 8D E2 40 10 8D E5 00 20 90 E5 0C 20 92 E5 32 FF 2F E1 0B 00 00 EA 28 00 9D E5 0D 60 A0 E1 10 60 8D E5 00 10 90 E5 0C 20 91 E5 06 10 A0 E1 32 FF 2F E1 10 00 9D E5 00 00 50 E3 E9 FF FF 1A 00 00 A0 E3 40 00 8D E5 00 00 A0 E3 28 00 0B E5 20 00 A0 E3 9B 0D F2 EB 00 50 A0 E1 04 02 9F E5 05 10 A0 E1 00 00 8F E0 08 00 80 E2 08 00 81 E4 40 00 9D E5 00 00 50 E3 06 00 00 0A 30 20 8D E2 00 00 52 E1 06 00 00 0A 18 00 85 E5 00 00 A0 E3 40 00 8D E5 06 00 00 EA 00 00 A0 E3 18 00 85 E5 03 00 00 EA 18 10 85 E5 00 20 90 E5 0C 20 92 E5 32 FF 2F E1 28 50 0B E5 38 50 4B E2 07 10 A0 E1 05 00 A0 E1 CF 1D F2 EB 28 00 1B E5 00 00 55 E1 04 00 00 0A 00 00 50 E3 05 00 00 0A 00 10 90 E5 14 10 91 E5 01 00 00 EA 00 10 90 E5 10 10 91 E5 31 FF 2F E1 40 00 9D E5 30 10 8D E2 00 00 51 E1 04 00 00 0A 00 00 50 E3 05 00 00 0A 00 10 90 E5 14 10 91 E5 01 00 00 EA 00 10 90 E5 10 10 91 E5 31 FF 2F E1 10 00 9D E5 00 00 56 E1 04 00 00 0A 00 00 50 E3 05 00 00 0A 00 10 90 E5 14 10 91 E5 01 00 00 EA 00 10 90 E5 10 10 91 E5 31 FF 2F E1 58 00 88 E2 04 10 A0 E1 BA 1F F2 EB 00 00 99 E5 18 10 8D E2 00 00 51 E1 04 00 00 0A 00 00 50 E3 05 00 00 0A 00 10 90 E5 14 10 91 E5 01 00 00 EA 00 10 90 E5 10 10 91 E5 31 FF 2F E1 D8 00 9F E5 1C 10 1B E5 00 00 9F E7 00 00 90 E5 01 00 50 E0 18 D0 4B 02 F0 8B BD 08 55 0D F2 EB 0F E0 A0 E1 A8 79 FD EA 0F E0 A0 E1 A6 79 FD EA FF FF FF EA 00 40 A0 E1 17 00 00 EA 00 40 A0 E1 40 00 9D E5 30 10 8D E2 00 00 51 E1 02 00 00 1A 00 10 90 E5 10 10 91 E5 03 00 00 EA 00 00 50 E3 02 00 00 0A 00 10 90 E5 14 10 91 E5 31 FF 2F E1 10 00 9D E5 00 00 56 E1 02 00 00 1A 00 10 90 E5 10 10 91 E5 03 00 00 EA 00 00 50 E3 02 00 00 0A 00 10 90 E5 14 10 91 E5 31 FF 2F E1 00 00 99 E5 18 10 8D E2 00 00 51 E1 02 00 00 1A 00 10 90 E5 10 10 91 E5 03 00 00 EA 00 00 50 E3 02 00 00 0A 00 10 90 E5 14 10 91 E5 31 FF 2F E1 04 00 A0 E1 0F E0 A0 E1 41 55 02 EA 14 D6 B3 00 18 1B B1 00 BC D3 B3 00
接下来,查找间隙:
很明显第一个LOAD具有可执行权限。准备好的二进制数据插到这个后面。
第一个LOAD结束地址为0x1304560, 第二个LOAD的开始地址:0x1305160 间隙大小:3072.. 大小完全足够。
准备好的二进制数据放到so里:
插入完,修改函数跳转地址,跳转到新添的二进制地方。
原有的跳转地址:
地址: 0x1311cd8 + 0x39000 + 0xacc = 0x134b7a4
跳到0x134b7a4地址, 将0x650440 替换成 0x1304560 (第一个LOAD的结束地址)
保存为so后,重新生成apk.