Skip to content
Lesson 2.5Following Instructions and Addresses

From a Game Value to the Code That Changes It

Follow a known gold address backward to the exact instruction that changes it.

Lesson 2.5
Read or listenPrint chapter or book
About 20 minutes

Keyboard shortcuts

?
Open this guide
Alt + B
Show or hide the lesson list
Alt + O
Show or fold the lesson outline
Alt + N
Open or close notes
Alt + H
Toggle semantic colours
Alt + D
Toggle page brightness
Alt + C
Toggle code brightness
← →
Move through a focused code trace
Home End
First or final step in a focused trace
Escape
Close this guide or an open panel

Reader shortcuts pause while you type in a text field.

Cheatsheet for Lesson 2.5Key ideas, reference and questions

A one-page summary of “From a Game Value to the Code That Changes It” you can keep beside your notes. Plain Markdown.

Lesson 2.5 — From a Game Value to the Code That Changes It: cheatsheet

  • Remember: Watching a data address finds every writer of a value. A code breakpoint tells you when one particular instruction runs.
  • Also useful: A register name is a width clue. Treat an 8-bit, 16-bit, and 32-bit write as different state changes even when they belong to one register family.

Key terms

  • al: eax, ax, ah, and al are views of the same register family, not four independent containers.
  • eax: In the course's 32-bit target, eax is the full-width view.
  • esi: For example, if esi holds 0x0A3C1200, the destination is 0x0A3C1200 + 0x30 = 0x0A3C1230.

Formulas and patterns

  • address = register value + offset; old = 32-bit value read from address; new = old - low 32 bits of eax; store new at address; update arithmetic flags

Review

  • Q: Why use a hardware write breakpoint on the gold address? A: It can reveal any instruction that writes the watched bytes
  • Q: Your match shows 100 gold and the recruited unit costs 15. What should you expect at the paused subtraction? A: The destination is the gold address and the price register holds 15
Download cheatsheet (.md)

In the previous memory lab, we found the current gold. Now we want to know:

Which instruction subtracts the price of a recruited unit?

Use the same offline Wesnoth 1.14.9 target and restore your clean VM snapshot before starting. For a concrete run, suppose you start at 100 gold and recruit a unit costing 15. The expected result is 85. Use the actual price and gold shown in your match when checking the paused instruction.

Launch Wesnoth, begin a local match, and find the gold address again. Then attach x64dbg to the running process.

The Attach command in x64dbg

x64dbg's Attach command hooks the debugger to the running game.

Selecting the Wesnoth process

Choose the Wesnoth process from the list.

The CPU view contains four useful areas:

  • disassembly—the instructions near the current position;
  • registers—the CPU’s current scratch values;
  • dump—raw memory;
  • stack—return addresses and temporary data.

The main x64dbg view

The CPU view: disassembly, registers, dump, and stack.

Attaching may pause in Windows system code. That is normal. Resume the process before triggering your experiment.

Open the dump view’s “go to expression” command and enter the address found by the memory scanner.

Going to an address in the dump

Go to expression in the dump, with the address the scanner found.

The player gold address in memory

The dump at the gold address, showing the value's bytes.

The bytes in the dump are little-endian. If the gold is 100, the 32-bit value 0x00000064 appears as:

64 00 00 00

The least-significant byte comes first.

Set a hardware breakpoint on write, covering four bytes at the gold address. The lesson uses x64dbg, but any debugger that can watch an address will do:

x64dbg

Select the four bytes in the dump, right-click, and choose Breakpoint, then Hardware, Write, then Dword.

WinDbg

Type ba w4 followed by the address, for example ba w4 0A3C1230, to break on a four-byte write. Then type g to let the game run.

Cheat Engine

Right-click the gold entry in the address list and choose Find out what writes to this address. Cheat Engine lists each instruction that writes it, with a count.

A hardware memory breakpoint does not replace the game’s instruction bytes. The debugger programs special CPU debug registers with an address, access type, and width. When an instruction writes across that watched range, the CPU raises a debug exception and Windows reports it to the debugger.

The width matters. Gold is believed to be a four-byte value, so watch all four bytes. Watching one byte can still trigger, but it hides whether the game wrote the complete integer or only part of it.

This breakpoint watches a data address, not one fixed instruction. If three different functions write gold, the same watch can reveal all three. A software breakpoint placed on a code address answers the opposite question: “When does this exact instruction execute?”

Setting a write breakpoint on gold

Select the four bytes, right-click, then Breakpoint, Hardware, Write, Dword.

Resume the game and recruit one unit. The debugger should pause close to an instruction that resembles:

sub dword ptr [reg+offset], eax

Do not copy the exact register or offset from this page. Read the instruction in your own debugger. A hardware data breakpoint can report an access after the instruction has run, so the highlighted next instruction may not be the one that wrote gold. Use the breakpoint’s access information and nearby disassembly to identify the triggering write, then confirm that its calculated destination is your gold address. Builds and runs can differ.

The instruction that changes player gold

The debugger paused at the instruction that changes gold.

