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.
Zero Tolerance for Disrespect

"IronFall: Invasion" Nintendo 3DS Custom Format and Engine.

Featured Replies

This is a game on the Nintendo 3ds written entirely in Assembly, 100% Custom bin encryption and custom Engine. No normal 3DS tool is able to recognize the format. It does not seem to have a header or "Magic bytes". I have worked on this for weeks, nothing. It does seem like some of the files are JSON format, just renamed to bin. I have linked a few files in this post. Every file can be found here: https://drive.google.com/drive/folders/1FhBMNJjLVHPhdhauYx8xIBJ57fXQDAeI?usp=sharing

Some.zip

  • 1 month later...
  • Localization

Took a deep dive into the sample archive you provided.

First off, to address the initial assumption: these files are not encrypted as a class.

Most of the .bin files are standard little-endian serialized C++ object graphs and raw PICA200 texture payloads without headers. A specific subset is indeed whitened/encrypted, but the rest of the game's data is completely readable once you know the container layout.

Here is a full breakdown of the formats, how they work, and working extraction/repacking tools.


1. Forensics & Triage (Debunking the "100% Encrypted" Claim)

A quick triage checking Shannon entropy vs. delta entropy (entropy of b[i] ^ b[i+1]) and byte distribution makes the structure immediately clear:

File

Entropy

Delta Entropy

Zero Bytes

Verdict

Text_English.bin

4.38

5.87

42.8%

Structured table

GameConstant.bin

3.13

4.32

63.4%

Structured (float/int table)

Material_Test.bin

1.59

1.73

79.7%

Structured object graph

etc_logo.bin

1.92

1.68

60.7%

Raw block data

Mesh_Test.bin

6.30

7.22

22.1%

Structured geometry

Level_Test.bin

7.18

7.74

< 5%

Whitened / Encrypted

Level_BarrageMulti.bin

7.24

7.82

< 4%

Whitened / Encrypted

Encrypted ciphertext exhibits delta entropy around 8.0 and a flat byte distribution. Files like Text_English.bin (delta 5.87, over 40% zero bytes) or etc_logo.bin are entirely unencrypted. Furthermore, human-readable strings like CMeshId_ExitFlash, LightId_Decor_000, and dependency paths like rom:/SkinMesh/Hero/SkinAnim_Hero_AttenteCockpitArriere.bin are visible in plain ASCII.


2. Text_English.bin (Fully Decoded + 1:1 Byte-Exact Repacker)

The text archive contains 1,178 localized strings. It does not use standard ASCII/UTF-8 directly; instead, glyph indices are stored with a constant offset shift:

  • Container layout:

u32 count                         // 1178 strings
u32 offsets[count]                // Absolute record offsets
// data base = 4 + (4 * count)    // 4716
Record:
  u32 keyRel                      // (recordStart - base) + 4 + 2*ncodes (points to key string)
  u16 codes[ncodes]               // Glyph stream (terminated by 0xFFFF)
  char id[]                       // Null-terminated ASCII key
  padding                         // Aligned to 4 bytes
  • Glyph stream header:
    The first 6 u16 values inside codes[] act as per-string metadata:

    • [0] style: 255 = dialog/subtitles, 0..3 = control scheme variants, 511 = item/system names

    • [1] speaker: 255 = none, 0/1/2 = character slot

    • [2] always 0

    • [3] glyphCount: verified matches exact string length (1178 / 1178 records)

    • [4] metric: layout/timing hint (0 for UI, >0 for subtitles)

    • [5] always 0

  • The encoding:

    • Standard dialog (style != 511): Unicode = code + 30

    • Item names / system text (style == 511): Unicode = code + 32

    • In-stream control codes: 0xFFFF = End of string, 0xFFFE = line break (\n), 0x0001 = page break.

Verification: Extracting the entire text database and rebuilding it produces an output 100% byte-identical to the original file (cmp clean).


