FFG.exe
testserver1.py

Im making Atom fishing server emulator. It's 2d game written on delphi. I need you to check first "testserver1.py" file (but don't be sure that information in it are correct, i just guess) and after that i need you to decompile FFG.exe and find CMD=120 and CMD=125 full structure, fields, leght and etc.

XOR key (52 bytes) — found at 0x568e7c in FFG.exe XOR_KEY = b"sdfgDDdffkojeroxdfJKHNplmkOIJHjklnIOJifg33gjkfsdpgko" XOR_KEY_LEN = 52

GameData.pkg RC6 key — found at 0x482c34 in FFG.exe RC6_KEY = b"jklHnKrt"

Dr.Binary

I'll read the testserver1.py file and open the binary in Ghidra simultaneously.

Call workspace_read_file

Arguments
{"filepath": "/sandbox/testserver1.py"}

Tool result
{"result":"#!/usr/bin/env python3\n\"\"\"\nAtom Fishing Game Server Emulator\n===================================\nReverse-engineered from FFG.exe (client binary) and protocol analysis.\n\nPROTOCOL ANALYSIS (from FFG.exe binary reverse engineering):\n============================================================\n\nPACKET HEADER (20 bytes, big-endian):\n  struct TPacketHeader {\n    uint32_t cmd;      // Command ID\n    uint32_t flags;    // 0 = text/KV payload, 1 = binary payload\n    uint32_t length;   // Payload length in bytes\n    uint32_t seq;      // Sequence number (server increments, client echoes)\n    uint32_t csum;     // Checksum: ((seq + cmd) * 3) ^ 0x1773\n  };\n\nXOR ENCRYPTION (confirmed from 0x568e1b, 0x569231 in FFG.exe):\n  KEY = b\"sdfgDDdffkojeroxdfJKHNplmkOIJHjklnIOJifg33gjkfsdpgko\"  (52 bytes)\n  encrypted[i] = plaintext[i] ^ KEY[i % 52] ^ (seq & 0xFF)\n  - CMD=1 inbound: NOT encrypted (handshake)\n  - All other payloads: XOR encrypted when sent by server\n\nCHECKSUM (confirmed from 0x569231 in FFG.exe):\n  csum = ((seq + cmd) * 3) ^ 0x1773\n\"\"\"\n\nimport socket\nimport struct\nimport threading\nimport time\nimport hashlib\nimport os\nimport traceback\nimport random\nfrom datetime import datetime\n\n# ═══════════════════════════════════════════════════════════════════\n# PROTOCOL CONSTANTS\n# ═══════════════════════════════════════════════════════════════════\n\n# XOR key (52 bytes) — found at 0x568e7c in FFG.exe\nXOR_KEY = b\"sdfgDDdffkojeroxdfJKHNplmkOIJHjklnIOJifg33gjkfsdpgko\"\nXOR_KEY_LEN = 52\n\n# GameData.pkg RC6 key — found at 0x482c34 in FFG.exe\nRC6_KEY = b\"jklHnKrt\"\n\n# Delphi TDateTime epoch\nDELPHI_EPOCH = datetime(1899, 12, 30)\n\n# Server network settings\nSERVER_HOST = \"0.0.0.0\"\nSERVER_PORT = 11000\n\n# Location/map file directories — adjust to your installation\nLOC_DIR = r\"E:\\Atom Fishing\\Data\\Maps\\Locs\"\nBASE_DIR = r\"E:\\Atom Fishing\\Data\\Maps\\Base\"\n\ndef brute_one_id_all_structs(srv, conn, player, cmd_id=160):\n    log(f\"===== BRUTE ONE ID={cmd_id} START =====\")\n\n    payloads = []\n\n    # ---- Пустые и простые ----\n    payloads += [\n        b\"\",\n        b\"\\x00\",\n        b\"\\x00\\x00\",\n        b\"\\x00\\x00\\x00\\x00\",\n        b\"\\xff\",\n        b\"\\xff\\xff\\xff\\xff\",\n    ]\n\n    # ---- Integer (разные endian и размеры) ----\n    for i in [0, 1, 2, 255, 256, 65535]:\n        payloads.append(struct.pack(\">I\", i))  # big endian\n        payloads.append(struct.pack(\"<I\", i))  # little endian\n        payloads.append(struct.pack(\">H\", i % 65536))\n        payloads.append(struct.pack(\"<H\", i % 65536))\n\n    # ---- Несколько чисел ----\n    payloads += [\n        struct.pack(\">II\", 1, 1),\n        struct.pack(\">III\", 1, 2, 3),\n        struct.pack(\"<III\", 1, 2, 3),\n    ]\n\n    # ---- Строки ----\n    payloads += [\n        b\"id=1\",\n        b\"opt=3\",\n        b\"map=1\",\n        b\"id=1\\r\\n\",\n        b\"opt=3\\r\\n\",\n        b\"map=1\\r\\n\",\n        b\"AAAA\",\n        b\"A\" * 32,\n        b\"A\" * 128,\n    ]\n\n    # ---- Null-terminated ----\n    payloads += [\n        b\"id=1\\x00\",\n        b\"test\\x00\",\n    ]\n\n    # ---- Случайные байты ----\n    for _ in range(20):\n        payloads.append(os.urandom(random.randint(1, 64)))\n\n    # ---- Повторяющиеся паттерны ----\n    payloads += [\n        b\"\\x00\" * 16,\n        b\"\\xff\" * 16,\n        b\"\\x41\\x41\\x41\\x41\",\n    ]\n\n    # ---- Длины (edge cases) ----\n    for size in [1, 2, 4, 8, 16, 32, 64, 128]:\n        payloads.append(b\"A\" * size)\n\n    # ---- Основной цикл ----\n    for flags in (0, 1):\n        for payload in payloads:\n            try:\n                log(f\"[BRUTE] CMD={cmd_id} flags={flags} len={len(payload)}\")\n\n                srv.send_pkt(\n                    conn,\n                    cmd=cmd_id,\n                    payload=payload,\n                    flags=flags,\n                    encrypt=False\n                )\n\n                time.sleep(2)\n\n            except Exception as e:\n                log(f\"[ERR] → {e}\")\n                return\n\n    log(\"===== BRUTE END =====\")\n\ndef brute_opt4(srv, conn, player):\n    log(\"===== BRUTE OPTID=3 START =====\")\n\n    test_cmds = list(range(15, 17))\n    payload = struct.pack(\"<II\", 1, 1)  # 2x uint32\n\n    for cmd in test_cmds:\n        try:\n            log(f\"[BRUTE] CMD={cmd} flags={1} len={len(payload)}\")\n\n            srv.send_pkt(conn, cmd=cmd, payload=payload, flags=1, encrypt=False)\n                        # маленькая пауза чтобы клиент успел отреагировать\n            time.sleep(2)\n            \n        except Exception as e:\n            log(f\"[ERR] CMD={cmd} → {e}\")\n            return\n\ndef brute_opt3(srv, conn, player):\n    log(\"===== BRUTE OPTID=3 START =====\")\n\n    test_cmds = list(range(201, 300))\n\n    payloads = [\n        b\"\",                                # пусто\n        b\"\\x00\\x00\\x00\\x01\",               # int=1\n        struct.pack(\">I\", 1),\n        struct.pack(\">II\", 1, 1),\n        b\"map=1\\r\\n\",\n        b\"id=1\\r\\n\",\n        b\"opt=3\\r\\n\",\n    ]\n\n    for cmd in test_cmds:\n        for flags in (0, 1):\n            for payload in payloads:\n                try:\n                    log(f\"[BRUTE] CMD={cmd} flags={flags} len={len(payload)}\")\n\n                    srv.send_pkt(conn, cmd=cmd, payload=payload, flags=flags, encrypt=False)\n\n                    # маленькая пауза чтобы клиент успел отреагировать\n                    time.sleep(0.15)\n\n                except Exception as e:\n                    log(f\"[ERR] CMD={cmd} → {e}\")\n                    return\n\ndef brute_cmd201(srv, conn, player):\n    log(\"===== BRUTE CMD=201 START =====\")\n\n    cmd = 113\n\n    payloads = []\n\n    # ── 1. Пустые / контрольные ──\n    payloads += [\n        b\"\",\n        b\"\\x00\",\n        b\"\\x00\\x00\\x00\\x00\",\n    ]\n\n    # ── 2. 32-bit ints ──\n    payloads += [\n        struct.pack(\">I\", 1),\n        struct.pack(\"<I\", 1),\n        struct.pack(\">I\", 3),\n    ]\n\n    # ── 3. 2x int struct ──\n    payloads += [\n        struct.pack(\">II\", 1, 1),\n        struct.pack(\"<II\", 1, 1),\n        struct.pack(\">II\", 201, 1),\n    ]\n\n    # ── 4. text KV ──\n    payloads += [\n        b\"opt=3\\r\\n\",\n        b\"optid=3\\r\\n\",\n        b\"id=201\\r\\n\",\n        b\"cmd=201\\r\\n\",\n    ]\n\n    # ── 5. возможный игровой стиль ──\n    payloads += [\n        b\"map=1\\r\",\n        b\"mapid=1\\r\\n\",\n        b\"type=3\\r\\n\",\n        b\"subid=3\\r\\n\",\n    ]\n\n    # ── BRUTE LOOP ──\n    for flags in (0, 1):\n        for payload in payloads:\n            try:\n                log(f\"[BRUTE] CMD=201 flags={flags} len={len(payload)} data={payload!r}\")\n\n                srv.send_pkt(\n                    conn,\n                    cmd=112,\n                    payload=payload,\n                    flags=flags,\n                    encrypt=False\n                )\n\n                time.sleep(0.10)\n\n            except Exception as e:\n                log(f\"[ERR] CMD=201 → {e}\")\n                return\n\n    log(\"===== BRUTE CMD=201 END =====\")\n\n    log(\"===== BRUTE END =====\")\n\ndef handle_map_enter(srv, conn, player, mapid):\n    log(f\"[ENTER MAP] id={mapid}\")\n\n    # 1. отправить локацию\n    send_location(srv, conn, loc_id=mapid, map_id=mapid)\n\n    # 2. базовые данные\n    send_player_data(srv, conn, player)\n\n    # 3. окружение\n    send_entities(srv, conn)\n    send_tile_info(srv, conn)\n\n    # 4. финализация\n    send_server_time(srv, conn)\n\n# ═══════════════════════════════════════════════════════════════════\n# CRYPTO / CHECKSUM\n# ═══════════════════════════════════════════════════════════════════\n\n\ndef xor_crypt(data: bytes, seq: int) -> bytes:\n    \"\"\"XOR cipher: data[i] ^= KEY[i % 52] ^ (seq & 0xFF)\"\"\"\n    seq_byte = seq & 0xFF\n    return bytes(b ^ XOR_KEY[i % XOR_KEY_LEN] ^ seq_byte for i, b in enumerate(data))\n\n\ndef make_csum(cmd: int, seq: int) -> int:\n    \"\"\"Checksum: ((seq + cmd) * 3) ^ 0x1773  — confirmed at 0x569231\"\"\"\n    return ((seq + cmd) * 3) ^ 0x1773\n\n\n# ═══════════════════════════════════════════════════════════════════\n# RAW SOCKET I/O\n# ═══════════════════════════════════════════════════════════════════\n\n\ndef recv_exact(conn: socket.socket, n: int) -> bytes:\n    buf = b\"\"\n    while len(buf) < n:\n        chunk = conn.recv(n - len(buf))\n        if not chunk:\n            raise ConnectionError(\"Connection closed by client\")\n        buf += chunk\n    return buf\n\n\ndef recv_pkt(conn: socket.socket):\n    \"\"\"\n    Read one complete packet from the socket.\n    Header: 5 × uint32 big-endian = 20 bytes\n    Returns: (cmd, flags, seq, payload_decrypted)\n    \"\"\"\n    hdr = recv_exact(conn, 20)\n    cmd, flags, length, seq, csum = struct.unpack(\">IIIII\", hdr)\n\n    expected = make_csum(cmd, seq)\n    csum_ok = csum == expected\n\n    payload_raw = recv_exact(conn, length) if length > 0 else b\"\"\n\n    # CMD=1 handshake payload is never XOR-encrypted\n    if cmd != 1 and length > 0:\n        payload = xor_crypt(payload_raw, seq)\n    else:\n        payload = payload_raw\n\n    log(\n        f\"<-- CMD={cmd} flags={flags} len={length} seq={seq} \"\n        f\"csum={'OK' if csum_ok else f'BAD(exp=0x{expected:08X})'}\"\n    )\n    if payload and len(payload) < 512:\n        try:\n            log(f\"    TXT: {payload.decode('utf-8', errors='replace')!r}\")\n        except Exception:\n            log(f\"    HEX: {payload.hex()}\")\n\n    return cmd, flags, seq, payload\n\n\n# ═══════════════════════════════════════════════════════════════════\n# SERVER STATE (per-connection)\n# ═══════════════════════════════════════════════════════════════════\n\n\nclass ServerState:\n    def __init__(self):\n        self.seq = 0  # server-side sequence counter (increments per send)\n\n    def send_pkt(\n        self,\n        conn: socket.socket,\n        cmd: int,\n        payload: bytes,\n        flags: int = 0,\n        encrypt: bool = False,\n    ):\n        \"\"\"\n        Build and transmit a packet.\n          flags=0 → text/KV payload (plain)\n          flags=1 → binary payload\n          encrypt → apply XOR cipher to payload before sending\n        \"\"\"\n        self.seq += 1\n        seq = self.seq\n        data = xor_crypt(payload, seq) if encrypt else payload\n        csum = make_csum(cmd, seq)\n        hdr = struct.pack(\">IIIII\", cmd, flags, len(payload), seq, csum)\n        conn.sendall(hdr + data)\n\n        enc_str = \"XOR\" if encrypt else \"plain\"\n        log(\n            f\"--> CMD={cmd} flags={flags} seq={seq} len={len(payload)} \"\n            f\"csum=0x{csum:08X} [{enc_str}]\"\n        )\n        if payload and len(payload) < 512:\n            try:\n                log(f\"    TXT: {payload.decode('utf-8', errors='replace')!r}\")\n            except Exception:\n                log(f\"    HEX: {payload.hex()}\")\n\n\n# ═══════════════════════════════════════════════════════════════════\n# UTILITIES\n# ═══════════════════════════════════════════════════════════════════\n\n\ndef log(msg: str):\n    ts = datetime.now().strftime(\"%H:%M:%S.%f\")[:-3]\n    print(f\"[{ts}] {msg}\")\n\n\ndef parse_kv(payload: bytes) -> dict:\n    \"\"\"Parse key=value payload (\\\\r\\\\n or \\\\n separated) into dict.\"\"\"\n    result = {}\n    text = payload.replace(b\"\\r\\n\", b\"\\n\").replace(b\"\\r\", b\"\\n\")\n    for line in text.split(b\"\\n\"):\n        line = line.strip()\n        if b\"=\" in line:\n            k, _, v = line.partition(b\"=\")\n            result[k.decode(\"utf-8\", errors=\"replace\").strip()] = v.decode(\n                \"utf-8\", errors=\"replace\"\n            ).strip()\n    return result\n\n\ndef delphi_now() -> float:\n    \"\"\"Current time as Delphi TDateTime (double: days since 1899-12-30).\"\"\"\n    delta = datetime.now() - DELPHI_EPOCH\n    return delta.days + delta.seconds / 86400.0 + delta.microseconds / 86_400_000_000.0\n\n\ndef delphi_datetime_str() -> str:\n    \"\"\"\n    Current date/time as Delphi-compatible string: D.M.YYYY H:MM:SS.0\n    Used in the 'datetime=' field of CMD=100 player data.\n    Delphi's StrToDateTime expects this exact format (no leading zeros in\n    day/month/hour is fine; the decimal .0 represents milliseconds).\n    \"\"\"\n    now = datetime.now()\n    return f\"{now.day}.{now.month}.{now.year} {now.hour}:{now.minute:02d}:{now.second:02d}.0\"\n\n\ndef get_game_time() -> tuple:\n    \"\"\"\n    Game time: 24 game-hours = 1 real hour.\n    Step = 10 game-minutes = 25 real seconds.\n    Returns: (real_datetime, game_hours, game_minutes)\n    \"\"\"\n    now = datetime.now()\n    real_seconds = now.minute * 60 + now.second\n    step = real_seconds // 25\n    game_hours = step // 6\n    game_minutes = (step % 6) * 10\n    return now, game_hours, game_minutes\n\n\ndef get_loc_hash(loc_id: int, map_id: int) -> str:\n    \"\"\"MD5 of the .loc or .base file for the given location.\"\"\"\n    if loc_id > 0:\n        filepath = os.path.join(LOC_DIR, f\"{loc_id}.loc\")\n    else:\n        filepath = os.path.join(BASE_DIR, f\"{map_id}.base\")\n\n    if not os.path.exists(filepath):\n        log(f\"  [HASH] File not found: {filepath} → returning zero hash\")\n        return \"00000000000000000000000000000000\"\n\n    with open(filepath, \"rb\") as f:\n        data = f.read()\n    md5 = hashlib.md5(data).hexdigest().upper()\n    log(f\"  [HASH] {filepath} → {md5}\")\n    return md5\n\n\n# ═══════════════════════════════════════════════════════════════════\n# PLAYER PROFILE BUILDER\n# ═══════════════════════════════════════════════════════════════════\n\n\ndef build_player_kv(\n    login: str = \"player\",\n    loc_id: int = 3,\n    map_id: int = 1,\n    player_id: int = 1,\n    level: int = 100,\n    raz: int = 20,\n    daycount: int = 30,\n    perkspoint: int = 4,\n    blife: int = 100,\n    life: int = 100,\n    rad: int = 5,\n    brad: int = 100,\n    fishcount: int = 2,\n    exp: int = 600,\n    levexp: int = 1000,\n    money: int = 1_000_000,\n    rmoney: int = 1_000_000,\n    invlines: int = 40,\n    admlevel: int = 7,\n    rating: int = 8,\n    artelid: int = 0,\n    artstat: int = 0,\n    artcreator: int = 0,\n) -> bytes:\n    \"\"\"\n    Build the CMD=100 text response payload.\n    Field names confirmed from FFG.exe strings @ 0x4e78d8 region.\n\n    FIX: 'datetime=' field MUST be included with current server date/time\n    in format D.M.YYYY H:MM:SS.0  (Delphi StrToDateTime compatible).\n    Absence of this field causes the \"0.0.0 0:0:0.0 is not a valid date\n    and time\" error in the client on login and every keepalive cycle.\n    \"\"\"\n    fields = [\n        (\"no_login\", \"0\"),\n        (\"id\", str(player_id)),\n        (\"name\", login),\n        (\"level\", str(level)),\n        (\"raz\", str(raz)),\n        (\"daycount\", str(daycount)),\n        (\"perkspoint\", str(perkspoint)),\n        (\"blife\", str(blife)),\n        (\"life\", str(life)),\n        (\"rad\", str(rad)),\n        (\"brad\", str(brad)),\n        (\"fishcount\", str(fishcount)),\n        (\"exp\", str(exp)),\n        (\"levexp\", str(levexp)),\n        (\"money\""}

Call ghidra_open_server

Arguments
{"filepath":"/sandbox/FFG.exe"}

