0

I am currently learning how to reverse engineer an APK and have made significant progress. Here’s what I've accomplished so far:

  1. Decryption & Code Browsing: Converted the Dalvik bytecode (.dex files) to readable Java and JavaScript code.
  2. Unbundling: Unbundled the decrypted JavaScript files. (Though they are still minified)
  3. UUID Decryption: Figured out how to decrypt UUIDs into filenames and vice versa, and found resource paths for some UUIDs.

However, I’m stuck on figuring out the correct folder structure for certain assets within the "Main" folder.

What I’ve Discovered So Far

Here’s what I know about the asset packs in the "Main" folder:

  • Each asset pack has a UUID, which corresponds to an image containing multiple assets.
  • There is a JSON file for each asset pack, but these don't provide much useful information regarding the folder structure.
  • Each asset in the image has its own JSON file that includes:
    • The pack name near the beginning.
    • Details about the asset's position in the image.
  • The manifest contains every asset's location, but only assets listed in /resources/config.json have "paths" to help re-map them.

My Questions

  1. How can I determine the correct folder structure for these assets?
  2. Is there a pattern or tool that can help map these assets to their appropriate locations?

Important Note: There is NO map file - the manifest lists the obfuscated names and their md5 or sha-256 depending on which one you look at, My goal is to reverse engineer back to the original format that the code references.

Code Samples & Structure

I’ve included some relevant code snippets and file structure details to illustrate what I’m working with:

Example config.json (UUIDs without paths):

{
    "paths": {},
    "types": [],
    "uuids": [
        "05mU7WsllFO4elu4Re6/pm",
        "fcTsdoxZlLpKd3It99/+h6"
    ],
    "scenes": {
        "db://assets/main.fire": 127,
        "db://assets/start.fire": 120
    },
    "redirect": [1, 0, 2, 0, 4, ... 0, 146, 0],
    "deps": ["resources", "internal"],
    "packs": {},
    "name": "main",
    "importBase": "import",
    "nativeBase": "native",
    "debug": false,
    "isZip": false,
    "encrypted": true
}

Example of Bundled Code Before Unbundling:

(but you can see the bottom section provides a filestructure / names for the bundles, which is how I reverse engineered and unbundled it)

