Reverse Engineering - Minesweeper Game
Hello Everyone,
This is my first experience Reverse Engineering a game. I had so much fun analyzing the code and it took five days to figure out the logic and design.
Tools Used:
Ollydbg, IDA Pro, MSDN, Procdump and Hex Calculator
My Goal:
- Find the GAME logic
- Simulate the game board WITHOUT PLAYING THE GAME
- Find the secret code (revealed when we win the game) of all three levels without playing the game
Find the GAME logic
I first used IDA Pro to review the Imports and strings that are being used in the executable (minesam.exe). The string tab did not have any useful strings that might give us a clue to understand the functionality of the code. The Import table has LoadStringsW and gives me a clue that a string is being loaded using this function.
After using IDA Pro, I used Ollydbg to debug the game. I tried to run the program and reviewed the memory dump for clues.
I got to see the minesweeper board with mines. The board starts at 0x01005340. The board’s border is designed using the hex value ‘10′ and the mines are represented by ‘8F’. The memory dump of the game board looks like the picture below.
Next I used IDA pro to find the cross reference calls to this memory address (to find out the functions that referenced to the 0x01005340 memory address). IDA pro showed the following list of cross references.
I carefully reviewed every function using the combination of both disassembler and debugger. I found the following code segment that adds ‘0F’ to the memory dump. This is the first step that is being iterated to create game board in the memory dump. It starts at (0x01005340 + 360) and replaces ‘00‘ with ‘0F‘. The game board gets filled with ‘0F‘ .
And then the next part of the code draws the vertical and horizontal borders to the memory dump.
The board in the memory dump looks like the image below and the mines are yet to be placed on the board.
Mine Calculation:
Lets look at how the mines are calculated and placed in the memory dump. First a number is generated using Rand Function(msvcrt). The random number is stored in both EAX and ECX. EAX is divided and the remainder is stored in EDX. EDX value is moved to EAX.
010036DB CALL minesam.01003940
01003940 CALL DWORD PTR DS:[<&msvcrt.rand>]
The function returns the EAX value and the value is moved to ESI. ESI will represent the column in the game board. For example if ESI = 2, the mine will be placed at second (2nd) column. The function CALL minesam.01003940 is called the second time to set the EAX value and the following offset [EAX+ESI+1005340] will help us to determine the location of the next mine.
010036F3 LEA EAX,DWORD PTR DS:[EAX+ESI+1005340]
After finding the location offset of the next mine, the code tries to change the value in that offset. The following screenshot shows the part the code that does the calculation.
An OR bitwise operation is applied between EAX value and 80. If EAX is equal to 0F , the result of OR logic will be ‘8F’. ‘8F’ is the value of a mine in the memory dump of the game. At the end of this function, the memory dump looks like the below image.
010036FA OR BYTE PTR DS:[EAX],80
We figured out the mine location of the board. Next I am going to cheat the game using the memory dump above.
After winning the game, I reviewed the memory dump again, and found that the values have been replaced with different numbers. The board now looks exactly like the actual GUI game board(image above).
By comparing the two images above, we make the following inferences:
A Mine new value is 8E. Old Value was 8F.
Now we will work on finding the logic in the code using Ollydbg.
After reviewing the code using breakpoints, I was able to nail down the logic. The cell that does not have a mine will either be blank or have a number.
The value of each cell is calculated using the following rule.
The number of mines (# of 8E) around the cell will determine the value of that cell.
Number of 8E:
The logic is available in the following code fragment/section.
The OR logic is used to calculate the cell value.
01003044 OR AL,40
The value is moved to that particular cell using the following command
01003047 MOV BYTE PTR DS:[ESI+1005340],AL
Finally we figured out how the hex values are changed in the memory dump while playing the game. Next we are going to simulate the board in command line without playing the game.
Simulate the game board WITHOUT PLAYING THE GAME
We will be using python and Procdump. And yes, We can cheat the game without playing the game. The following image shows the memory dump of the intermediate level challenge.
I wrote a python program, that reads the memory dump created by procdump. Then I apply the code logic to figure out the value of each cell and the output of the command line looks like this:
I was able to simulate the board in the command line without playing the game. In the above image,
~ represents Blank cell
1,2,3,4,5 represent the number of mines around that cell
* represents a mine
Find the secret code (revealed when we win the game) of all three levels (Beginner, Intermediate, Expert) without playing the game
There is a secret code that will be displayed when we win the game. There is a secret code for each level (3 levels available). We are going to apply reverse engineering techniques to figure out the location of the secret code. We are going to print the secret code without winning/playing the game.
The secret code (Smartie) is underlined in the above image.
To find out the code that stores the secret string, I used ollydbg and IDA pro in combination to figure out the offset and logic.
When I reviewed the imports of this executable in IDA pro, the following entry gave me a clue that strings are loaded using the LoadStringW :
00000000010010D0 LoadStringW USER32
I added a breakpoint at this location in ollydbg and started to debug the executable. The code stopped at breakpoint multiple times to load User name, game statistics (seconds, top score etc) and the message that had the secret code.
Lets take a look at the stack when LoadStringW is loaded with the message and secret code
I tried to step in to the function minesam.010039E7, one instruction at a time to track the strings in the stack. The following entries in the stack looked interesting.
000DF598 |0101E88C UNICODE "You have the fastest time
for beginner level.
000DF5B0 000DF5F0 UNICODE "You have the fastest time
for beginner level.
The secret word is Smartie!"
Let us have a look at the stack at this stage
When I reviewed the stack, the memory offset 0101E88C looked new and was out of range in the current memory dump. So I decided to right click and select “follow in dump”. Aha! look what I discovered at that offset:
So I want to find out the memory layout at the offset 0101E88C. I clicked the View -> Memory to view the current memory layout.
The offset 0101E88C is available in the below entry. The offset is part of the .rsrc folder as part of the Minesam.exe. I am going to double click on the entry to have a look at the resources folder dump.
After reviewing the resource folder dump, I was able to locate the secret code at the offset 0101E88C.
Hence the buffer in LoadStringsW function loads the secret code from the resource folder. But the code is loaded only after winning the game.
So now I have to print the secret code without playing the minesweeper game. I am going to use Python and Hex calculator, to access the memory and calculate the offset. The following sample code shows how the offset for expert level is calculated.
b= pe.sections[2].get_data()[100880:100935]
Please find below the output of python program.
Credit: Sam Bowne
0 notes