aboutsummaryrefslogtreecommitdiffstats
path: root/fw/pseudo (follow)
Commit message (Collapse)AuthorAge
* fw: command-surface dumps for all twelve TAs, with honest handler attributionuser2026-09-29
| | | | | | | | | | | | | | | | | | | | | | | | | | | GCP had a decompiled command-surface artifact and the other eleven did not, though the command surface is what an analyst reads first. fw/ta_surface.py emits one per TA into fw/pseudo/<ta>_command_surface.c. Two corrections were needed for these to be honest rather than merely present. First, prefer the address-keyed map: cmdmaps record handlers by name, captured before the renames, and the first run used the name map for GCP as well, resolving only 4 of its 17 handlers and silently replacing a good artifact with a worse one. The tool now prefers <ta>_ea.json where it exists. Second, separate function entries from labels inside functions: rap's cmd 1 points into start, two of auc's land inside another handler, and five of OPM's nine dispatch into the middle of larger functions, so printing the containing function as the handler would assert that start is rap's cmd 1 handler. Exact entries and internal labels are now separate sections, with the containing function reproduced in full under a warning that the command's code begins at the stated offset. IDA refuses to split those internal entries out, and undefining the owning function to force a split was not worth the risk so soon after repairing a corrupt database. OPM cmd 8 at 0x401320 is reported as entering opm_asd301_path+0x60 rather than asserted as a separate function, despite earlier notes calling it a merged handler. 62 exact handlers across the twelve, all decompiling, plus 9 internal-label entries each shipped with its containing code. TMZ has no command map, which is correct for a stub that answers every command id identically.
* fw: regenerate the GCP command-surface dump after the arity passuser2026-09-29
| | | | | | The committed surface predated the inferred-arity work, so its call sites still rendered with IDA's guessed argument counts. Regenerated from the final databases so the artifact matches the verified state: 17 handlers, no decompilation failures.
* fw: rebuild powerplay's corrupt database; verify all 632 functions decompileuser2026-09-29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | A full-coverage decompilation check, rather than the per-TA sampling used until now, exposed that powerplay's .i64 would not open at all. It was not a busy lease, since a copy failed identically, and its mtime placed it in the run whose worker exited mid-write while every healthy database was written a minute later. The header matched a good database, so only opening it revealed the damage, and sampling would have shipped a broken deliverable. Rebuilt from fw/libdumps/powerplay.json, which holds all boundaries and names and is the reason rebuilding was possible at all: fresh analysis, 79 names re-applied by address, the one function IDA does not find recovered by marking its extent as code before creating it, 27 residue comments re-applied, then prototypes and inferred arity. Worth recording that set_thumb is a toggle, so calling it on an already-Thumb address turns Thumb off and the instruction stops decoding, which is exactly what the first recovery attempt did. IDA gives the recovered function a 6-byte body where the old database recorded 112. The full extent is code but the function ends after 6 bytes, so the old figure was that database's boundary rather than ground truth, and it is left at IDA's value on the same principle as the reverted lvar type. ta_document_residue.py now applies comments headlessly through set_comments, which takes an address and reports per-item status, instead of the cursor-dependent TUI goto and comment pair. Final verified state across every function in every database: 632 functions, 555 named, 632 with a prototype, 632 decompiling cleanly.
* fw: recover helper arity by dataflow, validated first -- 632/632 functions ↵user2026-09-29
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | now typed 179 prototypes came from an established role, leaving ~450 helpers with none. Guessing their argument count would repeat the lvar mistake, producing output that reads well and says something false. Arity is recoverable instead: on AAPCS a register read before it is written on any path is an incoming parameter, so fw/ta_arity.py walks basic blocks from the entry and derives it. The validation is the point. The control is the set of handlers the dispatch table points at, which the dispatcher calls as mov r0,r5; mov r1,r4; bl handler, so their arity of two is proven rather than assumed, plus zero_fill and memcmp. Two attempts failed the control before one passed: push {r3,r4,r5,lr} is the alignment idiom and reads r3, making every such function look like it took four arguments; excluding push and pop then over-corrected by also excluding stm, which for the ASD RPC thunks is the argument-passing idiom, so those reported zero arguments. With push and pop excluded, stm and ldm treated as real dataflow, and the control restricted to proven arities, it agrees 19 of 19. That last correction disproved four prototypes already applied: gcp_asd_rpc_304 takes none since it zero-fills its own buffer, _107 takes two because movs r2,#0 writes r2 before the stm reads it, _202 takes four, and only _305 was the single argument all four had been declared with. Coverage is now 632 of 632 functions carrying a prototype across all twelve TAs, with 554 named and 78 documented. Measured against a pristine database, raw pointer-arithmetic casts fall from 81 to 8 and anonymous parameters from 113 to 0.
* fw: readable GCP command-surface dump + sharpen FE0F's in-database commentuser2026-09-29
| | | | | | | | | | | | | | | | | | | | Generates fw/pseudo/gcp_command_surface.c, the full GCP command surface decompiled with restored names, prototypes and structure types, with each handler's finding notes inline. This is the artifact the objective actually asks for: pseudocode plausible enough to analyse. Also corrects FE0F's comment, which predated the hardware work. It framed the issue as destroy-side only. The sharper and now proven statement is that FE0C never writes slot+0x18 at all, which is the field this search compares against, so that field is permanently zero for every session and an all-zero query matches the first slot whatever its state. Records the full hardware chain and the explicit finding that this is not a use-after-free, since the handle is a monotonic counter rebound on slot reuse and a stale handle is correctly rejected. Adds an explicit save_database plus lease release to fw/ta_ida.py: save_database is a client method rather than a remote_ops op, so the earlier call raised and was swallowed, leaving work only in the unpacked scratch files where an unclean worker exit would lose it. All twelve databases are now saved and released.
* fw: restore AMD's own function names and apply prototypes/types across the TAsuser2026-09-29
Names alone left Hex-Rays emitting *(_DWORD *)(a1 + 7680) for the most important expression in this audit, so this adds function prototypes and structure types, and in the process corrects names that had drifted. GCP logs AMD_TA_GCP: <Name> ENTER on entry to most handlers, which is ground truth. fw/ta_name_audit.py checks every derived symbol against it and found 18 mismatches in GCP, plus two false positives in WSPE where the logged words are ordinary prose. Combined with a fresh decode of the dispatcher's two tbb tables, giving command to handler address rather than the stale name-keyed map, this corrects: cmd 3 is ActivateDRMCertAuthSession and was not defined as a function at all; FE03 to FE06 are unimplemented and share the error arm; FE07 is CreateAuthenticatedSession; FE0C and FE0D are Create and DestroyCryptoSession; FE0A is QueryAuthenticatedSession rather than the invented QueryAccessibilityAttributes; FE0E and FE0F likewise. The hardware sweep independently agrees, since FE03 to FE06 all returned an identical 0x102 while FE07 alone returned 0, which had been sitting in the output mislabelled. This also corrects a finding's wording: FE0B manages the stride-80 auth array and FE0D the stride-88 crypto array, so they are two destroy paths over different arrays rather than a same-type sibling pair. The in-database comment is updated, including replacing its now-stale 'not yet shown' caveat with the hardware result. Five structures declared and verified by reading the layout back from IDA and comparing against the addressing the code performs; the three session arrays tile the context exactly, which is the check. 179 prototypes applied across all twelve TAs with no failures. Measured against a pristine database rather than one that already carries the work: raw casts 81 to 7, anonymous parameters 113 to 0. Method notes recorded: do not drive the TUI struct editor, since a focus change types into the filter box and a half-applied redeclare silently truncated three structs; declare interdependent structs in one parse unit; build prototypes from the database rather than the stale dump; a type that misrepresents addressing is worse than none, which is why the lvar retype was reverted; and two metric bugs were caught only by disbelieving a number that flattered or unfairly punished the work. Adds fw/ta_ida.py, fw/ta_name_audit.py, fw/ta_rename_from_logstrings.py, fw/cmdmaps/gcp_ea.json, fw/audits/name_vs_logstring.json and fw/pseudo/ artifacts.