Apply the five questions to the paused instruction:

  1. What is read? The current gold and the price in a register.
  2. What is written? Four bytes at the gold field.
  3. How many bytes? dword ptr means 32 bits.
  4. Signed or unsigned? Test nearby comparisons before deciding.
  5. Where next? The following instruction unless a branch changes the path.

Now compare the price register with the unit’s price. In the example run, it should be 15 and the destination should be the gold address that changed from 100 to 85. Matching both is stronger evidence than recognizing sub alone.

For sub dword ptr [reg+offset], eax, the complete before-and-after effect is:

address = register value + offset
old = 32-bit value read from address
new = old - low 32 bits of eax
store new at address
update arithmetic flags

That last line matters. Later branches may inspect zero, sign, carry, or overflow flags. Replacing the subtraction changes both the stored gold and those flags. Before a temporary patch, step forward and check whether nearby conditional jumps consume them.

The effective address calculation does not dereference reg and then add an offset to the loaded value. It adds the offset to the register first, then reads memory at the resulting address. Keep “calculate an address” separate from “read the value at that address.”

Register names can select overlapping bits

Section titled “Register names can select overlapping bits”

eax, ax, ah, and al are views of the same register family, not four independent containers. eax selects 32 bits, ax its low 16, ah bits 15–8, and al bits 7–0. In the course’s 32-bit target, eax is the full-width view. The diagram also shows the wider rax available in 64-bit mode.

One register, five namesRAX, EAX, AX, AH and AL are not five registers. They are five names for parts of one 64-bit register, drawn here as eight bytes.

Byte number, 7 on the left (most significant) to 0 on the right (least significant)

RAX
EAX
AX
AH
AL

Before: RAX = 0x1122334455667788

  1. 11
  2. 22
  3. 33
  4. 44
  5. 55
  6. 66
  7. 77
  8. 88

After mov eax, 0xAABBCCDD: RAX = 0x00000000AABBCCDD

  1. 00zero
  2. 00zero
  3. 00zero
  4. 00zero
  5. AAset
  6. BBset
  7. CCset
  8. DDset
  • set written by the instruction
  • zero cleared by the 32-bit rule
  • same left alone

mov eax, 0xAABBCCDD changes RAX from 0x1122334455667788 to 0x00000000AABBCCDD. Bytes 3 to 0 were written. Bytes 7 to 4 were cleared by the zero-extension rule: 11 22 33 44 became 00 00 00 00.

RAX (bits 63 to 0, 8 bytes)
Replaces all eight bytes.
EAX (bits 31 to 0, 4 bytes)
Replaces bytes 3 to 0 and clears bytes 7 to 4 to zero. This is a real x86-64 rule: a 32-bit write always zero-extends into the full register.
AX (bits 15 to 0, 2 bytes)
Replaces bytes 1 and 0. Bytes 7 to 2 keep their old values.
AH (bits 15 to 8, 1 byte)
Replaces byte 1 only. Every other byte keeps its old value.
AL (bits 7 to 0, 1 byte)
Replaces byte 0 only. Every other byte keeps its old value.

The same starting value, five different writes

Start with RAX = 0x1122334455667788, whose bytes from byte 7 down to byte 0 are 11 22 33 44 55 66 77 88. Each row below starts again from that value.

InstructionRAX afterwardsWhat happened to the bytes
mov al, 0xEE0x11223344556677EEByte 0 was written. Bytes 7 to 1 were not touched.
mov ah, 0xEE0x112233445566EE88Byte 1 was written. Bytes 7 to 2 and byte 0 were not touched.
mov ax, 0xEEFF0x112233445566EEFFBytes 1 to 0 were written. Bytes 7 to 2 were not touched.
mov eax, 0xAABBCCDD0x00000000AABBCCDDBytes 3 to 0 were written. Bytes 7 to 4 were cleared by the zero-extension rule: 11 22 33 44 became 00 00 00 00.
mov rax, 0x8899AABBCCDDEEFF0x8899AABBCCDDEEFFBytes 7 to 0 were written.

