Running log
Append-only. Newest entries at the bottom. One entry per work session or finding. Times are UTC on 2026-10-11 (host clock BST = UTC+1).
2026-10-11 11:42 - Case opened, static mapping
- Brief: the sample “might be a ransomware”; map the full program flow and the encryption routine.
- Ghidra MCP had the program open and analysed (2,580 functions). x64dbg was paused at the system breakpoint.
- Imports, segments and strings showed
.akira/.arika,akira_readme.txt, Restart Manager, WMI and QPC. Decompiledmain(0x14004ca40) and the per-file coroutine (0x1400ae840, 71 KB decompile →artifacts/ghidra/FUN_1400ae840_per_file_coroutine.decompile.c). FUN_140071d80decodes the shadow-copy PowerShell command with((0x39−b)·0x0B) mod 0x7F.- Sourcing policy: only our own static and dynamic findings are cited. No sandbox reports or blog write-ups were used.
2026-10-11 11:48 - Run 1 (escaped the folder, revert)
LoadBinaryarguments didn’t reach the PEB, so I relaunched with x64dbginit.- Captured four Yarrow seeds for thread 0x444 and the RSA plaintext blob. Python regenerated all key bytes from the seeds, which confirms the QPC-only seeding.
- Mistake: launched with
-p <path>, which the argh parser ignores. The sample swept C: and encrypted real files before I killed it. Snapshot reverted by the analyst. - Lesson recorded in memory: always use
--encryption_path=<p> -localonlyand a gate breakpoint onFUN_140073950.
2026-10-11 12:05 - Run 2 (cipher and mode validation, revert)
- Ghidra MCP was briefly unreachable (ECONNREFUSED); continued with x64dbg.
- KCipher-2: the α tables need different polynomials, so I rebuilt them from the binary’s basis entries. The model matches RFC 7008 C.1 and 64 B of live keystream.
- ChaCha: only the 128-bit-key 8-round variant matches live keystream (out of 6 variants).
- All three modes confirmed via the RSA blob of each test file. Part stripes read at 0, 360,000, 720,000 and 1,080,000. The footer is written at the original size.
- Run stayed in the samples folder (gate confirmed) but encrypted the other samples there. Snapshot reverted.
2026-10-11 12:42 - Report pass
- Filled the gaps: hashes and PE metadata, no anti-analysis, drive classification, the five-drive
sweep limit, the share-file reader, exclusion sets, and the
.arikajournal format (532 B). - 153 DB extensions decoded from
.rdata. The decompile ofFUN_140003680timed out and inline scripts are disabled, so I parsed the 1.65 MB disassembly and a.rdatadump on the host. - YARA rule, behavioural detections and ATT&CK mapping.
- Published the Claude Docs report “Akira Ransomware Analysis” with an execution-flow diagram.
2026-10-11 13:04 - Decryptor and run 3 (end-to-end capture)
- Built
akira_decrypt.py(pure Python, standard library only). Key sources:--keys,--seeds,--private-key. Journal support. - Run 3: zero-filled
e2e_small.txt,e2e_db.sqliteande2e_big.bin. Captured seeds and blobs per thread; each blob cross-checks against its seeds. The process exited on its own. - Pulled the three real
.akiraoutputs to the host with a Ghidra raw import plusread_memory. All decrypt byte-exact via--seedsand--keys. - VM: new
.akirafiles in the samples folder. Revert recommended. Ghidra/decrypt_testholds 4 closed raw imports, which can be deleted.
2026-10-11 13:20 - Seed brute-forcer (recover)
- Added
recoverandbenchmark. Every key is the first 16 B of one Yarrow draw, so one table of 16-byte prefixes serves all four values.- Stage 1: KCipher-2 known-header test on (key2, iv2) seed pairs.
- Stage 2: ChaCha (iv1, key1) seeds with known bytes or a zeros/text heuristic.
- Validated: all seeds of the 3 real files recovered from ±100-tick windows with 16 known zero bytes. A 20,012,001-pair stress run found the single true pair, with no false positives, in 69 s.
- Measured about 150k pairs/s on the 20-thread host. Open: the native seed-to-seed gap is unmeasured.
- Added a “Decryptor and key recovery” section to the report (rev 16), with consistency edits up to rev 23.
2026-10-11 17:13 - Case folder built
- At the analyst’s request, gathered everything from this engagement into this case folder:
- the decryptor, tests and fixtures, moved from
AI-MalwareAnalysis\akira_decryptorto06-decryptor/; - the validation scripts (
scripts/); - raw Ghidra outputs (
artifacts/ghidra/), decoded extension tables (artifacts/decoded/); - the RSA public key, the ransom note and the IOC CSV;
- the report exports (
report.md/.html/.pdf, rev 24) and the flow diagram.
- the decryptor, tests and fixtures, moved from
- RSA public key DER re-read from Ghidra at
0x1400ee010; SHA-256a40a55f2…9aaamatches. - Fixture bytes re-verified against the original VM transfer dumps: identical.
- Test suites re-run from the new location: selftest 8/8, real outputs 9/9, round trip 29/29
(
artifacts/test-run-2026-10-11.txt). - Report decryptor path updated to
cases\…\06-decryptor(doc rev 24).
2026-10-11 22:00 - API map, flow diagrams, decryptor demo
- API call sites: Ghidra cross-references to 49 behaviour-relevant imports, each mapped to its containing function
(
artifacts/ghidra/api_callsites.json). Write-up in03-static/09-api-behaviour-map.md.- Confirmed: QPC reaches the Yarrow seed via the clock wrapper
FUN_140078dd4(callersFUN_14007b1f0,FUN_14007bbe0,FUN_1400ae840, main). - Confirmed: the WMI strings and
ProcessIdcast toshort(decompile ofFUN_140071620saved). - Confirmed: read-only cleared and Restart Manager retried on error 0x20/0x21 (decompile lines 271–301).
- The only
TerminateThreadis asio’swin_thread::join(FUN_140036580, decompile saved): library code, not malicious.
- Confirmed: QPC reaches the Yarrow seed via the clock wrapper
- Diagrams added to the report: encryption flow and decryption flow. Each was checked in a screenshot render.
Files are in
artifacts/diagrams/(PNG + widget source). - Decryptor demo on the real run-3 files (
artifacts/decryptor-demo-2026-10-11.txt):- all three decrypt to all-zero files of the original sizes;
- a key2 seed one tick off gives garbage;
recoverwith a wrong gap finds nothing;recoverwith correct windows: Spot file 0.4 s, Full file all four seeds 0.8 s.- My first
recoverdemo passed the gap in the wrong unit (94,499 instead of 94,499,986 ticks). It correctly found nothing; I re-ran it with the correct value.
- Report (doc rev 31) gained four things:
- a Windows API section;
- the two diagrams;
- “Does it work?” results;
- the core decryption routine, with the full script attached as
akira_decrypt.py.txt, since.pyis not an accepted upload type.
- Local report exports refreshed to rev 31; the diagrams are embedded from
artifacts/diagrams/.
2026-10-11 23:20 - Run 4: native seed gap measured
- Method: no seed breakpoints. An in-process QPC logger was patched over the tail of
FUN_140078dd4(stub in an RWX allocation; stores QPC, caller and TID through alock xaddindex). An exit trap (EB FEonntdll!RtlExitUserProcess) kept the finished process alive.- Safety gates as before: WMI executor forced to return; gate confirmed the root was the samples folder.
- Test set: 20 zero-filled test files (16 Spot
.txt, 4 Full.sqlite) plus 1 pre-existing file.
- Detach/re-attach stalled with the buffer at 2 entries. A separate session reported a ScyllaHide modal dialog on re-attach as the cause, not the “frozen detach” I first assumed. All seed data therefore comes from an attached run with no breakpoints. Debug events in that window: 2 thread creations, 6 exits, 5 DLL loads, no exceptions.
- Timer integrity: the sample’s QPC import resolves to an unhooked
ntdll!RtlQueryPerformanceCounter; QPC bypass is on (0x7FFE03C6 = 0x83, user-mode TSC read); frequency is 10 MHz (0x7FFE0300). ScyllaHide hooks are not in the path. - Verified:
gap_00.txt.akiraandgap_db_0.sqlite.akiradecrypt to zeros with the logged values × 100. - Result over 21 files and 84 seeds:
- key1→iv1 median 4,119 ticks; iv1→key2 median 4,047; key2→iv2 median 4,121 (min 3,889, max 27,109); a file’s four seeds span a median of 1.25 ms.
- The floor is one Yarrow seeding; the tail comes from 2 threads competing on 2 vCPUs.
recoveron both native files with a ±2,500-tick key2 window and the 3,800–8,000 gap window: true pair found in 70 s and 85 s.- Code:
recovernow defaults to--gap 3800:8000, the default ChaCha windows are widened to the--gaprange, andbenchmarkdefaults to--gap-span 4200. The native files were added totest_real_outputs.py. Suites: 8/8, 12/12, 29/29. - VM: 21 more
.akirafiles in the samples folder;Desktop\gap_buffer*.bin; 4 more Ghidra raw imports. Revert recommended.
2026-10-12 07:25 - Victim timestamps as seed anchors
- Two read-only PowerShell probes ran on the VM from x64dbg; the script was written with
savedata, and the output pulled through Ghidra. They collected file times, QPC/clock pairs, boot events and the operator log. - Each of the 21 run-4 outputs was matched to its seed row by KCipher-2 over its first 16 bytes.
.akiramtime − key2 = +0.45..+5.36 ms (median 1.39). - Live QPC offset: fits to about 1 ms, 10 h later.
- Boot-time sources after a reboot:
LastBootUpTimeand Kernel-General 12StartTimeare off by +352 ms (0.5 s granularity);TimeCreatedby +1.5 s. The CKCL traces are absent on this VM. - Blind test:
recover --qpc-offset --mtimefoundgap_00’s seeds in 1,704 s with no seed input.gap_db_0was stopped at the user’s request. - Note:
04-dynamic/05-timestamp-seed-anchors.md.
2026-10-12 07:05 - Decryption evidence on existing outputs
06-decryptor/evidence_existing.py→artifacts/decryption-evidence-existing-2026-10-12.txt.- All 5 real
.akirafiles decrypt to the SHA-256 of their zero-filled originals. Negative controls (key2 seed +1 tick) fail as they should. - For run 3, the seed-derived keys equal those in the sample’s own RSA plaintext blob.
2026-10-12 10:45 - Run 5: blind recovery of real files
- Detonation: after a revert, 4 analyst-provided files (PDF, DOCX, 2 PNG) were placed in
samples\data. The sample ran with--encryption_path=...\samples\data -localonly. The WMI executor was forced to return and the gate root confirmed; then all breakpoints were removed. No seed capture. - Leftover session: x64dbg had an unknown sample instance paused at the system breakpoint. It was stopped before any of its code ran.
- Responder data: post-run QPC offset, mtimes, and known plaintext from the file type (PNG 16 B, PDF 7 B via the new mask) or rebuilt from the ZIP central directory (DOCX 28 B).
- Result: PDF, DOCX and the second PNG recovered with hash-exact output (28–31 min each). The first PNG was not found in the whole note-bounded window with gaps ≤ 8,000. The user chose to stop at 3 of 4.
- Code: 7-byte masked known plaintext,
--floor/--floor-only. Suites: 8/8, 13/13, 29/29. - Note:
04-dynamic/06-run5-blind-real-files.md. VM: revert needed (the data folder is encrypted).
2026-10-12 14:20 - Blog draft
blog/akira-recovery-blog.html, published as a private artifact: https://claude.ai/artifact/QzR7vuemQAMvsSVv1qvgzD (author Shayan Ahmed Khan, Lead Threat Detection & Response).- Placeholders:
- the hero image (the
HEROcomment); - 8 download cards that point to
#github-placeholder(theTODOcomment); collect_clock_and_times.ps1doesn’t exist yet. Derive it from04-dynamic/run5-blind/post_probe.ps1.
- the hero image (the
- Next: the author reads the draft and sends feedback. Revise the same file and republish it to the same URL.
- VM: still needs a revert. Ghidra
/decrypt_testimports can be deleted.
2026-10-12 15:59 - Run 5 fourth file recovered (4 of 4)
- Added
recover --anchor iv2: the window bounds iv2, and key2 = iv2 − gap. Tool SHA-256eac5d0d6…. Validated on the solved second PNG (0.8 s). All three suites pass. - Search:
Screenshot 2026-09-29 125745.png: iv2 in mtime −2.5/+0.1 ms, gaps 8,001–30,000 (572 M pairs), only the space earlier passes never searched.- Found after 1,240 s: key2 870409493800, iv2 870412165600, gap 26,718 ticks.
- Decrypted SHA-256
9d014edc…= original.
- Cause confirmed: a seed-gap outlier (cf. run 4’s 27,109). key2 sat 38 µs after the second PNG’s key2, so both threads set up a file at the same moment.
- Updated:
- the run-5 note and evidence (addendum 4);
- README (open question 7 resolved);
- the decryptor README.
- Also updated:
- the blog (republished to the same URL, with a new timeline and a second-pass command);
- the Claude Docs report (rev 41).
report.md/.html/.pdfare still the rev-38 export.- Regression test added:
06-decryptor/e2e-run5/fixture. Suites are 8/8, 14/14 and 29/29.
2026-10-12 19:20 - Numba engine for recover stage 1
- Installed
numpy2.5.4 +numba0.68.0 on the host Python 3.12. - New
06-decryptor/akira_fast.py: a line-for-line int64 port of_k2_ik/_k2_match, run in parallel withprange.recover --engine auto|numba|python; the default auto picks numba when it is installed.akira_decrypt.pystays standard-library only and falls back to Python.- At load the kernel is checked against the reference (400 checks), and every hit is confirmed with the full KCipher-2.
- Gotcha:
python -Ileaves the script folder offsys.path, so_load_fastadds it.
- Speed: 97M pairs/s in a burst and 40–45M/s sustained, against 150k/s before.
- Run-5 re-run (
artifacts/run5-numba-rerun-2026-10-12.txt), all four files hash-exact:- PDF 21 s, DOCX 26 s, second PNG 22 s (each about 30 min before);
- first PNG: default pass misses in 13 s, the
--anchor iv2pass finds it in 16 s (1,240 s before).
- Remaining cost: the Yarrow table (about 2k seeds/s per core) is now the larger part.
- Tests:
akira_fast.selftest(2,000 random cases) shows 0 mismatches. Suites: 8/8, 15/15 (new: gap_00 on both engines), 29/29. - Updated: README, the decryptor README (Speed section), the run-5 note, and the blog (republished).
2026-10-13 06:05 - Run 6 (fully independent blind test): protocol frozen before detonation
- The user asked for a fully independent test. They will revert the VM and place real files in
samples\data; Claude has not seen them. - Frozen before the run:
- the driver
04-dynamic/run6-blind/run6_blind_recover.py(ae0df7df…): pass 1 defaults, then automatic pass 2--anchor iv2 2.5:0.1, gap 8001:30000, type-based known plaintext; - the collector
collect_clock_and_times.ps1(15fbf579…); - the decryptor (
870c6db9…) andakira_fast.py(07352777…).
- the driver
- Protocol:
04-dynamic/07-run6-independent-blind.md. - Harness dry run on the run-5 files (scratch copy): 4/4 hash-exact in about 100 s (
artifacts/run6-driver-dryrun-on-run5-2026-10-13.txt). - A read-only VM state probe (PowerShell under x64dbg) was started, and then stopped by the user before it ran. They are reverting first.
2026-10-13 - Run 6: VM checked after the revert
- Leftover in x64dbg: a sample instance (image base
0x7FF781AD0000) paused at the system breakpoint, from the snapshot.- Its command line had no arguments, so it would not have been confined to
samples\data. - It was stopped before any of its code ran, the same as in run 5.
- Its command line had no arguments, so it would not have been confined to
- Pre-listing attempt 1 failed: PowerShell via
LoadBinarywith-EncodedCommand.- The PEB showed an empty command line: the long argument string was dropped.
- PowerShell sat at an interactive prompt, and no file was written. It was paused.
- Attempt 2, partial: writing the scripts into memory for
savedata.WriteMemToAddresscaps each write at 512 bytes, so only 3 × 512 bytes landed.- Generating the remaining chunks was refused by the auto-mode permission check. Waiting for the user.
- No sample code has run in run 6.
2026-10-13 09:33 - Run 6 detonation (after a full revert)
- VM after revert: x64dbg empty (no leftover instance). The user copied
collect_clock_and_times.ps1andstate_probe.ps1to the Desktop. The state probe is byte-identical to the frozen version; the collector is the same size (2,562 B) and its content was inspected. - Launching scripts:
LoadBinarydrops command-line arguments (the PEB showed an empty command line). The x64dbginit "exe", "args", "cwd"command works. - samples\data (state probe), 8 files:
20358696.jpg24,287;Autopsy_DFIR_Validation_Playbook_Extended.pdf481,630 (has ChaCha chunks);photo_2026-09-23_15-02-25.jpg172,871 andphoto_2026-09-24_12-44-15.jpg214,866;QC-STC-…_v1.0.docx42,333 (same document as in run 5);Screen Recording 2026-09-24 104237.mp46,799,834 (out of scope: no known-plaintext rule);Screenshot 2026-09-10 152951.png26,953;Screenshot 2026-09-29 125745.png47,803 (same file as in run 5).
- Pre-listing
pre_run6.txt(3,066 B) was taken, and a copy was imported into Ghidra/run6before detonation. It has not been read. - Detonation:
- image base
0x7FF658870000; entry+0x855B8(same as run 5); - command line
--encryption_path=...\samples\data -localonly; - the WMI executor
+0x71620was hit and forced to return (rax=0, return to+0x71F3A); - the root gate
+0x73950: one root,...\samples\data(0x27 chars); - then all breakpoints were deleted, and the sample ran to exit. No exceptions, no breakpoint hits, no hooks, no seed reads.
- image base
- Operator log
Log-13-10-2026-09-32-12.txt: 2 encryptor threads,44652 ms. - Post-run (same boot)
post_run6.txt, SHA-256228e3cd0…:- QPC 10 MHz; offset
134363534101375013(spread 69 ticks); - all 8 files are
.akira(+512 B);akira_readme.txtwas created; - the exe, zip and stage2 files are unchanged.
- QPC 10 MHz; offset
- Next: the user copies the
.akirafiles andpre_run6.txtto the host (too large to relay through Ghidra). The driver checks each.akiraSHA-256 against the post listing.
2026-10-13 09:50 - Run 6 result: 6 of 7 in-scope files hash-exact, independent blind
- The driver ran as frozen (
ae0df7df…, decryptor870c6db9…). Log:artifacts/run6-blind-recovery-2026-10-13.txt. Every.akirafile matches the VM’s post-run SHA-256. - MATCH on pass 1, about 25 s each:
20358696.jpgand bothphoto_*.jpg(JFIF 11 B);- the DOCX (28 B);
- both PNGs (16 B).
- Pass 2 never needed: gaps were 3,933–5,570.
- PDF (481,630 B): the KCipher-2 keys were found, but the ChaCha stage 2 found nothing its check accepts (24 M pairs). Outcome: KEYS FOUND, OUTPUT DIFFERS. This was a risk stated in advance.
- mp4: out of scope.
- Timing: mtime − iv2 was 0.55–1.86 ms; key2 sat 3.5–20.9 ms after the note.
- Open:
- byte-compare the host
pre_run6.txtwith the Ghidra/run6copy imported before detonation (the bridge disconnected); - the ChaCha stage-2 check on real data (PDF);
- VM revert.
- byte-compare the host
- Note:
04-dynamic/07-run6-independent-blind.md.
2026-10-13 10:05 - Blog updated with run 6 (v4, same URL)
blog/akira-recovery-blog.html→ https://claude.ai/artifact/QzR7vuemQAMvsSVv1qvgzD (version 4).- Key findings: new run-6 bullet (6 of 7 hash-exact; the PDF’s ChaCha middle not recovered).
- Proof section: retitled “two separate runs”; new “Run 6” subsection with the protocol, results table, findings and a PDF callout that says the cause is not settled.
- Recovery section: iv2 anchor range now 0.5–1.9 ms across 11 files.
- Limitations:
- new “Large files: ChaCha8 middle” card;
- the outlier card notes that run 6 had none;
- the known-bytes card mentions MP4.
- Downloads: new
run6_blind_recover.pycard (10 cards / 12 placeholder links). Date: updated 13 Oct 2026.
2026-10-13 10:15 - Claude Docs report updated with run 6 (rev 45)
- Lead: now mentions the independent blind test (6 of 7 in-scope files hash-exact).
- New “Independent blind test (run 6)” block after the run-5 paragraph:
- the protocol;
- an 8-row table;
- the PDF ChaCha paragraph (cause not settled).
- Limits: the stage-2 bullet now cites the run-6 PDF.
- Analysis notes: “six controlled runs” and a new run-6 bullet (including the
initvsLoadBinarynote). report.md/.html/.pdfare still the rev-38 export; re-export to refresh.
2026-10-13 11:10 - Blog updated with build 2 (v6, same URL)
- Key findings: new bullet on the second build (6 of 7 hash-exact, decryptor unchanged).
- Proof section: retitled “three runs across two builds”; new “A second build, same flaw” subsection (static match, protocol, 9-row table, verdict).
- Recovery section: iv2 anchor range now cites 18 files across both builds.
- Limitations: “This build only” became “Two builds tested”.
- IOCs: build-2 SHA-256 and MD5, and its victim code.
- v5 said “seventeen files”; v6 corrects it to 18 (16 hash-exact plus 2 PDFs with keys found).
2026-10-13 11:30 - MalwareAnalysisSeries bundle
export/Akira-MalwareAnalysisSeries-bundle-2026-10-13.zip(4.3 MB, 138 entries; zip SHA-25679989353…), built byexport/build_bundle.pyfromexport/src/and both case folders.- Layout follows the repo conventions:
Akira/{README, Akira-Recovery-Blog.html, Assets, sample, tools_and_scripts, Extracted_TTPs, analysis/<both cases>, MANIFEST.sha256}, plusIMPORT_INSTRUCTIONS_Akira.mdfor the repo session. - Left out: the analyst-owned test documents (encrypted copies and decrypted outputs, runs 5 and 6 and build 2), the
e2e-run5fixture, caches and unfilled templates. test_real_outputs.pynow skips the run-5 PNG test when its fixture is absent (new SHA-256dc0e3cc9…). The case suite still passes with the fixture (FAILURES: 0).- Bundle checks: extracted,
MANIFEST OK; selftest 8/8; real outputs FAILURES 0 (1 SKIP); round trip FAILURES 0.
2026-10-13 12:00 - Report updated with build 2 and re-exported (rev 47)
- Claude Docs report, rev 47:
- the lead mentions the second build;
- new “Second build (build 2, run 1)” block after run 6: static comparison, protocol, 9-row table and outcome;
- IOC rows for the build-2 SHA-256, MD5 and victim code;
- analysis notes: “six controlled runs of this build, plus one of a second build”, and a build-2 bullet.
- Local exports refreshed from rev 47:
report.md(53 KB) andreport.html: Docs export with the three embed placeholders replaced byartifacts/diagrams/*.png;report.pdf: 26 pages, 1.1 MB, Edge headless (Skia/PDF).
- The raw exports are in
export/report-rev47/. The previous PDF is kept asexport/report-rev47/report_rev38_previous.pdf. - Writing the export into the doc’s file store was refused (artifact store: not a writer through the service). The inline export was saved by the harness, then decoded locally.
2026-10-13 12:25 - Blog v7: hero image, lab section, key-generation boxes fixed
- Hero: the analyst-supplied image (
photo_2026-10-13_11-32-32.jpg, 1536 x 1024) is nowblog/Assets/hero.jpg, published with the artifact as a supporting file. The standalone HTML embeds it as a data URI. - New section 02, “How it was analysed”:
- Claude Code driving Ghidra 12.1.2 (GhidraMCP 6.0.0) and x64dbg through MCP in the VM;
- facts grid, a per-tool table, the seven-detonation table (runs 1-6 + B2), and the integrity practices;
- later sections renumbered 03-12, and the TOC entry added.
- Key-generation chain: CSS grid, 5 columns on desktop and 1 column under 860 px; arrows as
::after; long words wrap. Checked with headless Edge screenshots. - Download links: the placeholders are kept, at the analyst’s request.
- Bundle rebuilt: hero in
Akira/Assets/;IMPORT_INSTRUCTIONSsays to leave the placeholders until asked.
2026-10-13 - Stage 2 explained: the run-6 PDF recovered hash-exact
- Cause settled: the zeros/text heuristic, not the window. The PDF’s whole ChaCha region (65,535-196,605) is inside one FlateDecode stream (object 7), and the shipped test accepts 0 of 971 genuine 64-byte windows of it.
- New test (
06-decryptor/stage2-investigation/pdf_deflate_oracle.py):- continue object 7’s deflate from the known chunk-0 prefix;
- require valid content-stream syntax;
- verify with the full Adler-32 and the sealed SHA-256.
- Search: the same default window, 23,970,816 pairs, 2,300 s. Exactly 1 candidate passed.
- Seeds: 566543569000, 566543980000, 566544406300, 566544820400. Gaps: 4,110 / 4,263 / 4,141 ticks.
- Result: MATCH with
pre_run6.txt(a13ccfca…). The shippeddecrypt --seedsgives the same hash. - Run-6 tally: 7 of 7 in scope, with this targeted stage-2 rerun. The blind protocol result stays 6 of 7, because the shipped driver did not do this.
- Log:
artifacts/stage2-pdf-oracle-run6-window-2026-10-13.txt. The write-up is in06-decryptor/stage2-investigation/README.md.
2026-10-14 - PDF stage-2 fallback added to the decryptor
akira_decrypt.py(now SHA-25609170168…): newrecover --stage2 {auto,heuristic,pdf}.- auto (the default) runs the zeros/text test first, then, for
.pdf, two PDF tests on the same window. The tests work on the file after stage 1 (KCipher-2 chunks and tail readable):- xref: exact
N G objheaders inside ChaCha chunks, one ChaCha block per candidate. It is used only if every header in readable bytes matches the xref, and needs at least 90% of the in-chunk headers to confirm. - deflate: continue a page-content stream that crosses into the first ChaCha chunk, with a page-content syntax check. It is confirmed only if the whole stream inflates with a valid Adler-32.
- xref: exact
- If neither applies, it says so and the output is as before.
- auto (the default) runs the zeros/text test first, then, for
- Why a fallback, not the default test: each PDF test covers only some PDFs (no in-chunk objects + a binary stream at the boundary = no test). Both are slower than the zeros/text test, and the old behaviour for every other type is unchanged.
- Real PDFs, default command line (
artifacts/stage2-integrated-recover-2026-10-14.txt):- run-6 PDF via deflate, 8 min 16 s, SHA-256 = sealed;
- build-2 PDF via xref, 4 min 52 s, SHA-256 = sealed.
- Cross-check: deflate-only on the build-2 PDF finds the same seeds.
- Tests (
artifacts/test-run-2026-10-14.txt): selftest 8/8, real outputs 15/15, round trip 29/29, newtest_pdf_stage2.py3/3 (synthetic: xref, deflate, neither-applies). - Docs:
06-decryptor/README.md(stage-2 fallback, usage, validation rows), the addendum in04-dynamic/07-run6-independent-blind.md,README.md.
2026-10-18 - Report kept as Markdown only
- Deleted the case-root
report.htmlandreport.pdf(rev-56 copies ofreport.md).report.mdis the only report export now. export/process_report_export.pywrites onlyreport.mdby default. Add--html-pdfto regenerate the HTML and the Edge-printed PDF.- Left as they are:
export/report-rev47/,export/report-rev56/(raw exports + previous PDFs),export/bundle/and both bundle zips. The bundle still contains the HTML/PDF. A fresh bundle will be built when the GitHub repo is available.