Hi Aluigi,
Please help me, How do I extract the luac file? I have tried using the zt_qq_fo.bms script but failed. Files and screenshots attached
https://drive.google.com/file/d/12cw6JBPMn1BvHetgAtYKLl28ZixdFQAV/view?usp=drivesdk
How to extract file .luac extention [Rich and Famous]
-
- Posts: 13
- Joined: Sat Jul 07, 2018 8:12 am
-
- Site Admin
- Posts: 12984
- Joined: Wed Jul 30, 2014 9:32 pm
Re: How to extract file .luac extention
What's the name of the game?
That file is obfuscated, no idea how.
That file is obfuscated, no idea how.
-
- Posts: 13
- Joined: Sat Jul 07, 2018 8:12 am
Re: How to extract file .luac extention
aluigi wrote:What's the name of the game?
That file is obfuscated, no idea how.
name the game is "rich and famous"
-
- Posts: 250
- Joined: Sat Dec 27, 2014 8:49 pm
Re: How to extract file .luac extention [Rich and Famous]
Here's a small rundown of how to decrypt the files of this game, as well as a "guide" of how to deal with Cocos2 games. (This game uses the Cocos2 engine.)
The encryption information is located inside of the libcocos2dlua.so in this case. Other games are in the same/similar named module.
First, you want to locate where the Lua engine is being created and initialized. The easiest way to find this is in a tool like IDA or Ghidra, look for the following kinds of functions:
- AppDelegate::applicationDidFinishLaunching
- cocos2d::ScriptEngineManager::setScriptEngine
- register_<misc_name_here>_module
Follow references to those and you should eventually find a function that looks something like this:
This is where the Lua engine is being initialized and prepared. This is also were the Lua file encryption is setup. Not all games use the same setup in this function so it'll be up to you to determine the layout of the function for your game.
In this case, the game uses the default XXTEA encryption setup built into Cocos2 which is setup using:
The key is the actual encryption/decryption key used for the file data, the sign is just a pattern added to the start of the file to let the engine know if that file should be decrypted using the set key/sign information.
For this game, that data is encrypted itself as well to prevent reading that data easily using those 'cuteCode' calls. Those are set up like this:
The first block before the first Cutecode call is the 'Cutecode' key and the data to decrypt:
IDA and Ghidra both output this data in the wrong order so be cautious of trusting the output given. Instead the key and data should be laid out like this:
This will give us the XXTEA key of:
The second block can be decoded to get the sign, but that doesn't really matter but here is that:
Which gives back the sign: RUORUO
You can now decrypt this using any means of XXTEA, stepping over the 6 byte signature (RUORUO) at the top of the file. For the example file you gave, decrypted it is:
The encryption information is located inside of the libcocos2dlua.so in this case. Other games are in the same/similar named module.
First, you want to locate where the Lua engine is being created and initialized. The easiest way to find this is in a tool like IDA or Ghidra, look for the following kinds of functions:
- AppDelegate::applicationDidFinishLaunching
- cocos2d::ScriptEngineManager::setScriptEngine
- register_<misc_name_here>_module
Follow references to those and you should eventually find a function that looks something like this:
Code: Select all
__int64 sub_5A1498()
{
cocos2d::ScriptEngineManager *v0; // x0
cocos2d::ScriptEngineProtocol *v1; // x20
cocos2d::ScriptEngineManager *v2; // x0
__int64 v3; // x19
__int64 v4; // x21
unsigned int v5; // w24
__int64 v6; // x0
int v8; // [xsp+40h] [xbp-50h]
int v9; // [xsp+44h] [xbp-4Ch]
int v10; // [xsp+48h] [xbp-48h]
int v11; // [xsp+4Ch] [xbp-44h]
int v12; // [xsp+50h] [xbp-40h]
int v13; // [xsp+54h] [xbp-3Ch]
int v14; // [xsp+58h] [xbp-38h]
int v15; // [xsp+5Ch] [xbp-34h]
int v16; // [xsp+60h] [xbp-30h]
int v17; // [xsp+68h] [xbp-28h]
__int16 v18; // [xsp+6Ch] [xbp-24h]
char v19; // [xsp+6Eh] [xbp-22h]
__int64 v20; // [xsp+70h] [xbp-20h]
__int64 v21; // [xsp+78h] [xbp-18h]
char v22; // [xsp+80h] [xbp-10h]
v0 = (cocos2d::ScriptEngineManager *)cocos2d::LuaEngine::getInstance(_stack_chk_guard);
v1 = v0;
v2 = (cocos2d::ScriptEngineManager *)cocos2d::ScriptEngineManager::getInstance(v0);
cocos2d::ScriptEngineManager::setScriptEngine(v2, v1);
v3 = *(_QWORD *)(*((_QWORD *)v1 + 1) + 40LL);
register_cocosdenshion_module(*(_QWORD *)(*((_QWORD *)v1 + 1) + 40LL));
register_network_module(v3);
register_cocosbuilder_module(v3);
register_cocostudio_module(v3);
register_ui_moudle(v3);
register_extension_module(v3);
register_spine_module(v3);
register_cocos3d_module(v3);
register_audioengine_module(v3);
register_all_laky_actUpdate(v3);
register_physics3d_module(v3);
register_navmesh_module(v3);
luaopen_pb(v3);
v8 = 0;
v11 = 8;
v13 = 1;
v14 = 2;
v9 = 6;
v15 = 3;
v20 = 0xA9D3B6D3988A8BD1LL;
v21 = 0xDECEDC95A2DBD9CDLL;
v16 = 6;
v22 = 0;
v10 = 0;
v12 = 0;
Cutecode((char *)&v20, &v8);
v17 = 0xA5B0ACAD;
v18 = 0xB0AAu;
v19 = 0;
Cutecode((char *)&v17, &v8);
v4 = *((_QWORD *)v1 + 1);
v5 = strlen(&v20);
v6 = strlen(&v17);
(*(void (__fastcall **)(__int64, __int64 *, _QWORD, int *, __int64))(*(_QWORD *)v4 + 232LL))(v4, &v20, v5, &v17, v6);
(*(void (__fastcall **)(cocos2d::ScriptEngineProtocol *, const char *))(*(_QWORD *)v1 + 104LL))(v1, "main.lua");
return _stack_chk_guard;
}
This is where the Lua engine is being initialized and prepared. This is also were the Lua file encryption is setup. Not all games use the same setup in this function so it'll be up to you to determine the layout of the function for your game.
In this case, the game uses the default XXTEA encryption setup built into Cocos2 which is setup using:
Code: Select all
virtual void setXXTEAKeyAndSign (const char *key, int keyLen, const char *sign, int signLen)
The key is the actual encryption/decryption key used for the file data, the sign is just a pattern added to the start of the file to let the engine know if that file should be decrypted using the set key/sign information.
For this game, that data is encrypted itself as well to prevent reading that data easily using those 'cuteCode' calls. Those are set up like this:
Code: Select all
char CutecodeChar(char c, int32_t key)
{
return ~(c ^ key);
}
void Cutecode(char* str, int32_t* key)
{
const auto len = strlen(str);
for (auto x = 0; x < len; x++)
*(str + x) = CutecodeChar(*(str + x), key[x % 5]);
}
The first block before the first Cutecode call is the 'Cutecode' key and the data to decrypt:
Code: Select all
v8 = 0;
v11 = 8;
v13 = 1;
v14 = 2;
v9 = 6;
v15 = 3;
v20 = 0xA9D3B6D3988A8BD1LL;
v21 = 0xDECEDC95A2DBD9CDLL;
v16 = 6;
v22 = 0;
v10 = 0;
v12 = 0;
Cutecode((char *)&v20, &v8);
IDA and Ghidra both output this data in the wrong order so be cautious of trusting the output given. Instead the key and data should be laid out like this:
Code: Select all
int32_t cuteKey[5]{0, 6, 0, 8, 0};
char cuteStr[]{0xD1, 0x8B, 0x8A, 0x98, 0xD3, 0xB6, 0xD3, 0xA9, 0xCD, 0xD9, 0xDB, 0xA2, 0x95, 0xDC, 0xCE, 0xDE};
Cutecode(cuteStr, cuteKey);
This will give us the XXTEA key of:
Code: Select all
.ruo,I*V:&$[j+1!
The second block can be decoded to get the sign, but that doesn't really matter but here is that:
Code: Select all
char cuteSign[]{0xAD, 0xAC, 0xB0, 0xA5, 0xAA, 0xB0, 0x00};
Cutecode(cuteSign, cuteKey);
Which gives back the sign: RUORUO
You can now decrypt this using any means of XXTEA, stepping over the 6 byte signature (RUORUO) at the top of the file. For the example file you gave, decrypted it is:
Code: Select all
cc.FileUtils:getInstance():addSearchPath('res/LuaScript/')
if cc.exports then
cc.exports.ccslog = function(...) end
else
ccslog = function(...) end
end
local luaExtend = {}
local function getChildInSubNodes(nodeTable, key)
if #nodeTable == 0 then
return nil
end
local child = nil
local subNodeTable = {}
for _, v in ipairs(nodeTable) do
child = v:getChildByName(key)
if (child) then
return child
end
end
for _, v in ipairs(nodeTable) do
local subNodes = v:getChildren()
if #subNodes ~= 0 then
for _, v1 in ipairs(subNodes) do
table.insert(subNodeTable, v1)
end
end
end
return getChildInSubNodes(subNodeTable, key)
end
luaExtend.__index = function(table, key)
local root = table.root
local child = root[key]
if child then
return child
end
child = root:getChildByName(key)
if child then
root[key] = child
return child
end
child = getChildInSubNodes(root:getChildren(), key)
if child then root[key] = child end
return child
end
return luaExtend
-
- Site Admin
- Posts: 12984
- Joined: Wed Jul 30, 2014 9:32 pm
Re: How to extract file .luac extention [Rich and Famous]
Very good, just made a script with the additional cutecode stuff:
http://aluigi.org/bms/cocos2dx_xxtea_cutecode.bms
http://aluigi.org/bms/cocos2dx_xxtea_cutecode.bms
-
- Posts: 250
- Joined: Sat Dec 27, 2014 8:49 pm
Re: How to extract file .luac extention [Rich and Famous]
Better off labeling the script specifically for this game. The CuteCode stuff and the keys used won't be the same for other games.
-
- Site Admin
- Posts: 12984
- Joined: Wed Jul 30, 2014 9:32 pm
Re: How to extract file .luac extention [Rich and Famous]
Oh ok. The title of the script is "Rich and Famous cocos2 setXXTEAKeyAndSign/cutecode lua decrypt" which is ok, but the script filename is already done.