I am currently learning how to reverse engineer an APK and have made significant progress. Here’s what I've accomplished so far:
- Decryption & Code Browsing: Converted the Dalvik bytecode (.dex files) to readable Java and JavaScript code.
- Unbundling: Unbundled the decrypted JavaScript files. (Though they are still minified)
- 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
- How can I determine the correct folder structure for these assets?
- 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:
- Image file:
[
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!