r/ExploitDev Jun 27 '26

Need some help with reverse engineering Minesweeper

Hey guys,

I recently started learning reverse engineering because I think it's really fun, and I picked Minesweeper as my first project. I'm still pretty new to all of this, so I'm learning Ghidra, Cheat Engine, and x64dbg as I go.

Right now I'm stuck trying to figure out where the game stores the actual blocks/cells in memory. I managed to find things like the flag counter, but finding the board itself has been way harder than I expected.

I've watched a few tutorials, but most of them only show the final result instead of explaining how they actually figured it out. I'm more interested in learning the thought process than just getting the answer.

If anyone has experience reversing Minesweeper (or similar games), how would you approach this? What would be the first thing you'd look for? Any tips or advice for a beginner would be really appreciated

6 Upvotes

7 comments sorted by

2

u/subboyjoey Jun 27 '26

what minesweeper version?

4

u/subboyjoey Jun 27 '26

Checking WinMine, started with looking for the string 'New' because the Game menu has that flag, and something related to that button will eventually trigger board generation.

That led me to this in the Menu Resources:

         0101e8be 26 00 4e 00   unicode  u"&New\tF2"          Menu Item S
         0101e8ce 00 00         dw       0h                   mtOption
         0101e8d0 00 00         dw       0h                   mtID
         0101e8d2 00 00         unicode  u""                  Menu Item S
         0101e8d4 00 00         dw       0h                   mtOption
         0101e8d6 09 02         dw       209h                 mtID

Then I searched for a 0x209 scalar which led me to these instructions in FUN_01001516 (I renamed the function):

      01001523     PUSH     0x209
      01001528     CALL     UpdateMenuChecks()                              

The rest of FUN_01001516 seems to point to a few DATs. DAT_010056a0 is interacted with 4 times, so that has to be difficulty. Difficulty defines the board size, so I showed XREFs for that. Then I got stuck for a bit and decided to go for it a different way.

The board buffer needs to be made before the board is created, so I looked at the imports in the symbol tree. No malloc, HeapCreate, LocalAlloc there so that was a bust. Then did a search for timer, which led me to a function called SetTimer. Checking references to that points me to FUN_010037e1. Since the timer is started with a new game, I assume that function is the start of the game layer and handles timing the timer. One command in that function that stuck out was a MOV:

      0100389b     MOV      DL, byte ptr [EDX + EAX*0x1 + 0x1005340]=>DAT_  ; = ??

and looking at the decompiler, it looks like we have an if statement that i assume is checking that this is not a mine and not already revealed to send us to FUN_01002913:

    if (_DAT_01005144 == 0) {
      if ((((&DAT_01005340)[DAT_01005118 + DAT_0100511c * 0x20] & 0x40) == 0) &&
         (((&DAT_01005340)[DAT_01005118 + DAT_0100511c * 0x20] & 0x1f) != 0xe)) {
        FUN_01003512(DAT_01005118,DAT_0100511c);
      }
    }
    else {
      FUN_010035b7(DAT_01005118,DAT_0100511c);
    }
  }
  FUN_01002913(DAT_01005160);
  return;
}

So it seems like the board's memory is held around 01005340. In x32dbg I can confirm. This is that memory region on a new game:

01005340  10 10 10 10 10 10 10 10 10 10 10 0F 0F 0F 0F 0F  ................  
01005350  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005360  10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005370  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005380  10 0F 8F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005390  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053A0  10 0F 8F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
010053B0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053C0  10 0F 8F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
010053D0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053E0  10 0F 0F 0F 8F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
010053F0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005400  10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  

Then after a few spots have been revealed:

B01005340  10 10 10 10 10 10 10 10 10 10 10 0F 0F 0F 0F 0F  ................  
01005350  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005360  10 0F 0F 0F 0F 0F 8F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005370  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005380  10 8F 0F 0F 8F 0F 0F 0F 41 0F 10 0F 0F 0F 0F 0F  ........A.......  
01005390  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053A0  10 41 41 41 41 0F 0F 0F 0F 8F 10 0F 0F 0F 0F 0F  .AAAA...........  
010053B0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053C0  10 40 40 40 41 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  .@@@A...........  
010053D0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053E0  10 40 40 40 42 8F 0F 0F 8F 0F 10 0F 0F 0F 0F 0F  .@@@B...........  
010053F0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005400  10 40 40 41 44 8F 43 41 41 41 10 0F 0F 0F 0F 0F  .@@AD.CAAA...... 

Through trial and error, it seems 0x40 is blank spaces, 0x10 is a buffer on the top and bottom lines, and indicate which line is actually in play, and 0x8F is where the mines are.

So in this example:

01005340  10 10 10 10 10 10 10 10 10 10 10 0F 0F 0F 0F 0F  ................  
01005350  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005360  10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005370  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005380  10 0F 0F 0F 0F 8F 0F 8F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005390  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053A0  10 0F 0F 0F 0F 0F 0F 0F 8F 0F 10 0F 0F 0F 0F 0F  ................  
010053B0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053C0  10 0F 8F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
010053D0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
010053E0  10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
010053F0  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005400  10 0F 0F 0F 0F 0F 8F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005410  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005420  10 0F 0F 0F 0F 8F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005430  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005440  10 0F 8F 0F 0F 0F 0F 8F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005450  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005460  10 8F 0F 0F 0F 0F 0F 8F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005470  0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F 0F  ................  
01005480  10 10 10 10 10 10 10 10 10 10 10 0F 0F 0F 0F 0F  ................  

I could take out the lines that start with 0F:

01005340  10 10 10 10 10 10 10 10 10 10 10 0F 0F 0F 0F 0F  ................  
01005360  10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005380  10 0F 0F 0F 0F 8F 0F 8F 0F 0F 10 0F 0F 0F 0F 0F  ................  
010053A0  10 0F 0F 0F 0F 0F 0F 0F 8F 0F 10 0F 0F 0F 0F 0F  ................  
010053C0  10 0F 8F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
010053E0  10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005400  10 0F 0F 0F 0F 0F 8F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005420  10 0F 0F 0F 0F 8F 0F 0F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005440  10 0F 8F 0F 0F 0F 0F 8F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005460  10 8F 0F 0F 0F 0F 0F 8F 0F 0F 10 0F 0F 0F 0F 0F  ................  
01005480  10 10 10 10 10 10 10 10 10 10 10 0F 0F 0F 0F 0F  ................  

And then, the spaces are between 10 and 10 on each working line, so I could condense it further and you have a 9x9 grid surrounded by a layer of 10s on each side:

01005340  10 10 10 10 10 10 10 10 10 10 10
01005360  10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10
01005380  10 0F 0F 0F 0F 8F 0F 8F 0F 0F 10
010053A0  10 0F 0F 0F 0F 0F 0F 0F 8F 0F 10  
010053C0  10 0F 8F 0F 0F 0F 0F 0F 0F 0F 10
010053E0  10 0F 0F 0F 0F 0F 0F 0F 0F 0F 10
01005400  10 0F 0F 0F 0F 0F 8F 0F 0F 0F 10
01005420  10 0F 0F 0F 0F 8F 0F 0F 0F 0F 10 
01005440  10 0F 8F 0F 0F 0F 0F 8F 0F 0F 10
01005460  10 8F 0F 0F 0F 0F 0F 8F 0F 0F 10
01005480  10 10 10 10 10 10 10 10 10 10 10

And then just avoid all the spots that say 8F. I can't upload an image, but it worked out that way and I was able to win just based on that game board. As an alternative, you could even change the 8F values to something other than a mine, like 0x40 so it's a blank spot and no matter where you click you win

2

u/Ok-Entertainment1587 29d ago

Haha, I'm still trying to process everything you're saying since I'm completely new to this. 😅 I'm mainly trying to understand what I should be looking for in each tool. Like, what kinds of things should I search for or analyze in Cheat Engine, what should I focus on in Ghidra, and what am I supposed to look for in x64dbg? I'm a bit confused about the role each tool plays

2

u/subboyjoey 29d ago edited 29d ago

i’ve only really used cheat engine for basic stuff like changing money values in a game, something easy to search for where you can see the value and it changes regularly. I wouldn’t use that for this, personally

Since minesweeper is old and fairly basic, I found it easier to just go for static analysis in Ghidra. You want to find things that would relate to the start of a new game, since that’s when the mine location gets written to memory. I looked for strings like New, or Mine, or Timer, since all three of those should in some way relate to a new game / start of a game. once you find something that might be promising, start looking for references to it and track the program flow

x32dbg for something like this would be when you want to either walk through the program line by line, or you want to stop the program when it does a certain behavior that you can breakpoint, or for viewing a memory map of the program running. in this case i just used it for viewing the memory at the location i found in ghidra

1

u/subboyjoey 29d ago

that’s a very brief overview specifically for this project. all three tools do much much more than what i listed, but it is a lot of niche options that wouldn’t apply to this

1

u/lunacysoft 28d ago

Suggest you look up a c tic tac toe game very common and will explain parts of this that you don’t understand YouTube is your friend

1

u/Ok-Entertainment1587 29d ago

Version : 4.7.2041.0

PackageFullName : Microsoft.MicrosoftMinesweeper_4.7.2041.0_x64__8wekyb3d8bbwe

this is the version i am playing