Skip to content
View in the app

A better way to browse. Learn more.

ResHax

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.
Help us keep the site running.

How to extract file .luac extention [Rich and Famous]

Featured Replies

  • Author
  • Localization

aluigi, posted Tue Apr 14, 2020 11:04 am (55910)


What's the name of the game?
That file is obfuscated, no idea how.
  • Author
  • Localization

Maboyz59, posted Tue Apr 14, 2020 12:54 pm (55922)


aluigi wrote:
What's the name of the game?
That file is obfuscated, no idea how.


name the game is "rich and famous"
  • Author
  • Localization

atom0s, posted Thu Apr 16, 2020 11:03 pm (56003)


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__module

Follow references to those and you should eventually find a function that looks something like this:
Code:
__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:
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:
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:
  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:
    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:
.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:
    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:


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
  • Author
  • Localization

atom0s, posted Fri Apr 17, 2020 9:00 pm (56041)


Better off labeling the script specifically for this game. The CuteCode stuff and the keys used won't be the same for other games.
  • Author
  • Localization

aluigi, posted Sat Apr 18, 2020 2:21 pm (56061)


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.
Guest
This topic is now closed to further replies.

Account

Navigation

Search

Search

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.