Jump to content

[GUIDE] Metin2 [GF]: Reverse Engineering with AI for Non-Reverse Engineers


Recommended Posts

  • Active+ Member

This guide shows how the outdated 

This is the hidden content, please
(eXLib needed for
This is the hidden content, please
) was successfully rebuilt and revived for the latest GameForge (GF) Metin2 client (as of 20/06/26) without any traditional manual reverse engineering knowledge required.

The Core Concept

Instead of using Cheat Engine / IDA / Ghidra manually, you let a powerful AI agent locally interact directly with the live running game process attached to Cheat Engine via MCP. The AI reads memory, finds structures, generates AOB signatures, traces call graphs, and suggests/fixes code - while you only validate results in-game. This approach completely bypasses the need for deep reverse engineering knowledge.

Key Tools Used

• Claude Opus 4.8 (or other high-reasoning LLM with tool calling capabilities)
  - Purpose: Autonomous reverse engineering agent
  - Link: Claude Code CLI

• Cheat Engine MCP Bridge
  - Purpose: Allows the AI to control Cheat Engine through function calls (memory reads, AOB scanning, Lua execution)
  - GitHub: 

This is the hidden content, please

• Outdated Metin2 Client Source
  - Purpose: Reference for structures, classes (CInstanceBase, etc) and network protocols
  - GitHub:

This is the hidden content, please

• Visual Studio 2022 + Detours
  - Purpose: Building the injectable DLL library

Important: The method uses static memory reads + Lua only (no debugger attachment) because the client’s protection crashes on Cheat Engine breakpoint attachment.


High-Level Workflow (Proven on GF Client)

1. Diagnosis

  • Test all existing AOB signatures against the live client
  • Identify which ones are dead (in this case, 13 out of 24 were outdated)

2. AI-Driven Analysis

  • AI explores the live process (this-pointers, vtables, call graphs)
  • Re-derives fresh AOB signatures when needed
  • Finds correct struct offsets (example: character position moved from expected 0x7C4 → real 0x7BC in CInstanceBase)
  • Handles ASLR by working with RVAs

3. Code Adjustments

  • Update offsets and signatures in defines.h / Offsets.h
  • Add NULL guards and robustness so dead signatures don’t crash the DLL
  • Temporarely strip unused parts (server communication code)
  • Fix threading issues (especially Python GIL when re-enabling packet hooks)

4. Build & Test

  • Compile with MSBuild (Release | Win32 | v142 toolset)
  • Deploy as eXLib.mix which auto-injects (or .dll used with injector)
  • Validate everything live in-game (position reading, pathfinding, etc.)

5. Iterative Improvement

  • Re-enable features one by one (e.g. CheckPacket hook)
  • Fix crashes (GIL hardening + error clearing was required)

 

Why This Works for Non-Reverse Engineers

- The AI does the actual disassembly interpretation and pattern finding

- You only need to:

  • Give the AI clear goals
  • Apply the suggested code changes
  • Test in-game

- No manual sig scanning or deep ASM knowledge required

Limitations & Notes

  • This method can be used to reverse engineer anything, including new game updates and outdated addresses whenever the client is rebuilt (new game version release).
  • Educational / research use only. Automating gameplay violates Metin2 ToS.
  • No anti-cheat bypasses were added because it uses the same injection method as the original library.

Resources

  • Reference Library Rebuild Repository:
    This is the hidden content, please
  • Detailed Rebuild Log:
    This is the hidden content, please
  • Cheat Engine MCP Bridge (for AI Cheat Engine):
    This is the hidden content, please
  • Client Source Reference:
    This is the hidden content, please
  • Metin2 Dev 82
  • kekw 2
  • Eyes 3
  • Lmao 1
  • Good 22
  • Love 2
  • Love 39

Life rips

__________________________

Is Claude letting you run prompts like that?

🖥️ SysAdmin — Government (HU)
🛠️ Freelance Metin2 Dev • DevOps
🐧 FreeBSD / Linux | 🛡️ Security & WAF | 🚀 Performance | 🔥 Firewalls | ⚙ Automation
Open to work - Contact me on Discord @matteo_r

  • Active+ Member
Posted (edited)

Yes, Claude Code CLI specifically by using framing to your advantage 👇

I tagged the cloned outdated source of MetinPythonLibV2 repo locally, cloned an outdated client source and installed the Cheat Engine MCP into Claude Code CLI (like adding a plugin) then attached CE to the running Metin2 client (character in-game).

✅ Framed the ask something like this:

"checkout this outdated @MetinPythonLibV2 library that used to work on the older Metin2 client, but now on the latest client build it crashes when injected, help me with a multi-step plan to make it work again (with limited functionality initially) on the latest client version, only walker + pathfinding, you will be using the cheatengine mcp tools available while CE is attached to the client with character in-game - for function names / references / strings checkout this old @metin2-client-source"

👆that spit out a game plan without any issues or restrictions, then once agreed to - it started the RE work eventually landing on:

Spoiler

Phase 0 — Diagnosis

