This investigation attempted to decrypt the HTPX-encrypted global-metadata.dat and set up a cloud Android environment to run the White Out Survival XAPK for live traffic capture. Static decryption failed because HTPX uses a sophisticated position-dependent block cipher, but we discovered critical intelligence about the encryption system and identified viable cloud Android approaches for runtime decryption via Frida.
| Offset | Size | Value | Description |
|---|---|---|---|
| 0x00 | 4 | HTPX | Custom magic (replaces AF 1B B1 FA) |
| 0x04 | 4 | FC 30 94 00 | Original file size (9,711,868 bytes) |
| 0x08 | varies | Encrypted | 128-byte block encrypted data |
The HTProtect library (NetEase HTProtect, not just "N4tHTProtect") contains these potential encryption keys:
| Key String | Length | Context |
|---|---|---|
t76euy9fu8bv485zh | 17 | JNI interface parameter (with trailing 'h') |
hccd63688a790ca65 | 17 | JNIFactory identifier |
e9edd62242ad7aecf | 17 | Method signature area |
r316e12523620efb7 | 17 | Key storage area |
d0f149b4da6ec477 | 16 | Pure hex key |
f190da6241bff18bf | 17 | Key storage area |
r25d273c7ad4065c3 | 17 | Key storage area |
u233ace17d63ca9e | 16 | Pure hex key |
aebd1811194e82d9 | 16 | Pure hex key |
437ae92817f9fc85b7e5 | 20 | Extended key |
2be6951adc5b22410a5fd | 21 | Extended key |
Also found: 16 O0-obfuscated keys (e.g., O0O00o0o0o000OOo) and obfuscated string keys (e.g., ,4$8'9-6:.6$1#?*XhHpSeA~NrZlE)
The known HTProtect string table XOR key 0x56312342 was found at offset 0x0307a6f4 in libil2cpp.so. However, it's in the encrypted dynamic symbol table region, not as a standalone constant. This key is used for decrypting the ELF symbol/string tables after the SO is loaded, not for the global-metadata.dat encryption.
Java Interface:
com.netease.htprotect.factory.JNIFactory โ Native method factorycom.netease.htprotect.callback.HTPCallback โ Status callbackscom.netease.htprotect.HTProtectConfig โ ConfigurationNative Libraries:
libNetHTProtect.so (4.5 MB) โ Main protection engine with custom linkerlibhtpcrash.so (76 KB) โ Crash reporting/analyticslibhtpcrash_dumper.so (101 KB) โ Crash dump generatorProtection Layers:
| # | Service | Free Tier | XAPK | Frida | Traffic Capture | Best For |
|---|---|---|---|---|---|---|
| 1 | Genymotion SaaS | 60 min | โ ADB | โ | โ mitmproxy | Best overall |
| 2 | Appetize.io | 30 min/mo | โ Native .apks | โ | โ | App launch testing |
| 3 | Corellium | Trial | โ ADB | โ | โ | Best tech capability |
| 4 | AWS Device Farm | 1000 min | โ ADB | Limited | โ tcpdump | Automated testing |
| 5 | Redroid (Docker) | Free* | โ ADB | โ | โ | Long-term use |
| 6 | Firebase Test Lab | 20/day virtual | โ | โ | Limited | Quick tests |
| 7 | now.gg | Free | โ Pre-listed only | โ | โ | Playing only |
* Redroid requires a VPS with Docker + kernel binder module support (~$5-10/month)
# 1. Sign up at https://cloud.geny.io (free, no credit card)
# 2. Install CLI
pip install gmsaas
gmsaas auth login --email YOUR_EMAIL
# 3. Start Android 11 instance
gmsaas instances start --name wos --shape g2.8cpu.15gb.android11
gmsaas instances adbconnect wos
# 4. Install White Out Survival (split APK)
unzip wos_latest.xapk -d wos_xapk/
adb install-multiple wos_xapk/com.gof.global.apk \
wos_xapk/config.arm64_v8a.apk \
wos_xapk/game_asset.apk
# 5. Install Frida server
FRIDA_VER=16.1.4
curl -L -o frida-server.xz \
"https://github.com/frida/frida/releases/download/${FRIDA_VER}/frida-server-${FRIDA_VER}-android-arm64.xz"
xz -d frida-server.xz
adb push frida-server /data/local/tmp/frida-server
adb shell "chmod 755 /data/local/tmp/frida-server"
adb shell "/data/local/tmp/frida-server &"
# 6. Dump decrypted metadata
frida -U -f com.gof.global -l wos_frida_metadata_dump.js --no-pause
# 7. Hook sproto protocol
frida -U -f com.gof.global -l wos_frida_sproto_hook_v2.js --no-pause
# 8. Capture traffic with mitmproxy
pip install mitmproxy
mitmproxy --listen-port 8080
adb shell settings put global http_proxy YOUR_IP:8080
# 1. Sign up at https://appetize.io (free, email only)
# 2. Upload the merged APK via API
curl -X POST https://api.appetize.io/v1/apps \
-H "X-API-KEY: YOUR_TOKEN" \
-F "file=@whiteout_survival_merged.apk" \
-F "platform=android" \
-F "timeout=300"
# 3. Access in browser using the publicKey from response
# https://appetize.io/embed/PUBLIC_KEY?device=pixel6pro&osVersion=13.0
| File | Description | Size |
|---|---|---|
wos_frida_metadata_dump.js | Frida script to dump decrypted global-metadata.dat from memory | ~8 KB |
wos_frida_sproto_hook_v2.js | Frida script to hook sproto encode/decode in libtolua.so | ~6 KB |
wos_htpx_decrypt_toolkit.py | Python script with all static decryption attempts | ~7 KB |
wos_cloud_android_setup.sh | Step-by-step cloud Android setup guide | ~5 KB |
whiteout_survival_merged.apk | Merged APK (base + arm64 + assets) for cloud upload | ~1041 MB |
| Category | Count | Key Messages |
|---|---|---|
| NOTIFY (ServerโClient) | 78 | NOTIFY_PLAYER_POWER_UPDATE, NOTIFY_PLAYER_ACTIVITY_POWER_UPDATE, NOTIFY_STOVE_INFO |
| REQ (ClientโServer) | 132 | REQ_PLAYER, REQ_CENTER_RANK, REQ_SHOP_BUY, REQ_HERO_PROMOTE |
TCP Frame: [2B length BE][1B type][payload]
Type 0x00 REQUEST: [4B session_id][4B proto_id][sproto_packed_data]
Type 0x01 RESPONSE: [4B session_id][sproto_packed_data]
Type 0x02 NOTIFY: [4B proto_id][sproto_packed_data]
sproto Field Header (2 bytes, big-endian):
High byte = field number (1-based)
Low byte encoding:
0x00 โ next 4 bytes = int32
0xFF โ next 8 bytes = int64
0x01-7F โ inline value
0x80 โ length in next 2 bytes
0x81-FE โ length = low & 0x7F
sproto Pack (zero-byte compression):
16-byte chunks: [2B bitmap LE][non-zero bytes]
Bitmap bit[i]=1 โ byte present; bit[i]=0 โ byte is zero
| Type | Fields | Notes |
|---|---|---|
power_rank | id, abbr, gflag, __bg, leader, uid, language, power_rank | Alliance/player ranking data |
soldier_map | id, quality | Battle unit mapping |
hero_map | id, star, lev, name, power/Score, abbr | Hero data dictionary |
powerFight | pve, slg_skill_id, Reset, Helper, leader_type | Combat power calculation |
adb install-multiplewos_frida_metadata_dump.js to dump decrypted global-metadata.dat from memorywos_frida_sproto_hook_v2.js to capture live protocol traffic| Secret | Value | Usage |
|---|---|---|
| Web Sign Key | UxXkyv4g9nmvK8gP | MD5 signing for web API requests |
| Gift Code Salt | tB87#kPtkxqOS2 | Gift code validation signing |
| AES-192 Key | Jm93LUl9xqWd/1Ar+7QXeApCZw== | Data encryption key |
| Test Player | ID 250893802 | Nickname "FADL2", State 2007, Furnace Lv31 |
This investigation is for authorized security research purposes only. All findings are reported to Century Game engineering.