Tool result
{"result":"compilerID: borlanddelphi\nimports[5]:\n  - functions[2]: CoTaskMemAlloc,CoTaskMemFree\n    name: OLE32.DLL\n  - functions[11]: SysReAllocStringLen,SysFreeString,SysAllocStringLen,VariantInit,VariantClear,VariantCopy,SafeArrayCreate,SafeArrayGetLBound,SafeArrayGetUBound,SafeArrayPtrOfIndex,VariantChangeType\n    name: OLEAUT32.DLL\n  - functions[16]: BASS_SampleStop,BASS_MusicFree,BASS_Free,BASS_MusicLoad,BASS_MusicPlay,BASS_SampleLoad,BASS_SampleFree,BASS_SamplePlayEx,BASS_StreamFree,BASS_ChannelStop,BASS_ChannelSetAttributes,BASS_StreamCreateFile,BASS_StreamPlay,BASS_GetVersion,BASS_Init,BASS_Start\n    name: BASS.DLL\n  - functions[182]: CharNextA,MessageBoxA,LoadStringA,DefWindowProcA,DispatchMessageA,DispatchMessageW,EnumWindows,GetCapture,GetCursorPos,GetParent,GetPropA,GetWindow,GetWindowLongA,GetWindowThreadProcessId,IsDialogMessageA,IsDialogMessageW,IsIconic,IsWindowEnabled,IsWindowUnicode,IsWindowVisible,KillTimer,PeekMessageA,PeekMessageW,PtInRect,SendMessageA,SendMessageW,SetActiveWindow,SetTimer,SetWindowPos,SetWindowTextA,ShowOwnedPopups,ShowWindow,SystemParametersInfoA,TranslateMDISysAccel,TranslateMessage,UnhookWindowsHookEx,WaitMessage,WindowFromPoint,ActivateKeyboardLayout,CharLowerA,BeginPaint,CallNextHookEx,ChangeDisplaySettingsA,CharLowerBuffA,CharNextA,CharUpperBuffA,CheckMenuItem,ClientToScreen,CloseClipboard,CreateMenu,CreatePopupMenu,DeleteMenu,DestroyMenu,DestroyWindow,DrawEdge,DrawFrameControl,DrawMenuBar,DrawTextA,EnableMenuItem,EnableWindow,EndPaint,EnumClipboardFormats,EnumThreadWindows,EqualRect,FillRect,FindWindowA,FlashWindow,FrameRect,GetActiveWindow,GetClassInfoA,GetClassLongA,GetClassNameA,GetClipboardData,GetCursor,GetDC,GetDCEx,GetDesktopWindow,GetFocus,GetIconInfo,GetKeyNameTextA,GetKeyState,GetKeyboardLayout,GetKeyboardLayoutList,GetKeyboardLayoutNameA,GetLastActivePopup,GetMenu,GetMenuItemCount,GetMenuItemID,GetMenuItemInfoA,GetMenuState,GetMenuStringA,GetSubMenu,GetSysColor,GetSystemMenu,GetSystemMetrics,GetTopWindow,GetWindowPlacement,GetWindowRect,GetWindowTextA,InflateRect,InsertMenuA,InsertMenuItemA,IntersectRect,InvalidateRect,IsChild,IsWindow,LoadBitmapA,LoadCursorA,LoadIconA,MapVirtualKeyA,MapWindowPoints,MessageBoxA,MsgWaitForMultipleObjects,OemToCharA,OffsetRect,OpenClipboard,PostMessageA,PostQuitMessage,RedrawWindow,RegisterClassA,RegisterWindowMessageA,ReleaseCapture,ReleaseDC,RemoveMenu,RemovePropA,ScreenToClient,ScrollWindow,SetCapture,SetClassLongA,SetClipboardData,SetCursor,SetFocus,SetForegroundWindow,SetMenu,SetMenuItemInfoA,SetParent,SetPropA,SetRect,SetWindowLongA,SetWindowPlacement,SetWindowsHookExA,ShowCursor,UnregisterClassA,UpdateWindow,CreateWindowExA,CharToOemA,CreateIcon,EmptyClipboard,GetWindowLongW,LoadStringA,MessageBeep,SetWindowLongW,DrawIcon,GetKeyboardType,AdjustWindowRectEx,EnumChildWindows,GetClientRect,GetKeyboardState,GetMessagePos,GetWindowDC,IsRectEmpty,DestroyIcon,CallWindowProcA,DefFrameProcA,SetScrollInfo,RegisterClipboardFormatA,SetScrollRange,DestroyWindow,LoadKeyboardLayoutA,EnableScrollBar,DrawIconEx,GetSysColorBrush,GetScrollPos,ShowScrollBar,SetScrollPos,GetScrollRange,TrackPopupMenu,GetForegroundWindow,GetScrollInfo,IsZoomed,DestroyCursor,DefMDIChildProcA\n    name: USER32.DLL\n  - name: truncated... (more than 100 imports found)\n    functions[1]: truncated\nexports[1]{address,name}:\n  0056c060,entry\nformat: Portable Executable (PE)\nlanguageID: \"x86:LE:32:default\"\nprocessor: x86\nendianess: Little Endian\nsegments[12]{name,start,end}:\n  Headers,\"00400000\",004003ff\n  .text,\"00401000\",0056a7ff\n  .itext,0056b000,0056c1ff\n  .data,0056d000,005713ff\n  .bss,\"00572000\",0057e43b\n  .idata,0057f000,005821ff\n  .tls,\"00583000\",\"00583033\"\n  .rdata,\"00584000\",005841ff\n  .vmp0,\"00585000\",005a01ff\n  .rsrc,005a1000,005a83ff\n  .vmp1,005a9000,005a91ff\n  .reloc,005aa000,005c51ff\naddressSize: 32 bit\nimageBase: \"00400000\"\nnamedFunctions[1]{address,name}:\n  0056c060,entry\nstrings[101]{address,value}:\n  00581c66,ImageList_GetIconSize\n  004e8fb4,SHOP_BAITES\n  \"00454664\",traynotify\n  0054b298,spinid=\n  004dc530,\"[LOC]\"\n  \"00441866\",TDockOverEvent\n  004a83f8,glClipPlane\n  0049c3a0,glMultiTexCoord2dvARB\n  00499dc0,glGetIntegerv\n  00542c58,error.wav\n  \"00501498\",csIBM903\n  \"00516268\",_KeyCraft\n  0049bbc0,glVertexAttrib4Nubv\n  0049d850,glColorFragmentOp2ATI\n  004fefcc,csISO25French\n  004ba52c,glGenAsyncMarkersSGIX\n  \"00580242\",LoadLibraryExA\n  004684a0,LoadPlugin\n  \"00500378\",iso-ir-146\n  0051df54,\"http://stat.atomfish.ru/login.php\"\n  0049fa6c,glBindTextureUnitParameterEXT\n  004aaa80,glPrioritizeTextures\n  004a6594,GL_EXT_color_subtable\n  \"00430557\",ParentColor\n  \"00500e34\",cp423\n  004dc954,turnend\n  004a8b2c,glCopyPixels\n  004b1be4,glVertexAttrib4sARB\n  004a77d4,GL_SGIX_framezoom\n  00581f38,BASS_Free\n  004aaae8,glPushClientAttrib\n  \"0049e018\",glVertexStream3fATI\n  004ff39c,csISO60Norwegian1\n  004a65b4,GL_EXT_compiled_vertex_array\n  0049f1f4,glSecondaryColor3fEXT\n  004b81b8,glMultiTexCoord1hvNV\n  004b2a4c,glDeleteFragmentShaderATI\n  0051965c,Login\n  00581b98,SafeArrayPtrOfIndex\n  004274d4,clMenuText\n  \"00427470\",clInfoBk\n  004a8d8c,glDepthRange\n  00468dac,Get2DPos\n  0051543c,travelBack.jpg\n  005014fc,CP905\n  0049af5c,glMultiTexCoord3d\n  0050a6ec,Password\n  004a2684,glGlobalAlphaFactordSUN\n  0049cdfc,glVertexAttrib2dARB\n  0041058c,VarBstrFromDate\n  004974b4,gluNurbsCallback\n  004b13c8,glVertexAttrib4usv\n  004bb3a0,glGlobalAlphaFactordSUN\n  \"00536758\",baitid=\n  004594ac,OnMouseDownl;A\n  004ff61c,csISO87JISX0208\n  \"00501744\",csEBCDICIT\n  005002ec,\"ISO_8859-5:1988\"\n  00499ea0,glGetTexEnviv\n  004ac854,glConvolutionFilter1D\n  004a2358,glDeformSGIX\n  0055f4a4,\"GUI\\\\WinHeader.bmp\"\n  004ae2fc,glWindowPos3dv\n  004af028,glMultiTexCoord3iARB\n  004df2a0,fmask=\n  \"00454690\",window\n  \"00580314\",ExitProcess\n  00499c94,glEvalCoord2dv\n  004b26dc,glWindowPos3ivARB\n  004b17e8,glVertexAttrib3fvARB\n  005011ec,csIBM863\n  0049c520,glMultiTexCoord4dvARB\n  004ffe84,\"ISO_8859-6:1987\"\n  0052b0b4,turntype_\n  004230d2,IniFiles\n  004a0ec0,glCombinerParameterfvNV\n  004a3ee0,glValidateProgramARB\n  005154c0,plight.tga\n  004ab860,glTexCoord3f\n  0056ed38,incomplete dynamic bit lengths tree\n  004a4234,glGetQueryivARB\n  0049cda4,glVertexAttrib1fARB\n  004b7160,glNormalPointervINTEL\n  004af378,glPointParameterfvARB\n  004a2bb4,glTexCoord2fColor3fVertex3fSUN\n  0055f390,\"GUI\\\\LightPanel.jpg\"\n  004aa070,glLoadMatrixd\n  00440b9c,Controls\n  004a5e6c,GL_ARB_multisample\n  0052c3c4,\"http://stat.atomfish.ru/turn.php?turnid=%d&ttype=%d&uname=%s\"\n  004dcd55,\" : %s %s\"\n  0043117d,ParentColor\n  00500d78,csIBM290\n  \"004e7448\",optid\n  005017a8,EBCDIC-ES-A\n  \"00499928\",glColor3bv\n  0049e2e8,glColorSubTableEXT\n  004a2174,glPollInstrumentsSGIX\n  00554ae0,fishingreel.ogg\n  004363b8,\"\\\\tOnEndDragl;A\"\n  truncated... (more than 100 strings found),truncated\nfileSize: 1769472 bytes\nentryPoint: 0056c060"}

Good. Now let me search for CMD=120 and CMD=125 handlers in the binary by looking at strings and the packet dispatch logic.

Call ghidra_list_strings

Arguments
{"filepath": "/sandbox/FFG.exe", "filter": "cmd="}

Tool result
{"result":[]}

Call ghidra_search_functions_by_name

Arguments
{"filepath": "/sandbox/FFG.exe", "query": "recv"}

Tool result
{"result":["No functions matching 'recv'"]}

Call ghidra_search_functions_by_name

Arguments
{"filepath": "/sandbox/FFG.exe","query": "socket"}

Tool result
{"result":["No functions matching 'socket'"]}

Call ghidra_list_strings

Arguments
{"filepath":"/sandbox/FFG.exe", "filter":"login"}

Tool result
{"result":["00422b58: \"TaskDialogIndirect\"","004e72cc: \"login\"","004e730c: \"no_login=1\"","004e9c60: \"User logined:\"","0051237c: \"http://stat.atomfish.ru/login.php\"","0051965c: \"Login\"","00519768: \"no_login\"","0051a110: \"Login_\"","0051a134: \"login\"","0051a158: \"Login\"","0051a48c: \"Login_\"","0051a4b0: \"login\"","0051a4d4: \"Login\"","0051a814: \"login=\"","0051ad50: \"login=\"","0051c310: \"login\"","0051c350: \"mmLogin\"","0051c74c: \"http://stat.atomfish.ru/login.php\"","0051c78c: \"Login\"","0051c7fc: \"http://stat.atomfish.ru/changepass.php?login=%s&eml=%s&srv=%d\"","0051c844: \"http://stat.atomfish.ru/changepass2.php?login=%s&eml=%s&srv=%d\"","0051c940: \"nologin\"","0051df54: \"http://stat.atomfish.ru/login.php\"","005207e0: \"[login]\""]}

Let me look at the data region near 0x4e72cc (login/optid strings) and search for packet-related strings.

Call ghidra_list_strings

Arguments
{"filepath": "/sandbox/FFG.exe", "filter": "optid"}

Tool result
{"result":["004e7448: \"optid\"","0051ff18: \"optid=10\\rsubid=\"","005315c4: \"optid=\"","00533434: \"optid\""]}

Call ghidra_list_strings

Arguments
{"filepath": "/sandbox/FFG.exe", "filter": "baitid"}

Tool result
{"result":["004e73e4: \"baitid\"","004e87e4: \"otbaitid\"","004e9c00: \"otbaitid\"","004ea0a0: \"otbaitid=\"","0051eec0: \"baitid=\"","00520a38: \"baitid\"","00536758: \"baitid=\"","00537c0c: \"baitid=\"","00545b14: \"FBaitID=\"","0054b288: \"baitid=\"","0054fa30: \"baitid=\"","00550064: \"otbaitid=\""]}

Let me search for more relevant strings and find xrefs to key data strings to locate packet handlers.

Call ghidra_list_strings

Arguments
{"filepath": "/sandbox/FFG.exe", "filter": "cast"}

Tool result
{"result":["00468e2c: \"CastShadowMap\"","005161d8: \"_ReCast\"","005161e8: \"_AltReCast\"","00521878: \"castrod\""]}

Call ghidra_list_strings

Arguments
{"filepath": "/sandbox/FFG.exe", "filter":"fish"}

Tool result
{"result":["004d7340: \"fishs\"","004d7360: \"Fish%d.dta\"","004d8784: \"[fish]\"","004dca68: \"removefish\"","004dcf50: \"fishsale\"","004e1028: \"[fish]\"","004e739c: \"fishid\"","004e7ea4: \"fish=%d/%d/%d\"","004e812c: \"fish=%d/%d/%d\"","004e8560: \"fishcount=\"","004e9b64: \"fishid\"","004e9f50: \"fishid=\"","0051237c: \"http://stat.atomfish.ru/login.php\"","00514f68: \"Fisher.tga\"","00515160: \"FishMarker.tga\"","00515178: \"FishMarker2.tga\"","00515294: \"fishonrod.tga\"","0051553c: \"Fish.dta\"","00515580: \"fishlight.dta\"","00516168: \"Data\\Textures\\Fish\\\"","00516254: \"_relFish\"","0051c6a4: \"http://stat.atomfish.ru/stat.php\"","0051c6d8: \"http://www.atomfish.ru/\"","0051c74c: \"http://stat.atomfish.ru/login.php\"","0051c7fc: \"http://stat.atomfish.ru/changepass.php?login=%s&eml=%s&srv=%d\"","0051c844: \"http://stat.atomfish.ru/changepass2.php?login=%s&eml=%s&srv=%d\"","0051d684: \"Music\\atomfishingMenu.ogg\"","0051df54: \"http://stat.atomfish.ru/login.php\"","005208a8: \"fishid\"","0052189c: \"fishtorod\"","00522170: \"wpfishid\"","0052220c: \"[fish]\"","00522a8c: \"wpfishid\"","00522b28: \"[fish]\"","00524008: \"turnfish=\"","005241fc: \"FISHES\"","00524838: \"fish selector\"","005288b4: \"tfishid\"","0052a1ac: \"http://stat.atomfish.ru/turn.php?turnid=%d&ttype=%d&uname=%s\"","0052a5c0: \"fishid\"","0052b9b4: \"http://stat.atomfish.ru/turn.php?turnid=%d&ttype=%d&uname=%s\"","0052bc30: \"fishid\"","0052c3c4: \"http://stat.atomfish.ru/turn.php?turnid=%d&ttype=%d&uname=%s\"","0052cca0: \"http://stat.atomfish.ru/turn.php?turnid=%d&ttype=%d&uname=%s\"","0052cef4: \"fishid\"","0052e270: \"FISHES\"","00530e18: \"FISHES\"","00533324: \"nosalefish\"","00534cd4: \"fishoid=\"","00534ce8: \"fishid=\"","00534cf8: \"fishname=\"","00534d0c: \"fishweight=\"","00536738: \"fishoid=\"","0053692c: \"fishoid=\"","00536940: \"fishsplash7.ogg\"","00537530: \"fishoid=\"","00537544: \"fishid=\"","005391dc: \"FISHES\"","005396bc: \"salebigfish\"","0053970c: \"salesmallfish\"","0053ddb8: \"[url=http://stat.atomfish.ru/trophy.php?tid=%d][img]http://stat.atomfish.ru/fimg/%d.GIF[/img][/url] %s\"","0053de28: \"[url=http://stat.atomfish.ru/trophy2.php?tid=%d][img]http://stat.atomfish.ru/fimg/%d.GIF[/img][/url] %s\"","0053df3c: \"[url=http://stat.atomfish.ru/trophy.php?tid=%d][img]http://stat.atomfish.ru/fimg/%d.GIF[/img][/url] %s\\r\\n\"","0053dfb0: \"[url=http://stat.atomfish.ru/trophy2.php?tid=%d][img]http://stat.atomfish.ru/fimg/%d.GIF[/img][/url] %s\\r\\n\"","0053e0d4: \"http://www.atomfish.ru\"","0053e108: \"http://www.atomfish.ru/statistics/\"","0053fe94: \"FISHES\"","0054570c: \"FFishID=\"","00545720: \"FFishImageID=\"","0054a250: \"http://updates.atomfish.ru/services/artimager/index.php?artid=%d&randc=%d&sid=%d&cntrl=%s&curimgname=%s&artname=%s\"","0054bb2c: \"FishLog.txt\"","0054bf0c: \"fishcount\"","0054e220: \"FISHES\"","0054f0c6: \"TRodFish|\"","00554ae0: \"fishingreel.ogg\"","00554b74: \"fishreelgo.ogg\"","005551fc: \"fishingreel.ogg\"","005552b4: \"fishsplash\"","00558b9c: \"fish_broke\"","0055949c: \"fishPosControl posControl Error\"","0055958c: \"fishPosControl posControl Error\""]}

Let me get xrefs to the key fishing action strings to find packet handlers.

Call ghidra_get_xrefs_to

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x00521878"}

Tool result
{"result":["From 00521739 in FUN_0052162c [PARAM]"]}

Call ghidra_get_xrefs_to

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x0052189c"}

Tool result
{"result":["From 005217b1 in FUN_0052162c [PARAM]"]}

Call ghidra_get_xrefs_to

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x004dc954"}

Tool result
{"result":["From 004dab22 in FUN_004d99d8 [PARAM]"]}

Let me decompile FUN_0052162c (castrod/fishtorod handler) and also look for CMD-number dispatch.

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_0052162c"}

Tool result
{"result":"\nvoid FUN_0052162c(undefined4 param_1,int param_2)\n\n{\n  char cVar1;\n  int *piVar2;\n  LPCSTR lpFile;\n  HWND hwnd;\n  short extraout_CX;\n  int iVar3;\n  undefined4 extraout_ECX;\n  undefined4 extraout_ECX_00;\n  undefined4 *in_FS_OFFSET;\n  int local_c8 [2];\n  int local_c0;\n  int local_a0 [2];\n  int local_98;\n  int local_78 [2];\n  int local_70;\n  undefined4 uStackY_58;\n  longlong *in_stack_ffffffb0;\n  LPCSTR lpOperation;\n  LPCSTR lpParameters;\n  int in_stack_ffffffbc;\n  LPCSTR lpDirectory;\n  INT nShowCmd;\n  undefined4 uStack_3c;\n  undefined1 *puStack_38;\n  undefined1 *local_34;\n  undefined4 uStack_2c;\n  undefined1 *puStack_28;\n  undefined1 *puStack_24;\n  undefined4 uStack_20;\n  undefined1 *local_1c;\n  int *local_18;\n  \n  iVar3 = 0x18;\n  do {\n    iVar3 = iVar3 + -1;\n  } while (iVar3 != 0);\n  local_18 = (int *)0x521651;\n  FUN_00405b24((int)&stack0xffffffb4,(int)PTR_DAT_0041efec);\n  local_1c = &LAB_0052183d;\n  uStack_20 = *in_FS_OFFSET;\n  *in_FS_OFFSET = &uStack_20;\n  puStack_24 = (undefined1 *)0x52166b;\n  local_18 = (int *)&stack0xfffffffc;\n  piVar2 = (int *)FUN_00404154((int *)PTR_PTR_0041475c,'\\x01',extraout_ECX);\n  puStack_28 = &LAB_005217fc;\n  uStack_2c = *in_FS_OFFSET;\n  *in_FS_OFFSET = &uStack_2c;\n  puStack_24 = &stack0xfffffffc;\n  (**(code **)(*piVar2 + 0x2c))(piVar2,*(undefined4 *)(param_2 + 0x34));\n  iVar3 = (**(code **)(*piVar2 + 0x14))();\n  if (-1 < iVar3 + -1) {\n    local_1c = (undefined1 *)iVar3;\n    (**(code **)(*piVar2 + 0xc))(piVar2,0,&stack0xffffffb0);\n    FUN_0041f32c(in_stack_ffffffb0,(int *)&stack0xffffffb4);\n    local_34 = (undefined1 *)0x5216d1;\n    local_18 = (int *)FUN_0041fa5c((int *)PTR_DAT_0041f034,'\\x01',\n                                   CONCAT31((int3)((uint)extraout_ECX_00 >> 8),0x7c),\n                                   in_stack_ffffffbc);\n    puStack_38 = &LAB_005217d3;\n    uStack_3c = *in_FS_OFFSET;\n    *in_FS_OFFSET = &uStack_3c;\n    local_34 = &stack0xfffffffc;\n    cVar1 = FUN_0041fcac((int)&stack0xffffffb4,0x521854);\n    if (cVar1 != '\\0') {\n      nShowCmd = 0;\n      lpDirectory = (LPCSTR)0x0;\n      lpParameters = (LPCSTR)0x0;\n      lpFile = FUN_004054f4((undefined *)0x0);\n      lpOperation = \"open\";\n      hwnd = (HWND)(**(code **)PTR_DAT_00570c7c)();\n      uStackY_58 = 0x521716;\n      ShellExecuteA(hwnd,lpOperation,lpFile,lpParameters,lpDirectory,nShowCmd);\n    }\n    cVar1 = FUN_0041fcac((int)&stack0xffffffb4,0x521868);\n    if (cVar1 != '\\0') {\n      FUN_0054fdf8(*(int *)PTR_DAT_00570c84,(int)local_34,extraout_CX);\n    }\n    cVar1 = FUN_0041fcac((int)&stack0xffffffb4,0x521878);\n    if (cVar1 != '\\0') {\n      FUN_0041fb1c((int)local_18,2,local_78);\n      FUN_0041fb1c((int)local_18,1,local_a0);\n      FUN_0041fb1c((int)local_18,0,local_c8);\n      FUN_0054f594(*(int *)PTR_DAT_00570c84,local_c0,local_98,local_70);\n    }\n    cVar1 = FUN_0041fcac((int)&stack0xffffffb4,0x521888);\n    if (cVar1 != '\\0') {\n      FUN_005382e8();\n    }\n    FUN_0041fcac((int)&stack0xffffffb4,0x52189c);\n    *in_FS_OFFSET = uStack_3c;\n    local_34 = &DAT_005217da;\n    puStack_38 = (undefined1 *)0x5217d2;\n    FUN_00404184(local_18);\n    return;\n  }\n  *in_FS_OFFSET = uStack_2c;\n  puStack_24 = &LAB_00521803;\n  puStack_28 = (undefined1 *)0x5217fb;\n  FUN_00404184(piVar2);\n  return;\n}\n\n"}

Call ghidra_get_xrefs_to

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x004e739c"}

Tool result
{"result":["From 004e6881 in FUN_004e6464 [PARAM]","From 004e6909 in FUN_004e6464 [PARAM]","From 004e6b38 in FUN_004e6464 [PARAM]","From 004e6a9a in FUN_004e6464 [PARAM]"]}

FUN_004e6464 references fishid multiple times - likely the main packet handler. Let me decompile it.

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_004e6464"}

