What a Memory Scan Really Finds
Find, test, and change one gold value in Wesnoth, and see what each scan does and does not prove.
Cheatsheet for Lesson 1.9
A one-page summary of “What a Memory Scan Really Finds” you can keep beside your notes. Plain Markdown.
Lesson 1.9 — What a Memory Scan Really Finds: cheatsheet
- Remember: Each Next Scan only re-checks the old candidates and keeps the ones that now match, so the list shrinks every time.
- Also useful: Think of a guessing game with yes or no questions: each new gold value removes addresses that could not be the answer.
Reading map
- Prepare the target
- Perform the first value scan
- Change the game once
- Test one candidate reversibly
- Why several copies may all be related
- What the scan established
Formulas and patterns
new_candidates = old_candidates ∩ addresses_currently_equal_to_85
Review
- Q: A first scan finds many addresses containing 100. You recruit a unit and the visible gold changes to 85. Which addresses should the next scan inspect? A: Only the first scan's candidates, keeping those now holding 85
- Q: What does attaching a memory scanner to a running process accomplish? A: It selects which process's memory the scanner reads
An address names a location, while a type tells a program what its bytes mean. We will use a memory scanner on Wesnoth: observe a gold value, search for matching bytes, make one in-game change, and filter the results.
The goal is not merely to reach a final address. The goal is to understand why each scan removes some candidates and why one test still does not prove that a candidate is the main game-play value.
Prepare the target
Section titled “Prepare the target”Use the course build of Wesnoth 1.14.9 in the Windows VM. Start a local match and pause before recruiting a unit.

Suppose the screen shows 100 gold and the unit you plan to recruit costs 15. After recruiting, the visible value should become 100 − 15 = 85.
Attach Cheat Engine to the game process
Section titled “Attach Cheat Engine to the game process”Open Cheat Engine, choose the process button, and select the running Wesnoth process.

Attaching tells Cheat Engine which process address space to read. It does not yet tell the scanner where gold is or how it is stored.
Perform the first value scan
Section titled “Perform the first value scan”Enter the visible gold amount. Use:
- Value Type: 4 Bytes;
- Scan Type: Exact Value;
- Value: the current gold amount.
Start the first scan.

The scan will probably find many addresses. That is expected. The number 100 can appear in timers, object fields, capacities, interface data, and unrelated allocations.
At this point, each result proves only this:
These four bytes were readable as the integer 100 when the scanner checked them.
It does not prove that the address controls gold.
Change the game once
Section titled “Change the game once”Return to Wesnoth and perform the planned action. Recruit the unit and read the new gold value off the screen.

If the value changed from 100 to 85, return to Cheat Engine, enter 85, and choose Next Scan.
The scanner does not search the whole process from the beginning. It checks the previous candidate addresses and keeps only those that now contain 85. In set notation:
new_candidates = old_candidates ∩ addresses_currently_equal_to_85You do not need the symbol memorized. It means “keep items that are in both groups.”
What Next Scan does with each candidate. This step-by-step trace needs JavaScript. Here is the code and where the run ends.
candidates = [A, B, C] # every address that held 100
# you recruit a unit; the screen now shows new_gold
kept = []
for addr in candidates:
now = read_4_bytes(addr)
if now == new_gold:
kept.append(addr) # keep it
# otherwise it is dropped
candidates = keptNext Scan leaves B and C. Both followed the gold, so one may be the field and the other a copy for the screen. Repeat with a different change to tell them apart.
Final values: candidates = B, C; new_gold = 85; kept = B, C; addr = C; now = 85.
Read every step of the lesson’s example
Step 1, line 1. The first scan for 100 left three candidates. Each one only proved that its four bytes read as 100 at that moment.
candidates = A, B, C.
Memory: address A = 100; address B = 100; address C = 100.
Step 2, line 2. The screen now shows 85. B and C changed with it, but A, which only happened to be 100, did not.
candidates = A, B, C; new_gold = 85.
Memory: address A = 100; address B = 85; address C = 85.
Step 3, line 3. Start an empty list for the addresses that survive.
candidates = A, B, C; new_gold = 85; kept = (empty).
Memory: address A = 100; address B = 85; address C = 85.
Step 4, line 4. Take the next candidate: A.
candidates = A, B, C; new_gold = 85; kept = (empty); addr = A.
Memory: address A = 100 (reading now); address B = 85; address C = 85.
Step 5, line 5. Read the four bytes at A right now. They read as 100.
candidates = A, B, C; new_gold = 85; kept = (empty); addr = A; now = 100.
Memory: address A = 100 (reading now); address B = 85; address C = 85.
Step 6, line 8. 100 does not equal 85, so A is dropped. Its value did not follow the gold.
candidates = A, B, C; new_gold = 85; kept = (empty); addr = A; now = 100.
Memory: address A = 100 (reading now); address B = 85; address C = 85.
Step 7, line 4. Take the next candidate: B.
candidates = A, B, C; new_gold = 85; kept = (empty); addr = B; now = 100.
Memory: address A = 100; address B = 85 (reading now); address C = 85.
Step 8, line 5. Read the four bytes at B right now. They read as 85.
candidates = A, B, C; new_gold = 85; kept = (empty); addr = B; now = 85.
Memory: address A = 100; address B = 85 (reading now); address C = 85.
Step 9, line 7. 85 equals 85, so B stays in the list.
candidates = A, B, C; new_gold = 85; kept = B; addr = B; now = 85.
Memory: address A = 100; address B = 85 (reading now); address C = 85.
Step 10, line 4. Take the next candidate: C.
candidates = A, B, C; new_gold = 85; kept = B; addr = C; now = 85.
Memory: address A = 100; address B = 85; address C = 85 (reading now).
Step 11, line 5. Read the four bytes at C right now. They read as 85.
candidates = A, B, C; new_gold = 85; kept = B; addr = C; now = 85.
Memory: address A = 100; address B = 85; address C = 85 (reading now).
Step 12, line 7. 85 equals 85, so C stays in the list.
candidates = A, B, C; new_gold = 85; kept = B, C; addr = C; now = 85.
Memory: address A = 100; address B = 85; address C = 85 (reading now).
Step 13, line 9. Next Scan leaves B and C. Both followed the gold, so one may be the field and the other a copy for the screen. Repeat with a different change to tell them apart.
candidates = B, C; new_gold = 85; kept = B, C; addr = C; now = 85.
Memory: address A = 100; address B = 85; address C = 85.
Repeat with a different change
Section titled “Repeat with a different change”Make another controlled change with a different result. For example, recruit a unit with another cost or end a turn if the scenario changes gold in a known way. Enter the new gold value and perform another Next Scan.

