fix: decode Fire Kirin obfuscated native assets - #35
Open
babyRess wants to merge 2 commits into
Open
Conversation
Cocos 2.4 builds served by the Fire Kirin platform prepend an obfuscation header to native binary assets. cc-reverse copied those bytes verbatim, so recovered PNG/JPEG/MP3 files were unusable (file(1) reports "data"). The prefix is present in the server-delivered bytes, not introduced by cc-reverse. The algorithm is taken from the game's own loader (CommLoading/downLoadPlugin.js), which uses two markers and two code paths: "@@@adw@@@%%" (11 bytes) "Gj&e5/S%*z]~)i!O`r" (18 bytes) Images travel the blob path and are header-stripped only; the 18-byte marker carries an additional 74-byte pad. Audio and other binaries travel the arraybuffer path and are additionally XOR-decrypted -- constant 1 for the first marker, a 16-byte rotating key for the second. Unmarked input is returned byte-identical, so non-obfuscated projects are unaffected.
Covers the full scheme x loader-path matrix: 11-byte marker, image/blob -> strip 11 11-byte marker, arraybuffer -> strip 11 + XOR 1 18-byte marker, image/blob -> strip 18 + 74 18-byte marker, arraybuffer -> strip 18 + rotating-key XOR The roundtrip suite builds a real, minimal, valid PNG in-code (zlib deflate plus a hand-rolled CRC32), obfuscates it under each scheme, decodes it back, and asserts byte-exact equality plus independent re-parse via image-size -- so the image branches are proven to yield a decodable artifact, not merely correct prefix arithmetic. The rotating-key fixture exceeds 16 bytes so key wraparound is exercised. All fixtures are synthetic. No game assets are vendored into the repo.
babyRess
marked this pull request as ready for review
August 7, 2026 11:36
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Cocos Creator 2.4 builds served by the Fire Kirin platform prepend an obfuscation
header to native binary assets. cc-reverse copies those bytes verbatim, so recovered
PNG/JPEG/MP3 files are unusable —
file(1)reportsdata, and neither an imagedecoder nor Cocos Creator will open them.
The prefix is present in the bytes the server delivers; it is not introduced by
cc-reverse. cc-reverse simply has no notion of it.
Observed on a real capture: 57 of 59 images and 129 of 129 audio files were
unreadable after recovery.
Algorithm
Taken from the game's own loader (
CommLoading/downLoadPlugin.js), not reverse-guessed.Two markers, two code paths:
1The
+74pad on the image path is empirically derived — it is what the loader does,and it holds across all 167 marker-B images in the sample, but I do not know why it
is 74. Flagging that honestly rather than implying it is understood.
Unmarked input is returned byte-identical, so non-obfuscated projects are unaffected.
Scope of this PR
This PR adds the decoder module and its tests only. The module is inert: it
exports a pure byte transform and is not wired into any pipeline here. Nothing in
cc-reverse's behaviour changes until a caller invokes it deliberately.
The obfuscation is Fire Kirin-specific, not a general Cocos feature. Integration
into the recovery pipeline is deliberately kept out of this PR; in my downstream branch
it sits behind an explicit
--deobfuscate fire-kirinflag, with detection reported butnever silently applied. Happy to follow up with that wiring if you want it in-tree.
Verification
obfuscate it under each scheme, decode it back, and assert byte-exact equality plus
independent re-parse via
image-size. So the image branches are proven to produce adecodable artifact, not merely correct prefix arithmetic.
Notes for review
zlibis a Node built-in;image-sizewas already a dep).deobfuscateAsset(buffer, ext)returns{ data, scheme }so callers can reportwhat happened rather than guess.