Tool result
{"result":"Succeeded and the artifact is saved at /sandbox/ghidra/decompiled_0x4e6464.txt. Please find the table of contents below. \n[{'funcName': 'FUN_00405088', 'lineNum': 137}, {'funcName': 'FUN_00405088', 'lineNum': 139}, {'funcName': 'FUN_00405088', 'lineNum': 141}, {'funcName': 'FUN_00405064', 'lineNum': 143}, {'funcName': 'FUN_004168a4', 'lineNum': 147}, {'funcName': 'FUN_004099ec', 'lineNum': 154}, {'funcName': 'FUN_004053f8', 'lineNum': 159}, {'funcName': 'FUN_0046984c', 'lineNum': 160}, {'funcName': 'FUN_004e5508', 'lineNum': 164}, {'funcName': 'FUN_004e5fc8', 'lineNum': 165}, {'funcName': 'FUN_004e8a58', 'lineNum': 166}, {'funcName': 'FUN_004e5fc8', 'lineNum': 167}, {'funcName': 'FUN_004e8994', 'lineNum': 168}, {'funcName': 'FUN_004e5fc8', 'lineNum': 169}, {'funcName': 'FUN_004e62f4', 'lineNum': 173}, {'funcName': 'FUN_004e6288', 'lineNum': 174}, {'funcName': 'FUN_004e6288', 'lineNum': 176}, {'funcName': 'FUN_004e6288', 'lineNum': 178}, {'funcName': 'FUN_004e7618', 'lineNum': 181}, {'funcName': 'FUN_004e6288', 'lineNum': 183}, {'funcName': 'FUN_004099ec', 'lineNum': 186}, {'funcName': 'FUN_004099ec', 'lineNum': 191}, {'funcName': 'FUN_004053f8', 'lineNum': 194}, {'funcName': 'FUN_004e5fc8', 'lineNum': 196}, {'funcName': 'FUN_004e6288', 'lineNum': 198}, {'funcName': 'FUN_0054daac', 'lineNum': 200}, {'funcName': 'FUN_004e6288', 'lineNum': 203}, {'funcName': 'FUN_004e81c8', 'lineNum': 206}, {'funcName': 'FUN_004e6288', 'lineNum': 208}, {'funcName': 'FUN_0054e824', 'lineNum': 211}, {'funcName': 'FUN_004e81c8', 'lineNum': 213}, {'funcName': 'FUN_004033f0', 'lineNum': 216}, {'funcName': 'FUN_004e5d88', 'lineNum': 218}, {'funcName': 'FUN_004e6288', 'lineNum': 221}, {'funcName': 'FUN_004e904c', 'lineNum': 223}, {'funcName': 'FUN_004e8210', 'lineNum': 225}, {'funcName': 'FUN_004e5fc8', 'lineNum': 227}, {'funcName': 'FUN_004e89ec', 'lineNum': 229}, {'funcName': 'FUN_004e5fc8', 'lineNum': 231}, {'funcName': 'FUN_004e8a58', 'lineNum': 233}, {'funcName': 'FUN_004e5fc8', 'lineNum': 235}, {'funcName': 'FUN_004e8994', 'lineNum': 237}, {'funcName': 'FUN_004e5fc8', 'lineNum': 239}, {'funcName': 'FUN_004e62f4', 'lineNum': 242}, {'funcName': 'FUN_004e90c0', 'lineNum': 243}, {'funcName': 'FUN_004e5fc8', 'lineNum': 245}, {'funcName': 'FUN_004e8210', 'lineNum': 248}, {'funcName': 'FUN_004e5fc8', 'lineNum': 251}, {'funcName': 'FUN_004e89ec', 'lineNum': 253}, {'funcName': 'FUN_004e5fc8', 'lineNum': 254}, {'funcName': 'FUN_0040b75c', 'lineNum': 257}, {'funcName': 'FUN_0040537c', 'lineNum': 258}, {'funcName': 'FUN_004e5fc8', 'lineNum': 259}, {'funcName': 'FUN_004e8580', 'lineNum': 260}, {'funcName': 'FUN_004e5fc8', 'lineNum': 261}, {'funcName': 'FUN_004e5508', 'lineNum': 262}, {'funcName': 'FUN_004e5fc8', 'lineNum': 263}, {'funcName': 'FUN_004e8a58', 'lineNum': 264}, {'funcName': 'FUN_004e5fc8', 'lineNum': 265}, {'funcName': 'FUN_004e8994', 'lineNum': 266}, {'funcName': 'FUN_004e5fc8', 'lineNum': 267}, {'funcName': 'FUN_0040ac40', 'lineNum': 272}, {'funcName': 'FUN_004e5fc8', 'lineNum': 273}, {'funcName': 'FUN_004e6288', 'lineNum': 277}, {'funcName': 'FUN_004e7758', 'lineNum': 278}, {'funcName': 'FUN_004e89ec', 'lineNum': 279}, {'funcName': 'FUN_004e5fc8', 'lineNum': 280}, {'funcName': 'FUN_004e89ec', 'lineNum': 283}, {'funcName': 'FUN_004e5fc8', 'lineNum': 284}, {'funcName': 'FUN_004e6288', 'lineNum': 287}, {'funcName': 'FUN_004e891c', 'lineNum': 288}, {'funcName': 'FUN_004e6288', 'lineNum': 289}, {'funcName': 'FUN_004e88e0', 'lineNum': 290}, {'funcName': 'FUN_0040ac40', 'lineNum': 295}, {'funcName': 'FUN_004e5fc8', 'lineNum': 296}, {'funcName': 'FUN_004e8acc', 'lineNum': 297}, {'funcName': '(ram, 0x4e6218, 8)', 'lineNum': 301}, {'funcName': 'FUN_004e6288', 'lineNum': 304}, {'funcName': 'FUN_004e6288', 'lineNum': 306}, {'funcName': 'FUN_004e7ef4', 'lineNum': 308}, {'funcName': 'FUN_004e8210', 'lineNum': 310}, {'funcName': 'FUN_004e5fc8', 'lineNum': 312}, {'funcName': 'FUN_004e89ec', 'lineNum': 314}, {'funcName': 'FUN_004e5fc8', 'lineNum': 316}, {'funcName': 'FUN_004e8580', 'lineNum': 318}, {'funcName': 'FUN_004e5fc8', 'lineNum': 320}, {'funcName': 'FUN_004e5fc8', 'lineNum': 322}, {'funcName': 'FUN_004e6288', 'lineNum': 325}, {'funcName': 'FUN_004e7f0c', 'lineNum': 326}, {'funcName': 'FUN_004e8210', 'lineNum': 327}, {'funcName': 'FUN_004e5fc8', 'lineNum': 328}, {'funcName': 'FUN_004e89ec', 'lineNum': 329}, {'funcName': 'FUN_004e5fc8', 'lineNum': 330}, {'funcName': 'FUN_004e8580', 'lineNum': 331}, {'funcName': 'FUN_004e5fc8', 'lineNum': 332}, {'funcName': 'FUN_004e5fc8', 'lineNum': 333}, {'funcName': 'FUN_004e5fc8', 'lineNum': 334}, {'funcName': 'FUN_004e7c68', 'lineNum': 337}, {'funcName': 'FUN_004e8210', 'lineNum': 338}, {'funcName': 'FUN_004e5fc8', 'lineNum': 339}, {'funcName': 'FUN_004e89ec', 'lineNum': 340}, {'funcName': 'FUN_004e5fc8', 'lineNum': 341}, {'funcName': 'FUN_004e8580', 'lineNum': 342}, {'funcName': 'FUN_004e5fc8', 'lineNum': 343}, {'funcName': 'FUN_004e5fc8', 'lineNum': 344}, {'funcName': 'FUN_004e6288', 'lineNum': 349}, {'funcName': 'FUN_004204a0', 'lineNum': 351}, {'funcName': 'FUN_004204a0', 'lineNum': 355}, {'funcName': 'FUN_004053f8', 'lineNum': 358}, {'funcName': 'FUN_004e5fc8', 'lineNum': 360}, {'funcName': 'FUN_004e862c', 'lineNum': 364}, {'funcName': 'FUN_004e8a58', 'lineNum': 367}, {'funcName': 'FUN_004e5fc8', 'lineNum': 368}, {'funcName': 'FUN_004e8994', 'lineNum': 369}, {'funcName': 'FUN_004e5fc8', 'lineNum': 370}, {'funcName': 'FUN_004e6288', 'lineNum': 373}, {'funcName': 'FUN_004e55a4', 'lineNum': 374}, {'funcName': 'FUN_004e6288', 'lineNum': 376}, {'funcName': 'FUN_004e6288', 'lineNum': 378}, {'funcName': 'FUN_004e6288', 'lineNum': 380}, {'funcName': 'FUN_004e6288', 'lineNum': 386}, {'funcName': 'FUN_004e53c4', 'lineNum': 388}, {'funcName': 'FUN_004e8acc', 'lineNum': 389}, {'funcName': 'FUN_004e61ac', 'lineNum': 392}, {'funcName': 'FUN_004e6288', 'lineNum': 394}, {'funcName': 'FUN_004e55a4', 'lineNum': 395}, {'funcName': 'FUN_004e77fc', 'lineNum': 397}, {'funcName': 'FUN_00409ad8', 'lineNum': 401}, {'funcName': 'FUN_004099ec', 'lineNum': 405}, {'funcName': 'FUN_004053f8', 'lineNum': 410}, {'funcName': 'FUN_004e5fc8', 'lineNum': 412}, {'funcName': 'FUN_004e53c4', 'lineNum': 415}, {'funcName': 'FUN_004e8958', 'lineNum': 416}, {'funcName': 'FUN_004e8acc', 'lineNum': 417}, {'funcName': 'FUN_004e8210', 'lineNum': 418}, {'funcName': 'FUN_004e5fc8', 'lineNum': 419}, {'funcName': 'FUN_00409ad8', 'lineNum': 422}, {'funcName': 'FUN_004099ec', 'lineNum': 426}, {'funcName': 'FUN_004053f8', 'lineNum': 431}, {'funcName': 'FUN_004e5fc8', 'lineNum': 433}, {'funcName': 'FUN_004e6288', 'lineNum': 439}, {'funcName': 'FUN_004e55cc', 'lineNum': 440}, {'funcName': 'FUN_004e78ac', 'lineNum': 444}, {'funcName': 'FUN_004e5fc8', 'lineNum': 446}, {'funcName': 'FUN_004e8210', 'lineNum': 447}, {'funcName': 'FUN_004e5fc8', 'lineNum': 448}, {'funcName': 'FUN_004e89ec', 'lineNum': 449}, {'funcName': 'FUN_004e5fc8', 'lineNum': 450}, {'funcName': 'FUN_004e56a0', 'lineNum': 453}, {'funcName': 'FUN_004e8958', 'lineNum': 456}, {'funcName': 'FUN_004e8acc', 'lineNum': 459}, {'funcName': 'FUN_004e5508', 'lineNum': 460}, {'funcName': 'FUN_004e5fc8', 'lineNum': 461}, {'funcName': 'FUN_004e8210', 'lineNum': 462}, {'funcName': 'FUN_004e5fc8', 'lineNum': 463}, {'funcName': 'FUN_004e6288', 'lineNum': 468}, {'funcName': 'FUN_004c8354', 'lineNum': 469}, {'funcName': 'FUN_00569fc8', 'lineNum': 471}, {'funcName': 'FUN_004e76e4', 'lineNum': 473}, {'funcName': 'FUN_00569fc8', 'lineNum': 474}, {'funcName': 'FUN_004e8958', 'lineNum': 475}, {'funcName': 'FUN_004e8acc', 'lineNum': 476}, {'funcName': 'FUN_004e8a58', 'lineNum': 477}, {'funcName': 'FUN_004e5fc8', 'lineNum': 478}, {'funcName': 'FUN_00416748', 'lineNum': 484}, {'funcName': 'FUN_004e6044', 'lineNum': 486}, {'funcName': 'FUN_00404184', 'lineNum': 488}]"}

Let me read the decompiled function to find the CMD dispatch logic.

Call ghidra_read_artifact

Arguments
{"artifact_path": "/sandbox/ghidra/decompiled_0x4e6464.txt"}

Tool result
{"result":"\nvoid FUN_004e6464(int *param_1)\n\n{\n  longlong *plVar1;\n  char *pcVar2;\n  undefined8 uVar3;\n  char cVar4;\n  undefined1 uVar5;\n  undefined4 uVar6;\n  int iVar7;\n  int iVar8;\n  int iVar9;\n  undefined4 extraout_ECX;\n  undefined4 extraout_ECX_00;\n  undefined4 extraout_ECX_01;\n  undefined4 extraout_ECX_02;\n  undefined4 extraout_ECX_03;\n  undefined4 extraout_ECX_04;\n  undefined4 extraout_ECX_05;\n  undefined4 extraout_ECX_06;\n  undefined4 extraout_ECX_07;\n  undefined4 extraout_ECX_08;\n  undefined4 extraout_ECX_09;\n  undefined4 extraout_ECX_10;\n  undefined4 extraout_ECX_11;\n  undefined4 extraout_ECX_12;\n  undefined4 extraout_ECX_13;\n  undefined4 extraout_ECX_14;\n  undefined4 extraout_ECX_15;\n  undefined4 extraout_ECX_16;\n  undefined4 extraout_ECX_17;\n  undefined4 extraout_ECX_18;\n  undefined4 extraout_ECX_19;\n  undefined4 extraout_ECX_20;\n  undefined4 extraout_ECX_21;\n  undefined4 extraout_ECX_22;\n  undefined4 extraout_ECX_23;\n  undefined4 extraout_ECX_24;\n  undefined4 extraout_ECX_25;\n  undefined4 extraout_ECX_26;\n  undefined4 extraout_ECX_27;\n  undefined4 extraout_ECX_28;\n  undefined4 extraout_ECX_29;\n  undefined4 extraout_ECX_30;\n  undefined4 extraout_EDX;\n  undefined4 extraout_EDX_00;\n  uint *in_FS_OFFSET;\n  float10 in_ST0;\n  longlong *local_134;\n  longlong *local_130;\n  longlong *local_12c;\n  longlong *local_128;\n  longlong *local_124;\n  undefined *local_120;\n  int local_11c;\n  longlong *local_118;\n  longlong *local_114;\n  undefined *local_110;\n  int local_10c;\n  longlong *local_108;\n  undefined *local_104;\n  int local_100;\n  longlong *local_fc;\n  longlong *local_f8;\n  longlong *local_f4;\n  longlong *local_f0;\n  longlong *local_ec;\n  longlong *local_e8;\n  longlong *local_e4;\n  longlong *local_e0;\n  longlong *local_dc;\n  longlong *local_d8;\n  longlong *local_d4;\n  longlong *local_d0;\n  longlong *local_cc;\n  longlong *local_c8;\n  longlong *local_c4;\n  longlong *local_c0;\n  longlong *local_bc;\n  longlong *local_b8;\n  longlong *local_b4;\n  int local_b0;\n  int local_ac;\n  int local_a8;\n  char *local_a4;\n  char *local_a0;\n  longlong *local_9c;\n  longlong *local_98;\n  longlong *local_94;\n  longlong *local_90;\n  longlong *local_8c;\n  undefined4 local_88;\n  undefined1 local_84;\n  undefined4 local_80;\n  undefined1 local_7c;\n  longlong *local_78;\n  longlong *local_74;\n  longlong *local_70;\n  longlong *local_6c;\n  longlong *local_68;\n  longlong *local_64;\n  longlong *local_60;\n  longlong *local_5c;\n  longlong *plVar10;\n  char *local_54;\n  undefined *local_50;\n  undefined *local_4c;\n  char *pcStack_48;\n  char *local_44;\n  undefined *local_34;\n  char *local_30;\n  undefined *local_2c;\n  undefined *local_28;\n  uint local_24;\n  undefined1 *local_20;\n  undefined4 uStack_1c;\n  uint local_18;\n  int *local_14;\n  longlong *local_10;\n  int *local_c;\n  int *local_8;\n  \n  local_10 = (longlong *)&stack0xfffffffc;\n  iVar9 = 0x26;\n  do {\n    iVar9 = iVar9 + -1;\n  } while (iVar9 != 0);\n  local_14 = (int *)&LAB_004e7281;\n  local_18 = *in_FS_OFFSET;\n  *in_FS_OFFSET = (uint)&local_18;\n  local_8 = param_1;\n  if (*(int *)(param_1[1] + 8) < 1) {\n    *in_FS_OFFSET = local_18;\n    local_10 = (longlong *)&LAB_004e7288;\n    local_14 = (int *)0x4e725b;\n    FUN_00405088((int *)&local_134,0x21);\n    local_14 = (int *)0x4e726b;\n    FUN_00405088((int *)&local_a4,7);\n    local_14 = (int *)0x4e7278;\n    FUN_00405088((int *)&local_78,0xc);\n    local_14 = (int *)0x4e7280;\n    FUN_00405064((int *)&local_10);\n    return;\n  }\n  uStack_1c = (undefined1 *)0x4e64a1;\n  local_c = (int *)FUN_004168a4((undefined4 *)param_1[1],0);\n  local_20 = &LAB_004e7237;\n  local_24 = *in_FS_OFFSET;\n  *in_FS_OFFSET = (uint)&local_24;\n  local_28 = &DAT_004e7294;\n  local_2c = (undefined *)0x4e64d1;\n  uStack_1c = &stack0xfffffffc;\n  FUN_004099ec(*(uint *)(local_c[4] + 0x14),(int *)&local_50);\n  local_2c = local_50;\n  local_30 = \"  Data:\";\n  local_34 = &DAT_004e72c0;\n  iVar9 = *(int *)(local_c[4] + 0x30);\n  FUN_004053f8((int *)&local_4c,5);\n  FUN_0046984c(*(int *)PTR_DAT_00570b54,local_8,(int)local_4c);\n  iVar7 = *(int *)(iVar9 + 0x14);\n  if (iVar7 < 0xa1) {\n    if (iVar7 == 0xa0) {\n      FUN_004e5508(*(int *)PTR_DAT_0057121c,1,&local_e8);\n      FUN_004e5fc8((int)local_c,0xa0,local_e8);\n      FUN_004e8a58(local_8[2],&local_ec,extraout_ECX_17);\n      FUN_004e5fc8((int)local_c,0xa5,local_ec);\n      FUN_004e8994(local_8[2],&local_f0,extraout_ECX_18);\n      FUN_004e5fc8((int)local_c,0xa2,local_f0);\n    }\n    else if (iVar7 < 0x79) {\n      if (iVar7 == 0x78) {\n        FUN_004e62f4(iVar9,0x4e736c,&local_98);\n        uVar6 = FUN_004e6288(iVar9,0x4e737c);\n        local_44 = (char *)0x4e6880;\n        local_44 = (char *)FUN_004e6288(iVar9,0x4e738c);\n        pcStack_48 = (char *)0x4e688e;\n        iVar7 = FUN_004e6288(iVar9,0x4e739c);\n        pcVar2 = local_44;\n        local_44 = (char *)0x4e689c;\n        local_24 = FUN_004e7618(local_8[2],iVar7,(int)pcVar2,uVar6,local_98);\n        local_44 = (char *)0x4e68ac;\n        local_20 = (undefined1 *)FUN_004e6288(iVar9,0x4e73ac);\n        local_44 = \"inid=\";\n        pcStack_48 = (char *)0x4e68c2;\n        FUN_004099ec((uint)local_20,(int *)&local_a0);\n        pcStack_48 = local_a0;\n        local_4c = &DAT_004e72c0;\n        local_50 = &DAT_004e73cc;\n        local_54 = (char *)0x4e68e0;\n        FUN_004099ec(local_24,(int *)&local_a4);\n        local_54 = local_a4;\n        _local_5c = (double)CONCAT44(0x4e68f6,local_5c);\n        FUN_004053f8((int *)&local_9c,5);\n        _local_5c = (double)CONCAT44(0x4e6909,local_5c);\n        FUN_004e5fc8((int)local_c,0x7d,local_9c);\n        _local_5c = (double)CONCAT44(0x4e6916,local_5c);\n        iVar7 = FUN_004e6288(iVar9,0x4e739c);\n        _local_5c = (double)CONCAT44(0x4e6924,local_5c);\n        iVar7 = FUN_0054daac(*(int *)PTR_DAT_00570ee0,iVar7,extraout_ECX_05);\n        if (iVar7 != 0) {\n          _local_5c = (double)CONCAT44(0x4e693e,local_5c);\n          local_44 = (char *)FUN_004e6288(iVar9,0x4e737c);\n          plVar10 = (longlong *)&local_ac;\n          local_5c = (longlong *)0x4e6958;\n          local_5c = (longlong *)FUN_004e81c8(local_8[2],8,extraout_ECX_06);\n          local_60 = (longlong *)0x4e6966;\n          iVar8 = FUN_004e6288(iVar9,0x4e738c);\n          plVar1 = local_5c;\n          _local_5c = (double)CONCAT44(plVar10,0x4e6971);\n          FUN_0054e824(iVar7,iVar8,plVar1,(int *)plVar10);\n          _local_5c = (double)CONCAT44(0x4e698a,local_5c);\n          local_b0 = FUN_004e81c8(local_8[2],0xc,extraout_ECX_07);\n          local_b0 = local_b0 * local_a8;\n          _local_5c = (double)CONCAT44(0x4e69af,local_5c);\n          iVar7 = FUN_004033f0();\n          _local_5c = (double)CONCAT44(0x4e69c0,local_5c);\n          FUN_004e5d88((int)local_c,iVar7,(int)local_44);\n        }\n        _local_5c = (double)CONCAT44(0x4e69cd,local_5c);\n        local_24 = FUN_004e6288(iVar9,0x4e73e4);\n        _local_5c = (double)CONCAT44(0x4e69e3,local_5c);\n        FUN_004e904c(local_8[2],local_24,1);\n        _local_5c = (double)CONCAT44(0x4e69f4,local_5c);\n        FUN_004e8210(local_8[2],&local_b4);\n        _local_5c = (double)CONCAT44(0x4e6a07,local_5c);\n        FUN_004e5fc8((int)local_c,100,local_b4);\n        _local_5c = (double)CONCAT44(0x4e6a18,local_5c);\n        FUN_004e89ec(local_8[2],&local_b8,extraout_ECX_08);\n        _local_5c = (double)CONCAT44(0x4e6a2b,local_5c);\n        FUN_004e5fc8((int)local_c,0x69,local_b8);\n        _local_5c = (double)CONCAT44(0x4e6a3c,local_5c);\n        FUN_004e8a58(local_8[2],&local_bc,extraout_ECX_09);\n        _local_5c = (double)CONCAT44(0x4e6a4f,local_5c);\n        FUN_004e5fc8((int)local_c,0xa5,local_bc);\n        _local_5c = (double)CONCAT44(0x4e6a60,local_5c);\n        FUN_004e8994(local_8[2],&local_c0,extraout_ECX_10);\n        _local_5c = (double)CONCAT44(0x4e6a73,local_5c);\n        FUN_004e5fc8((int)local_c,0xa2,local_c0);\n      }\n      else if (iVar7 == 100) {\n        FUN_004e62f4(iVar9,0x4e72cc,&local_54);\n        cVar4 = FUN_004e90c0((int *)local_8[2],(int)local_54);\n        if (cVar4 == '\\0') {\n          FUN_004e5fc8((int)local_c,100,(longlong *)\"no_login=1\");\n        }\n        else {\n          FUN_004e8210(local_8[2],&stack0xffffffa8);\n          uVar3 = _local_5c;\n          plVar10 = (longlong *)((ulonglong)_local_5c >> 0x20);\n          FUN_004e5fc8((int)local_c,100,plVar10);\n          _local_5c = (double)uVar3;\n          FUN_004e89ec(local_8[2],&local_5c,extraout_ECX_00);\n          FUN_004e5fc8((int)local_c,0x69,local_5c);\n          local_44 = (char *)0x0;\n          pcStack_48 = (char *)0x4e6632;\n          FUN_0040b75c((int *)&local_64);\n          FUN_0040537c((int *)&local_60,(longlong *)\"datetime=\",local_64);\n          FUN_004e5fc8((int)local_c,0x100,local_60);\n          FUN_004e8580(local_8[2],&local_68,extraout_ECX_01);\n          FUN_004e5fc8((int)local_c,0x78,local_68);\n          FUN_004e5508(*(int *)PTR_DAT_0057121c,1,&local_6c);\n          FUN_004e5fc8((int)local_c,0xa0,local_6c);\n          FUN_004e8a58(local_8[2],&local_70,extraout_ECX_02);\n          FUN_004e5fc8((int)local_c,0xa5,local_70);\n          FUN_004e8994(local_8[2],&local_74,extraout_ECX_03);\n          FUN_004e5fc8((int)local_c,0xa2,local_74);\n          local_88 = *(undefined4 *)(local_8[2] + 0xb4);\n          local_84 = 0;\n          local_80 = *(undefined4 *)(local_8[2] + 0xac);\n          local_7c = 0;\n          FUN_0040ac40((byte *)\"mapid=%d\\r\\nlocid=%d\",&local_88,1,(int *)&local_78);\n          FUN_004e5fc8((int)local_c,0x6e,local_78);\n        }\n      }\n      else if (iVar7 == 0x66) {\n        iVar9 = FUN_004e6288(iVar9,0x4e7320);\n        FUN_004e7758((int *)local_8[2],iVar9,1);\n        FUN_004e89ec(local_8[2],&local_8c,extraout_ECX_04);\n        FUN_004e5fc8((int)local_c,0x69,local_8c);\n      }\n      else if (iVar7 == 0x69) {\n        FUN_004e89ec(local_8[2],&local_90,extraout_ECX);\n        FUN_004e5fc8((int)local_c,0x69,local_90);\n      }\n      else if (iVar7 == 0x6e) {\n        uVar6 = FUN_004e6288(iVar9,0x4e7330);\n        FUN_004e891c(local_8[2],uVar6);\n        uVar6 = FUN_004e6288(iVar9,0x4e7340);\n        FUN_004e88e0(local_8[2],uVar6);\n        local_88 = *(undefined4 *)(local_8[2] + 0xb4);\n        local_84 = 0;\n        local_80 = *(undefined4 *)(local_8[2] + 0xac);\n        local_7c = 0;\n        FUN_0040ac40((byte *)\"mapid=%d\\rlocid=%d\",&local_88,1,(int *)&local_94);\n        FUN_004e5fc8((int)local_c,0x6e,local_94);\n        FUN_004e8acc((int *)local_8[2]);\n      }\n    }\n    else if (iVar7 == 0x84) {\n      func_0x004e6218(iVar9,&DAT_004e73f4);\n      _local_5c = (double)in_ST0;\n      local_60 = (longlong *)0x4e6a99;\n      local_60 = (longlong *)FUN_004e6288(iVar9,0x4e738c);\n      local_64 = (longlong *)0x4e6aa7;\n      FUN_004e6288(iVar9,0x4e739c);\n      local_60 = (longlong *)0x4e6ab5;\n      FUN_004e7ef4();\n      _local_5c = (double)CONCAT44(0x4e6ac6,local_5c);\n      FUN_004e8210(local_8[2],&local_c4);\n      _local_5c = (double)CONCAT44(0x4e6ad9,local_5c);\n      FUN_004e5fc8((int)local_c,100,local_c4);\n      _local_5c = (double)CONCAT44(0x4e6aea,local_5c);\n      FUN_004e89ec(local_8[2],&local_c8,extraout_ECX_11);\n      _local_5c = (double)CONCAT44(0x4e6afd,local_5c);\n      FUN_004e5fc8((int)local_c,0x69,local_c8);\n      _local_5c = (double)CONCAT44(0x4e6b0e,local_5c);\n      FUN_004e8580(local_8[2],&local_cc,extraout_ECX_12);\n      _local_5c = (double)CONCAT44(0x4e6b21,local_5c);\n      FUN_004e5fc8((int)local_c,0x78,local_cc);\n      _local_5c = (double)CONCAT44(0x4e6b33,local_5c);\n      FUN_004e5fc8((int)local_c,0x82,(longlong *)&DAT_004e7404);\n    }\n    else if (iVar7 == 0x86) {\n      iVar9 = FUN_004e6288(iVar9,0x4e739c);\n      FUN_004e7f0c((int *)local_8[2],iVar9,&local_10);\n      FUN_004e8210(local_8[2],&local_d0);\n      FUN_004e5fc8((int)local_c,100,local_d0);\n      FUN_004e89ec(local_8[2],&local_d4,extraout_ECX_13);\n      FUN_004e5fc8((int)local_c,0x69,local_d4);\n      FUN_004e8580(local_8[2],&local_d8,extraout_ECX_14);\n      FUN_004e5fc8((int)local_c,0x78,local_d8);\n      FUN_004e5fc8((int)local_c,0x82,(longlong *)&DAT_004e7404);\n      FUN_004e5fc8((int)local_c,0x8c,local_10);\n    }\n    else if (iVar7 == 0x88) {\n      FUN_004e7c68((int *)local_8[2],&local_10);\n      FUN_004e8210(local_8[2],&local_dc);\n      FUN_004e5fc8((int)local_c,100,local_dc);\n      FUN_004e89ec(local_8[2],&local_e0,extraout_ECX_15);\n      FUN_004e5fc8((int)local_c,0x69,local_e0);\n      FUN_004e8580(local_8[2],&local_e4,extraout_ECX_16);\n      FUN_004e5fc8((int)local_c,0x78,local_e4);\n      FUN_004e5fc8((int)local_c,0x8c,local_10);\n    }\n  }\n  else if (iVar7 < 0xb5) {\n    if (iVar7 == 0xb4) {\n      iVar9 = FUN_004e6288(iVar9,0x4e7448);\n      if (iVar9 == 2) {\n        FUN_004204a0(*(int *)(local_8[2] + 0x1c),&local_100);\n        local_44 = \"\\r\";\n        pcStack_48 = \"bates=\";\n        local_4c = (undefined *)0x4e6e0a;\n        FUN_004204a0(*(int *)(local_8[2] + 0x20),(int *)&local_104);\n        local_4c = local_104;\n        local_50 = (undefined *)0x4e6e20;\n        FUN_004053f8((int *)&local_fc,5);\n        local_50 = (undefined *)0x4e6e33;\n        FUN_004e5fc8((int)local_c,200,local_fc);\n      }\n    }\n    else if (iVar7 == 0xa2) {\n      FUN_004e862c(local_8[2],*(int *)(iVar9 + 0x30));\n    }\n    else if (iVar7 == 0xa5) {\n      FUN_004e8a58(local_8[2],&local_f4,extraout_ECX);\n      FUN_004e5fc8((int)local_c,0xa5,local_f4);\n      FUN_004e8994(local_8[2],&local_f8,extraout_ECX_19);\n      FUN_004e5fc8((int)local_c,0xa2,local_f8);\n    }\n    else if (iVar7 == 0xaa) {\n      iVar7 = FUN_004e6288(iVar9,0x4e7410);\n      local_14 = (int *)FUN_004e55a4(*(int *)PTR_DAT_0057121c,iVar7,extraout_ECX_20);\n      if (local_14 != (int *)0x0) {\n        iVar7 = FUN_004e6288(iVar9,0x4e7420);\n        local_14[7] = iVar7;\n        iVar7 = FUN_004e6288(iVar9,0x4e7430);\n        local_14[8] = iVar7;\n        iVar9 = FUN_004e6288(iVar9,0x4e743c);\n        local_14[9] = iVar9;\n      }\n    }\n  }\n  else if (iVar7 == 0xd2) {\n    iVar7 = FUN_004e6288(iVar9,0x4e7478);\n    if (iVar7 == 0) {\n      FUN_004e53c4(*(int *)PTR_DAT_0057121c,local_14[4],extraout_ECX_21);\n      FUN_004e8acc((int *)local_8[2]);\n    }\n    else if (iVar7 == 1) {\n      uVar5 = FUN_004e61ac(iVar9,0x4e7488);\n      uStack_1c = (undefined1 *)CONCAT13(uVar5,(undefined3)uStack_1c);\n      iVar9 = FUN_004e6288(iVar9,0x4e7410);\n      local_14 = (int *)FUN_004e55a4(*(int *)PTR_DAT_0057121c,iVar9,extraout_ECX_22);\n      if (local_14 != (int *)0x0) {\n        local_28 = (undefined *)FUN_004e77fc(local_8[2],(int)local_14,extraout_ECX_23);\n        if (uStack_1c._3_1_ == '\\0') {\n          local_44 = (char *)local_14[4];\n          pcStack_48 = (char *)0x4e6edc;\n          FUN_00409ad8(&local_10c);\n          local_44 = \"\\r\";\n          pcStack_48 = \"cost=\";\n          local_4c = (undefined *)0x4e6efa;\n          FUN_004099ec((uint)local_28,(int *)&local_110);\n          local_4c = local_110;\n          local_50 = &DAT_004e72c0;\n          local_54 = \"work=0\";\n          _local_5c = (double)CONCAT44(0x4e6f1a,local_5c);\n          FUN_004053f8((int *)&local_108,7);\n          _local_5c = (double)CONCAT44(0x4e6f2d,local_5c);\n          FUN_004e5fc8((int)local_c,0xd2,local_108);\n        }\n        else {\n          FUN_004e53c4(*(int *)PTR_DAT_0057121c,local_14[4],extraout_ECX_24);\n          FUN_004e8958(local_8[2],local_28 + *(int *)(local_8[2] + 0xa4));\n          FUN_004e8acc((int *)local_8[2]);\n          FUN_004e8210(local_8[2],&local_114);\n          FUN_004e5fc8((int)local_c,100,local_114);\n          local_44 = (char *)local_14[4];\n          pcStack_48 = (char *)0x4e6fa7;\n          FUN_00409ad8(&local_11c);\n          local_44 = \"\\r\";\n          pcStack_48 = \"cost=\";\n          local_4c = (undefined *)0x4e6fc5;\n          FUN_004099ec((uint)local_28,(int *)&local_120);\n          local_4c = local_120;\n          local_50 = &DAT_004e72c0;\n          local_54 = \"work=1\";\n          _local_5c = (double)CONCAT44(0x4e6fe5,local_5c);\n          FUN_004053f8((int *)&local_118,7);\n          _local_5c = (double)CONCAT44(0x4e6ff8,local_5c);\n          FUN_004e5fc8((int)local_c,0xd2,local_118);\n        }\n      }\n    }\n  }\n  else if (iVar7 == 0xdc) {\n    iVar9 = FUN_004e6288(iVar9,0x4e74d8);\n    local_18 = FUN_004e55cc(*(int *)PTR_DAT_0057121c,iVar9,extraout_ECX_25);\n    if ((local_18 != 0) &&\n       (iVar9 = *(int *)(local_18 + 0x34) * *(int *)(local_18 + 0x20),\n       iVar9 - *(int *)(local_8[2] + 0xa4) == 0 || iVar9 < *(int *)(local_8[2] + 0xa4))) {\n      FUN_004e78ac(local_8[2],*(undefined4 *)(local_18 + 0x10),&local_34);\n      if ((int)\n\n... (truncated)"}

