#!/usr/bin/env python3 """Find what signals canary tid=17's NtWaitForSingleObjectEx event. The wait at idx=432-435 is for an event created by tid=17 itself. Find handle_semantic_ids for events tid=17 creates, then find wait.wake / NtSetEvent on those handles from OTHER tids. """ import json import os from collections import defaultdict, Counter INPUT = "/home/fabi/RE - Project Sylpheed/xenia-canary/build-cross/bin/Windows/Debug/canary-jitter-1.jsonl" OUTDIR = os.path.dirname(os.path.abspath(__file__)) # Look at window [1.9..2.1s] for all events. T_LO = 1_900_000_000 T_HI = 2_100_000_000 # Handles created by tid=17: tid17_creates = [] # wait.begin by tid=17: tid17_waits = [] # NtSetEvent / NtReleaseSemaphore by ALL tids in window with handle ids: signal_events = [] # wait.wake/end events with handle ids: wake_events = [] # Also track all handle.create events in window. all_handles = {} with open(INPUT, "r") as f: for line in f: if '"host_ns":' not in line: continue try: i = line.index('"host_ns":') + len('"host_ns":') j = i while j < len(line) and (line[j].isdigit() or line[j] == '-'): j += 1 host_ns = int(line[i:j]) except (ValueError, IndexError): continue if host_ns < T_LO: continue if host_ns >= T_HI: break try: ev = json.loads(line) except json.JSONDecodeError: continue kind = ev.get("kind", "") tid = ev.get("tid") payload = ev.get("payload", {}) if kind == "handle.create": hsid = payload.get("handle_semantic_id") rh = payload.get("raw_handle_id") ot = payload.get("object_type") all_handles[hsid] = {"raw_handle_id": rh, "object_type": ot, "creator_tid": tid, "host_ns": host_ns} if tid == 17: tid17_creates.append(ev) elif kind == "wait.begin" and tid == 17: tid17_waits.append(ev) elif kind in ("wait.wake", "wait.end"): wake_events.append(ev) elif kind == "import.call": n = payload.get("name", "") if n in ("NtSetEvent", "NtReleaseSemaphore", "NtSetEventBoostPriority", "KeSetEvent"): signal_events.append((host_ns, ev["tid_event_idx"], tid, n, payload)) print(f"tid=17 handle.create events: {len(tid17_creates)}") print(f"tid=17 wait.begin events: {len(tid17_waits)}") print(f"signal events (NtSetEvent/NtReleaseSemaphore/...): {len(signal_events)}") print(f"wait.wake/end events: {len(wake_events)}") # Show the wait.begin events on tid=17. print("\n=== tid=17 wait.begin events ===") for ev in tid17_waits[:30]: pl = ev["payload"] hids = pl.get("handles_semantic_ids", []) timeout = pl.get("timeout_ns") # Resolve handle: info = [all_handles.get(h, {}) for h in hids] print(f" t={ev['host_ns']/1e9:.5f}s idx={ev['tid_event_idx']} handles={hids} timeout={timeout}") for h, inf in zip(hids, info): print(f" {h} -> {inf}") # Wake events for tid=17 in window. print("\n=== wake events targeting tid=17 ===") for ev in wake_events: pl = ev["payload"] if ev.get("tid") == 17: print(f" t={ev['host_ns']/1e9:.5f}s idx={ev['tid_event_idx']} kind={ev['kind']} payload={json.dumps(pl)[:250]}") # Now find signalers of tid=17's wait handles. # Build set of hsid that tid=17 waited on. wait_hsids = set() for ev in tid17_waits: for h in ev["payload"].get("handles_semantic_ids", []): wait_hsids.add(h) print(f"\n=== Unique handle semantic IDs waited on by tid=17: {len(wait_hsids)} ===") for h in list(wait_hsids)[:20]: info = all_handles.get(h, {}) print(f" {h} -> {info}") # Check: for each, who created it? Object type? In this window's signal_events, who signals? # The NtSetEvent / NtReleaseSemaphore events don't carry handle info in payload by default # (payload is empty args:{}). Print first few to confirm. print("\n=== Sample signal events (first 10) ===") for s in signal_events[:10]: print(f" t={s[0]/1e9:.5f}s idx={s[1]} tid={s[2]} name={s[3]} payload_keys={list(s[4].keys())}") # Count signal events per tid in the window. sig_counts = Counter() for s in signal_events: sig_counts[(s[2], s[3])] += 1 print(f"\n=== Signal event counts by (tid, name) in window [{T_LO/1e9}..{T_HI/1e9}s] ===") for (tid, name), c in sorted(sig_counts.items()): print(f" tid={tid:3d} {name:30s} {c}") # Save tid=17 timeline showing wait.begin/wait.wake. with open(os.path.join(OUTDIR, "canary-tid17-waits.csv"), "w") as f: f.write("host_ns,tid_event_idx,kind,handles,timeout_ns,result\n") for ev in tid17_waits: pl = ev["payload"] hids = ",".join(pl.get("handles_semantic_ids", [])) timeout = pl.get("timeout_ns", "") f.write(f'{ev["host_ns"]},{ev["tid_event_idx"]},{ev["kind"]},"{hids}",{timeout},\n') for ev in wake_events: if ev.get("tid") != 17: continue pl = ev["payload"] hids = ",".join(pl.get("handles_semantic_ids", [])) f.write(f'{ev["host_ns"]},{ev["tid_event_idx"]},{ev["kind"]},"{hids}","","{json.dumps(pl)[:200]}"\n') print(f"\nWrote canary-tid17-waits.csv")