Home Reverse engineering Windows 7 Minesweeper
Post
Cancel

Reverse engineering Windows 7 Minesweeper

Introduction

This blog post is about how to approach reverse engineering using the Windows 7 version of Minesweeper as an example. You can get the Windows 7 Minesweeper from https://win7games.com/.

I have created a trainer and a CheatEngine cheat table as well. You can find it here.

This post is written for beginners, however, I recommend having the following already:

  • Basic understanding of Pointers
  • Basic understanding of the C/C++ language
  • Good understanding of Cheat Engine
  • A little bit of ASM knowledge
  • Native Decompiler (IDA, Ghidra, …)
  • Patience

Finding a starting point

Whenever you want to reverse engineer something, you need a starting point. This could be anything from an interesting instruction to a global variable. CheatEngine is a tool that is very helpful to find such variables. For example, in a First-person-shooter game, I would start scanning for values like the health or bullet count, however, in Minesweeper I decided to scan for the timer value.
The timer value is on the bottom left

As you can see the Timer value is 6 in this image. So I started to scan for a 4-byte value.
I did not get a single result. Then I tried a different datatype: float.
The right address popped up in the first scan. When I changed it, the timer in the game changed as well, so I know it was the right one. Now we have found the value of the timer.

Tinkering around with the Timer

Of course, we can now set the timer value to anything we want. But what else can we do? By right-clicking the address in Cheat Engine and then clicking Find out what writes to this address we can determine the instruction, that is writing to the address. We can select the instruction and show it in the disassembler. This takes us directly to the part in the code responsible for updating the timer.

We can see that the instruction adding to the timer value is addss xmm0,[7FF7812E4454] , which means if we patch that to subss xmm0,[7FF7812E4454] (add stands for add, sub stands for subtract), then we will see the timer running backward.

Finding more values

In the instruction from the previous headline we could see that the address of the timer value is at rax + 0x20. We can assume that rax is a pointer to some kind of structure containing other useful variables. To check that we right-click the address and hit Browse this memory region in CheatEngine. Now the bottom part of the memory viewer will show the neighboring addresses. Click inside that window and hit Ctrl + 6 to change the datatype to 4 bytes. Scroll up a bit to be able to see the values that come right before the timer.

The value highlighted in red is the timer value. It’s being displayed wrongly because we set the datatype to 4 bytes instead of float. However, it is surrounded by other values. Now you need to look at which addresses change when you do something. I’ve already done that. The first address, which is at offset 0x8 from the beginning of the structure is the number of bombs. It is followed by FieldSizeY, FieldSizeX. The next 0 is the number of flags, the 6 is the number of revealed fields, and the 1 is how many times you have clicked. The 1 right next to the timer is the difficulty level. To find a Pointer for that struct, you can run a pointer scan or manually reverse it. I manually reversed it: Minesweeper.exe+ 0xAAA38 ] + 0x18 ].
If you dereference this pointer and add 0x20 to it, you will get the address of the timer (think of the rax + 0x20 from earlier).

Finding the bomb array

I figured out that a good approach to finding the bomb array is to find the function that is called whenever I click a field. Do you remember the value that counts how many times you click?
This pointer points to it: Minesweeper.exe+ 0xAAA38 ] + 0x18 ] + 0x1C.
It must be associated with the function we are searching for in some way, so let’s do the trick again: right-click the address -> Find out what writes to this address. Now you need to click a field in Minesweeper. You will see an instruction popping up in CheatEngine: inc [rbx+1C]. This instruction increases [rbx + 0x1C] by one. RBX contains the address of that same structure from earlier again here. I will be calling it GameManager from now on.
Now, this is where our Decompiler comes into play. I’m going to use IDA.
Load Minesweeper.exe into the decompiler, let the analysis finish, and rebase the image. In IDA you can do this by going to Edit -> Segments -> Rebase program. Enter the module base address of Minesweeper in there, which you can get from CheatEngine.
After that is done, jump to the instruction address that increased the click count in IDA.

In IDA you can hit F5 to decompile it to pseudo-C-code.

I recommend converting the pointer offsets from decimal to hexadecimal by clicking them and hitting H on the keyboard. First of all, the ++v6[7] in line 22 is the instruction that increased the counter.
Now I analyzed the parameters that have been passed into the function by setting a breakpoint at the start of the function in CheatEngine. I clicked another field to trigger the breakpoint. The first parameter is the GameManager from earlier, the second parameter was the X coordinate I clicked, and the third one is the Y coordinate. I renamed them accordingly in IDA.

Now I saw those two big if statements, both using the X and Y variable. After looking up, what their values are, I found out, that they are two different data structures. One of them contains the state of the field (for example if it has been revealed already), and the second one only contains information about the mine placement (Bomb check in the image).

If we oversimplify the bomb check, it basically would boil down to something like a jagged array.

1
2
3
if(mines[x][y] == 1) {
       GameOver();
}

If we actually wanted to see if there is a bomb at a certain coordinate, we can simply dereference the following pointer after inserting X and Y accordingly:
Minesweeper.exe+ 0xAAA38 ] + 0x18 ] + 0x58 ] + 0x10 ] + 0x8 * x ] + 0x10] + 0x4 * y

Conclusion

I ended up creating a small trainer and a cheat table in the end. Both can be found in the post linked in the Introduction.

This post is licensed under CC BY 4.0 by the author.