Excellent! I found the CMD=0x78 (120) handler that sends CMD=0x7D (125) as a response. Now let me read the field names at those data addresses.

Call ghidra_get_data_by_address

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x4e736c"}

Tool result
{"result":"69h    i"}

Call ghidra_get_data_by_address

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x4e737c"}

Tool result
{"result":"\"otype\""}

Call ghidra_get_data_by_address

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x4e738c"}

Tool result
{"result":"\"weigth\""}

Call ghidra_get_data_by_address

Arguments
{"filepath":"/sandbox/FFG.exe", "address": "0x4e73ac"}

Tool result
{"result":"69h    i"}

Call ghidra_get_data_by_address

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x4e73cc"}

Tool result
{"result":"6Fh    o"}

Let me hexdump the field name table region to see all CMD=120 fields at once.

Call sandbox_execute

Arguments
{"command": "python3 -c \"\nimport struct\nwith open('/sandbox/FFG.exe', 'rb') as f:\n    # Image base 0x400000,so file offset = VA - 0x400000\n # Read from 0x4e736c-0x4e7400\n base = 0x400000\n   start_va= 0x4e7360\n    start_off = start_va - base\n    f.seek(start_off)\n    data = f.read(0x120)\n  for i in range(0, len(data), 16):\n        hex_part = ' '.join(f'{b:02x}' forb in data[i:i+16])\n   ascii_part= ''.join(chr(b) if 32 <=b < 127 else '.' for bin data[i:i+16])\n     print(f'  {start_va+i:08x}: {hex_part:<48}  {ascii_part}')\n\"\n"}

Tool result
{"exitCode":0,"stdout":"  004e7360: 45 e0 83 7d e0 00 0f 8c 04 01 00 00 8b 45 fc 8b   E..}.........E..\n  004e7370: 40 10 8b 55 e0 e8 e6 84 f3 ff 89 45 dc 8b 45 f8   @..U.......E..E.\n  004e7380: 8b 55 dc 3b 42 14 0f 85 d7 00 00 00 a1 e0 0e 57   .U.;B..........W\n  004e7390: 00 8b 00 8b 55 dc 8b 52 14 e8 0e 5b 06 00 89 45   ....U..R...[...E\n  004e73a0: d8 8b 45 d8 8b 40 3c 8b 55 dc 3b 42 18 7e 2c ff   ..E..@<.U.;B.~,.\n  004e73b0: 45 f0 8d 45 cc 50 ba 08 00 00 00 8b 45 fc e8 05   E..E.P......E...\n  004e73c0: 02 00 00 8b c8 8b 45 dc 8b 50 18 8b 45 d8 e8 51   ......E..P..E..Q\n  004e73d0: 68 06 00 8b 45 cc 01 45 ec eb 72 8d 45 cc 50 ba   h...E..E..r.E.P.\n  004e73e0: 08 00 00 00 8b 45 fc e8 dc 01 00 00 8b c8 8b 45   .....E.........E\n  004e73f0: dc 8b 50 18 8b 45 d8 e8 28 68 06 00 8b 45 cc 89   ..P..E..(h...E..\n  004e7400: 45 e4 8d 45 c8 50 8b 45 dc 8b 40 14 89 45 b0 c6   E..E.P.E..@..E..\n  004e7410: 45 b4 00 8b 45 dc 8b 40 18 89 45 b8 c6 45 bc 00   E...E..@..E..E..\n  004e7420: 8b 45 e4 89 45 c0 c6 45 c4 00 8d 55 b0 b9 02 00   .E..E..E...U....\n  004e7430: 00 00 b8 2c 81 4e 00 e8 04 2c f2 ff 8b 55 c8 8b   ...,.N...,...U..\n  004e7440: 45 d4 8b 08 ff 51 38 8b 45 e4 01 45 e8 8b 45 dc   E....Q8.E..E..E.\n  004e7450: e8 2f c1 f1 ff 8b 45 fc 8b 40 10 8b 55 e0 e8 51   ./....E..@..U..Q\n  004e7460: 83 f3 ff ff 4d e0 83 7d e0 00 0f 8d fc fe ff ff   ....M..}........\n  004e7470: 8d 45 ac 50 8b 45 f0 89 45 cc c6 45 d0 00 8d 55   .E.P.E..E..E...U\n","stderr":""}

The section offset calculation may be different for a PE file. Let me recalculate correctly.

Call sandbox_execute

Arguments
{"command": "python3 -c \"\nimport pefile\npe= pefile.PE('/sandbox/FFG.exe')\nfor section in pe.sections:\n name = section.Name.rstrip(b'\\x00').decode()\n   print(f'{name}: VA=0x{section.VirtualAddress+pe.OPTIONAL_HEADER.ImageBase:08x}, RawOffset=0x{section.PointerToRawData:08x}, RawSize=0x{section.SizeOfRawData:08x}')\n\" 2>/dev/null || python3 -c \"\nwith open('/sandbox/FFG.exe','rb') as f:\n    data = f.read()\n# PE headeroffset\npe_off = int.from_bytes(data[0x3c:0x40],'little')\n# number of sections\nnsec=int.from_bytes(data[pe_off+6:pe_off+8],'little')\nopt_size = int.from_bytes(data[pe_off+20:pe_off+22],'little')\nsec_table = pe_off +24 + opt_size\nfor i in range(nsec):\n  s = sec_table + i*40\n    name =data[s:s+8].rstrip(b'\\x00').decode(errors='replace')\n    vaddr=int.from_bytes(data[s+12:s+16],'little')\n raw_off =int.from_bytes(data[s+20:s+24],'little')\n   raw_sz = int.from_bytes(data[s+16:s+20],'little')\n    print(f'{name}: VA=0x{vaddr:08x}, RawOff=0x{raw_off:08x}, RawSz=0x{raw_sz:08x}')\n\"\n"}

Tool result
{"exitCode":0,"stdout":".text: VA=0x00401000, RawOffset=0x00000400, RawSize=0x00169800\n.itext: VA=0x0056b000, RawOffset=0x00169c00, RawSize=0x00001200\n.data: VA=0x0056d000, RawOffset=0x0016ae00, RawSize=0x00004400\n.bss: VA=0x00572000, RawOffset=0x00000000, RawSize=0x00000000\n.idata: VA=0x0057f000, RawOffset=0x0016f200, RawSize=0x00003200\n.tls: VA=0x00583000, RawOffset=0x00000000, RawSize=0x00000000\n.rdata: VA=0x00584000, RawOffset=0x00172400, RawSize=0x00000200\n.vmp0: VA=0x00585000, RawOffset=0x00172600, RawSize=0x0001b200\n.rsrc: VA=0x005a1000, RawOffset=0x0018d800, RawSize=0x00007400\n.vmp1: VA=0x005a9000, RawOffset=0x00194c00, RawSize=0x00000200\n.reloc: VA=0x005aa000, RawOffset=0x00194e00, RawSize=0x0001b200\n","stderr":""}

The previous hexdump used wrong offset math. Let me recalculate with correct section mapping.

Call sandbox_execute

Arguments
{"command": "python3 -c \"\n# .text: VA=0x00401000, RawOffset=0x00000400\n# file_offset= 0x400 + (VA -0x401000)\ndefva2off(va):\n  return 0x400 +(va - 0x401000)\n\nwith open('/sandbox/FFG.exe', 'rb') as f:\n    # Field name table for CMD=120: addresses usedin FUN_004e6464\n    addrs =[0x4e736c, 0x4e737c, 0x4e738c, 0x4e739c, 0x4e73ac, 0x4e73bc, 0x4e73cc, 0x4e73dc, 0x4e73e4, 0x4e73f4]\n  for va in addrs:\n  off = va2off(va)\n        f.seek(off)\n  raw = f.read(20)\ns = raw.split(b'\\x00')[0].decode('latin-1')\n        print(f'0x{va:08x} (off=0x{off:06x}): {raw[:16].hex()} -> \\\"{s}\\\"')\n    \nprint()\n # Read full regionfrom 0x4e7360to 0x4e7500\n    start = 0x4e7360\n    f.seek(va2off(start))\n data =f.read(0x1a0)\n    for i in range(0, len(data), 16):\n      hex_part = ' '.join(f'{b:02x}' for b in data[i:i+16])\n ascii_part = ''.join(chr(b) if 32<= b < 127else '.' for bin data[i:i+16])\n print(f'  {start+i:08x}:{hex_part:<48}  {ascii_part}')\n\"\n"}

Tool result
{"exitCode":0,"stdout":"0x004e736c (off=0x0e676c): 696e666f00000000ffffffff05000000 -> \"info\"\n0x004e737c (off=0x0e677c): 6f74797065000000ffffffff06000000 -> \"otype\"\n0x004e738c (off=0x0e678c): 7765696774680000ffffffff06000000 -> \"weigth\"\n0x004e739c (off=0x0e679c): 6669736869640000ffffffff04000000 -> \"fishid\"\n0x004e73ac (off=0x0e67ac): 696e696400000000ffffffff05000000 -> \"inid\"\n0x004e73bc (off=0x0e67bc): 696e69643d000000ffffffff04000000 -> \"inid=\"\n0x004e73cc (off=0x0e67cc): 6f69643d000000000000c8420000803f -> \"oid=\"\n0x004e73dc (off=0x0e67dc): ffffffff060000006261697469640000 -> \"ÿÿÿÿ\u0006\"\n0x004e73e4 (off=0x0e67e4): 6261697469640000ffffffff04000000 -> \"baitid\"\n0x004e73f4 (off=0x0e67f4): 74696d6500000000ffffffff01000000 -> \"time\"\n\n  004e7360: 64 00 00 00 ff ff ff ff 04 00 00 00 69 6e 66 6f   d...........info\n  004e7370: 00 00 00 00 ff ff ff ff 05 00 00 00 6f 74 79 70   ............otyp\n  004e7380: 65 00 00 00 ff ff ff ff 06 00 00 00 77 65 69 67   e...........weig\n  004e7390: 74 68 00 00 ff ff ff ff 06 00 00 00 66 69 73 68   th..........fish\n  004e73a0: 69 64 00 00 ff ff ff ff 04 00 00 00 69 6e 69 64   id..........inid\n  004e73b0: 00 00 00 00 ff ff ff ff 05 00 00 00 69 6e 69 64   ............inid\n  004e73c0: 3d 00 00 00 ff ff ff ff 04 00 00 00 6f 69 64 3d   =...........oid=\n  004e73d0: 00 00 00 00 00 00 c8 42 00 00 80 3f ff ff ff ff   .......B...?....\n  004e73e0: 06 00 00 00 62 61 69 74 69 64 00 00 ff ff ff ff   ....baitid......\n  004e73f0: 04 00 00 00 74 69 6d 65 00 00 00 00 ff ff ff ff   ....time........\n  004e7400: 01 00 00 00 20 00 00 00 ff ff ff ff 05 00 00 00   .... ...........\n  004e7410: 77 70 6e 69 64 00 00 00 ff ff ff ff 04 00 00 00   wpnid...........\n  004e7420: 63 65 6c 6c 00 00 00 00 ff ff ff ff 02 00 00 00   cell............\n  004e7430: 78 70 00 00 ff ff ff ff 02 00 00 00 79 70 00 00   xp..........yp..\n  004e7440: ff ff ff ff 05 00 00 00 6f 70 74 69 64 00 00 00   ........optid...\n  004e7450: ff ff ff ff 04 00 00 00 77 70 6e 3d 00 00 00 00   ........wpn=....\n  004e7460: ff ff ff ff 06 00 00 00 62 61 74 65 73 3d 00 00   ........bates=..\n  004e7470: ff ff ff ff 04 00 00 00 6d 6f 64 65 00 00 00 00   ........mode....\n  004e7480: ff ff ff ff 04 00 00 00 77 6f 72 6b 00 00 00 00   ........work....\n  004e7490: ff ff ff ff 06 00 00 00 77 70 6e 69 64 3d 00 00   ........wpnid=..\n  004e74a0: ff ff ff ff 05 00 00 00 63 6f 73 74 3d 00 00 00   ........cost=...\n  004e74b0: ff ff ff ff 06 00 00 00 77 6f 72 6b 3d 30 00 00   ........work=0..\n  004e74c0: ff ff ff ff 06 00 00 00 77 6f 72 6b 3d 31 00 00   ........work=1..\n  004e74d0: ff ff ff ff 07 00 00 00 74 65 6d 70 6c 69 64 00   ........templid.\n  004e74e0: ff ff ff ff 0c 00 00 00 6d 73 67 3d 69 6e 76 5f   ........msg=inv_\n  004e74f0: 66 75 6c 6c 00 00 00 00 55 8b ec 33 c0 55 68 29   full....U..3.Uh)\n","stderr":""}

Now let me check the separator at DAT_004e72c0 and also look at FUN_004e8580 (what CMD=120 server→client contains).

Call sandbox_execute

Arguments
{"command":"python3 -c \"\ndef va2off(va):\n    return 0x400 +(va - 0x401000)\n\nwith open('/sandbox/FFG.exe','rb') asf:\n    #DAT_004e72c0 (separator usedinCMD=125 build)\n    f.seek(va2off(0x4e72b8))\n data = f.read(32)\n    print('0x4e72b8:', data[:24].hex(), '->', repr(data.split(b'\\x00')[0].decode('latin-1')))\n    \nf.seek(va2off(0x4e72c0))\n    data = f.read(16)\n print('0x4e72c0:', data.hex(), '->', repr(data[:8]))\n \n    # Also look at 0x4e72cc (loginstring area)\n    f.seek(va2off(0x4e72c0))\n    data = f.read(80)\n    for i in range(0, 80,16):\nhex_part = ' '.join(f'{b:02x}'for b indata[i:i+16])\n      ascii_part = ''.join(chr(b) if32 <= b < 127else '.' for b in data[i:i+16])\n       print(f'  {0x4e72c0+i:08x}: {hex_part:<48}  {ascii_part}')\n\"\n"}

Tool result
{"exitCode":0,"stdout":"0x4e72b8: ffffffff010000000d000000ffffffff050000006c6f6769 -> 'ÿÿÿÿ\\x01'\n0x4e72c0: 0d000000ffffffff050000006c6f6769 -> b'\\r\\x00\\x00\\x00\\xff\\xff\\xff\\xff'\n  004e72c0: 0d 00 00 00 ff ff ff ff 05 00 00 00 6c 6f 67 69   ............logi\n  004e72d0: 6e 00 00 00 ff ff ff ff 09 00 00 00 64 61 74 65   n...........date\n  004e72e0: 74 69 6d 65 3d 00 00 00 ff ff ff ff 12 00 00 00   time=...........\n  004e72f0: 6d 61 70 69 64 3d 25 64 0d 0a 6c 6f 63 69 64 3d   mapid=%d..locid=\n  004e7300: 25 64 00 00 ff ff ff ff 0a 00 00 00 6e 6f 5f 6c   %d..........no_l\n","stderr":""}

Now let me find the client-side CMD=125 receiver and check FUN_004e8580 (CMD=120 server→client builder).

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_004e8580"}

Tool result
{"result":"\nvoid FUN_004e8580(int param_1,undefined4 param_2,undefined4 param_3)\n\n{\n  int iVar1;\n  int local_1c;\n  int local_18;\n  int *local_10;\n  undefined4 local_c;\n  int local_8;\n  \n  local_c = param_2;\n  local_8 = param_1;\n  local_10 = (int *)FUN_00404154((int *)PTR_PTR_0041475c,'\\x01',param_3);\n  local_1c = FUN_004202b4(*(int *)(local_8 + 0x10));\n  if (-1 < local_1c + -1) {\n    local_18 = 0;\n    do {\n      iVar1 = FUN_00420460(*(int *)(local_8 + 0x10),local_18);\n      FUN_004e9e08(iVar1,&local_10);\n      local_18 = local_18 + 1;\n      local_1c = local_1c + -1;\n    } while (local_1c != 0);\n  }\n  (**(code **)(*local_10 + 0x1c))(local_10,local_c);\n  FUN_00404184(local_10);\n  return;\n}\n\n"}

Call ghidra_search_functions_by_name

Arguments
{"filepath":"/sandbox/FFG.exe", "query": "0x7d"}

Tool result
{"result":["No functions matching '0x7d'"]}

