Advertisements

Recently I tweeted a screenshot where I won the Minesweeper game by looking at the mine field from the memory. I posted this for no reason, just for fun since I was happy that I finally won this game. I used to play this game back in 2002 in Windows XP and I never won this game, I never even understood how this game works until today when I read how it really works 😀



In few minutes my notifications were flooded, I didn’t expect to get this much of likes. Some people asked me a tutorial on this. I thought of writing a very quick blog post on this. Pardon me if I missed anything.



After tweeting that screenshot I saw this blog post by @DidierStevens where he shows a video on hacking Minesweeper with Mimikatz from @gentilkiwi. It’s awesome to include such a functionality inside Mimkatz. Let’s try to code a simple dirty hack for Minesweeper in XP.

In Windows XP you can find the binary from %systemroot%\system32\winmine.exe

If you don’t have Windows XP you can still download the original binary from here.

Static Analysis

First, let’s have a look if the binary has ASLR enabled. The DLL Characteristics got a value of 0x8000 which is ‘IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE’. It’s confirmed that this PE was compiled with no ASLR protection. We can easily hardcode the addresses if we are coding a hack for this.

Looking at the IAT we can determine the program uses the Microsoft Windows graphics device interface (GDI) by looking at the functions imported from the ‘gdi32.dll’. This is obvious since this is a game We can also see Registry APIs used from the ‘advapi32.dll’ which means we can suspect the application accesses the registry.

Hacking the Scores

The scores are stored in the registry and the values are read from the registry. If you check all the imports and find references to ‘RegQueryValueExW’ API and hit a break point you can find the location of the registry. Another easy way would be hooking the API

After the breakpoint is hit you can see the parameters on the stack and you can open the location in the registry.

HKEY_CURRENT_USER\software\Microsoft\winmine

You can modify the names, scores and other options such as colour, difficulty, height, width, etc. The value of ‘Name1’ corresponds with the score value of ‘Time1’ in hex.

Hacking the Mine Field

Let’s hit a breakpoint at the ‘BeginPaint’ API.



Let’s step inside the function

01001C4C |. E8 720E0000 CALL Winmine_.01002AC3

Then again step inside the function.

01002AE6 |. 56 PUSH ESI ; /Arg1

01002AE7 |. E8 BBFBFFFF CALL Winmine_.010026A7 ; \Winmine_.010026A7



You will see the ‘BitBlt’ api is used to draw the blocks one by one.

If we check the registers, the EBX contains the mine field 0x010056360 and the ESI register is used to increment each byte.

If we dump the EBX register we can determine starting point from 0x01005340.

It adds 0x20 to EBX which we can determine the end of each field.

0100271D |. 83C3 20 |ADD EBX,20



Coding a Dirty Hack

First, we have to open the process of the game. For this we will use FindWindow and get the handle of the window and then pass it to ‘GetWindowThreadProcessId’ and once we get the ‘dwProcessId’ we can pass that value to ‘OpenProcess’ API. You can also use ‘CreateToolhelp32Snapshot’ technique discussed here.

HWND window = FindWindow(NULL, L"Minesweeper"); if (window == NULL) return wprintf(L"[-] Failed to find Minesweeper process"); GetWindowThreadProcessId(window, &dwProcessId); HANDLE process = OpenProcess(PROCESS_VM_READ, FALSE, dwProcessId);

Next, we will allocate our buffer to store our mine field data.

LPBYTE buffer = (LPBYTE)malloc(size); if (buffer == NULL) return wprintf(L"[-] Failed to allocated memory");

Finally we will write an infinite loop to read memory from the starting address of the memory using the ‘ReadProcessMemory’ API, so that each time we click a field the fields get updated. We can use 0x20 as the end of each line in the field.

while (true) { BOOL ret = ReadProcessMemory(process, (LPVOID)start, buffer, size, &dwRead); if (ret == NULL) return wprintf(L"[-] Failed to read memory"); for (size_t i = 0, j = 0; i < size; i++, j++) { if (j == 0x20) { puts(""); j = 0; } printf("%c", buffer[i]); } Sleep(1500); system("cls"); }

We just dumped the mind field from memory using ‘ReadProcessMemory’ API

Here’s the full source code.

https://github.com/OsandaMalith/GameHacking/blob/master/Minesweeper/Hack.c

#include "stdafx.h" #include <stdio.h> #include <tchar.h> #include <windows.h> #define start 0x1005340 #define end 0x10056A0 int _tmain(int argc, _TCHAR* argv[]) { DWORD dwProcessId = 0; DWORD dwRead = 0; HWND window = FindWindow(NULL, L"Minesweeper"); if (window == NULL) return wprintf(L"[-] Failed to find Minesweeper process"); GetWindowThreadProcessId(window, &dwProcessId); HANDLE process = OpenProcess(PROCESS_VM_READ, FALSE, dwProcessId); DWORD size = end - start; LPBYTE buffer = (LPBYTE)malloc(size); if (buffer == NULL) return wprintf(L"[-] Failed to allocated memory"); while (true) { wprintf(L"[+] Minesweeper Dirty hack

"); wprintf(L"[+] Author: @OsandaMalith

"); wprintf(L"[+] Website: https://osandamalith.com



"); BOOL ret = ReadProcessMemory(process, (LPVOID)start, buffer, size, &dwRead); if (ret == NULL) return wprintf(L"[-] Failed to read memory"); BYTE field = NULL; for (size_t i = 0, j = 0; i < size; i++, j++) { if (j == 0x20) { puts(""); j = 0; } printf("%c", buffer[i]); } Sleep(1500); system("cls"); } return 0; }

You can modify the byte values and print something like this, I’ll leave that to you

You can check my friend Ophir Harpaz has nicely patched the program where she has made, if the al == 0x8f which is a mine, change it to a flag which is 0x0E inside the code cave.

https://github.com/ophirharpaz/Patched-Minesweeper

I hope this post will be useful to you get started with hacking simple games

Translations

Хакинг Minesweeper – https://howtorecover.me/khaking-minesweeper