Oninit® Forensic Tools — ondebug CLI
ondebug is a single-file C front-end over the ondebug library, modelled after the Oninit reference tools ondump and onpatch. One invocation reads one encrypted page from a chunk file and emits the plaintext — either as a hex dump on stdout or as raw bytes to a file. With -w it also patches a single plaintext byte and writes the re-encrypted page back to the chunk in place.
Usage
ondebug -P <page_index> [-C <chunk_id>] [-p <page_size>]
[-O | -x | -o <out.bin>
| -w --row <hex> --col <hex> --value <hex>
| -w --offset <hex> --value <hex>] <chunk_file>
# alternative key-material forms (no SEK file required at decrypt time):
ondebug --keystore <base> --dbsnum <N> -P <page_index> … <chunk_file>
ondebug --mek <file> --dbsnum <N> -P <page_index> … <chunk_file>
# minimal form when $INFORMIXDIR is set (keystore + dbsnum auto-detected):
ondebug -P <page_index> -C <chunk_id> <chunk_file>
The standard read invocation reduces to the page address (-P / -C) and the chunk file. Page size auto-detects by decrypting page 1 at each candidate size and validating the post-decrypt storage-identity stamp; the cipher and mode default to Informix EAR's values. Each can be overridden when the situation calls for it.
Flags
- -P N — logical page index in the chunk (required). Numeric argument; accepts hex (0x…), decimal, or octal.
- -C N — chunk_id (default 0). Numeric, hex / decimal / octal.
- -p N — page size in bytes (must be a positive multiple of 16). Optional; defaults to auto-detection by decrypting page 1 at each candidate size (2048, 4096, 6144, 8192, 16384) and validating the post-decrypt storage-identity stamp (page index in bytes 0..3, chunk id in bytes 4..5). Pass explicitly when the chunk file contains fewer than two pages, or when the SEK or chunk_id is wrong — in those cases auto-detect fails by design rather than locking onto a wrong size.
- -O — oncheck-format pretty-print (header line, slot table, slot bodies) instead of a flat hex dump. See the Examples page for output.
- -o FILE — write raw plaintext bytes to FILE.
- -x — force hex dump to stdout. The hex dump format includes a column-index header row (00 01 02 … 0f) so each byte is addressable as row R, col C.
- -w — patch mode: decrypt the page, splice one
plaintext byte at the addressed position, re-encrypt the page,
and pwrite the new ciphertext back to the chunk file in place.
Required companion long options:
- --value <hex> — the byte to write (00..ff). Always required when -w is set.
- --row <hex> + --col <hex> — matrix-form addressing. Row is a hex byte offset, 16-byte aligned, copied straight off the column header in the hex dump; col is 0..f within that row.
- --offset <hex> — flat byte offset within the page. Mutually exclusive with --row + --col.
Key material flags
For invocations that read the live keystore directly (instead of the default cached-SEK lookup — see the Examples — reading page §"Key material" for the two flows side-by-side):
- --keystore <base> — keystore base path, with no .p12 / .sth suffix (e.g. /home/informix/live/etc/db_keystore). When set, ondebug reads the key from the live keystore in-process, so no separate key file is required at decrypt time. Optional when $INFORMIXDIR is set — if omitted, ondebug reads $INFORMIXDIR/etc/$ONCONFIG's DISK_ENCRYPTION line and auto-discovers the keystore path. Mutually exclusive with --mek.
- --mek <file> — supply a 32-byte key file directly instead of reading the keystore. Useful when the keystore isn't accessible at decrypt time but the key is (key-escrow handover, prior-engagement capture). Requires --dbsnum; mutually exclusive with --keystore.
- --dbsnum N — target dbspace number (1..65535). Tells ondebug which dbspace's key to use. Optional in keystore / MEK mode: if omitted, ondebug reads the rootdbs chunk descriptor table (path from $ONCONFIG's ROOTPATH) and matches the target chunk file's basename to pick the owning dbspace number automatically. Pass explicitly when auto-detect fails (e.g. chunk file renamed, operating on a chunk not in the rootdbs descriptor table). The operator looks this up via onstat -d's number column.
Crypto-context overrides (rarely needed)
- -c NAME — cipher: aes128, aes192, or aes256 (default aes256, matching Informix EAR).
- -m NAME — mode: ecb, cbc, ctr, gcm, xts, or cfb (default cfb, matching the empirically-observed EAR transform — see Phase C Findings).
Exit codes
- 0 — success.
- 1 — I/O or library error (chunk file unreadable, SEK length wrong for cipher, mode/cipher not implemented, short read).
- 2 — usage error (missing required flag, bad numeric).
Output format
With -o FILE, the page's plaintext bytes are written to FILE verbatim (exactly page_size bytes).
Without -o, the page is hex-dumped to stdout in the standard 16-bytes-per-row format with a column-index header (00 01 02 … 0f), the row offset prefix, and an ASCII gutter:
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f
00000000 36 00 00 00 04 00 e1 1b 02 00 01 00 e8 00 0c 07 |6...............|
00000010 00 00 00 00 00 00 00 00 00 00 00 01 49 6e 66 6f |............Info|
00000020 72 6d 69 78 20 69 73 20 70 75 72 65 20 64 65 61 |rmix is pure dea|
…
The header row makes a byte position addressable as row R, col C — e.g. the page-header nslots field at row 0x00, col 08–09 reads as 0x0002.
With -w, no stdout output is produced — the page is modified on disk in place. A confirmation line goes to stderr:
ondebug: patched chunk=4 page=54 offset=0x32 (row=0x30 col=0x2): 0x62 -> 0x42
Subcommands
The default mode (page decrypt + optional patch, documented above) is the unnamed primary invocation. ondebug also accepts named subcommands for operations that don't fit the per-page read/write model.
rm-dbspace — offline dbspace removal
ondebug rm-dbspace --dbsnum <N> [--apply] [--backup] <rootdbs>
- --dbsnum N — target dbspace number to remove. Required. Rootdbs (dbsnum 1) and the physical-log dbspace are refused; other dbspaces are accepted.
- --apply — without this flag ondebug prints the planned edit and exits without writing (dry-run). With --apply the edit is committed to the rootdbs image file.
- --backup — write a timestamped pre-edit backup before the --apply write. Required to combine with --apply; ondebug rejects --apply without --backup to keep a rollback path on disk.
- <rootdbs> — path to the rootdbs chunk file. The engine MUST be offline; editing rootdbs while the engine has it open invites torn writes.
See Examples — dropping a dbspace for the full worked run.
unload-page — readable dump of one page
ondebug unload-page -P <page_index> [-C <chunk_id>] [-p <page_size>]
[--unload-to <path>] <chunk_file>
Read-only render: decrypts the page, prints its slot table (always), and prints each slot's body in oncheck-format hex+ASCII when the page is a DATA page (header flag = 1). For any other page type (chunk reserved, freelist, bitmap, …) the slot table is shown and the slot bodies are skipped with a one-line non-DATA page (flag=N); slot bodies suppressed note. The render is byte-identical to the legacy -O mode on DATA pages.
- --unload-to <path> — redirect the render to a named file (use - for stderr, the default). The flag also enables unload mode on its own — --unload-to without the unload-page subcommand prefix produces the same output.
- -P / -C / -p / -k / --keystore / --mek / --dbsnum / -c / -m — same flag set as the page-decrypt primary mode; see §Flags + §"Key material flags" above. Page size and (in keystore mode) dbsnum auto-detect.
Mutually exclusive with -w / -O / -x / -o: pick one render per invocation.
rm-page — offline single-page removal from a table
ondebug rm-page --partpage <P> --target <T> [-C <chunk_id>]
[-p <page_size>] [--unload-to <path>]
[--apply] [--backup] <chunk_file>
Removes one page from a table by editing the owning partition page's extent map and aggregate counters. The operator looks up the partition page address via oncheck -pT <db>:<tab> (Physical Address column) and passes it as --partpage; the page to remove is --target. Before any edit, the target page is rendered via the same render unload-page produces (slot table + DATA bodies) so the operator sees what content is being orphaned.
- --partpage P — page index of the owning partition page (header flag = 2). Required.
- --target T — page index to remove from the partition. Required. Must be claimed by an extent of --partpage; must not equal --partpage.
- --apply — commit the edit (default: dry-run prints the planned edit + the unload, exits without writing).
- --backup — write a 2 KB sidecar containing the original ciphertext of the partition page; required when --apply is set. Rollback is dd if=<backup> of=<chunk_file> bs=<page_size> seek=<P> conv=notrunc.
- --unload-to <path> — redirect the pre-removal target-page render to a named file (default: stderr).
- -C / -p / key-material flags — same flag set as the page-decrypt primary mode; auto-detect applies.
The four edit cases (sole-page extent, first page, last page, interior split) are detected automatically from the target's position within its extent. Descriptor counters (npused, npdata, nrows) are recomputed; chksum is recomputed per the V14 5-XOR formula. Engine MUST be offline.
See Examples — removing a page for the full worked run.
Examples
With key material in place and page size auto-detected, the standard form is just the page address and the output flag:
oncheck-format dump of encryptdbs page 54
ondebug -P 54 -C 4 -O /home/informix/data/encryptdbs
Hex dump of the same page (with column-index header)
ondebug -P 54 -C 4 /home/informix/data/encryptdbs
Decrypt to a binary file for further analysis
ondebug -P 54 -C 4 -o /tmp/page54_plain.bin \
/home/informix/data/encryptdbs
xxd /tmp/page54_plain.bin | head
Decrypt against a live keystore (no SEK file required)
ondebug --keystore /home/informix/live/etc/db_keystore \
--dbsnum 4 \
-P 54 -C 4 -O /home/informix/data/encryptdbs
ondebug reads the key in-process from the live keystore; no ~/.ondebug/sek.bin cache file is required at decrypt time. See the Examples — reading page §"Key material" for the two key-source flows side-by-side.
Same decrypt with keystore and dbsnum auto-detected
ondebug -P 54 -C 4 -O /home/informix/data/encryptdbs
With $INFORMIXDIR and $ONCONFIG set, ondebug reads the keystore path from $ONCONFIG's DISK_ENCRYPTION line and reads the dbspace number from the rootdbs chunk descriptor table by matching the target chunk's basename. The bare form is equivalent to the explicit --keystore + --dbsnum form above when both sources are available; pass either flag explicitly to override.
Unload one page's slot table + row bodies to stderr
ondebug unload-page -P 54 -C 4 /home/informix/data/encryptdbs
Renders the page's slot table and (since flag=1, DATA) each slot's row bytes in hex+ASCII to stderr. With $INFORMIXDIR set the keystore + dbsnum auto-detect; otherwise pass --keystore + --dbsnum or -k explicitly.
Same render to a named file
ondebug unload-page -P 54 -C 4 \
--unload-to /tmp/page54_unload.txt \
/home/informix/data/encryptdbs
cat /tmp/page54_unload.txt
Remove a page from a table (dry-run)
oncheck -pT testdb:test_enc # → Physical Address 4:5
# → Extent at logical 0: 4:53 size 8
ondebug rm-page --partpage 5 --target 54 -C 4 \
/home/informix/data/encryptdbs
Renders the target page (slot table + DATA rows) to stderr, then prints the planned edit: case (d) interior split of extent {start=53, count=8} into {start=53, count=1} + {start=55, count=6}; descriptor counters npused 2→1, npdata 1→0, nrows 2→0. No write happens without --apply.
Commit the removal (engine offline)
onmode -ky # take the engine offline first
ondebug rm-page --partpage 5 --target 54 -C 4 \
--apply --backup \
/home/informix/data/encryptdbs
oninit -vw # bring the engine back up
--backup writes a 2 KB sidecar of the original partition page next to the chunk file (path <chunk_file>.rm-page-<P>.<timestamp>); rollback is dd if=<sidecar> of=<chunk_file> bs=<page_size> seek=<P> conv=notrunc.
Patch one byte (engine offline)
onmode -ky # take the engine offline first
ondebug -P 54 -C 4 \
-w --row 0x30 --col 0x02 --value 0x42 \
/home/informix/data/encryptdbs
oninit -vw # bring the engine back up
Decrypts page 54, flips the byte at row 0x30, column 0x02 to 0x42, re-encrypts the page, and writes the new ciphertext back to the chunk file in place. See the Patching examples page for the full round trip with dbaccess verification.