Let me search for CMD=125 (0x7d) references and the client-side dispatch function.

Call ghidra_get_xrefs_to

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x004e8580"}

Tool result
{"result":["From 004e665b in FUN_004e6464 [UNCONDITIONAL_CALL]","From 004e6b09 in FUN_004e6464 [UNCONDITIONAL_CALL]","From 004e6ba9 in FUN_004e6464 [UNCONDITIONAL_CALL]","From 004e6c4a in FUN_004e6464 [UNCONDITIONAL_CALL]"]}

Call ghidra_search_functions_by_name

Arguments
{"filepath": "/sandbox/FFG.exe", "query": "packet"}

Tool result
{"result":["No functions matching 'packet'"]}

Let me search for other CMD dispatch functions that handle 0x78 and 0x7d as received commands.

Call sandbox_execute

Arguments
{"command": "python3 -c \"\n# Search for comparison with0x78 (CMD=120) and 0x7d (CMD=125) in .text\n# Lookfor patterns like'cmp reg, 0x78' or 'cmp reg, 0x7d'\n# Inx86: 83 F8 78 (cmp eax, 0x78),83 7? 0x78 (various)\n# or:3D 78 00 00 00 (cmp eax, 0x78), 81 F9 78 00 00 00 etc.\n\nwith open('/sandbox/FFG.exe', 'rb')as f:\n  data = f.read()\n\ntext_start_va = 0x401000\ntext_raw_off= 0x400\ntext_size =0x169800\n\ntext = data[text_raw_off:text_raw_off + text_size]\n\nhits_78= []\nhits_7d = []\n\n#Lookfor: 83 F8 78 (cmp eax, 0x78),83 F978 (cmp ecx, 0x78), 83 FB 78 (cmp ebx, 0x78)\n# Also: 3D 78 00 00 00 (cmp eax, 0x78)\nimport re\n\nfor i in range(len(text)-4):\n    b= text[i]\n b1 = text[i+1]\n    b2 = text[i+2]\n \n# cmpreg8,imm8 pattern: 83 /7imm8\n    if b== 0x83 and (b1 & 0xF8) ==0xF8 and b2 == 0x78:\n   hits_78.append(text_start_va +i)\n    if b ==0x83 and (b1 & 0xF8) == 0xF8 and b2==0x7d:\n    hits_7d.append(text_start_va+ i)\n   \n# cmp eax, imm32: 3D 78 00 00 00\n   ifb == 0x3Dand b1 == 0x78 and text[i+2:i+5]== b'\\x00\\x00\\x00':\nhits_78.append(text_start_va +i)\n  if b == 0x3D and b1 == 0x7d and text[i+2:i+5]== b'\\x00\\x00\\x00':\n        hits_7d.append(text_start_va + i)\n\nprint(f'CMD=0x78 comparisons at: {[hex(a) for a in hits_78[:30]]}')\nprint(f'CMD=0x7d comparisons at:{[hex(a) fora in hits_7d[:30]]}')\n\"\n"}

Tool result
{"exitCode":0,"stdout":"CMD=0x78 comparisons at: ['0x4471eb', '0x4e6519']\nCMD=0x7d comparisons at: []\n","stderr":""}

Found another CMD=0x78 comparison at 0x4471eb. Let me find what function that belongs to.

Call ghidra_get_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "0x4471eb"}

Tool result
{"result":"No function found at 0x4471eb"}

Call sandbox_execute

Arguments
{"command": "python3 -c \"\n# Search morebroadly for 0x78and 0x7d asDWORD values indata sections\n# and incode as constants\n# Also look for 'cmp [mem], 78' or 'moveax, 78' patterns\nwith open('/sandbox/FFG.exe', 'rb') as f:\n    data = f.read()\n\ntext_start_va = 0x401000\ntext_raw_off = 0x400\ntext_size = 0x169800\ntext = data[text_raw_off:text_raw_off +text_size]\n\nhits =[]\nfor iin range(len(text)-4):\n    b= text[i:i+4]\n # Looking for comparisons to 0x78 or 0x7d as 32-bit in EAX\n# 3D7D 0000 00\n    iftext[i] == 0x3D and text[i+1] in [0x7d, 0x78] andtext[i+2:i+5] == b'\\x00\\x00\\x00':\n       hits.append((text_start_va+i, text[i+1]))\n    # 81 F? 7D 00 00 00 or78 00 0000\n    iftext[i] == 0x81 and(text[i+1] & 0xC0 in [0x80, 0xC0]) and text[i+2] in[0x7d, 0x78] andtext[i+3:i+6] == b'\\x00\\x00\\x00':\n   hits.append((text_start_va+i,text[i+2]))\n\nprint('Hits:', [(hex(a), hex(v)) for a,v in hits[:30]])\n\"\n"}

Tool result
{"exitCode":0,"stdout":"Hits: []\n","stderr":""}

Call sandbox_execute

Arguments
{"command": "python3 -c \"\n# Find function containing0x4471eb by looking for nearbyfunction starts\n# Let'sdisassemble the bytes around 0x4471eb\ndef va2off(va):\n    return 0x400 + (va - 0x401000)\n\nwith open('/sandbox/FFG.exe', 'rb') as f:\n    f.seek(va2off(0x4471d0))\n    data = f.read(80)\n  \nprint('Hex dump around 0x4471d0:')\nfor iin range(0, 80,16):\n    hex_part = ' '.join(f'{b:02x}' for b in data[i:i+16])\n   ascii_part = ''.join(chr(b) if 32 <= b <127 else'.' forb in data[i:i+16])\n   print(f'  {0x4471d0+i:08x}: {hex_part:<48}  {ascii_part}')\n\n#Also check broader - look for all places where0x7d (125) appears as a \n#CMD number in send calls like 'push 0x7d'\nwithopen('/sandbox/FFG.exe', 'rb') as f:\n    data = f.read()\n\ntext_raw_off = 0x400\ntext_size = 0x169800\ntext_start_va =0x401000\ntext = data[text_raw_off:text_raw_off + text_size]\n\nhits =[]\nfor i in range(len(text)-1):\n  #'push imm8': 6A 7D\n   if text[i] == 0x6Aand text[i+1]== 0x7D:\n  hits.append((text_start_va+i, '6a 7d'))\n # 'push imm32': 68 7D 000000\nif text[i] == 0x68 and text[i+1] == 0x7D and text[i+2:i+5] == b'\\x00\\x00\\x00':\n   hits.append((text_start_va+i, '68 7d'))\n   #Also find push0x78 \n    iftext[i] == 0x6A and text[i+1] == 0x78:\n    hits.append((text_start_va+i, '6a 78'))\n    iftext[i]== 0x68 and text[i+1] ==0x78 and text[i+2:i+5] == b'\\x00\\x00\\x00':\n        hits.append((text_start_va+i, '68 78'))\n\nprint()\nprint('Push 0x78/0x7d instructions:')\nfor addr, pat in hits[:40]:\n    print(f'  {addr:08x}: {pat}')\n\"\n"}

Tool result
{"exitCode":0,"stdout":"Hex dump around 0x4471d0:\n  004471d0: 55 ff 8b c7 66 be e0 ff e8 a3 d1 fb ff 88 45 f6   U...f.........E.\n  004471e0: 8b 87 98 00 00 00 99 33 c2 2b c2 83 f8 78 7d 8b   .......3.+...x}.\n  004471f0: 0f b6 45 f6 5f 5e 5b 8b e5 5d c2 04 00 8d 40 00   ..E._^[..]....@.\n  00447200: 53 56 57 83 c4 f4 8b f1 8d 7c 24 01 a5 a5 88 14   SVW......|$.....\n  00447210: 24 c6 44 24 09 00 66 83 b8 4a 01 00 00 00 74 1f   $.D$..f..J....t.\n\nPush 0x78/0x7d instructions:\n  004c785e: 6a 78\n  004d28c8: 6a 7d\n  004ed5c2: 6a 7d\n  004f2de9: 6a 78\n  004f2e26: 6a 78\n  0051b34d: 6a 78\n  0051b40e: 6a 78\n  0051b484: 6a 78\n  0051b551: 6a 78\n  0051b926: 6a 78\n  0051b951: 6a 78\n  00535934: 6a 78\n  005417d8: 6a 78\n  00543138: 6a 7d\n  00544de3: 6a 7d\n  0054869e: 6a 78\n  00548828: 6a 7d\n  005490a1: 6a 7d\n","stderr":""}

Let me look at FUN_004e9e08 (builds items for server→client CMD=120) and examine the push 0x78 locations for client→server structure.

Call ghidra_decompile_function

Arguments
{"filepath":"/sandbox/FFG.exe", "name_or_address":"FUN_004e9e08"}

Tool result
{"result":"\nvoid FUN_004e9e08(int param_1,undefined4 *param_2)\n\n{\n  undefined4 uVar1;\n  undefined4 *in_FS_OFFSET;\n  float10 fVar2;\n  longlong *local_30;\n  int local_2c;\n  int local_28;\n  longlong *local_24;\n  undefined2 local_20;\n  undefined2 uStack_1e;\n  longlong *local_1c;\n  undefined1 *local_18;\n  longlong *local_14;\n  int local_10;\n  undefined4 *local_c;\n  int local_8;\n  \n  local_14 = (longlong *)&stack0xfffffffc;\n  local_10 = 5;\n  do {\n    local_10 = local_10 + -1;\n  } while (local_10 != 0);\n  local_18 = &LAB_004e9f2a;\n  local_1c = (longlong *)*in_FS_OFFSET;\n  *in_FS_OFFSET = &local_1c;\n  local_24 = *(longlong **)(param_1 + 0x10);\n  local_20 = 0;\n  uStack_1e = 0;\n  local_28 = 0x4e9e3e;\n  local_c = param_2;\n  local_8 = param_1;\n  FUN_00409ad8((int *)&local_14);\n  local_20 = 0x9e4e;\n  uStack_1e = 0x4e;\n  FUN_0040537c(&local_10,(longlong *)&DAT_004e9f40,local_14);\n  local_20 = 0x9e5b;\n  uStack_1e = 0x4e;\n  (**(code **)(*(int *)*local_c + 0x38))((int *)*local_c,local_10);\n  local_20 = 0x9e69;\n  uStack_1e = 0x4e;\n  FUN_004099ec(*(uint *)(local_8 + 0x14),(int *)&local_1c);\n  local_20 = 0x9e79;\n  uStack_1e = 0x4e;\n  FUN_0040537c((int *)&local_18,(longlong *)\"fishid=\",local_1c);\n  local_20 = 0x9e86;\n  uStack_1e = 0x4e;\n  (**(code **)(*(int *)*local_c + 0x38))((int *)*local_c,local_18);\n  local_20 = 0x9e94;\n  uStack_1e = 0x4e;\n  FUN_004099ec(*(uint *)(local_8 + 0x18),(int *)&local_24);\n  local_20 = 0x9ea4;\n  uStack_1e = 0x4e;\n  FUN_0040537c((int *)&local_20,(longlong *)\"weigth=\",local_24);\n  uVar1 = CONCAT22(uStack_1e,local_20);\n  local_20 = 0x9eb1;\n  uStack_1e = 0x4e;\n  (**(code **)(*(int *)*local_c + 0x38))((int *)*local_c,uVar1);\n  local_20 = 0x9ec4;\n  uStack_1e = 0x4e;\n  FUN_0040537c(&local_28,(longlong *)\"info=\",*(longlong **)(local_8 + 0x28));\n  local_20 = 0x9ed1;\n  uStack_1e = 0x4e;\n  (**(code **)(*(int *)*local_c + 0x38))((int *)*local_c,local_28);\n  fVar2 = (float10)*(double *)(local_8 + 0x20);\n  local_28 = SUB104(fVar2,0);\n  local_24 = (longlong *)((unkuint10)fVar2 >> 0x20);\n  local_20 = (undefined2)((unkuint10)fVar2 >> 0x40);\n  local_2c = 0x4e9ee6;\n  FUN_0040b75c((int *)&local_30);\n  local_20 = 0x9ef6;\n  uStack_1e = 0x4e;\n  FUN_0040537c(&local_2c,(longlong *)\"time=\",local_30);\n  local_20 = 0x9f03;\n  uStack_1e = 0x4e;\n  (**(code **)(*(int *)*local_c + 0x38))((int *)*local_c,local_2c);\n  local_20 = 0x9f0f;\n  uStack_1e = 0x4e;\n  (**(code **)(*(int *)*local_c + 0x38))((int *)*local_c,0);\n  *in_FS_OFFSET = local_1c;\n  local_14 = (longlong *)&LAB_004e9f31;\n  local_18 = (undefined1 *)0x4e9f29;\n  FUN_00405088((int *)&local_30,9);\n  return;\n}\n\n"}

Call sandbox_execute

Arguments
{"command": "python3 -c \"\ndef va2off(va):\n    return 0x400 +(va - 0x401000)\n\n# Checkcontext around push 0x78 at 0x0051b34d\nwithopen('/sandbox/FFG.exe','rb') as f:\n  for va in[0x004ed5c2, 0x0051b34d, 0x00535934,0x005417d8]:\n f.seek(va2off(va-32))\n  d = f.read(80)\n print(f'=== {va:08x}===')\n   for i in range(0, 80, 16):\n      hex_part = ' '.join(f'{b:02x}' forb in d[i:i+16])\n ascii_part = ''.join(chr(b)if 32 <= b <127 else '.' for b in d[i:i+16])\n   print(f' {va-32+i:08x}:{hex_part:<48}  {ascii_part}')\n       print()\n\"\n"}

Tool result
{"exitCode":0,"stdout":"=== 004ed5c2 ===\n  004ed5a2: 30 9b df e0 9e 76 04 c6 45 f7 00 8b 45 fc 8b 40   0....v..E...E..@\n  004ed5b2: 1c 81 78 14 f4 01 00 00 75 6e 80 7d f7 00 74 35   ..x.....un.}..t5\n  004ed5c2: 6a 7d 8b 45 f8 8b 40 28 83 e8 28 83 e8 16 50 6a   j}.E..@(..(...Pj\n  004ed5d2: 64 6a 16 68 a0 d6 4e 00 68 70 b4 4e 00 6a 01 6a   dj.h..N.hp.N.j.j\n  004ed5e2: 00 8b 45 f8 8b 48 14 b2 01 a1 b8 b2 55 00 e8 93   ..E..H......U...\n\n=== 0051b34d ===\n  0051b32d: 48 14 b2 01 a1 5c b8 55 00 e8 29 17 04 00 6a 23   H....\\.U..)...j#\n  0051b33d: 6a 37 68 e6 00 00 00 6a 6c 6a 00 68 20 20 20 00   j7h....jlj.h   .\n  0051b34d: 6a 78 8b 45 f8 8b 48 14 b2 01 a1 68 b6 55 00 e8   jx.E..H....h.U..\n  0051b35d: 6f 66 04 00 6a 28 6a 3c 68 bc c3 51 00 6a 01 a1   of..j(j<h..Q.j..\n  0051b36d: b0 0b 57 00 8b 00 b9 dc c3 51 00 ba ec c3 51 00   ..W......Q....Q.\n\n=== 00535934 ===\n  00535914: 40 8b 45 f0 8b 40 14 50 6a 00 6a 00 8b 45 f4 8b   @.E..@.Pj.j..E..\n  00535924: 48 14 b2 01 a1 d0 b5 55 00 e8 66 b3 02 00 6a 10   H......U..f...j.\n  00535934: 6a 78 8b 45 f4 8b 40 24 83 e8 20 50 8b 45 f4 8b   jx.E..@$.. P.E..\n  00535944: 40 28 2d 2c 01 00 00 50 8b 45 f0 8b 40 1c 50 6a   @(-,...P.E..@.Pj\n  00535954: 00 a1 78 0b 57 00 8b 00 50 8b 45 f4 8b 48 14 b2   ..x.W...P.E..H..\n\n=== 005417d8 ===\n  005417b8: 45 bc 50 6a 00 8b 45 e8 8b 48 14 b2 01 a1 b8 b2   E.Pj..E..H......\n  005417c8: 55 00 e8 b9 b7 01 00 c6 40 60 00 e9 6f 01 00 00   U.......@`..o...\n  005417d8: 6a 78 68 be 00 00 00 68 94 22 54 00 68 ff a0 00   jxh....h.\"T.h...\n  005417e8: 00 6a 00 6a 00 8b 45 e8 8b 48 14 b2 01 a1 5c b8   .j.j..E..H....\\.\n  005417f8: 55 00 e8 65 b2 01 00 8b 15 a8 11 57 00 8b 12 e8   U..e.......W....\n\n","stderr":""}

FUN_004e9e08 builds per-fish entries with fields: fishid=, weigth=, info=, time=. Let me check DAT_004e9f40 and the function at 0x4ed5b2.

Call ghidra_get_data_by_address

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x004e9f40"}

Tool result
{"result":"66h    f"}

Call ghidra_get_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "0x004ed5a2"}

Tool result
{"result":"No function found at 0x004ed5a2"}

Call sandbox_execute

Arguments
{"command": "python3 -c \"\ndef va2off(va):\n    return 0x400 + (va -0x401000)\n\nwithopen('/sandbox/FFG.exe','rb') as f:\n# DAT_004e9f40\nf.seek(va2off(0x4e9f30))\n   data = f.read(48)\n    print('0x4e9f30 region:')\n    for i in range(0, 48, 16):\n      h =''.join(f'{b:02x}' for b in data[i:i+16])\n     a = ''.join(chr(b) if 32 <= b < 127 else '.' for b in data[i:i+16])\n  print(f'  {0x4e9f30+i:08x}: {h:<48}  {a}')\n\"\n"}

Tool result
{"exitCode":0,"stdout":"0x4e9f30 region:\n  004e9f30: eb 8b e5 5d c3 00 00 00 ff ff ff ff 04 00 00 00   ...]............\n  004e9f40: 66 69 64 3d 00 00 00 00 ff ff ff ff 07 00 00 00   fid=............\n  004e9f50: 66 69 73 68 69 64 3d 00 ff ff ff ff 07 00 00 00   fishid=.........\n","stderr":""}

Let me decompile FUN_004e7618 (fishing action processor) and also the function at 0x535900 (likely client-side CMD=120 send).

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_004e7618"}

Tool result
{"result":"\nvoid FUN_004e7618(int param_1,int param_2,int param_3,undefined4 param_4,longlong *param_5)\n\n{\n  undefined4 extraout_ECX;\n  undefined4 extraout_ECX_00;\n  undefined4 extraout_ECX_01;\n  undefined4 *in_FS_OFFSET;\n  undefined4 uStack_2c;\n  undefined1 *puStack_28;\n  undefined1 *puStack_24;\n  int local_1c;\n  int *local_18;\n  undefined4 local_14;\n  int local_10;\n  int local_c;\n  int local_8;\n  \n  puStack_24 = (undefined1 *)0x4e762f;\n  local_10 = param_3;\n  local_c = param_2;\n  local_8 = param_1;\n  FUN_004054e4((int)param_5);\n  puStack_28 = &LAB_004e76d3;\n  uStack_2c = *in_FS_OFFSET;\n  *in_FS_OFFSET = &uStack_2c;\n  local_14 = 0xffffffff;\n  puStack_24 = &stack0xfffffffc;\n  local_1c = FUN_0054daac(*(int *)PTR_DAT_00570ee0,local_c,extraout_ECX);\n  if (local_1c != 0) {\n    local_18 = FUN_0042099c((int *)PTR_DAT_004e7534,'\\x01',extraout_ECX_00);\n    *(int *)(local_8 + 0x7c) = *(int *)(local_8 + 0x7c) + 1;\n    local_18[4] = *(int *)(local_8 + 0x7c);\n    local_18[5] = local_c;\n    local_18[6] = local_10;\n    FUN_004050b8(local_18 + 10,param_5);\n    FUN_0041ff48(*(int *)(local_8 + 0x10),local_18,extraout_ECX_01,local_18[5],local_18[5] >> 0x1f);\n    local_14 = *(undefined4 *)(local_8 + 0x7c);\n  }\n  *in_FS_OFFSET = uStack_2c;\n  puStack_24 = &LAB_004e76da;\n  puStack_28 = (undefined1 *)0x4e76d2;\n  FUN_00405064((int *)&param_5);\n  return;\n}\n\n"}

Call ghidra_get_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "0x005358e0"}

Tool result
{"result":"No function found at 0x005358e0"}

Call ghidra_get_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "0x00535900"}

Tool result
{"result":"No function found at 0x00535900"}

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address":"0x00535870"}

Tool result
{"result":"Function not found"}

Call sandbox_execute

Arguments
{"command": "python3 -c \"\ndef va2off(va):\n    return 0x400 + (va - 0x401000)\n\nwith open('/sandbox/FFG.exe','rb') as f:\n    # Look back from 0x535934 to find function start\n # Functionstarts usuallybegin with 'push ebp; mov ebp,esp' -> 55 8B EC\nf.seek(va2off(0x535600))\n data = f.read(0x400)\n    \n    #Find last 55 8B ECbefore 0x535934\n  base= 0x535600\n    starts = []\n    for i in range(len(data)-2):\nif data[i] == 0x55 and data[i+1] == 0x8B and data[i+2] == 0xEC:\nstarts.append(base + i)\n  \n    print('Function startsnear 0x535934:', [hex(a) for a instarts[-5:]])\n \n    # Also look right at the preceding bytes\n    f.seek(va2off(0x5358e0))\n  d = f.read(16)\n    print('0x5358e0:', d.hex())\n    \n    f.seek(va2off(0x535840))\n    d = f.read(16)\n print('0x535840:',d.hex())\n\"\n"}

Tool result
{"exitCode":0,"stdout":"Function starts near 0x535934: ['0x5356ac', '0x53581c']\n0x5358e0: 60006a01a1a81157008b00508b45f48b\n0x535840: 0c57008b008b55fce8c37701008945f0\n","stderr":""}

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_0053581c"}