{
    1: [function(e, t, i) {
        "use strict";
        const n = i;
        n.bignum = e("bn.js");
        n.define = e("./asn1/api").define;
        n.base = e("./asn1/base");
        n.constants = e("./asn1/constants");
        n.decoders = e("./asn1/decoders");
        n.encoders = e("./asn1/encoders");
    }, {
        "./asn1/api": 2,
        "./asn1/base": 4,
        "./asn1/constants": 8,
        "./asn1/decoders": 10,
        "./asn1/encoders": 13,
        "bn.js": 15
    }],

File Structure

Here’s a partial view of the file structure I’m working with:

Directory: T:\assets
  Subdirectory: ad-viewer
  Subdirectory: assets
  Subdirectory: dexopt
  Subdirectory: jsb-adapter
  Subdirectory: src
  File: audience_network.dex
  File: cid
  File: main.js
  File: project.json
  File: tt_mime_type.pro

Directory: T:\assets\assets
  Subdirectory: internal
  Subdirectory: localizeData
  Subdirectory: main
  Subdirectory: manifest
  Subdirectory: resources
  Subdirectory: Script

Directory: T:\assets\assets\internal
  Subdirectory: import
  Subdirectory: native
  File: config.json
  File: index.js

Directory: T:\assets\assets\internal\import
  Subdirectory: 09

Directory: T:\assets\assets\internal\import\09
  File: 0967b326a.json

Directory: T:\assets\assets\internal\native
  Subdirectory: 02

Directory: T:\assets\assets\internal\native\02
  File: 0275e94c-56a7-410f-bd1a-fc7483f7d14a.png

Directory: T:\assets\assets\localizeData
  File: config.json
  File: index.js

Directory: T:\assets\assets\main
  Subdirectory: import
  Subdirectory: native
  File: config.json
  File: index.js

Directory: T:\assets\assets\main\import
  Subdirectory: 05
  Subdirectory: 06
  Subdirectory: 08
  Subdirectory: 12
.....
Directory: T:\assets\assets\manifest
  Subdirectory: import
  Subdirectory: native
  File: config.json
  File: index.js

Directory: T:\assets\assets\manifest\import
  Subdirectory: 83

Directory: T:\assets\assets\manifest\import\83
  File: 83f57686-53e5-4bc7-bdf0-33bcd506f93b.json

Directory: T:\assets\assets\manifest\native
  Subdirectory: 83

Directory: T:\assets\assets\manifest\native\83
  File: 83f57686-53e5-4bc7-bdf0-33bcd506f93b.manifest

Directory: T:\assets\assets\resources
  Subdirectory: import
  Subdirectory: native
  File: config.json
  File: index.js

Directory: T:\assets\assets\resources\import
  Subdirectory: 00
  Subdirectory: 01
  Subdirectory: 02
....
Directory: T:\assets\assets\Script
  Subdirectory: import
  File: config.json
  File: index.js

Directory: T:\assets\assets\Script\import
  Subdirectory: c8

Directory: T:\assets\assets\Script\import\c8
  File: c85c3dbd-5a7d-424c-8e07-965706736336.json

Directory: T:\assets\dexopt
  File: baseline.prof
  File: baseline.profm

Directory: T:\assets\jsb-adapter
  File: jsb-builtin.js
  File: jsb-engine.js

Directory: T:\assets\src
  Subdirectory: assets
  File: cocos2d-jsb.js
  File: settings.js

Directory: T:\assets\src\assets
  Subdirectory: libs

Directory: T:\assets\src\assets\libs
  File: thinkingdata.mg.cocoscreator.min.js

Specific Asset Example

  • Asset pack UUID: 1e58fbfa7
    • Image file: assets\assets\main\native\1e\1e58fbfa7.png
    • JSON file: assets\assets\main\import\1e\1e58fbfa7.json JSON Contents:
[
    1,
    0,
    0,
    [
        "cc.Texture2D"
    ],
    0,
    [
        "0,9729,9729,33071,33071,0,0,0",
        -1
    ],
    [
        0
    ],
    0,
    [],
    [],
    []
]

Traceback

I search for that string (1e58fbfa7) in all files and find a matching JSON for each of the assets on that image, here is an example of one: (I do understand what these are - they are stating where the asset that relates to that file / UUID is on the pack)

[
    1,
    [
        "1e58fbfa7"
    ],
    [
        "_textureSetter"
    ],
    [
        "cc.SpriteFrame"
    ],
    0,
    [
        {
            "name": "UI_Bt_world",
            "rect": [
                342,
                446,
                127,
                115
            ],
            "offset": [
                0,
                0.5
            ],
            "originalSize": [
                129,
                116
            ],
            "capInsets": [
                0,
                0,
                0,
                0
            ]
        }
    ],
    [
        0
    ],
    0,
    [
        0
    ],
    [
        0
    ],
    [
        0
    ]
]

That JSON is \assets\assets\main\import\3a\3aa50555-73a6-416d-b35a-cfab79466fa7.json

If I convert that to a UUID (3apQVVc6ZBbbNaz6t5Rm+n) I will find it in two locations, config.json (snippet provided above) and another location (\assets\assets\main\import\9f\9fde386a-2232-446d-9554-549e101dde19.json) which is somewhat similar to the config.json, but not quite... snippet:

[
    1,
    [
        "ecpdLyjvZBwrvm+cedCcQy",
...
    [
        "node",
        "_spriteFrame",
        "_N$file",
...
   [
        [
            "cc.Node",
            [
                "_name",
...
               "_children"
            ],
            -2,
            4,
...
                ]
            ],
            [
                0,
                "58H6b2PPdJip4dKNTXDv0T",
                1,
                0
            ],
            [
                4,
                4278190080
            ],
            [
                5,
                1242,
                2688
            ]
        ]
    ],
    0,
    [
        0,
        12,
...
        96,
        97,
        1
    ]
]

I convert that file name into a UUID (9f3jhqIjJEbZVUVJ4QHd4Z) and find it in yet another file (\assets\assets\main\import\d7\d726ed83-41aa-4389-bd34-dd1e963ba515.json)...

[
    1,
    [
        "9f3jhqIjJEbZVUVJ4QHd4Z"
    ],
    [
        "mainNode",
        "node",
        "scene"
    ],
    [
        [
            "cc.SceneAsset",
            [
                "_name",
                "asyncLoadAssets"
            ],
            1
        ],
        [
            "cc.Scene",
            [
                "_name",
...
    [
        0,
        -1,
        2,
        0,
        1,
        2,
        0,
        2,
        1,
        2
    ],
    [
        0
    ],
    [
        0
    ],
    [
        0
    ]
]

I went even deeper, converted that file name to a UUID (d7Ju2DQapDib003R6WO6UV) and looked and found it in one location.... the original config file. So now I'm back to the beginning!

1 Answer 1

0

It sounds like you’re making impressive progress with your reverse engineering efforts. You’re stuck at reconstructing the folder structure of the assets, and this can indeed be tricky. However, based on the patterns you’ve discovered, we can attempt to create a strategy to reverse the structure:

Strategy for Determining the Folder Structure

  1. Analyze UUID Relationships:
  • You’ve identified that UUIDs correspond to both asset packs and individual assets. By converting these UUIDs back and forth between JSON files and their image counterparts, you have already managed to trace some dependencies.
  • To move forward, it’s important to explore any hierarchical relationships between these UUIDs. For example, when an asset UUID appears in a JSON file, check how it references other assets and their corresponding files. This often gives hints about the structure, such as child/parent relationships.
  1. Use the Asset Pack Information (e.g., “rect”, “offset”, “originalSize”):
  • The metadata in the JSON files, particularly fields like "rect", "offset", and "originalSize", gives clues about how assets were packed into a texture atlas. If certain assets are packed together (as indicated by shared UUIDs or proximity in the texture), they may belong in the same folder or share a common prefix in the file structure.
  • Pattern Recognition: Look for patterns in asset metadata to determine if they relate to certain parts of the game. For example, UI elements might share common characteristics, which could suggest they belong in a UI folder.
  1. Path Reconstruction from Known UUIDs:
  • Since some assets in the config.json have paths, you can use these as a starting point for the folder structure. For example, assets related to specific game scenes like "db://assets/main.fire" might reside in the assets/main folder.
  • Use the assets that have paths as “anchors” and attempt to match their structure to the UUIDs that don’t yet have paths. You can cross-reference these with their relationships in the JSON files.
  1. Examine Obfuscated Names and Hashes (MD5 or SHA-256):
  • The manifest contains MD5 or SHA-256 hashes of asset files. These are likely computed from the file contents, filenames, or paths. While it’s difficult to reverse these directly, you might observe patterns between the hashes of similar assets (e.g., UI elements, textures).
  • You could attempt to compute hashes of certain path combinations and compare them against the values in the manifest to reconstruct parts of the folder structure.
  1. Folder Structure from Resource Metadata:
  • The "packs": {} section of config.json indicates grouping of certain assets. Investigate if these groupings follow a consistent naming convention or folder hierarchy.
  • Check if there are any consistent prefixes or suffixes in the UUIDs or paths for assets that should belong in the same folder (e.g., textures, models, sounds). This could provide insights into how folders should be organized.

Tools & Techniques to Help

  1. Automated Dependency Trackers:
  • Tools like Unity Asset Bundle Extractor (even if you’re not working with Unity, these tools might help interpret textures and packed assets) or APK reverse-engineering tools like JEB could help in further automating the analysis.
  • You might use a script (e.g., Python) to recursively trace dependencies through the JSON files, reconstructing the relationships between assets and helping generate a potential folder structure.
  1. Cross-reference UUIDs and Hashes:
  • Consider generating a script to extract UUIDs and their corresponding asset data (e.g., position in atlas, size, type) and then attempt to sort them into potential folder structures based on their metadata. As you process more files, patterns should emerge.
  1. Visualization of Assets in Texture Atlases:
  • Visualizing the rect coordinates and asset positions on the texture atlas might help you guess at the logical grouping of assets. If you can map assets spatially, it might reveal clues about folder structure (e.g., UI elements packed closely together).
  • Tools like Texture Packer can be used to visualize texture atlases and help you identify how the assets are grouped.

Additional Steps to Consider

  • Recursive Conversion of UUIDs: You’ve done this manually, but consider writing a script to automate the process of recursively converting UUIDs and tracing the connections between assets. This can speed up the process of identifying groupings and dependencies.
  • Guess the Original Folder Structure: For assets you can’t place definitively, consider trying common folder structures used in game development (e.g., UI, Textures, Audio, Scenes, Scripts) and see if these align with any of the UUID patterns or JSON relationships.
  • Test Iterations: Once you’ve mapped out a possible structure, you could attempt a test reorganization and see if it matches what’s expected in the execution of the app, based on the decompiled JavaScript code.

With these strategies, you should be able to progress further in reconstructing the original asset structure from the obfuscated files.

1
  • This reads like its written by chatgpt
    – sudhackar
    Commented Nov 7 at 11:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.