3. Textures & Materials (etc_*.bin & Material_<level>.bin)

The reason texture files do not have magic bytes or headers is because their header is external: it lives inside the corresponding Material_*.bin file!

  • Texture metadata table (starts at toff in the material header, 156-byte stride):

    • +0: char[96] Payload filename

    • +97: u8 Format (12 = ETC1, 13 = ETC1A4)

    • +98: u16 Width

    • +100: u16 Height

    • +102: u8 Mip levels (halvings = value + 1)

    • +103: u8 Flag (0 = raw payload, 1 = trailer payload)

  • Byte size rule:
    Every clean texture payload on disk perfectly matches:
    Total Size = Sum of all mip levels [ ceil(W/4) * ceil(H/4) * 8 * (1 if ETC1 else 2) ]
    (e.g., etc_logo 256x256 ETC1 mip 4 = exactly 43,648 bytes).

  • PICA200 Swizzle:
    Blocks are arranged in 2x2 block (8x8 pixel) tiles in standard raster order. UI and HUD textures (etc_logo, etc_divers, etc_divers normal, etc_neutre normal) decode cleanly into PNG/DDS with sharp text, gauges, and reticles.


4. Structural Assets (Light, Mission, GameConstant, Mesh)

  • Light_*.bin: 240-byte records containing RGBA intensity, truncated s16 coords, float32 world transforms (f32[3]), and ASCII IDs (LightId_Decor_000).

  • GameConstant.bin: Flat array of 4-byte values (floats and gameplay ints) followed by animation state identifiers (AttenteCockpitAvant, TrouveArme, etc.).

  • Mission_*.bin: Level load lists and dependency tables with 163 rom:/ paths and object IDs.

  • Mesh_Test.bin: First two u32 integers add up to the exact file size (1560 + 13320 = 14880). Object graph definitions up to ~0x610, followed by float vertex streams and a u16 index buffer at the end.


5. What IS Protected (The Encrypted Subset)

Only a specific subset is protected:

  1. Geometry/Level blobs: Level_Test.bin, Level_BarrageMulti.bin

  2. Shadow maps: ShadowMap/etca_Shad l0 salle_001.bin

  3. 6 photographic surface textures: etc_sol, etc_porte, etc_rouge, etc_jaune, etc_plafond blanc (+normal)

Evidence:

  • Flat byte histogram, but the file length is strictly equal to the uncompressed size (or matches declared dimensions). No compression padding.

  • Level_*.bin and ShadowMap contain an 8-byte trailer at EOF:
    [u32: filesize | (method << 24)] followed by [u32: decompressed_size].

  • Standard compression (zlib, gzip, bzip2, lzma, 3DS LZ11/LZSS) and trivial byte/XOR transforms have been tested and ruled out. This is a custom cipher or whitening routine.


6. Tools

I wrote a small Python toolchain to handle extraction, repacking, and inspecting:

  • ifall_text.py: Extracts Text_English.bin to TXT/JSON and repacks it byte-identically. Supports arbitrary string lengths.

  • ifall_tex.py: Resolves Material_*.bin metadata and batch-converts raw ETC1/ETC1A4 payloads to PNG and uncompressed RGBA DDS.

  • ifall_struct.py: Dumps Materials, Lights, Missions, Constants, and Mesh identifiers to clean JSON.

  • picatex.py: Standalone PICA200 ETC1/ETC1A4 tile & swizzle decoder library.

(Tool scripts are attached to this post).


Next Step for the Protected Files:

To defeat the cipher on the Level_*.bin files and the 6 surface textures, we need the game executable (code.bin / decompressed ExeFS or .cro modules). The loader function that parses the 8-byte trailer and decrypts the payload in ARM assembly will give away the algorithm and key in a few minutes.

If you can dump and share the decrypted code.bin, I can reverse the decryption routine and finish the remaining formats.

IronFall_tools.zip

Create an account or sign in to comment

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.