PPM packaging and acceptance

Separate the emitted body, 0x90-byte package trailer, and original file acceptance checks.

Serialisation, packaging and opening a file are three different stages in the original program. The serialiser builds a PPM body; the package bridge appends a reserved trailer; an input handler later decides whether the buffered bytes are acceptable. A parser that displays frames has proved only its own decode path, not that the original application would accept the file. Addresses below are loaded ARM9 addresses for the named build. [1][2][3]

BuildPackage bridge (112 bytes)Buffered input handler (200 bytes)Input validator (68 bytes)
JP V10201CD440201D5B00201D2F0
JP V202020E70020216DC0202141C
US V2020209280202119402020ED4
EU V202020AB00202131C0202105C

The package descriptor

The bridge takes a staging pointer and its body size. It places four words on the stack: source pointer, source size, source pointer plus size, and output capacity 0x90. The output begins at the end of the staged body. After Open, Apply and Close service calls, the bridge reports size + 0x90. The trailer is distinct from the 0x90-byte author metadata near file offset 0x10; the equal sizes are a source of mistaken offset calculations. [1]

The observed bridge does not fully propagate failure from Open or Apply. In a zero-context case, Apply can still attempt a context-relative write rather than returning a clean error. Its output area is cleared before a digest and operation provider run. These observations explain the staging margin and call order, but they do not establish that every reported output contains a valid signature or that arbitrary files can be signed. [1]

Buffered acceptance starts after transport or reading

The 200-byte input handler receives bytes that have already been downloaded or read into a shared buffer. It rejects totals shorter than 0x90, then treats the preceding bytes as body and the final 0x90 as trailer. The validation route uses a digest and public-key material from a system-provided ARM9i copy. A second branch compares an SD path with a formatted record in the payload. These checks can fail independently; neither a plausible filename nor a good decoder display substitutes for the whole acceptance path. [2][3]

SD path comparison is narrow

The observed path matcher accepts a path that does not contain sdmc: without doing its SD-name comparison. For an SD path it requires a final slash, formats an 18-byte record beginning at payload +0x78, and compares from character +1 of the formatted name against character +2 after the slash. Thus the leading characters do not participate in that particular comparison. This describes the operands compared by that branch. It does not establish that the author ID is genuine. [2]

What the evidence can and cannot prove

  • Original instruction bounds, call operands and regional addresses for the packaging and input functions were checked against the studied binaries. [1][2]
  • Focused fixtures verified selected control-flow, error and operand cases. They did not verify a real Nintendo signature, original hardware timing or every possible file. [2]
  • The public verification container is available to original code, but the research does not supply private signing material or claim a general-purpose original signing workflow. [1][2]
  • The library scan decides which candidate paths to inspect; the save worker decides when a newly built file reaches storage. [3]

Sources

  1. [1] Flipnote Decompilation Project — PPM container and original serialisation
  2. [2] Flipnote Decompilation Project — Saving, loading and library indexing
  3. [3] Flipnote Decompilation Project — Coverage and limits

← All documentation