Tool result
{"result":"\nvoid FUN_0053581c(int param_1,uint param_2)\n\n{\n  int iVar1;\n  undefined4 *in_FS_OFFSET;\n  undefined4 uVar2;\n  undefined *puVar3;\n  undefined4 uStack_28;\n  undefined1 *puStack_24;\n  undefined1 *puStack_20;\n  int local_1c;\n  int local_18;\n  int *local_14;\n  int local_10;\n  uint local_c;\n  int local_8;\n  \n  puStack_20 = &stack0xfffffffc;\n  local_18 = 0;\n  local_1c = 0;\n  puStack_24 = &LAB_00535a0d;\n  uStack_28 = *in_FS_OFFSET;\n  *in_FS_OFFSET = &uStack_28;\n  local_c = param_2;\n  local_8 = param_1;\n  local_14 = FUN_0054d010(*(int *)PTR_DAT_00570c9c,param_1,0);\n  local_10 = FUN_0055e99c(*(int *)PTR_DAT_00570fe0,0x1a4,400,0,(longlong *)0x0);\n  FUN_005619d0((int *)PTR_PTR_0055b668,'\\x01',*(int *)(local_10 + 0x14),0xfa,0,0xa7d0d4,\n               *(int *)(local_10 + 0x28) + -0x10,*(int *)(local_10 + 0x24) + -0x10,8,8);\n  puVar3 = &DAT_00535a20;\n  FUN_00567a28(local_c,&local_1c);\n  iVar1 = local_1c;\n  FUN_004053f8(&local_18,3);\n  FUN_0055ca64((int *)PTR_PTR_0055b85c,'\\x01',*(int *)(local_10 + 0x14),*(int *)PTR_DAT_005711a8,1,\n               0x600000,local_18,iVar1,(int)puVar3);\n  iVar1 = (int)*(uint *)(local_10 + 0x24) >> 1;\n  if (iVar1 < 0) {\n    iVar1 = iVar1 + (uint)((*(uint *)(local_10 + 0x24) & 1) != 0);\n  }\n  FUN_00560c98((int *)PTR_PTR_0055b5d0,'\\x01',*(int *)(local_10 + 0x14),(longlong *)0x0,0,\n               local_14[5],0x40,0x40,0x32,iVar1 + -0x20);\n  iVar1 = FUN_005621b0((int *)PTR_PTR_0055b49c,'\\x01',*(int *)(local_10 + 0x14),\n                       *(int *)PTR_DAT_00570b78,'\\0',local_14[7],*(int *)(local_10 + 0x28) + -300,\n                       *(int *)(local_10 + 0x24) + -0x20,0x78,0x10);\n  *(undefined1 *)(iVar1 + 0xa1) = 1;\n  iVar1 = FUN_005621b0((int *)PTR_PTR_0055b49c,'\\x01',*(int *)(local_10 + 0x14),\n                       *(int *)PTR_DAT_0057126c,'\\0',local_14[8],100,\n                       *(int *)(local_10 + 0x24) + -0x20,0xe0,0x10);\n  *(undefined1 *)(iVar1 + 0xa1) = 1;\n  iVar1 = (int)*(uint *)(local_10 + 0x24) >> 1;\n  if (iVar1 < 0) {\n    iVar1 = iVar1 + (uint)((*(uint *)(local_10 + 0x24) & 1) != 0);\n  }\n  uVar2 = 0;\n  FUN_0055cf88((int *)PTR_PTR_0055b2b8,'\\x01',*(int *)(local_10 + 0x14),(longlong *)0x0,0,0x55bc8c,\n               (longlong *)&DAT_00535a30,0x16,100,*(int *)(local_10 + 0x28) + -0x32,iVar1 + -0x32);\n  *in_FS_OFFSET = uVar2;\n  FUN_00405088(&local_1c,2);\n  return;\n}\n\n"}

Call ghidra_decompile_function

Arguments
{"filepath":"/sandbox/FFG.exe", "name_or_address": "FUN_005356ac"}

Tool result
{"result":"Function not found"}

Call sandbox_execute

Arguments
{"command":"python3 -c \"\ndef va2off(va):\n    return 0x400+ (va - 0x401000)\n\nwith open('/sandbox/FFG.exe','rb') as f:\n    # Look atpush 0x78 at 0x535934 andsurroundingcontext more carefully\nf.seek(va2off(0x5358f0))\n    data= f.read(0x100)\n    print('0x5358f0 - 0x5359f0:')\n  for i in range(0, 0x100, 16):\n        h =' '.join(f'{b:02x}' for b in data[i:i+16])\n      a = ''.join(chr(b) if 32 <= b< 127 else '.' for bin data[i:i+16])\nprint(f'  {0x5358f0+i:08x}: {h:<48}  {a}')\n\"\n"}

Tool result
{"exitCode":0,"stdout":"0x5358f0 - 0x5359f0:\n  005358f0: 48 14 b2 01 a1 5c b8 55 00 e8 66 71 02 00 8b 45   H....\\.U..fq...E\n  00535900: f4 8b 40 24 d1 f8 79 03 83 d0 00 83 e8 20 50 6a   ..@$..y...... Pj\n  00535910: 32 6a 40 6a 40 8b 45 f0 8b 40 14 50 6a 00 6a 00   2j@j@.E..@.Pj.j.\n  00535920: 8b 45 f4 8b 48 14 b2 01 a1 d0 b5 55 00 e8 66 b3   .E..H......U..f.\n  00535930: 02 00 6a 10 6a 78 8b 45 f4 8b 40 24 83 e8 20 50   ..j.jx.E..@$.. P\n  00535940: 8b 45 f4 8b 40 28 2d 2c 01 00 00 50 8b 45 f0 8b   .E..@(-,...P.E..\n  00535950: 40 1c 50 6a 00 a1 78 0b 57 00 8b 00 50 8b 45 f4   @.Pj..x.W...P.E.\n  00535960: 8b 48 14 b2 01 a1 9c b4 55 00 e8 41 c8 02 00 c6   .H......U..A....\n  00535970: 80 a1 00 00 00 01 6a 10 68 e0 00 00 00 8b 45 f4   ......j.h.....E.\n  00535980: 8b 40 24 83 e8 20 50 6a 64 8b 45 f0 8b 40 20 50   .@$.. Pjd.E..@ P\n  00535990: 6a 00 a1 6c 12 57 00 8b 00 50 8b 45 f4 8b 48 14   j..l.W...P.E..H.\n  005359a0: b2 01 a1 9c b4 55 00 e8 04 c8 02 00 c6 80 a1 00   .....U..........\n  005359b0: 00 00 01 8b 45 f4 8b 40 24 d1 f8 79 03 83 d0 00   ....E..@$..y....\n  005359c0: 83 e8 32 50 8b 45 f4 8b 40 28 83 e8 32 50 6a 64   ..2P.E..@(..2Pjd\n  005359d0: 6a 16 68 30 5a 53 00 68 8c bc 55 00 6a 00 6a 00   j.h0ZS.h..U.j.j.\n  005359e0: 8b 45 f4 8b 48 14 b2 01 a1 b8 b2 55 00 e8 96 75   .E..H......U...u\n","stderr":""}

Let me find and decompile the function at 0x4ed5c2 (push 0x7d context) which likely handles CMD=125 receive/send.

Call sandbox_execute

Arguments
{"command": "python3 -c \"\ndef va2off(va):\n    return 0x400 +(va - 0x401000)\n\nwithopen('/sandbox/FFG.exe','rb') as f:\n    # Find function startbefore 0x4ed5c2\n   f.seek(va2off(0x4ed400))\n    data= f.read(0x300)\n    base= 0x4ed400\n   starts = []\n for i in range(len(data)-2):\n   if data[i] == 0x55 and data[i+1] == 0x8B and data[i+2] == 0xEC:\n starts.append(base +i)\nprint('Function starts:', [hex(a)for ain starts])\n\"\n"}

Tool result
{"exitCode":0,"stdout":"Function starts: ['0x4ed42c', '0x4ed6a8']\n","stderr":""}

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_004ed42c"}

Tool result
{"result":"\n/* WARNING: Globals starting with '_' overlap smaller symbols at the same address */\n\nvoid FUN_004ed42c(int param_1,undefined4 param_2,undefined4 param_3,char param_4)\n\n{\n  int iVar1;\n  int *piVar2;\n  char local_d;\n  \n  DAT_0057aa2c = param_1;\n  iVar1 = FUN_0055e99c(*(int *)PTR_DAT_00570fe0,0x217,0x136,1,(longlong *)&DAT_004ed638);\n  FUN_0055accc(*(int *)PTR_DAT_00570ddc,(longlong *)\"drag_onmouseup.wav\",0);\n  piVar2 = FUN_005619d0((int *)PTR_PTR_0055b668,'\\x01',*(int *)(iVar1 + 0x14),0xfa,0,0xa7d0d4,\n                        *(int *)(iVar1 + 0x28) + -0x26,*(int *)(iVar1 + 0x24) + -0x10,0x1e,8);\n  piVar2[0xf] = (int)&LAB_004eb830;\n  FUN_005621b0((int *)PTR_PTR_0055b49c,'\\x01',*(int *)(iVar1 + 0x14),0,'\\0',\n               *(int *)(*(int *)(DAT_0057aa2c + 0x1c) + 0x28),0x4b,0x15e,0x91,0x82);\n  FUN_0055cf88((int *)PTR_PTR_0055b2b8,'\\x01',*(int *)(iVar1 + 0x14),(longlong *)0x0,0,0x55bc8c,\n               (longlong *)&DAT_004ed670,0x16,100,*(int *)(iVar1 + 0x28) + -0x3e,\n               *(int *)(iVar1 + 0x24) + -0x78);\n  if (param_4 == '\\0') {\n    FUN_0055cf88((int *)PTR_PTR_0055b2b8,'\\x01',*(int *)(iVar1 + 0x14),(longlong *)0x0,0,0x4ed374,\n                 (longlong *)&DAT_004ed680,0x16,100,*(int *)(iVar1 + 0x28) + -0x3e,\n                 *(int *)(iVar1 + 0x24) + -0xe1);\n    if (((*(char *)(*(int *)(param_1 + 0x1c) + 0x69) == '\\0') &&\n        (local_d = '\\x01', 0 < *(int *)(*(int *)(param_1 + 0x1c) + 0x3c))) &&\n       ((float10)*(float *)(param_1 + 0x30) <\n        _DAT_004ed68c * (float10)*(int *)(*(int *)(param_1 + 0x1c) + 0x3c))) {\n      local_d = '\\0';\n    }\n    if (*(int *)(*(int *)(param_1 + 0x1c) + 0x14) == 500) {\n      if (local_d == '\\0') {\n        FUN_0055cf88((int *)PTR_PTR_0055b2b8,'\\x01',*(int *)(iVar1 + 0x14),(longlong *)0x0,1,\n                     0x4eb470,(longlong *)&DAT_004ed6a0,0x16,100,*(int *)(iVar1 + 0x28) + -0x3e,0x14\n                    );\n      }\n      else {\n        FUN_0055cf88((int *)PTR_PTR_0055b2b8,'\\x01',*(int *)(iVar1 + 0x14),(longlong *)0x0,1,\n                     0x4eb470,(longlong *)&DAT_004ed6a0,0x16,100,*(int *)(iVar1 + 0x28) + -0x3e,0x7d\n                    );\n      }\n    }\n  }\n  return;\n}\n\n"}

Let me check the remaining CMD=0x7d push locations more systematically.

Call sandbox_execute

Arguments
{"command":"python3 -c \"\ndef va2off(va):\n return 0x400 + (va - 0x401000)\n\nwith open('/sandbox/FFG.exe','rb') as f:\n   for va in [0x004d28c8,0x00543138, 0x00544de3, 0x00548828, 0x005490a1]:\nf.seek(va2off(va-20))\n   d = f.read(48)\nh = ' '.join(f'{b:02x}' for b in d)\n  a = ''.join(chr(b) if 32 <=b <127 else '.' for b in d)\n    print(f'{va:08x}: {h}')\n    print(f'  {a}')\n  print()\n\"\n"}

Tool result
{"exitCode":0,"stdout":"004d28c8: ff 84 c0 74 28 a1 10 13 57 00 8b 00 8b 40 34 99 52 50 6a 00 6a 7d e8 01 af f9 ff 50 c1 f8 1f 3b c2 58 74 05 e8 6f 17 f3 ff 8b f0 eb 05 be 7d 00\n         ...t(...W....@4.RPj.j}.....P...;.Xt..o........}.\n\n00543138: 6a 00 8b 45 f8 8b 48 14 b2 01 a1 b8 b2 55 00 e8 50 9e 01 00 6a 7d 8b 45 f8 8b 40 28 83 e8 2d 50 6a 64 6a 16 68 9c 32 54 00 68 54 c7 53 00 6a 69\n         j..E..H......U..P...j}.E..@(..-Pjdj.h.2T.hT.S.ji\n\n00544de3: 40 1c e8 ba 47 ec ff 83 bd 90 fe ff ff 00 0f 95 c0 5a 88 02 6a 7d a1 b8 e1 57 00 8b 40 28 83 e8 2d 50 6a 64 6a 16 68 30 50 54 00 68 bc 33 54 00\n         @...G............Z..j}...W..@(..-Pjdj.h0PT.h.3T.\n\n00548828: 00 50 8b 45 f4 8b 48 14 b2 01 a1 5c b8 55 00 e8 3c 42 01 00 6a 7d 8b 45 f4 8b 40 28 83 e8 2f 50 6a 64 6a 16 68 6c 8c 54 00 68 7c 60 54 00 68 2c\n         .P.E..H....\\.U..<B..j}.E..@(../Pjdj.hl.T.h|`T.h,\n\n005490a1: 01 a1 b8 b2 55 00 e8 f0 3e 01 00 8b 15 1c e2 57 00 89 50 68 6a 7d 8b 45 f4 8b 40 28 83 e8 2f 50 6a 64 6a 16 68 c8 91 54 00 68 9c 5f 54 00 6a 00\n         ....U...>......W..Phj}.E..@(../Pjdj.h..T.h._T.j.\n\n","stderr":""}

FUN_004e6464 is the server-side handler. I need to find the client-side packet dispatch. Let me search for the client's CMD=120 receive handler.

Call sandbox_execute

Arguments
{"command": "python3 -c \"\n# Search forclient-side dispatch that handlesCMD=0x78(120) and 0x7d (125)\n# Pattern: cmp [reg+0x14], 0x78 orsimilar\n# Or look for all functions that reference field names from CMD=120 response\n\ndef va2off(va):\n    return 0x400 + (va -0x401000)\n\nwith open('/sandbox/FFG.exe','rb') as f:\n    text_data = f.read()\n\ntext_start_va = 0x401000\ntext_raw_off = 0x400\ntext_size = 0x169800\n\ntext = text_data[text_raw_off:text_raw_off+ text_size]\n\n# Search forpattern: mov eax, [reg+0x14] and cmpeax, 0x78\n# Pattern: 8B4? 14 (mov [e/r]cx, [reg+0x14])followed by comparison\nhits = []\nfori in range(len(text)-10):\n    # Looking for:mov reg,[reg+0x14]thencompare to0x78\n    b =text[i:i+3]\n  if b[0]== 0x8Band (b[1]&0x40) == 0x40 and (b[1]& 0x07) !=0x04 and b[2] ==0x14:\n   # Foundmov reg,[something+0x14]\n     #Check if followed by cmp to 0x78 withinnext 20 bytes\n        following = text[i+3:i+25]\n        forj inrange(len(following)-1):\n          if following[j] == 0x83and (following[j+1] & 0xF8)== 0xF8 and following[j+2] == 0x78:\n      hits.append(text_start_va + i)\n      break\n if following[j] == 0x3Dand following[j+1]== 0x78 and following[j+2:j+5] == b'\\\\x00\\\\x00\\\\x00':\n     hits.append(text_start_va + i)\n    break\n\nprint('Potential CMD dispatch locations:', [hex(a)for a in hits[:20]])\n\"\n"}

Tool result
{"exitCode":1,"stdout":"","stderr":"Traceback (most recent call last):\n  File \"<string>\", line 29, in <module>\n    if following[j] == 0x83 and (following[j+1] & 0xF8) == 0xF8 and following[j+2] == 0x78:\n                                                                    ~~~~~~~~~^^^^^\nIndexError: index out of range\n"}

Call sandbox_execute

Arguments
{"command":"python3 << 'EOF'\ndef va2off(va):\n  return0x400 + (va - 0x401000)\n\nwith open('/sandbox/FFG.exe','rb') as f:\n text_data = f.read()\n\ntext_raw_off= 0x400\ntext_size = 0x169800\ntext_start_va = 0x401000\ntext =text_data[text_raw_off:text_raw_off + text_size]\n\nhits =[]\nfor i in range(len(text)-25):\n   b0, b1, b2 = text[i], text[i+1], text[i+2]\n  # mov reg, [reg+0x14]\n    if b0== 0x8B and (b1 & 0xC7) ==0x47and b2 == 0x14:\n    following = text[i+3:i+23]\n        for jin range(len(following)-2):\n   if following[j] == 0x83 and following[j+2] == 0x78:\n   hits.append(text_start_va + i)\n    break\n\nprint('CMD dispatchlocations:', [hex(a) for a in hits[:20]])\n\n# Also search forthe string \"fishid=\" xrefto find the CLIENT receive handler\n# The client would parse fishid= from incoming CMD=120from server\n# \"fishid=\" is at 0x4e9f50\n# Let'sfind xrefs \ntarget_addr =0x4e9f50  # \"fishid=\" in CMD=120 builder\ntarget_bytes_le =target_addr.to_bytes(4, 'little')\npositions= []\nfor i in range(len(text)-3):\n  if text[i:i+4] == target_bytes_le:\npositions.append(text_start_va + i)\n\nprint('Refs to 0x4e9f50 (fishid= in CMD=120builder):', [hex(p) for pin positions])\nEOF\n"}

Tool result
{"exitCode":0,"stdout":"CMD dispatch locations: []\nRefs to 0x4e9f50 (fishid= in CMD=120 builder): ['0x4e9e70']\n","stderr":""}

Let me find the client-side CMD=125 handler by searching for references to "oid=" used in parsing.

Call ghidra_get_xrefs_to

Arguments
{"filepath": "/sandbox/FFG.exe", "address": "0x004e73cc"}

Tool result
{"result":["From 004e68cd in FUN_004e6464 [DATA]"]}

Call ghidra_list_strings

Arguments
{"filepath": "/sandbox/FFG.exe", "filter": "oid="}

Tool result
{"result":["00534cd4: \"fishoid=\"","00536738: \"fishoid=\"","0053692c: \"fishoid=\"","00537530: \"fishoid=\""]}

Let me trace back from FUN_0052162c to understand when CMD=120 is received client-side.

Call ghidra_get_function_xrefs

Arguments
{"filepath": "/sandbox/FFG.exe", "name":"FUN_0052162c"}

Tool result
{"result":["From 00518c6a in FUN_005170e4 [UNCONDITIONAL_CALL]"]}

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_005170e4"}

