# MessageServer_Release_x64.exe — finding ledger - SHA-256 `7911b15c4379625eaa12ff227708aa3a033bc6ac2cf6b34283136e3a62df25f1`, 1,850,368 bytes - PE32+ x86-64, Windows CUI, MSVC linker 10.0 (VS2010), timestamp 2013-02-06 09:50:56 UTC - PDB reference `c:\work\Project\Output\exe\MessageServer_Release_x64.pdb` (GUID cde07e33-d76f-49e7-887c-43afecaef251, age 1) — PDB not available - Imports: WS2_32, MSWSOCK, WINMM, KERNEL32, USER32, ADVAPI32, OLEAUT32, MSVCP100, RPCRT4, MSVCR100, BugTrapU-x64, ole32, dbghelp - Ghidra 12.1.2 via REA 6.5.0: 7,728 procedures, 1,803 defined strings (`ev_3112fedf…`) - Full Evidence: `evidence-bundle.json` (18 records). Static analysis only — nothing observed at runtime. ## Status: first pass (RMI protocol surface). Startup, config parsing, DBC link not yet decompiled. ## Language: C++ (MSVC 2010) — confirmed 180 RTTI descriptors (`.?AV…`), `__CxxFrameHandler3`, MSVCP100 import. ## Third-party libraries (all already documented in `third-party/README.md`) | Library | Signal in this binary | |---|---| | ProudNet (static) | 51 `Proud::` RTTI classes (`CNetServerImpl`, `CNetClientImpl`, …), assert strings | | TinyXML 2.5.x (static) | `TiXml*` RTTI; error table incl. `Memory allocation failed.` (removed in 2.6) | | BugTrap | `BugTrapU-x64.dll` import, `BT_SetAppVersion`, `BT_SetSupportEMail` | | dbghelp | import | | ATL | `CAtlException` RTTI | No new library found. ## Outputs | Path | Content | |---|---| | `full/functions/.c`, `full/index.tsv` | Ghidra headless pseudocode for 7,370 functions (2 failed: `0x14000cfa0` overlapping varnodes, `0x140039f20` timeout) | | `full/vtables.tsv` | 2,624 RTTI vftable slots | | `.pseudo.c` | Copies of the analysed functions below | ## Findings | # | Conclusion | Type | Evidence | |---|---|---|---| | 1 | Server-to-server chat/notice relay. RTTI classes: `RNP::Servers2MsgStub` (inbound), `RNP::Msg2ServersProxy` (outbound), `MagiMsgNetwork`/`MagiMsgServer` app classes | Observed (RTTI); role is inference | `full/vtables.tsv` | | 2 | `Servers2MsgStub::ProcessReceivedMessage` (`0x140011930`) dispatches 8 RMI IDs 0x3a99–0x3aa0 (table below) | Observed | `0x140011930.pseudo.c`, `ev_1d95f4cc…` | | 3 | Handlers are overridden in `MagiMsgNetwork` vftable `0x14015a9e8` slots 7–14 | Observed | `full/vtables.tsv` | | 4 | Whisper / all-chat / enchant notice / mail notify / unique-item notice / channel chat: collect **every** connected host ID from the host list (`this+0xc0`, lock `this+0x110`) and forward via the proxy — i.e. broadcast to all connected servers; target filtering is left to receivers | Observed (code); "receivers filter" is **inference** | `0x140007480.pseudo.c`, `0x1400075d0.pseudo.c`, `ev_f3d6252d…`, `ev_227d432a…` | | 5 | Guild chat: same broadcast but **excludes the sending host** | Observed | `0x140007340.pseudo.c`, `0x1400078e0.pseudo.c` | | 6 | Whisper ACK: unicast — looks up a key from the payload in a hash table (`this+0xb0`, bucket count `this+0xd0`) and forwards only if found | Observed; meaning of the key (server ID vs. char ID) **unknown** | `0x140007770.pseudo.c` | | 7 | Each handler logs/profiles via `FUN_1400486e0(name, …)` with `timeGetTime()` | Observed call; purpose **inference** | handlers | | 8 | Also links to DBC (`Servers2DbcProxy` 512 slots, `Dbc2ServersStub`, `MGDBCMsgSession`) and to Agent (`Agent2ServerStub`, `Server2AgentProxy`, `MGSAgentSession`) | Observed (RTTI) | `full/vtables.tsv` | | 9 | Config files referenced: `option\agent.xml`, `option\customoption.xml`, `option\patch.xml`, `option\service_control.xml` | Observed (strings); which are read **unknown** | strings | ### RMI table (Servers2Msg) | RMI ID | Name | Handler | Routing | Proxy vfn offset | |---|---|---|---|---| | 0x3a99 | REQ_MSG_WHISPER | `0x1400075d0` | all hosts | +0x28 | | 0x3a9a | REQ_MSG_WHISPER_ACK | `0x140007770` | lookup → one host | +0x40 | | 0x3a9b | REQ_MSG_GUILD_CHATTING | `0x1400078e0` | all except sender | +0x48 | | 0x3a9c | REQ_MSG_ALL_CHATTING | `0x140007a30` | all hosts | +0x58 | | 0x3a9d | REQ_MSG_ALL_ENCHANT_NOTICE | `0x140007b80` | all hosts | +0x68 | | 0x3a9e | REQ_MSG_NEW_MAIL_NOTIFY | `0x140007dd0` | all hosts | +0x78 | | 0x3a9f | REQ_MSG_ALL_UNIQUE_ITEM_GET_NOTICE | `0x140007ca0` | all hosts | +0xa8 | | 0x3aa0 | REQ_MSG_CHANNEL_CHATTING | `0x140007ed0` | all hosts | +0xb8 | ## Config, startup and DBC (second pass) Shared framework findings are written up in `docs/SHARED_FRAMEWORK.md`. The MessageServer-specific points are: | # | Conclusion | Type | Evidence | |---|---|---|---| | 10 | Startup (`0x140004f00`) runs these steps in order: AGENT, DB_LOAD (4 DBC session pools: GAME/LOG/CHAT/EMERGENCY), SESSION_CONNECT, SERVER_RUN. The main loop pumps `DBCSessionManager` and `AgentSession`, and retries failed connects | Observed | `full/functions/0x140004f00.c` | | 11 | Its default config file is `option\msg_serveroption.xml`. If `argv[1]` is numeric it runs in agent mode | Observed | `0x14012e5c0`, `0x14005c7b0` | | 12 | The option loader parses peers agentmanager, db_cache, db_log_cache, msg/gm/auction/manager/match/agent_server and api. It ignores gate/dungeon/pvp/guild/lobby | Observed | `0x14005dc20` | | 13 | The Dbc2Servers dispatcher `0x140039f20` failed to decompile (timeout) | Observed | `full/index.tsv` | | 14 | `0x140007480`/`0x140007340` iterate the host list at `+0xc0`. Where hosts are added to that list remains **unknown** | Open | | ## Proposed names (not applied) | Address | Name | |---|---| | `0x140011930` | `Servers2MsgStub::ProcessReceivedMessage` | | `0x140007480` | `MagiMsgNetwork::CollectAllHosts` | | `0x140007340` | `MagiMsgNetwork::CollectAllHostsExcept` | | `0x1400075d0`…`0x140007ed0` | `MagiMsgNetwork::On` per table | ## Open questions - Where host IDs are inserted into `this+0xc0` list and `this+0xb0` map (connect handlers / registration RMI). - What `dbc_chat` / `Servers2DbcProxy` is used for (chat logging?). - Startup/main loop, config parsing. - Payload layouts of each RMI (proxy marshalling functions `0x140010290`…`0x140011590`).