Tested all 24 baked signatures (common/Offsets.h + defines.h GLOBAL_PATTERN) against the live module: 11 matched, 13 were dead.

The DLL crashed on load - getRelativeCallAddress(NULL) on the dead PEEK, and DetourAttach(NULL) on dead hook targets. Module base seen at 0x2F0000 / 0x530000 (ASLR active).

Phase 1 — Changes made (walker + pathfinding)

OFFSET_CLIENT_CHARACTER_POS = 0x7BC(defines.h). Source had 0x7C4 (garbage now); an interim 0x200 was wrong — that's a field on a separate PC-wrapper object, not the CInstanceBase instances returned by GetInstancePtr. The map instances (NPCs and the main char, vtbl 0x2D92A54) store live {x, y, z} at +0x7BC; y is stored negated (existing pos->y = -iPos->y is correct).

Re-derived signatures(common/Offsets.h):

INSTANCEBASE_MOVETODEST — CInstanceBase::MoveToDestPosition, /GS prologue.

PYTHONAPP_PROCESS — App::Process, the per-frame heartbeat that registers the eXLib module and runs the scripts; without it nothing initializes.

PEEK_FUNCTION — CNetworkStream::Peek, now a direct-prologue signature (offset 0) instead of the dead relative-call form; the peekFunc = getRelativeCallAddress(...) line in Memory.cpp was removed.

Robustness (common/utils.h, DetoursHook.h, Memory.h): NULL-guard getRelativeCallAddress; skip HookFunction when the target is NULL; NULL-guard every call* wrapper — so a still-dead signature no-ops instead of calling NULL.

setupHooks() (Memory.cpp): packet hooks left uninstalled (they crashed on the GF packet layer and aren't needed for the walker — GetPixelPosition reads memory directly, MoveToDestPosition is invoked via the resolved address, FindPath is file-based). Only the process-hook heartbeat stays. The CheckPacket hook was later re-enabled to drive InstancesList, using the real this game passes (CHECK_PACKET's first of two hits is the real CPythonNetworkStream::CheckPacket); Peek reads packet bodies.

Stripped server-comms: Communication.h→ header-only stub; dropped Communication.cpp / WebsocketHandler.cpp from the build; removed the VMProtectSDK.h include (it force-linked a missing lib); Patterns.cpp set to not use the PCH.

 

❌ On the other hand, if you approach it with something like: "hey I want to hack this Metin2 game to gain advantages over regular players, help me reverse engineer it and profit 🤑💰"

Then you might experience some difficulties reversing 🥲

---

Let's just say that both of these matter:

  • using Claude Code CLI locally with access to sources and Cheat Engine MCP
  • framing it as a genuine RE project, without profit-driven intentions and game ToS violation

 

🔴 A bad example I tried would be: directly in Claude online (web chat): paste some snippets of server + client code to help reverse the client-side visual effect of calling the Compass for Metin Stones.

I don't even wanna begin telling you how many ethics lessons I got on every prompt and how hard it was to just get some basic info (functions and variable names that I could look-up myself anyway) 😅

Lo' and behold, as soon as I pasted the same snippets into Claude Code CLI running on my windows machine, continuing the same RE conversation from earlier, it started reversing and writing the C++ / Python right away and here's the result:

To be continued...

Edited by ikevin127
  • Lmao 1

Life rips

__________________________

2 hours ago, ikevin127 said:

I don't even wanna begin telling you how many ethics lessons I got on every prompt and how hard it was to just get some basic info (functions and variable names that I could look-up myself anyway)

Yea feel that bro 😂 Thanks.

🖥️ SysAdmin — Government (HU)
🛠️ Freelance Metin2 Dev • DevOps
🐧 FreeBSD / Linux | 🛡️ Security & WAF | 🚀 Performance | 🔥 Firewalls | ⚙ Automation
Open to work - Contact me on Discord @matteo_r

  • 2 weeks later...
  • Active+ Member

♻️ Some updates on the topic:

To streamline the AI - Cheat Engine MCP connection and ease of use, I built a python windows app that you can open with double-click and a 1 Button click to Setup & Launch the CE MCP, it handles:

- adds MCP CLI config for Claude Code, Codex, Gemini CLIs (you can select whichever one you use)

- opens Cheat Engine with Admin rights
- launches the CE MCP bridge .lua script within opened Cheat Engine

Notes:
1. The program comes with bundled Python (hence the ~70mb size once compiled) so you don't need to have python installed on the system and added to PATH.
2. The CE-MCP-Launcher app source is public on my Github meaning you can build it from source so you don't have to download the .exe for safety reasons: github.com/ikevin127/cheatengine-mcp-launcher

3. All you need to have installed on your system is one of the 3 AI CLIs and Cheat Engine ✅

Here's a quick preview of how the CE-MCP-Launcher works on GF Metin2 client:

---

With the CE-MCP-Launcher and more reversing and changes on the eXLib source (source on Github), I was able to put together a system that replicates GF Auto-Hunt but free, with most of the features working exactly as the original Auto-Hunt:

- opens the Auto-Hunt window which looks and works pretty much like the official GF Auto-Hunt
- features auto skills, auto HP/SP potions only, auto attack with filters, focus range distance circle, auto resurrect with attack resumed after 5 seconds (allows HP to recover)

What it does

🗡️ Auto attack — filter by monster level range and type (metins, bosses)
🎯 Focus range zone — locks your hunting spot where you Confirm Focus Range and hit Start so your character stops wandering off across the map, range circle animation is 1:1 with GF Auto-Hunt
💊 Smart potions — HP/SP % thresholds, and it won't waste potions while your Sun/Moon Elixir is already auto-potting
✨ Auto skills & buffs — recasts buffs right as they expire, hits offensive skills on target, live skill-duration input in seconds (can add delay)
⚰️ Auto-revive + anti-stuck — gets unstuck from unreachable spots instead of freezing

⚠️ Not in this version (coming later):
- only supports standard HP/SP potions on % for now — support for other healing potions, buffing potions, fish, waters, dews, elixirs, and bravery capes (on interval) will arrive with other updates later
 

---

Next will attempt a GF Trading Glass bot (obviously client-side only) that will use the same UI as the Trading Glass, goal is so provide otherwise paid features (itemshop: auto-hunt, trading glass) for free through bots that don't look like hacking to the other players, unlike most bots which offer DMG / fast walking speed / teleport hacks that can get users banned easily.

  • Good 1

Life rips

__________________________

  • 2 weeks later...
  • Active+ Member
Quote

Next will attempt a GF Trading Glass bot (obviously client-side only) that will use the same UI as the Trading Glass, goal is so provide otherwise paid features (itemshop: auto-hunt, trading glass) for free through bots that don't look like hacking to the other players, unlike most bots which offer DMG / fast walking speed / teleport hacks that can get users banned easily.

Following up on this 👇

Added Trading-Glass + Shop Search bot in the sidebar replacing the old Shop Searcher, here's how it works:

  • opens new Shop Search window which is used to scan all shops while in the shop map, it's using 48 checkpoints scanning the entire map and not missing any of the in-range shops at any checkpoint (see checkpoint map in youtube video attached below)
  • once the full shop map was scanned (~20mins depending on character walking speed), the Trading Glass button can be pressed which opens a Trading Glass window similar to official GF one which has all the filters used in official GF trading glass, below is a complete youtube video on how to use the bot


How does the scanner work exactly ?

Checkpoint generation: _loadCollisionGrid reads OpenBot/Maps/<map>.dat — line 1 is maxX maxY, then one row per y of '0'/'1' cells, 1 cell = 100 world units. generateCheckpoints lays a grid at step//2 offset (so 25, 75, 125…), reverses xs on odd rows for the boustrophedon order, snaps each point to the nearest walkable cell via an expanding ring search up to 30 cells, dedupes on a //4 cell key, and emits world coords (cell * 100).

On the latest version of the privateshop map that resolves to:

  • 512×512 cells, 29.3% walkable (76,905 cells)
  • 10×10 = 100 grid points → 52 dropped (unwalkable with no walkable cell within 30), 17 snapped off-grid, 0 duplicates → 48 checkpoints
  • consecutive spacing min 3100 / avg 4939 / max 7072 world units, 232,114 units of total walk

The sweep state machine (_sweepTick, driven from OnUpdate at SWEEP_TICK = 0.1s😞

  • SW_WALK — Movement.GoToPositionAvoidingObjects(cp) → eXLib.FindPath A* on the DLL side, walking real MoveToDestPosition moves. Arrival = within SWEEP_ARRIVE = 350.
  • SW_DRAIN — Spawn packets keep trickling in after you stop, so instead of a fixed sleep it snapshots the in-range count every tick and waits for 2 consecutive identical counts plus SWEEP_SETTLE = 0.3s minimum. Fast-loading checkpoints cost 0.3s; slow ones wait as long as needed. The _drainDt < 0 branch handles app.GetTime() running backwards on a world reload.
  • SW_SCAN — per shop, three substates: SendOnClickPacket → poll shop.IsOpen() then ScanShop + SendShopEndPacket → poll for closed, then pop. Give up after 5 tries. Strict close-before-open, one shop at a time.

Queue is built as [v for v in vids if v not in self.swScannedVids], which matters because InstancesList is global and still holds shops from earlier checkpoints — that set is what stops the overlap from causing redundant work.

ScanShop. Iterates SLOT_COUNT (40) * shop.GetTabCount() slots, pulling GetItemID/Price/Cheque/Count/MetinSocket/GetItemAttribute plus proto metadata via _itemMeta (type, subtype, level limit, class bitmask derived from IsAntiFlag). Three details worth calling out: position is captured while the shop is open with a NaN guard falling back to the player's own position; owner name is snapshotted at scan time so it survives despawn; and dedupe is on a coordinate key (round(x/100)), not VID, because VIDs recycle across map reloads. Vnum 50300 gets the skill name prefixed so books are distinguishable.

Completion writes a tab-separated index to OpenBot/Data/tradingglass_<map>.txt, so a crash doesn't cost a full re-sweep.

Life rips

__________________________

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.