Tool result
{"result":"Succeeded and the artifact is saved at /sandbox/ghidra/decompiled_0x5170e4.txt. Please find the table of contents below. \n[{'funcName': 'FUN_00405b24', 'lineNum': 134}, {'funcName': 'FUN_0052835c', 'lineNum': 142}, {'funcName': 'FUN_0053421c', 'lineNum': 149}, {'funcName': 'FUN_00569b08', 'lineNum': 158}, {'funcName': 'FUN_00569de0', 'lineNum': 160}, {'funcName': 'FUN_00569b08', 'lineNum': 161}, {'funcName': 'FUN_0041fa5c', 'lineNum': 163}, {'funcName': 'FUN_0041fa5c', 'lineNum': 164}, {'funcName': 'FUN_0041fb1c', 'lineNum': 167}, {'funcName': 'FUN_0041fb1c', 'lineNum': 169}, {'funcName': 'FUN_0041fb1c', 'lineNum': 171}, {'funcName': 'FUN_0041fb1c', 'lineNum': 175}, {'funcName': 'FUN_0041fb1c', 'lineNum': 178}, {'funcName': 'FUN_0041fb1c', 'lineNum': 181}, {'funcName': 'FUN_00478fe0', 'lineNum': 184}, {'funcName': 'FUN_00404184', 'lineNum': 187}, {'funcName': 'FUN_0055eb34', 'lineNum': 191}, {'funcName': 'FUN_004e2950', 'lineNum': 192}, {'funcName': 'FUN_00569708', 'lineNum': 194}, {'funcName': 'FUN_004053f8', 'lineNum': 197}, {'funcName': 'FUN_0055e264', 'lineNum': 198}, {'funcName': 'FUN_0055e264', 'lineNum': 199}, {'funcName': 'FUN_004d38d8', 'lineNum': 202}, {'funcName': 'FUN_0055eb34', 'lineNum': 207}, {'funcName': 'FUN_004e2950', 'lineNum': 208}, {'funcName': 'FUN_00569708', 'lineNum': 210}, {'funcName': 'FUN_004053f8', 'lineNum': 212}, {'funcName': 'FUN_0055e264', 'lineNum': 213}, {'funcName': 'FUN_0055e264', 'lineNum': 214}, {'funcName': 'FUN_004d38d8', 'lineNum': 217}, {'funcName': 'FUN_0055eb34', 'lineNum': 222}, {'funcName': 'FUN_004e2950', 'lineNum': 223}, {'funcName': 'FUN_0055e264', 'lineNum': 224}, {'funcName': 'FUN_004d38d8', 'lineNum': 228}, {'funcName': 'FUN_00569b08', 'lineNum': 233}, {'funcName': 'FUN_004099ec', 'lineNum': 234}, {'funcName': 'FUN_0040537c', 'lineNum': 235}, {'funcName': 'FUN_00469584', 'lineNum': 236}, {'funcName': 'FUN_00569a34', 'lineNum': 237}, {'funcName': 'FUN_00409dc4', 'lineNum': 238}, {'funcName': 'FUN_0040537c', 'lineNum': 239}, {'funcName': 'FUN_00469584', 'lineNum': 240}, {'funcName': 'FUN_00569b68', 'lineNum': 241}, {'funcName': 'FUN_00409ad8', 'lineNum': 242}, {'funcName': 'FUN_0040537c', 'lineNum': 243}, {'funcName': 'FUN_00469584', 'lineNum': 244}, {'funcName': 'FUN_00569da0', 'lineNum': 245}, {'funcName': 'FUN_004099ec', 'lineNum': 246}, {'funcName': 'FUN_0040537c', 'lineNum': 247}, {'funcName': 'FUN_00469584', 'lineNum': 248}, {'funcName': 'FUN_00569de0', 'lineNum': 249}, {'funcName': 'FUN_0040537c', 'lineNum': 250}, {'funcName': 'FUN_00469584', 'lineNum': 251}, {'funcName': 'FUN_00569de0', 'lineNum': 252}, {'funcName': 'FUN_0040537c', 'lineNum': 253}, {'funcName': 'FUN_00469584', 'lineNum': 254}, {'funcName': 'FUN_00569d14', 'lineNum': 255}, {'funcName': 'FUN_0040b75c', 'lineNum': 257}, {'funcName': 'FUN_0040537c', 'lineNum': 258}, {'funcName': 'FUN_00469584', 'lineNum': 259}, {'funcName': 'FUN_004d99d8', 'lineNum': 263}, {'funcName': 'FUN_004d81a4', 'lineNum': 267}, {'funcName': 'FUN_004ddaa0', 'lineNum': 271}, {'funcName': 'FUN_004dd144', 'lineNum': 275}, {'funcName': 'FUN_004dd504', 'lineNum': 279}, {'funcName': 'FUN_004dd9d0', 'lineNum': 283}, {'funcName': 'FUN_004dd77c', 'lineNum': 287}, {'funcName': 'FUN_004dd334', 'lineNum': 291}, {'funcName': 'FUN_004dd264', 'lineNum': 295}, {'funcName': 'FUN_004dd504', 'lineNum': 299}, {'funcName': 'FUN_004dcfa4', 'lineNum': 303}, {'funcName': 'FUN_004dde7c', 'lineNum': 307}, {'funcName': 'FUN_004d8e30', 'lineNum': 311}, {'funcName': 'FUN_004df2bc', 'lineNum': 315}, {'funcName': 'FUN_004df3e4', 'lineNum': 319}, {'funcName': 'FUN_00569708', 'lineNum': 325}, {'funcName': 'FUN_004c7ab0', 'lineNum': 326}, {'funcName': 'FUN_0055e264', 'lineNum': 327}, {'funcName': 'FUN_0055e264', 'lineNum': 328}, {'funcName': 'FUN_00569678', 'lineNum': 332}, {'funcName': 'FUN_0055fc34', 'lineNum': 334}, {'funcName': 'FUN_0055eb88', 'lineNum': 335}, {'funcName': 'FUN_004099ec', 'lineNum': 336}, {'funcName': 'FUN_0040537c', 'lineNum': 337}, {'funcName': '(unique, 0x17200, 4)', 'lineNum': 338}, {'funcName': '(unique, 0x17200, 4)', 'lineNum': 339}, {'funcName': 'FUN_004099ec', 'lineNum': 340}, {'funcName': 'FUN_0040537c', 'lineNum': 341}, {'funcName': '(unique, 0x17200, 4)', 'lineNum': 342}, {'funcName': '(unique, 0x17200, 4)', 'lineNum': 343}, {'funcName': 'FUN_0055e264', 'lineNum': 345}, {'funcName': 'FUN_00569678', 'lineNum': 348}, {'funcName': 'FUN_0055fc34', 'lineNum': 350}, {'funcName': 'FUN_0055e264', 'lineNum': 352}, {'funcName': 'FUN_0055fc34', 'lineNum': 358}, {'funcName': 'FUN_00569708', 'lineNum': 362}, {'funcName': 'FUN_00569708', 'lineNum': 365}, {'funcName': 'FUN_0040ac40', 'lineNum': 368}, {'funcName': 'FUN_0055e264', 'lineNum': 370}, {'funcName': 'FUN_00569678', 'lineNum': 375}, {'funcName': 'FUN_0054bbe8', 'lineNum': 377}, {'funcName': 'FUN_0055fc34', 'lineNum': 380}, {'funcName': 'FUN_0055e264', 'lineNum': 382}, {'funcName': 'FUN_004099ec', 'lineNum': 385}, {'funcName': 'FUN_0040537c', 'lineNum': 386}, {'funcName': 'FUN_00469584', 'lineNum': 387}, {'funcName': 'FUN_0054bff0', 'lineNum': 391}, {'funcName': 'FUN_0055fc34', 'lineNum': 395}, {'funcName': 'FUN_0055accc', 'lineNum': 396}, {'funcName': 'FUN_004f7998', 'lineNum': 397}, {'funcName': 'FUN_0055fc34', 'lineNum': 401}, {'funcName': 'FUN_004f7188', 'lineNum': 402}, {'funcName': 'FUN_0055fc34', 'lineNum': 406}, {'funcName': 'FUN_004f7998', 'lineNum': 407}, {'funcName': 'FUN_0054c26c', 'lineNum': 412}, {'funcName': 'FUN_0054cc50', 'lineNum': 416}, {'funcName': 'FUN_0053f8f8', 'lineNum': 420}, {'funcName': 'FUN_0055eb34', 'lineNum': 421}, {'funcName': 'FUN_00533cd0', 'lineNum': 422}, {'funcName': 'FUN_00569678', 'lineNum': 423}, {'funcName': 'FUN_0054d53c', 'lineNum': 424}, {'funcName': 'FUN_00569678', 'lineNum': 425}, {'funcName': 'FUN_0054d520', 'lineNum': 426}, {'funcName': 'FUN_005335d0', 'lineNum': 427}, {'funcName': 'FUN_00569708', 'lineNum': 428}, {'funcName': 'FUN_00533644', 'lineNum': 429}, {'funcName': 'FUN_0054fcb8', 'lineNum': 431}, {'funcName': '(ram, 0x4e2268, 8)', 'lineNum': 432}, {'funcName': '(ram, 0x4e2268, 8)', 'lineNum': 433}, {'funcName': 'FUN_004e28e4', 'lineNum': 434}, {'funcName': 'FUN_004e2950', 'lineNum': 436}, {'funcName': 'FUN_004e28c8', 'lineNum': 438}, {'funcName': '(unique, 0x17200, 4)', 'lineNum': 439}, {'funcName': 'FUN_0053f288', 'lineNum': 440}, {'funcName': 'FUN_00533df8', 'lineNum': 446}, {'funcName': 'FUN_0053421c', 'lineNum': 453}, {'funcName': 'FUN_0054ce4c', 'lineNum': 461}, {'funcName': 'FUN_00569678', 'lineNum': 470}, {'funcName': 'FUN_00569b08', 'lineNum': 477}, {'funcName': 'FUN_00569b08', 'lineNum': 479}, {'funcName': 'FUN_00569b08', 'lineNum': 481}, {'funcName': 'FUN_00569b08', 'lineNum': 483}, {'funcName': 'FUN_00569b08', 'lineNum': 485}, {'funcName': 'FUN_00569b08', 'lineNum': 487}, {'funcName': 'FUN_004e46cc', 'lineNum': 491}, {'funcName': 'FUN_004e4678', 'lineNum': 493}, {'funcName': 'FUN_004e4720', 'lineNum': 495}, {'funcName': 'FUN_0046984c', 'lineNum': 497}, {'funcName': 'FUN_0046984c', 'lineNum': 498}, {'funcName': 'FUN_004099ec', 'lineNum': 499}, {'funcName': 'FUN_0040537c', 'lineNum': 500}, {'funcName': 'FUN_0046984c', 'lineNum': 501}, {'funcName': 'FUN_004099ec', 'lineNum': 502}, {'funcName': 'FUN_0040537c', 'lineNum': 503}, {'funcName': 'FUN_0046984c', 'lineNum': 504}, {'funcName': 'FUN_004099ec', 'lineNum': 505}, {'funcName': 'FUN_0040537c', 'lineNum': 506}, {'funcName': 'FUN_0046984c', 'lineNum': 507}, {'funcName': 'FUN_004099ec', 'lineNum': 508}, {'funcName': 'FUN_0040537c', 'lineNum': 509}, {'funcName': 'FUN_0046984c', 'lineNum': 510}, {'funcName': 'FUN_004099ec', 'lineNum': 511}, {'funcName': 'FUN_0040537c', 'lineNum': 512}, {'funcName': 'FUN_0046984c', 'lineNum': 513}, {'funcName': 'FUN_00569b08', 'lineNum': 514}, {'funcName': 'FUN_00569b08', 'lineNum': 516}, {'funcName': 'FUN_00569b08', 'lineNum': 518}, {'funcName': 'FUN_00569b08', 'lineNum': 520}, {'funcName': 'FUN_00569b08', 'lineNum': 522}, {'funcName': 'FUN_00569b08', 'lineNum': 524}, {'funcName': 'FUN_0046984c', 'lineNum': 526}, {'funcName': 'FUN_004099ec', 'lineNum': 527}, {'funcName': 'FUN_0040537c', 'lineNum': 528}, {'funcName': 'FUN_0046984c', 'lineNum': 529}, {'funcName': 'FUN_004099ec', 'lineNum': 530}, {'funcName': 'FUN_0040537c', 'lineNum': 531}, {'funcName': 'FUN_0046984c', 'lineNum': 532}, {'funcName': 'FUN_004099ec', 'lineNum': 533}, {'funcName': 'FUN_0040537c', 'lineNum': 534}, {'funcName': 'FUN_0046984c', 'lineNum': 535}, {'funcName': 'FUN_004099ec', 'lineNum': 536}, {'funcName': 'FUN_0040537c', 'lineNum': 537}, {'funcName': 'FUN_0046984c', 'lineNum': 538}, {'funcName': 'FUN_004099ec', 'lineNum': 539}, {'funcName': 'FUN_0040537c', 'lineNum': 540}, {'funcName': 'FUN_0046984c', 'lineNum': 541}, {'funcName': 'FUN_005245f4', 'lineNum': 545}, {'funcName': 'FUN_00569b08', 'lineNum': 549}, {'funcName': 'FUN_00554bd4', 'lineNum': 555}, {'funcName': 'FUN_0054ca20', 'lineNum': 561}, {'funcName': 'FUN_0054c674', 'lineNum': 565}, {'funcName': 'FUN_0054b774', 'lineNum': 569}, {'funcName': 'FUN_0054b664', 'lineNum': 573}, {'funcName': 'FUN_00539f2c', 'lineNum': 577}, {'funcName': 'FUN_0055fc34', 'lineNum': 582}, {'funcName': 'FUN_00536200', 'lineNum': 583}, {'funcName': 'FUN_00536178', 'lineNum': 587}, {'funcName': 'FUN_005391e4', 'lineNum': 591}, {'funcName': 'FUN_004eb1d0', 'lineNum': 595}, {'funcName': 'FUN_0054d254', 'lineNum': 600}, {'funcName': 'FUN_0054cee0', 'lineNum': 605}, {'funcName': 'FUN_0054d07c', 'lineNum': 609}, {'funcName': 'FUN_004f1bac', 'lineNum': 616}, {'funcName': 'FUN_004f68c8', 'lineNum': 621}, {'funcName': 'FUN_00569678', 'lineNum': 625}, {'funcName': 'FUN_00565310', 'lineNum': 626}, {'funcName': 'FUN_005695e4', 'lineNum': 627}, {'funcName': 'FUN_00469584', 'lineNum': 629}, {'funcName': 'FUN_005695e4', 'lineNum': 632}, {'funcName': 'FUN_00569678', 'lineNum': 638}, {'funcName': 'FUN_0054b4f0', 'lineNum': 639}, {'funcName': 'FUN_00565214', 'lineNum': 640}, {'funcName': 'FUN_004f694c', 'lineNum': 646}, {'funcName': 'FUN_004f31e8', 'lineNum': 652}, {'funcName': 'FUN_004eaf08', 'lineNum': 656}, {'funcName': 'FUN_004ea3e4', 'lineNum': 662}, {'funcName': 'FUN_004fa38c', 'lineNum': 669}, {'funcName': 'FUN_004f2ef8', 'lineNum': 673}, {'funcName': 'FUN_00535a38', 'lineNum': 680}, {'funcName': 'FUN_004f999c', 'lineNum': 686}, {'funcName': 'FUN_004f81b8', 'lineNum': 690}, {'funcName': 'FUN_004f9e98', 'lineNum': 696}, {'funcName': 'FUN_004f2888', 'lineNum': 703}, {'funcName': 'FUN_00520b80', 'lineNum': 708}, {'funcName': 'FUN_004d38d8', 'lineNum': 714}, {'funcName': 'FUN_0055accc', 'lineNum': 715}, {'funcName': 'FUN_00525944', 'lineNum': 721}, {'funcName': 'FUN_0054b6f4', 'lineNum': 725}, {'funcName': 'FUN_00569578', 'lineNum': 731}, {'funcName': 'FUN_00569708', 'lineNum': 736}, {'funcName': 'FUN_0040bce0', 'lineNum': 738}, {'funcName': 'FUN_00478f88', 'lineNum': 740}, {'funcName': 'FUN_0040d268', 'lineNum': 742}, {'funcName': 'FUN_0055accc', 'lineNum': 745}, {'funcName': 'FUN_00525990', 'lineNum': 753}, {'funcName': 'FUN_00526fd0', 'lineNum': 758}, {'funcName': 'FUN_00525a28', 'lineNum': 763}, {'funcName': 'FUN_005259dc', 'lineNum': 768}, {'funcName': 'FUN_005207f8', 'lineNum': 778}, {'funcName': 'FUN_00520988', 'lineNum': 782}, {'funcName': 'FUN_00520cb8', 'lineNum': 788}, {'funcName': 'FUN_00520a50', 'lineNum': 795}, {'funcName': 'FUN_00520540', 'lineNum': 801}, {'funcName': 'FUN_005208c0', 'lineNum': 807}, {'funcName': 'FUN_00569708', 'lineNum': 814}, {'funcName': '(unique, 0x17200, 4)', 'lineNum': 815}, {'funcName': '(unique, 0x17200, 4)', 'lineNum': 816}, {'funcName': 'FUN_0055e264', 'lineNum': 818}, {'funcName': 'FUN_0055fc34', 'lineNum': 819}, {'funcName': 'FUN_00522278', 'lineNum': 825}, {'funcName': 'FUN_0051fc30', 'lineNum': 830}, {'funcName': 'FUN_00521294', 'lineNum': 834}, {'funcName': 'FUN_00520eac', 'lineNum': 838}, {'funcName': 'FUN_00520f78', 'lineNum': 844}, {'funcName': 'FUN_0052162c', 'lineNum': 850}, {'funcName': 'FUN_00521958', 'lineNum': 854}, {'funcName': 'FUN_00522b94', 'lineNum': 860}, {'funcName': 'FUN_0054c3c0', 'lineNum': 867}, {'funcName': 'FUN_0053b4bc', 'lineNum': 868}, {'funcName': 'FUN_0055fc34', 'lineNum': 872}, {'funcName': 'FUN_00521958', 'lineNum': 873}, {'funcName': 'FUN_00535e84', 'lineNum': 874}, {'funcName': 'FUN_0054ccd8', 'lineNum': 878}, {'funcName': 'FUN_00569708', 'lineNum': 879}, {'funcName': 'FUN_00569678', 'lineNum': 883}, {'funcName': 'FUN_00542eec', 'lineNum': 884}, {'funcName': 'FUN_0054c3c0', 'lineNum': 890}, {'funcName': 'FUN_00543664', 'lineNum': 896}, {'funcName': 'FUN_00543538', 'lineNum': 900}, {'funcName': 'FUN_005445cc', 'lineNum': 906}, {'funcName': 'FUN_0052fb84', 'lineNum': 913}, {'funcName': 'FUN_0055e264', 'lineNum': 919}, {'funcName': 'FUN_004d96e8', 'lineNum': 924}, {'funcName': 'FUN_0054c830', 'lineNum': 928}, {'funcName': 'FUN_00542cac', 'lineNum': 929}, {'funcName': 'FUN_00535e84', 'lineNum': 933}, {'funcName': 'FUN_0054c698', 'lineNum': 937}, {'funcName': 'FUN_005429a8', 'lineNum': 938}, {'funcName': 'FUN_00542448', 'lineNum': 944}, {'funcName': 'FUN_005410d0', 'lineNum': 950}, {'funcName': 'FUN_00549858', 'lineNum': 954}, {'funcName': 'FUN_004d38d8', 'lineNum': 960}, {'funcName': 'FUN_0052f8d4', 'lineNum': 967}, {'funcName': 'FUN_0055e264', 'lineNum': 972}, {'funcName': 'FUN_0052feb4', 'lineNum': 976}, {'funcName': 'FUN_0052fc5c', 'lineNum': 982}, {'funcName': 'FUN_0052f6ec', 'lineNum': 988}, {'funcName': 'FUN_00530290', 'lineNum': 994}, {'funcName': 'FUN_00547b0c', 'lineNum': 1001}, {'funcName': 'FUN_00530f28', 'lineNum': 1006}, {'funcName': 'FUN_0052faf8', 'lineNum': 1010}, {'funcName': 'FUN_00530eec', 'lineNum': 1014}, {'funcName': 'FUN_0052fc20', 'lineNum': 1020}, {'funcName': 'FUN_005303a8', 'lineNum': 1026}, {'funcName': 'FUN_0055e264', 'lineNum': 1030}, {'funcName': 'FUN_0055fc34', 'lineNum': 1032}, {'funcName': 'FUN_00548d70', 'lineNum': 1038}, {'funcName': 'FUN_00569578', 'lineNum': 1046}, {'funcName': 'FUN_004d8c28', 'lineNum': 1048}, {'funcName': 'FUN_004e1f94', 'lineNum': 1049}, {'funcName': 'FUN_0055accc', 'lineNum': 1050}, {'funcName': 'FUN_00569578', 'lineNum': 1053}, {'funcName': 'FUN_004d8c28', 'lineNum': 1055}, {'funcName': 'FUN_004e1f94', 'lineNum': 1056}, {'funcName': 'FUN_0055accc', 'lineNum': 1058}, {'funcName': 'FUN_00569578', 'lineNum': 1061}, {'funcName': 'FUN_004d8c28', 'lineNum': 1063}, {'funcName': 'FUN_004e1f94', 'lineNum': 1064}, {'funcName': 'FUN_0055accc', 'lineNum': 1066}, {'funcName': 'FUN_00569578', 'lineNum': 1069}, {'funcName': 'FUN_004d8c28', 'lineNum': 1071}, {'funcName': 'FUN_004e1f94', 'lineNum': 1072}, {'funcName': 'FUN_0055accc', 'lineNum': 1074}, {'funcName': 'FUN_00569578', 'lineNum': 1077}, {'funcName': 'FUN_004d8c28', 'lineNum': 1079}, {'funcName': 'FUN_004e1f94', 'lineNum': 1080}, {'funcName': 'FUN_00569578', 'lineNum': 1083}, {'funcName': 'FUN_004d8c28', 'lineNum': 1085}, {'funcName': 'FUN_004e1f94', 'lineNum': 1086}, {'funcName': 'FUN_0055accc', 'lineNum': 1088}, {'funcName': 'FUN_0054a5a4', 'lineNum': 1092}, {'funcName': 'FUN_0054850c', 'lineNum': 1097}, {'funcName': 'FUN_0040548c', 'lineNum': 1103}, {'funcName': 'FUN_0055e264', 'lineNum': 1108}, {'funcName': 'FUN_0040548c', 'lineNum': 1110}, {'funcName': 'FUN_0055e264', 'lineNum': 1115}, {'funcName': 'FUN_0040548c', 'lineNum': 1117}, {'funcName': 'FUN_004d8c28', 'lineNum': 1119}, {'funcName': 'FUN_004e1f94', 'lineNum': 1120}, {'funcName': 'FUN_0055fc34', 'lineNum': 1122}, {'funcName': 'FUN_00569578', 'lineNum': 1128}, {'funcName': 'FUN_0055e264', 'lineNum': 1131}, {'funcName': 'FUN_00569578', 'lineNum': 1133}, {'funcName': 'FUN_0055e264', 'lineNum': 1136}, {'funcName': 'FUN_0055fc34', 'lineNum': 1138}, {'funcName': 'FUN_00569578', 'lineNum': 1145}, {'funcName': 'FUN_00569708', 'lineNum': 1147}, {'funcName': 'FUN_004053f8', 'lineNum': 1149}, {'funcName': 'FUN_004d8c28', 'lineNum': 1150}, {'funcName': 'FUN_004e1f94', 'lineNum': 1151}, {'funcName': 'FUN_00569708', 'lineNum': 1154}, {'funcName': 'FUN_004053f8', 'lineNum': 1156}, {'funcName': 'FUN_004d8c28', 'lineNum': 1157}, {'funcName': 'FUN_004e1f94', 'lineNum': 1158}, {'funcName': 'FUN_0054a2cc', 'lineNum': 1163}, {'funcName': 'FUN_005491e4', 'lineNum': 1169}, {'funcName': 'FUN_00404184', 'lineNum': 1173}, {'funcName': 'FUN_00405088', 'lineNum': 1175}, {'funcName': 'FUN_00405088', 'lineNum': 1176}, {'funcName': 'FUN_00405c40', 'lineNum': 1177}, {'funcName': 'FUN_004065d0', 'lineNum': 1178}, {'funcName': 'FUN_00405bf4', 'lineNum': 1179}, {'funcName': 'FUN_00405064', 'lineNum': 1180}, {'funcName': 'FUN_00405064', 'lineNum': 1181}]"}

FUN_005170e4 is the client-side packet handler (calls FUN_0052162c at line 850). Let me search that artifact for CMD=120/125.

Call ghidra_search_artifact

Arguments
{"artifact_path": "/sandbox/ghidra/decompiled_0x5170e4.txt", "regex": "0x78|0x7d|cmd.*120|cmd.*125"}

Tool result
{"result":"          FUN_004f7998(param_1[0xd]);\n          break;\n        case 0x69:\n          *(int *)PTR_DAT_0057086c = *(int *)PTR_DAT_0057086c + -1;\n          puStack_14 = &stack0xfffffffc;\n          FUN_0054c26c(*(int *)PTR_DAT_00570c9c,param_1[0xd]);\n          break;\n        case 0x6a:\n          puStack_14 = &stack0xfffffffc;\n          FUN_0054cc50(*(int *)PTR_DAT_00570c9c,(int)param_1);\n          break;\n        case 0x6e:\n          puStack_14 = &stack0xfffffffc;\n          FUN_0053f8f8();\n          FUN_0055eb34(*(int *)PTR_DAT_00570fe0);\n          FUN_00533cd0(*(int *)PTR_DAT_00570c08,0xfa);\n          uVar7 = FUN_00569678((int)param_1,0x519800);\n          FUN_0054d53c(*(int *)PTR_DAT_00570c9c,uVar7);\n          uVar7 = FUN_00569678((int)param_1,0x519810);\n          FUN_0054d520(*(int *)PTR_DAT_00570c9c,uVar7);\n          FUN_005335d0(*(int *)PTR_DAT_00570c08,*(int *)(*(int *)PTR_DAT_00570c9c + 0x78));\n          FUN_00569708((int)param_1,0x519820,&local_1fc);\n          FUN_00533644(*(int *)PTR_DAT_00570c08,*(int *)(*(int *)PTR_DAT_00570c9c + 0x3c),local_1fc)\n          ;\n          FUN_0054fcb8(*(int *)PTR_DAT_00570c84);\n          func_0x004e2268(*(undefined4 *)(*(int *)PTR_DAT_00570d28 + 0x28));\n          func_0x004e2268(*(undefined4 *)(*(int *)PTR_DAT_00570d28 + 0x2c));\n          iVar8 = FUN_004e28e4(*(int *)PTR_DAT_00570b24);\n          if (iVar8 != 3) {\n            FUN_004e2950(*(int *)PTR_DAT_00570b24,3,extraout_ECX_04);\n          }\n          puVar5 = (undefined4 *)FUN_004e28c8(*(int *)PTR_DAT_00570b24);\n          (**(code **)*puVar5)();\n          FUN_0053f288();\n          break;\n        case 0x6f:\n          puStack_14 = &stack0xfffffffc;\n          if (*(int *)(*(int *)(*(int *)PTR_DAT_00570c08 + 0x10) + 0x24) != 0) {\n            puStack_14 = &stack0xfffffffc;\n            FUN_00533df8(*(int *)(*(int *)(*(int *)PTR_DAT_00570c08 + 0x10) + 0x20),(int)param_1);\n...\n          FUN_0046984c(*(int *)PTR_DAT_00570b54,(int *)0x0,local_240);\n          FUN_004099ec(*(uint *)(*(int *)PTR_DAT_00571180 + 0x58),(int *)&local_24c);\n          FUN_0040537c(&local_248,(longlong *)&DAT_0051989c,local_24c);\n          FUN_0046984c(*(int *)PTR_DAT_00570b54,(int *)0x0,local_248);\n          break;\n        case 0x74:\n          puStack_14 = &stack0xfffffffc;\n          FUN_005245f4((int)param_1);\n          break;\n        case 0x77:\n          puStack_14 = &stack0xfffffffc;\n          uVar4 = FUN_00569b08((int)param_1);\n          **(undefined1 **)(*(int *)PTR_DAT_00570c84 + uVar4 * 4) = 0;\n          if ((((*(char *)(*(int *)(*(int *)PTR_DAT_00570c84 + uVar4 * 4) + 0x2e) != '\\0') &&\n               (*(char *)(*(int *)(*(int *)PTR_DAT_00570c84 + uVar4 * 4) + 0x2d) != '\\0')) &&\n              (*(char *)(*(int *)(*(int *)PTR_DAT_00570c84 + uVar4 * 4) + 0x30) == '\\0')) &&\n             (*PTR_DAT_00570c90 == '\\0')) {\n            FUN_00554bd4(*(int *)(*(int *)PTR_DAT_00570c84 + uVar4 * 4),(int)param_1);\n          }\n          break;\n        case 0x78:\n          *(int *)PTR_DAT_0057086c = *(int *)PTR_DAT_0057086c + -1;\n          puStack_14 = &stack0xfffffffc;\n          FUN_0054ca20(*(int *)PTR_DAT_00570c9c,(int)param_1);\n          break;\n        case 0x7a:\n          puStack_14 = &stack0xfffffffc;\n          FUN_0054c674(*(int *)PTR_DAT_00570c9c,(int)param_1);\n          break;\n        case 0x7d:\n          puStack_14 = &stack0xfffffffc;\n          FUN_0054b774(*(int *)PTR_DAT_00570c9c,(int)param_1);\n          break;\n        case 0x7e:\n          puStack_14 = &stack0xfffffffc;\n          FUN_0054b664(*(int *)PTR_DAT_00570c9c,(int)param_1);\n          break;\n        case 0x82:\n          puStack_14 = &stack0xfffffffc;\n          FUN_00539f2c(0);\n          break;\n        case 0x84:\n        case 0x85:\n          puStack_14 = &stack0xfffffffc;\n          FUN_0055fc34(*(int *)PTR_DAT_00570fe0,0);\n          FUN_00536200((int)param_1);\n          break;\n        case 0x86:\n          puStack_14 = &stack0xfffffffc;\n...\n      else {\n        puStack_14 = &stack0xfffffffc;\n        if (iVar8 == 0x4b2) {\n          puStack_14 = &stack0xfffffffc;\n          FUN_0052fc5c(*(undefined4 *)PTR_DAT_00570924,(int)param_1);\n        }\n      }\n    }\n    else if ((iVar8 == 0x4e2) || (iVar8 == 0x4e7)) {\n      puStack_14 = &stack0xfffffffc;\n      FUN_0052f6ec(*(int **)PTR_DAT_00570924,(int)param_1);\n    }\n    else {\n      puStack_14 = &stack0xfffffffc;\n      if (iVar8 == 0x4ec) {\n        puStack_14 = &stack0xfffffffc;\n        FUN_00530290(*(undefined4 *)PTR_DAT_00570924,(int)param_1);\n      }\n    }\n  }\n  else if (iVar8 < 0x7d2) {\n    if (iVar8 == 0x7d1) {\n      puStack_14 = &stack0xfffffffc;\n      FUN_00547b0c(*(int *)PTR_DAT_00570ed0,(int)param_1);\n    }\n    else if (iVar8 < 0x506) {\n      if (iVar8 == 0x505) {\n        puStack_14 = &stack0xfffffffc;\n        FUN_00530f28(*(undefined4 *)PTR_DAT_00570924,(int)param_1,extraout_ECX);\n      }\n      else if (iVar8 == 0x4f7) {\n        puStack_14 = &stack0xfffffffc;\n        FUN_0052faf8(*(int *)PTR_DAT_00570924,(int)param_1);\n      }\n      else if (iVar8 == 0x500) {\n        puStack_14 = &stack0xfffffffc;\n        FUN_00530eec(*(undefined4 *)PTR_DAT_00570924,(int)param_1);\n      }\n      else {\n        puStack_14 = &stack0xfffffffc;\n        if (iVar8 == 0x502) {\n...\n        uStackY_40 = uStackY_40 & 0xffffff;\n      }\n      cVar2 = FUN_00569578((int)param_1,0x519d10);\n      if (cVar2 != '\\0') {\n        iVar8 = FUN_004d8c28((int *)PTR_DAT_004d7ae4,'\\x01',(longlong *)&DAT_00519d20);\n        FUN_004e1f94(*(int *)(*(int *)PTR_DAT_00570d28 + 0x30),iVar8);\n        uStackY_40 = uStackY_40 & 0xffffff;\n      }\n      cVar2 = FUN_00569578((int)param_1,0x519d4c);\n      if (cVar2 != '\\0') {\n        iVar8 = FUN_004d8c28((int *)PTR_DAT_004d7ae4,'\\x01',(longlong *)&DAT_00519d60);\n        FUN_004e1f94(*(int *)(*(int *)PTR_DAT_00570d28 + 0x30),iVar8);\n        in_stack_ffffffd8 = (int *)0x50;\n        FUN_0055accc(*(int *)PTR_DAT_00570ddc,(longlong *)\"error.wav\",0);\n        uStackY_40 = uStackY_40 & 0xffffff;\n      }\n      if (uStackY_40._3_1_ != '\\0') {\n        FUN_0054a5a4(*(undefined4 *)PTR_DAT_00570ed0,(int)param_1);\n      }\n    }\n    else if (iVar8 == 0x7da) {\n      puStack_14 = &stack0xfffffffc;\n      FUN_0054850c(*(int *)PTR_DAT_00570ed0,(int)param_1);\n    }\n    else {\n      bVar9 = iVar8 == 0x7ee;\n      if (bVar9) {\n        puStack_14 = &stack0xfffffffc;\n        FUN_0040548c((char *)param_1[0xd],\"artremove_ok\");\n        uVar10 = 0;\n        if (bVar9) {\n          uVar10 = 1;\n          in_stack_ffffffd8 = (int *)0x518fdb;\n          FUN_0055e264(*(int *)PTR_DAT_00570fe0,0x519ae4,(longlong *)0x0,0,'\\x02');\n        }\n        FUN_0040548c((char *)param_1[0xd],\"artremove_noall\");\n        uVar11 = 0;\n        if ((bool)uVar10) {\n          in_stack_ffffffd8 = (int *)0x0;\n          uVar11 = 1;"}