The AH and AL names exist because the 8086 had 8-bit halves; the 32-bit and 64-bit names were added later as the register grew. The zero-extension rule for EAX applies in 64-bit mode. In 32-bit mode (this course's target programs) EAX is the whole register and there is no RAX. Microsoft documents the x64 rules in its x64 architecture reference.

In 64-bit mode, a write to eax also clears rax bits 63–32. Writes to ax, ah, or al preserve bits outside the selected part. Microsoft’s x64 register reference documents this distinction. For the gold instruction, the operand width still tells us that exactly four memory bytes are changed.

Read the brackets as an address calculation

Section titled “Read the brackets as an address calculation”

For an instruction such as:

sub dword ptr [esi+30h], eax

read it from the inside outward:

  1. take the address currently stored in esi;
  2. add hexadecimal offset 0x30;
  3. treat the four bytes at that final address as the destination;
  4. subtract the lower 32 bits of eax from that destination;
  5. store the result back to the same four bytes;
  6. update CPU flags for later branches.

The bracketed expression accesses memory. Without brackets, esi+30h would be an address calculation rather than a read or write of the bytes at that address.

Read the live value of esi in the register panel and add 0x30 yourself. For example, if esi holds 0x0A3C1200, the destination is 0x0A3C1200 + 0x30 = 0x0A3C1230. If the sum equals the candidate gold address, this instruction writes the gold you found.

One instruction, step by step: sub dword ptr [esi+30h], eax. This step-by-step trace needs JavaScript. Here is the code and where the run ends.

; sub dword ptr [esi+30h], eax
address = esi + 0x30
old     = read_u32(address)
new     = old - eax  ; low 32 bits
write_u32(address, new)
flags   = ZF, SF, CF, OF from this result

The flags are set from the result: ZF (zero) 0, SF (top bit) 0, CF (borrow) 0, OF (signed overflow) 0. Later conditional jumps read these flags, not the stored gold, so a patch that removes this instruction removes them too.

Final values: esi = 0x0A3C1200; eax = 15; address = 0x0A3C1230; old = 100; new = 85; flags = ZF=0 SF=0 CF=0 OF=0.

Read every step of the lesson’s example
  1. Step 1, line 1. Before it runs: esi holds 0x0A3C1200 and eax holds the price, 15. The four bytes at 0x0A3C1230 hold the gold, 100, stored lowest byte first as 64 00 00 00.

    esi = 0x0A3C1200; eax = 15.

    Memory: …1230 = 64; …1231 = 00; …1232 = 00; …1233 = 00.

  2. Step 2, line 2. Brackets mean an address calculation first: 0x0A3C1200 + 0x30 = 0x0A3C1230. Nothing is read yet.

    esi = 0x0A3C1200; eax = 15; address = 0x0A3C1230.

    Memory: …1230 = 64; …1231 = 00; …1232 = 00; …1233 = 00.

  3. Step 3, line 3. Now read the four bytes at 0x0A3C1230 as one number: 0x64 = 100.

    esi = 0x0A3C1200; eax = 15; address = 0x0A3C1230; old = 100.

    Memory: …1230 = 64; …1231 = 00; …1232 = 00; …1233 = 00.

  4. Step 4, line 4. Subtract the price: 100 - 15 = 85. The result is held in the CPU and has not touched memory yet.

    esi = 0x0A3C1200; eax = 15; address = 0x0A3C1230; old = 100; new = 85.

    Memory: …1230 = 64; …1231 = 00; …1232 = 00; …1233 = 00.

  5. Step 5, line 5. Store the result back to the same four bytes. They now read 55 00 00 00.

    esi = 0x0A3C1200; eax = 15; address = 0x0A3C1230; old = 100; new = 85.

    Memory: …1230 = 55; …1231 = 00; …1232 = 00; …1233 = 00.

  6. Step 6, line 6. The flags are set from the result: ZF (zero) 0, SF (top bit) 0, CF (borrow) 0, OF (signed overflow) 0. Later conditional jumps read these flags, not the stored gold, so a patch that removes this instruction removes them too.

    esi = 0x0A3C1200; eax = 15; address = 0x0A3C1230; old = 100; new = 85; flags = ZF=0 SF=0 CF=0 OF=0.

    Memory: …1230 = 55; …1231 = 00; …1232 = 00; …1233 = 00.

Copy the original instruction bytes first, so you can write them back. Then temporarily replace the entire subtraction instruction with the same number of nop bytes.

Filling the instruction with NOP bytes

Fill the whole instruction with nop bytes.

Resume and recruit another unit. If gold no longer decreases, this instruction is the one that subtracts the price. Restore the original bytes immediately afterward.

The patched instruction

The instruction after patching: only nop bytes remain.

Turn one discovery into a repeatable patch

Section titled “Turn one discovery into a repeatable patch”

Our tools will not hardcode “whatever address worked once.” They will:

  1. open the controlled process;
  2. locate a module or scan a known pattern;
  3. confirm the expected original bytes;
  4. apply a temporary patch;
  5. restore the bytes on exit.

Checking the original bytes is crucial. Refusing to patch an unknown version is safer than writing to the wrong place.

Remove the breakpoint through x64dbg’s Breakpoints tab and confirm the original instruction is restored.

The Breakpoints tab

The Breakpoints tab lists every breakpoint and removes it.

The scan gave us a candidate value; the write breakpoint gave us a specific instruction and the register values from one recruitment. The reversible patch checked its effect, but the instruction may also run for other gold-changing actions. Lesson 2.6 follows the call path to identify which event, caller, and affordability check selected this gold write.

Knowledge check

Watch the data, not one function

Why use a hardware write breakpoint on the gold address?

Finished Lesson 2.5?

Mark it done and the lesson list shows a beside it. A chapter whose lessons are all done is marked done too. Progress is saved in this browser only.

Chapter 2: 10 lessons

This book grew out of the original Game Hacking Academy by attilathedud and has been rewritten as a beginner-first course. Like the original repository, its source is published under the Apache License 2.0.