# Agent_Release_x64.exe — finding ledger - SHA-256 `6f2be7b8eb799ba51b359d1958720aac5baee5b7ee0d1d36684d3cbd72d45469`, 1,472,512 bytes - PE32+ x86-64, Windows CUI, MSVC linker 10 (VS2010; imports MSVCR100/MSVCP100) - PDB reference `F:\work\Project\Output\Exe\Agent_Release_x64.pdb` (GUID a4775113-…, age 1) — PDB not available; names are Ghidra defaults - Ghidra 12.1.2 via REA 6.5.0; 6,814 procedures, 1,472 defined strings (`ev_9fe3a449…`) - Full Evidence: `evidence-bundle.json` (14 records). Static analysis only — nothing here was observed at runtime. ## Status: first pass (process-control core). Network protocol and config parsing not yet decompiled. ## Language: C++ (high confidence) Observed C++-only artifacts: MSVC RTTI type descriptors (`.?AV…@@`, incl. templates `MBISingleton`, `CFastArray`), vftables, `__CxxFrameHandler3` (C++ EH), `operator new/delete`, MSVCP100 `std::basic_ostream` imports. Multiple vftables per class (e.g. `MagiAgentNetwork`, `MGAgentManagerSession`) indicate multiple inheritance. Statically linked C++ libraries: ProudNet, TinyXML (`TiXml*`), ATL. ## Outputs Porting spec (Win32 → Linux substitutions, behaviour to reproduce, original bugs): `porting.md`. | Path | Content | |---|---| | `full/functions/.c` | Ghidra pseudocode for all 6,423 non-thunk functions (1 failed; see `full/index.tsv`). Includes library code (ProudNet, TinyXML, CRT) — not yet labelled. | | `full/index.tsv` | address, namespace, name, body size, decompile status | | `full/vtables.tsv` | 1,430 RTTI vftable slots → function addresses (all classes) | | `cpp/classes.hpp` | Generated C++ skeleton of 43 application classes from vftables (compiles); method names unknown | | `cpp/AgentProcessControl.cpp` | Hand-lifted C++ for the 6 analyzed functions; names inferred, not compilable as-is | | `../scripts/ExportDecomp.java`, `VTableMap.java` | Ghidra headless scripts that produced `full/` | Additional observations from the lift (`cpp/AgentProcessControl.cpp`): - Watcher thread never closes the process handle → handle leak per launch (observed). - `LaunchProcess` passes a stack `PROCESS_INFORMATION*` to the watcher thread; safe only because of the following `Sleep(1000)` (observed race, inference about intent). - `KillProcessByName` leaks the snapshot handle on the success path (observed). - RMI stubs give the protocol handler tables: `AgentManager2AgentStub` 24 slots, `Server2AgentStub` 19 (`full/vtables.tsv`). ## Findings | # | Conclusion | Type | Evidence | |---|---|---|---| | 1 | Process supervisor for the other server EXEs: launches them, kills them, watches for exit | **Observed** (code) | `0x1400094e0`, `0x140009780`, `0x140008c90` below | | 2 | Launch: `CreateProcessW(NULL, cmdline, …, CREATE_NEW_CONSOLE (0x10), …, workdir, …)`; console 700×110, fill attr 0x17; closes thread handle, spawns watcher thread, returns PID (0 on failure, logs `=======Server Fail=======` + Path/File) | Observed | `0x1400094e0.pseudo.c`, `ev_e77cf4b5…` | | 3 | Command line = ` + " " + `; args either generated (`FUN_140027540`, a global option flag at `+0x152` selects) or the numeric server code. Logs `FAILED SERVER ON %s` on failure; reports result to AgentManager via RMI proxy | Observed (flow); arg contents **unknown** | `0x140008ea0.pseudo.c`, `ev_e87b1dd7…` | | 4 | Kill: Toolhelp32 snapshot, case-insensitive exe-name match, `OpenProcess(PROCESS_TERMINATE)`, `TerminateProcess(h,0)` — kills the **first** match only, by image name (not PID) | Observed | `0x140009780.pseudo.c`, `ev_ad71d730…` | | 5 | Watcher: polls `GetExitCodeProcess` every 10 ms while `STILL_ACTIVE` (0x103); on exit sends two RMI notifications to AgentManager; **relaunches** if per-server revive flag (`+0xd5`) or global flag (`+0x171`) is set | Observed; mapping of flags to `revive_server` XML key is **inference** | `0x140008c90.pseudo.c` | | 6 | Single instance via named mutex `Global\RustyHearts_Agent`; on ERROR_ALREADY_EXISTS / ACCESS_DENIED prints, sleeps 3 s, returns failure | Observed | `0x1400100b0.pseudo.c` | | 7 | Main run loop: startup banner, `CoInitialize`, builds network objects, kills a stale process by name before running (type `0x18` entry), loop `Sleep(1)` with 100 ms tick and 1 s FPS counter; optional delayed "Start Auto Server On" after a configured time (`+0x178`) | Observed | `0x1400037a0.pseudo.c`, `ev_2fa3bc1d…` | | 8 | Networking is **ProudNet** (Nettention) — `Proud::CNetServerImpl`, `CNetClientImpl`, RMI stubs/proxies | Observed (RTTI + assert strings) | strings `ev_47e1666c…` | | 9 | Agent is both a ProudNet server (for game servers: `SERVER2AGENT_PROTOCOL` stub, `AGENT2SERVER` proxy) and client of AgentManager (`AGENTMANAGER2AGENT` stub, `AGENT2AGENTMANAGER` proxy) | Inference from RTTI class names | strings `ev_47e1666c…` | | 10 | Config files: `option\agent_serveroption.xml`, `option\agent.xml`, `option\total_option.xml`, `option\patch.xml`, `option\customoption.xml`, `option\service_control.xml` | Observed (strings); which are actually read is **unknown** — `option\agent.xml` referenced from `FUN_1400f06e0` only | `ev_d4bb4bc3…` | | 11 | Crash reporting via BugTrap (`BT_*` imports) + `MiniDumpWriteDump`; also an HTTP error reporter `GET /PNReport/ReportError.php?Text=` (ProudNet's) | Observed (imports/strings); host contacted **unknown** | imports | ## Named-function map (proposed, not applied in a persistent DB) | Address | Proposed name | |---|---| | `0x1400037a0` | `MagiAgentServer::Run` (main loop) | | `0x140008ea0` | `ServerOn(serverEntry)` | | `0x1400094e0` | `LaunchProcess(cmdline) -> pid` | | `0x140008c90` | `ProcessWatchThread` | | `0x140009780` | `KillProcessByName(name)` | | `0x1400100b0` | `AcquireSingleInstanceMutex` | ## Open questions / next steps - Decode RMI message IDs/handlers for `AGENTMANAGER2AGENT` and `SERVER2AGENT` (commands: All Server On/Down/Kill, Server Info, Shutdown, Notice, Patch). - Parse config XML loaders (`FUN_1400f06e0`, `MagiServerOption`), and map fields (`start_server`, `revive_server`, ports) to struct offsets. - Identify `FUN_140027540` (argument builder) to learn exact launch arguments. - Locate ProudNet SDK version to label library code (likely large share of the 6,814 functions).