Found it! Client dispatches CMD=120 → FUN_0054ca20, CMD=125 → FUN_0054b774. Let me decompile both.

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_0054ca20"}

Tool result
{"result":"\nvoid FUN_0054ca20(int param_1,int param_2)\n\n{\n  bool bVar1;\n  char cVar2;\n  uint uVar3;\n  undefined4 uVar4;\n  int iVar5;\n  undefined4 extraout_ECX;\n  undefined4 extraout_ECX_00;\n  undefined4 extraout_ECX_01;\n  undefined4 extraout_ECX_02;\n  undefined1 *extraout_ECX_03;\n  undefined4 extraout_ECX_04;\n  undefined4 *in_FS_OFFSET;\n  undefined4 uStack_34;\n  undefined1 *puStack_30;\n  undefined1 *puStack_2c;\n  longlong *local_28;\n  longlong *local_24;\n  int local_20;\n  int local_1c;\n  int *local_18;\n  int local_14;\n  int local_10;\n  int local_c;\n  int local_8;\n  \n  puStack_2c = &stack0xfffffffc;\n  local_28 = (longlong *)0x0;\n  local_24 = (longlong *)0x0;\n  puStack_30 = &LAB_0054cc43;\n  uStack_34 = *in_FS_OFFSET;\n  *in_FS_OFFSET = &uStack_34;\n  local_c = param_2;\n  local_8 = param_1;\n  local_18 = FUN_004201a0((int *)PTR_DAT_0041fdd8,'\\x01',0);\n  do {\n    bVar1 = FUN_00569818(local_c);\n    if (bVar1) {\n      FUN_004205a8(*(int *)(local_8 + 0x14),'\\0',extraout_ECX_03);\n      iVar5 = FUN_004202b4((int)local_18);\n      if (-1 < iVar5 + -1) {\n        local_10 = 0;\n        local_20 = iVar5;\n        do {\n          local_14 = FUN_00420460((int)local_18,local_10);\n          FUN_0041ff48(*(int *)(local_8 + 0x14),local_14,extraout_ECX_04,*(int *)(local_14 + 8),0);\n          local_10 = local_10 + 1;\n          local_20 = local_20 + -1;\n        } while (local_20 != 0);\n      }\n      FUN_00404184(local_18);\n      cVar2 = FUN_005365d0();\n      if (cVar2 != '\\0') {\n        FUN_00539f2c(0);\n      }\n      *in_FS_OFFSET = uStack_34;\n      puStack_2c = &LAB_0054cc4a;\n      puStack_30 = (undefined1 *)0x54cc42;\n      FUN_00405088((int *)&local_28,2);\n      return;\n    }\n    local_1c = FUN_00569b68(local_c);\n    local_14 = FUN_00420090(*(int *)(local_8 + 0x14),0,extraout_ECX,local_1c,0);\n    uVar4 = extraout_ECX_00;\n    if (local_14 == 0) {\n      local_14 = FUN_00404154((int *)PTR_DAT_0054accc,'\\x01',extraout_ECX_00);\n      *(int *)(local_14 + 8) = local_1c;\n      uVar4 = extraout_ECX_01;\n    }\n    FUN_0041ff48((int)local_18,local_14,uVar4,*(int *)(local_14 + 8),0);\n    if ((int)DAT_0057e22c < 0) {\n      if ((int)DAT_0057e22c >> 0x1f < 0) goto LAB_0054caca;\n    }\n    else if (DAT_0057e22c < local_1c + 1U) {\nLAB_0054caca:\n      DAT_0057e22c = local_1c + 1;\n    }\n    *(uint *)(local_14 + 4) = DAT_0057e22c;\n    uVar3 = FUN_00569b08(local_c);\n    *(uint *)(local_14 + 0xc) = uVar3;\n    uVar4 = FUN_0054daac(*(int *)PTR_DAT_00570ee0,*(int *)(local_14 + 0xc),extraout_ECX_02);\n    *(undefined4 *)(local_14 + 0x14) = uVar4;\n    FUN_0054e53c(*(int *)(local_14 + 0x14));\n    uVar3 = FUN_00569b08(local_c);\n    *(uint *)(local_14 + 0x18) = uVar3;\n    uVar4 = FUN_00569b68(local_c);\n    *(undefined4 *)(local_14 + 0x20) = uVar4;\n    FUN_00569b08(local_c);\n    FUN_00569b08(local_c);\n    FUN_00569b08(local_c);\n    bVar1 = FUN_00569a34(local_c);\n    *(bool *)(local_14 + 0x10) = bVar1;\n    bVar1 = FUN_00569a34(local_c);\n    *(bool *)(local_14 + 0x3e) = bVar1;\n    bVar1 = FUN_00569a34(local_c);\n    *(bool *)(local_14 + 0x3c) = bVar1;\n    FUN_00569de0(local_c,(int *)&local_24);\n    FUN_004050b8((int *)(local_14 + 0x30),local_24);\n    uVar3 = FUN_00569b08(local_c);\n    *(uint *)(local_14 + 0x34) = uVar3;\n    FUN_00569de0(local_c,(int *)&local_28);\n    FUN_004050b8((int *)(local_14 + 0x38),local_28);\n  } while( true );\n}\n\n"}

Call ghidra_decompile_function

Arguments
{"filepath":"/sandbox/FFG.exe", "name_or_address": "FUN_0054b774"}

Tool result
{"result":"\nvoid FUN_0054b774(int param_1,int param_2)\n\n{\n  char cVar1;\n  int iVar2;\n  int iVar3;\n  int *piVar4;\n  undefined4 extraout_ECX;\n  undefined4 extraout_ECX_00;\n  undefined4 extraout_ECX_01;\n  undefined4 extraout_ECX_02;\n  undefined4 extraout_ECX_03;\n  int *in_FS_OFFSET;\n  int local_90;\n  undefined4 local_8c;\n  undefined1 local_88;\n  int local_84;\n  undefined1 local_80;\n  uint local_7c;\n  undefined1 local_78;\n  longlong *local_74;\n  int local_70;\n  int local_6c;\n  undefined4 local_68;\n  undefined1 local_64;\n  undefined4 local_60;\n  undefined1 local_5c;\n  int local_58;\n  undefined1 local_54;\n  int *local_50;\n  undefined1 local_4c;\n  undefined4 local_48;\n  undefined1 local_44;\n  int local_40;\n  longlong *local_3c;\n  undefined4 local_38;\n  int local_34;\n  int *local_30;\n  uint local_2c;\n  uint local_28;\n  uint local_24;\n  undefined1 local_1e;\n  undefined1 local_1d;\n  int local_1c;\n  uint local_18;\n  undefined4 local_14;\n  uint local_10;\n  int local_c;\n  int local_8;\n  \n  local_74 = (longlong *)0x0;\n  local_90 = 0;\n  local_70 = 0;\n  local_6c = 0;\n  local_38 = 0;\n  local_3c = (longlong *)0x0;\n  iVar3 = *in_FS_OFFSET;\n  *in_FS_OFFSET = (int)&stack0xffffff60;\n  local_c = param_2;\n  local_8 = param_1;\n  local_10 = FUN_00569b08(param_2);\n  local_14 = FUN_00569b68(local_c);\n  local_18 = FUN_00569b08(local_c);\n  local_24 = FUN_00569b08(local_c);\n  local_30 = (int *)FUN_00569b08(local_c);\n  local_1d = FUN_00569a34(local_c);\n  local_28 = FUN_00569b08(local_c);\n  local_1e = FUN_00569a34(local_c);\n  local_2c = FUN_00569b08(local_c);\n  FUN_00569de0(local_c,(int *)&local_3c);\n  local_40 = FUN_004202b4(*(int *)(local_8 + 0x14));\n  local_1c = 0;\n  do {\n    iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n    if (*(uint *)(iVar2 + 4) == local_10) {\n      local_34 = FUN_0054daac(*(int *)PTR_DAT_00570ee0,local_24,extraout_ECX);\n      if (local_34 != 0) {\n        local_68 = *(undefined4 *)(local_34 + 0x20);\n        local_64 = 0;\n        local_60 = *(undefined4 *)(local_34 + 0x18);\n        local_5c = 0xb;\n        piVar4 = local_30;\n        FUN_005685b8(&local_6c,(int)local_30 >> 0x1f,extraout_ECX_00,(int)local_30,\n                     (int)local_30 >> 0x1f);\n        local_58 = local_6c;\n        local_54 = 0xb;\n        local_50 = local_30;\n        local_4c = 0;\n        iVar3 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n        local_48 = *(undefined4 *)(iVar3 + 0x30);\n        local_44 = 0xb;\n        FUN_0040ac40((byte *)\" %d  | %s | %s | %d | %s\",&local_68,4,piVar4);\n        FUN_0040537c(&local_70,*(longlong **)PTR_DAT_00570e18,(longlong *)\"FishLog.txt\");\n        (**(code **)PTR_DAT_00570f04)();\n        local_8c = *(undefined4 *)(local_34 + 0x18);\n        local_88 = 0xb;\n        iVar3 = (int)local_30 >> 0x1f;\n        piVar4 = local_30;\n        FUN_005685b8(&local_90,iVar3,extraout_ECX_01,(int)local_30,iVar3);\n        local_84 = local_90;\n        local_80 = 0xb;\n        local_7c = local_28;\n        local_78 = 0;\n        FUN_0040ac40(&LAB_0054bb40,&local_8c,2,piVar4);\n        iVar2 = FUN_004d8c28((int *)PTR_DAT_004d7ae4,'\\x01',local_74);\n        FUN_004e1f94(*(int *)(*(int *)PTR_DAT_00570d28 + 0x28),iVar2);\n      }\n      FUN_0054e53c(local_34);\n      FUN_00420160(*(int *)(local_8 + 0x14),local_1c,extraout_ECX_02,local_14,0);\n      cVar1 = (**(code **)(**(int **)PTR_DAT_00570bb0 + 0x10))\n                        (*(int **)PTR_DAT_00570bb0,\"Options\",\"opensadok\",1);\n      if (cVar1 == '\\0') {\n        piVar4 = (int *)FUN_005455c8((int *)PTR_PTR_005450e4,'\\x01',local_24);\n        FUN_00545398(*(int *)PTR_DAT_00571030,piVar4,extraout_ECX_03);\n      }\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(int *)(iVar2 + 0x14) = local_34;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(uint *)(iVar2 + 0xc) = local_24;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(int **)(iVar2 + 0x18) = local_30;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(undefined4 *)(iVar2 + 8) = local_14;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(uint *)(iVar2 + 0x20) = local_18;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(undefined1 *)(iVar2 + 0x10) = local_1d;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(undefined1 *)(iVar2 + 0x3d) = 0;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(undefined1 *)(iVar2 + 0x3c) = local_1e;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      *(uint *)(iVar2 + 0x34) = local_2c;\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      FUN_004050b8((int *)(iVar2 + 0x38),local_3c);\n      iVar2 = FUN_00420460(*(int *)(local_8 + 0x14),local_1c);\n      FUN_005346e0(*(int *)PTR_DAT_00570b6c,iVar2);\n      break;\n    }\n    local_1c = local_1c + 1;\n    local_40 = local_40 + -1;\n  } while (local_40 != 0);\n  *in_FS_OFFSET = iVar3;\n  FUN_00405064(&local_90);\n  FUN_00405088((int *)&local_74,3);\n  FUN_00405088((int *)&local_3c,2);\n  return;\n}\n\n"}

The client uses stream readers FUN_00569b08/FUN_00569b68. Let me verify these functions to understand binary vs text parsing.

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_00569b08"}

Tool result
{"result":"\nuint FUN_00569b08(int param_1)\n\n{\n  byte bVar1;\n  byte bVar2;\n  byte bVar3;\n  byte bVar4;\n  \n  bVar1 = FUN_00569a60(param_1);\n  bVar2 = FUN_00569a60(param_1);\n  bVar3 = FUN_00569a60(param_1);\n  bVar4 = FUN_00569a60(param_1);\n  return (uint)bVar1 << 0x18 | (uint)bVar2 << 0x10 | (uint)bVar3 << 8 | (uint)bVar4;\n}\n\n"}

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_00569b68"}

Tool result
{"result":"\nvoid FUN_00569b68(int param_1)\n\n{\n  byte bVar1;\n  undefined4 *in_FS_OFFSET;\n  undefined4 uStack_30;\n  undefined1 *puStack_2c;\n  undefined1 *puStack_28;\n  undefined4 local_24 [2];\n  uint local_1c;\n  uint local_18;\n  uint local_14;\n  uint local_10;\n  int local_8;\n  \n  puStack_28 = &stack0xfffffffc;\n  local_24[0] = 0;\n  puStack_2c = &LAB_00569d03;\n  uStack_30 = *in_FS_OFFSET;\n  *in_FS_OFFSET = &uStack_30;\n  local_8 = param_1;\n  bVar1 = FUN_00569a60(param_1);\n  local_1c = (uint)bVar1;\n  local_18 = 0;\n  bVar1 = FUN_00569a60(local_8);\n  local_18 = local_18 << 8 | local_1c >> 0x18;\n  local_1c = local_1c << 8 | (uint)bVar1;\n  bVar1 = FUN_00569a60(local_8);\n  local_18 = local_18 << 8 | local_1c >> 0x18;\n  local_1c = local_1c << 8 | (uint)bVar1;\n  bVar1 = FUN_00569a60(local_8);\n  local_18 = local_18 << 8 | local_1c >> 0x18;\n  local_1c = local_1c << 8 | (uint)bVar1;\n  bVar1 = FUN_00569a60(local_8);\n  local_18 = local_18 << 8 | local_1c >> 0x18;\n  local_1c = local_1c << 8 | (uint)bVar1;\n  bVar1 = FUN_00569a60(local_8);\n  local_18 = local_18 << 8 | local_1c >> 0x18;\n  local_1c = local_1c << 8 | (uint)bVar1;\n  bVar1 = FUN_00569a60(local_8);\n  local_18 = local_18 << 8 | local_1c >> 0x18;\n  local_1c = local_1c << 8 | (uint)bVar1;\n  bVar1 = FUN_00569a60(local_8);\n  local_18 = local_18 << 8 | local_1c >> 0x18;\n  local_1c = local_1c << 8 | (uint)bVar1;\n  *in_FS_OFFSET = uStack_30;\n  puStack_28 = &LAB_00569d0a;\n  puStack_2c = (undefined1 *)0x569d02;\n  local_14 = local_1c;\n  local_10 = local_18;\n  FUN_004065d0(local_24,(int)PTR_DAT_0046cb7c);\n  return;\n}\n\n"}

The stream readers read raw bytes big-endian (binary format). Let me check FUN_00569a60 (single byte reader) and FUN_00569de0 (string reader).

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_00569a60"}

Tool result
{"result":"\nundefined1 FUN_00569a60(int param_1)\n\n{\n  undefined1 local_9;\n  int local_8;\n  \n  local_8 = param_1;\n  FUN_0041955c(*(int **)(param_1 + 0x14),&local_9,1);\n  return local_9;\n}\n\n"}

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_00569de0"}

Tool result
{"result":"\nvoid FUN_00569de0(int param_1,int *param_2)\n\n{\n  undefined1 uVar1;\n  int iVar2;\n  undefined4 *in_FS_OFFSET;\n  undefined4 uStack_2c;\n  undefined1 *puStack_28;\n  undefined1 *puStack_24;\n  int local_1c;\n  int local_18;\n  longlong *local_14;\n  short local_e;\n  int *local_c;\n  int local_8;\n  \n  puStack_24 = &stack0xfffffffc;\n  local_14 = (longlong *)0x0;\n  puStack_28 = &LAB_00569e7d;\n  uStack_2c = *in_FS_OFFSET;\n  *in_FS_OFFSET = &uStack_2c;\n  local_c = param_2;\n  local_8 = param_1;\n  local_e = FUN_00569da0(param_1);\n  if (local_e < 1) {\n    FUN_00405064(local_c);\n  }\n  else {\n    FUN_00405784((int *)&local_14,(int)local_e);\n    local_1c = (int)local_e;\n    if (0 < local_1c) {\n      local_18 = 1;\n      do {\n        uVar1 = FUN_00569a60(local_8);\n        iVar2 = thunk_FUN_00405508((int *)&local_14);\n        *(undefined1 *)(iVar2 + -1 + local_18) = uVar1;\n        local_18 = local_18 + 1;\n        local_1c = local_1c + -1;\n      } while (local_1c != 0);\n    }\n    FUN_004050b8(local_c,local_14);\n  }\n  *in_FS_OFFSET = uStack_2c;\n  puStack_24 = &LAB_00569e84;\n  puStack_28 = (undefined1 *)0x569e7c;\n  FUN_00405064((int *)&local_14);\n  return;\n}\n\n"}

Let me check FUN_00569818 (EOF check) and FUN_00569a34 (bool reader) and FUN_00569da0 (length prefix reader).

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_00569818"}

Tool result
{"result":"\nbool FUN_00569818(int param_1)\n\n{\n  uint uVar1;\n  uint uVar2;\n  int extraout_EDX;\n  int extraout_EDX_00;\n  bool bVar3;\n  \n  uVar1 = (**(code **)**(undefined4 **)(param_1 + 0x14))();\n  uVar2 = FUN_00419330(*(int **)(param_1 + 0x14));\n  if (extraout_EDX_00 == extraout_EDX) {\n    bVar3 = uVar1 <= uVar2;\n  }\n  else {\n    bVar3 = extraout_EDX <= extraout_EDX_00;\n  }\n  return bVar3;\n}\n\n"}

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_00569a34"}

Tool result
{"result":"\nbool FUN_00569a34(int param_1)\n\n{\n  char cVar1;\n  \n  cVar1 = FUN_00569a60(param_1);\n  return cVar1 != '\\0';\n}\n\n"}

Call ghidra_decompile_function

Arguments
{"filepath": "/sandbox/FFG.exe", "name_or_address": "FUN_00569da0"}

Tool result
{"result":"\nundefined2 FUN_00569da0(int param_1)\n\n{\n  undefined1 uVar1;\n  undefined1 uVar2;\n  \n  uVar1 = FUN_00569a60(param_1);\n  uVar2 = FUN_00569a60(param_1);\n  return CONCAT11(uVar1,uVar2);\n}\n\n"}

Let me check where FUN_004e9e08 is called to verify it's actually for CMD=120.

Call ghidra_get_function_xrefs

Arguments
{"filepath": "/sandbox/FFG.exe","name": "FUN_004e9e08"}

Tool result
{"result":["From 004e8d2b in FUN_004e8acc [UNCONDITIONAL_CALL]","From 004e85cd in FUN_004e8580 [UNCONDITIONAL_CALL]"]}

Call ghidra_get_function_xrefs

Arguments
{"filepath": "/sandbox/FFG.exe", "name": "FUN_004e8580"}

Tool result
{"result":["From 004e665b in FUN_004e6464 [UNCONDITIONAL_CALL]","From 004e6b09 in FUN_004e6464 [UNCONDITIONAL_CALL]","From 004e6ba9 in FUN_004e6464 [UNCONDITIONAL_CALL]","From 004e6c4a in FUN_004e6464 [UNCONDITIONAL_CALL]"]}

Now I have a clear picture. Let me check the format string at 0x54bb40 and also verify the CMD=120 client→server text fields.

Call sandbox_execute

Arguments
Dr.Binary

Inference interrupted by user.