Using different values is important. If you repeat only 100 → 85 → 100, an unrelated value that happens to follow the same pattern can remain in the list.
Continue until you have a small number of candidates. Do not assume the first remaining address is correct.
Test one candidate reversibly
Section titled “Test one candidate reversibly”Add one candidate to the address list. Before changing it:
- copy its current value so you can put it back;
- confirm the game still shows the expected gold;
- choose a small replacement value;
- write the replacement once;
- observe the screen and one real purchase;
- restore the original value.

Different results support different explanations:
| What happens | Likely meaning |
|---|---|
| the amount changes and the next purchase uses that amount | strong candidate for game-play state |
| only the text changes | likely a display copy |
| the value changes back on the next update | another system recomputes or owns it |
| nothing visible changes | unrelated value or a copy used elsewhere |
| nearby behavior breaks | wrong address, type, or field width may have been changed |
A single run can mislead, because an unrelated value might change at the same moment by coincidence. Getting the same result again from the same starting state makes that explanation less likely.
Why several copies may all be related
Section titled “Why several copies may all be related”The game can legitimately keep more than one gold-related value:
- the current simulation value;
- a previous value used by an animation;
- text prepared for the interface;
- a value in a replay, event, or network message;
- a temporary calculation.
That is why value scanning is usually the start of reverse engineering. A write breakpoint later shows which instruction changes the strongest candidate. The surrounding instructions can reveal the object base and other fields.
Treat the address as temporary
Section titled “Treat the address as temporary”The address you found belongs to this run of the game. After a restart, gold may live somewhere else, because the process layout and the heap can change between runs. A later lesson on building and loading a program explains why some distances stay fixed within one build even when absolute addresses move. First, a debugger lets us follow the candidate value to the instruction that changes it.
What the scan established
Section titled “What the scan established”The first scan returned readable candidates that matched while it ran; it did not identify “the gold address.” Each controlled game change filtered that candidate set. Changing one survivor and then making a real purchase showed whether it affected gameplay, only the display, or neither. Restoring the original value leaves the game in a known state for another run.
The candidate address tells us where to look, but not why the value changes. When a purchase subtracts gold, which instruction performs the subtraction, and what decides whether the player can afford it? What a Debugger Can Reveal begins Chapter 2 with that question. We will pause the program at the change, then learn how source code becomes the instructions the debugger shows.
Use a controlled change
A first scan finds many addresses containing 100. You recruit a unit and the visible gold changes to 85. Which addresses should the next scan inspect?
A value scan is an iterative filtering algorithm. Each controlled change narrows the existing candidate set instead of starting over from the whole process.
Finished Lesson 1.9?
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.
Plain Markdown, saved in this browser.
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.