Skip to lesson
Game Hacking Academy
Preparing lesson text…
Exit reader mode
Voice and speed

Preparing read-aloud controls…

Lesson 2.10 Listening edition

What a Working Detour Must Preserve

Build a temporary debugger-only detour, prove every hop, and restore the target.

About 17 minutes

This lesson follows the Terrain Description menu in offline, 32-bit Wesnoth 1.14.9. A six-byte instruction span in that path will become a temporary detour. Use x64dbg to trace every hop before automating its lifecycle in Lesson 8.3.

Section: Detour vocabulary before touching bytes.

A hook site is the address where normal execution is redirected. A detour is that redirection. A code cave is executable storage holding the added instructions. A return address is the first untouched instruction where normal execution resumes.

Some tools use the word trampoline for a small block that replays displaced instructions and jumps back. Names vary, but every working detour must answer the same questions:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

The C P U, central processing unit, has no concept of “our patch.” It only follows the instruction pointer. A single wrong length or destination sends that pointer into unrelated bytes.

Section: Choose a harmless trigger.

Right-click a tile and open Terrain Description to trigger this path. It gives us an easy local-menu event without changing competitive or networked behavior.

The terrain-description function

Pause the game and choose a hook site with enough complete instructions for a jump. Building the detour takes five facts about that site. For the exact course build they are:

Code example. The surrounding prose explains this example; the full lesson contains the exact code.

The byte count comes from instruction decoding, not subtraction by guesswork. 8B 01 is the two-byte mov e a x,[e c x], and 8D 74 26 00 is a four-byte lea that changes nothing and exists only as alignment padding, so the two instructions cover 2 + 4 equals 6 bytes. The return address is the first byte after them: this value + 6 equals this value, because hexadecimal 8 A is 8 times 16 + 10 equals 138, and 138 + 6 equals 144 equals 9 times 16 equals hexadecimal 9 0.

Do not continue until the return address points to the first untouched instruction.

x86 instructions have different lengths. A five-byte jump cannot safely replace the first five bytes of a six-byte instruction. The overwrite must end exactly on an instruction boundary, even when that means replacing six, eight, or more bytes and filling unused space with nop.

Section: Find a suitable cave.

For this historical debugger exercise, locate executable padding inside the controlled module.

An empty-looking area near the end of the module

“Looks empty” is enough for this one debugger experiment, not for a repeatable hook installer. A detour installed whenever the game starts should allocate its own cave, request the needed page protection, verify the hook bytes, and release or restore everything during shutdown. Here we use existing padding so you can see the control-flow idea before building that machinery in chapter 6.

Section: Build the smallest detour.

Start with no extra behavior:

Code example. The code’s comments explain: replay the complete instructions removed from the hook

At the hook site, write a jump to the cave and fill any remaining whole bytes with nop.

A jump from the hook into the cave

Set breakpoints at:

the hook;

the first cave instruction;

the return address.

Trigger the menu once. You should see the breakpoints in that order. This proves the path before new logic complicates it.

Alternative: Think of test-driving a new road with an empty truck first. Only when the trip works do you load the cargo, meaning the new logic.

Section: Preserve the interrupted calculation.

The hook interrupts a function in the middle of its work. Registers, flags, and stack entries may already carry values needed by later instructions.

The cave must normally:

save any register or flag it will change but the original code expects;

run the added behavior;

restore that machine state;

replay the complete displaced instructions exactly once;

jump to the first untouched instruction.

Replaying an instruction twice is just as wrong as skipping it. Changing the stack pointer without undoing the change can make a later ret jump to garbage. These delayed failures are why a hook may appear to work once and crash later.

In brief: The cave must leave the interrupted code as it found it: save state, run your logic, restore state, replay the removed instructions once, then jump back.

Predict first

The game reaches the hook with e c x equals this value, the object that the displaced mov e a x,[e c x] reads. The cave's extra logic sets e c x to 1 for its own work.

The cave forgets to restore e c x, then replays mov e a x,[e c x]. What happens?

Answer: It reads from address shown here and faults. mov e a x,[e c x] uses the current e c x, which is 1. Nothing is mapped at address 1, so the read faults. Saving e c x before the extra logic and restoring it afterwards would have put this value back.

The cave breakpoint firing

Section: Add one observable change.

Only after the round trip works, add a tiny change such as writing a known value to the already-identified gold field.

A cave containing the test change

Trigger once, observe once, and stop. If the wrong action triggers it, your hook is too broad or your model is wrong.

Section: Diagnose by symptom.

Detour symptoms

Lesson table

Change one variable per retry.

Section: Restore the target.

Before closing the debugger:

pause the game;

restore the hook’s original bytes;

remove breakpoints;

verify the original behavior;

restore the V M, virtual machine, snapshot if anything is uncertain.

The lasting result is your map of the detour, not the temporary patch.

After this debugger-only round trip, Lesson 8.3 implements the same map in a D L L, dynamic link library. It verifies the six bytes, replaces them with E9 rel32 90, runs a naked x86 cave, sets Wesnoth gold to 888, replays the removed behavior, jumps to this value, and restores the bytes when disabled. The complete source is also in game_hooks.rs.

Chapter 3 uses the verified addresses and types from this chapter to build an external memory tool. The D L L hook remains a later application of this same control-flow model.