Results 1 to 15 of 15

Thread: Reversing our M$ game: Minesweeper

  1. #1
    Red wine, not vodka! ZaiRoN's Avatar
    Join Date
    Oct 2001
    Location
    Italy
    Posts
    922
    Blog Entries
    17

    Reversing our M$ game: Minesweeper

    Hi All,
    I would like to present something unusual for this area, a game reversing (a M$ game reversing ).
    In my mind I was thinking to modify the program in order to show where the bombs are. This is not the classical "game cheating" but something a little bit hard, that will imply not only a reverse approach but also a programming aspect.

    Talking with Kayaker, he suggeted some tasks:
    1. Give option to user to use the "cheat" feature. Add a new menu item or an hotkey (or why not both of them), something that will let you to switch from the normal to the cheat mode and viceversa.
    2. Try to understand how (and where) the program stores the position of the bombs.
    3. Show where the bombs are as a *mouse-over* effect as the cursor moves over each grid square. How does the program unhide the grid windows? Show them briefly as the mouse cursor passes by. Or use a tooltip or other way of signifying there's a hidden mine down there.
    4. Package your cheat in a dll module, and add the new functionality patch in memory with only the code that will call the export function(s).

    More or less it's all here. We will use the standard 2k/XP (english) version of the game as a target but everyone can play with his own version. I take a look at different versions of this game, they are similar and you should not have problems :-)

    Before leaving you, I would like to suggest these two tutorials as a support for the beginning of the project:
    http://www.woodmann.net/fravia/menusspa.htm
    http://www.woodmann.net/fravia/TracePlus_MenuPatch.html

    There are some interesting aspects involved in this project so, don't be shy and don't hesitate to ask something; there are many people willing to help you

    Regards,
    ZaiRoN

  2. #2
    Programmer Run Amock... Bengaly's Avatar
    Join Date
    Aug 2001
    Location
    Somewhere over the Rainbow
    Posts
    289
    Blog Entries
    1
    http://codeproject.com/csharp/minememoryreader.asp?target=minesweeper
    "knowledge is now free at last, everything should be free from now on, enjoy knowledge and life and never work for everybody else"

  3. #3
    Red wine, not vodka! ZaiRoN's Avatar
    Join Date
    Oct 2001
    Location
    Italy
    Posts
    922
    Blog Entries
    17
    Hi Bengaly,
    I know this article and would have post the link in the future . It's a nice article but it's only a simple process memory reader :-p

    Ciao,
    ZaiRoN

  4. #4
    Programmer Run Amock... Bengaly's Avatar
    Join Date
    Aug 2001
    Location
    Somewhere over the Rainbow
    Posts
    289
    Blog Entries
    1
    Hi ZaiRon,
    hehe yeah i know =)
    you challenge is very good practice, was just reffering to this article of some will want to know stuff faster
    "knowledge is now free at last, everything should be free from now on, enjoy knowledge and life and never work for everybody else"

  5. #5
    I used to play Minesweeper quite a lot in the Windows 3.1 days (I did the expert on ~100 seconds), so forgive me for remembering this cheat..:

    http://www.eeggs.com/items/470.html
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  6. #6
    Teach, Not Flame Kayaker's Avatar
    Join Date
    Oct 2000
    Posts
    4,146
    Blog Entries
    5
    Originally posted by ughugh
    forgive me for remembering this cheat..:
    http://www.eeggs.com/items/470.html
    Lol, that's a good one. Sure enough there's this stupid little pixel at 0,0 on your desktop which blinks on and off as you pass over a mine. Start up a winmine game, type 'xyzzy' and press Enter, then press one of the Shift buttons and if you squint really hard you can see it working.

    Now try setting a breakpoint on SetPixel and do the same and you can see which code is called to perform this amazing MS trick, heh. If you have the Windows Debug symbols installed, under ..\symbols\exe is the winmine dbg version which can be loaded into Softice and it's a bit easier to follow the 'xyzzy' Eegg. I always wondered how people found Easter eggs...

    Well this is great, but has anyone except ZaiRoN given a go at reversing this thing or is the challenge to find how many cheats already exist on the net?

    Kayaker

  7. #7
    Programmer Run Amock... Bengaly's Avatar
    Join Date
    Aug 2001
    Location
    Somewhere over the Rainbow
    Posts
    289
    Blog Entries
    1
    but has anyone except ZaiRoN given a go at reversing this thing or is the challenge to find how many cheats already exist on the net?
    hi Kayaker,
    yeah i give it a shot, for now i found a useless function in minesweeper and removed it's code to inject the caller code of the dll, it works ok, i guess i now need to play with the app and see how things works in order to hook it up with the dll.
    dunno how much time it will take me.
    ttl
    Last edited by Bengaly; September 15th, 2003 at 17:02.
    "knowledge is now free at last, everything should be free from now on, enjoy knowledge and life and never work for everybody else"

  8. #8
    Red wine, not vodka! ZaiRoN's Avatar
    Join Date
    Oct 2001
    Location
    Italy
    Posts
    922
    Blog Entries
    17
    Hi All,

    I did take a glance at the target starting from the easy part, the new menu item. In this post I will explain the way I used to add the new menu item, find the part of the window procedure where menu items are processed and finally write the first dll function.

    Add new menu item
    As always happens, this is the most easy part of the reversing session. Load the file into your preferred resource editor and add the new item under the menu section. You have to assign an identifier (a number...) to the new item, remember that it must be a number that is not used by the other items.

    Find the point where the program checks whether a menu item is been pressed
    This task is useful because we need to add/manage the new menu item, the special mode option. If you check the 'special mode', the game will show you the bomb, otherwise the game will remain the same.
    There are many ways to solve this second point.
    - You can use Spy++, a little application that gives you a view of many informations about a process that is running on your system. Run Minesweeper and then run Spy++. You will see a list of the running processes, find Minesweeper process and double click on it. A dialog will show you some informations about the game, one of them is the window procedure.
    - Another way to locate the window procedure is to use Ida. This is more or less the way explained by +Spath in his tutorial.
    Load the file into ida and press ctrl-p; a dialog appears. This dialog contains the functions used by the program and, we are interested in WinMain function, the one used to define the window class. This is useful because from here you can understand where the window procedure is. The program uses RegisterClassW function to register the window class:

    ATOM RegisterClass(
    CONST WNDCLASS *lpWndClass // address of structure with class data
    );

    and:

    typedef struct _WNDCLASS {
    UINT style;
    WNDPROC lpfnWndProc;
    int cbClsExtra;
    int cbWndExtra;
    HANDLE hInstance;
    HICON hIcon;
    HCURSOR hCursor;
    HBRUSH hbrBackground;
    LPCTSTR lpszMenuName;
    LPCTSTR lpszClassName;
    } WNDCLASS;

    This structure contains the window attributes; we are interested in lpfnWndProc because it points to the window procedure. Look at the disasm Ida gave you and take the address we were looking for.

    Ok, we now know where the window procedure is.
    It's time to use a debugger, Ollydbg. Load the program and jump to the window procedure, we need to set a breakpoint. Remembering that we are trying to find the part of the procedure which check whether a menu item is clicked, we need to break if and only if a menu item is clicked. When an item is clicked, a specific WM_COMMAND message is sent to the procedure. This specific message contains the menu item identifier in the loworder word of the wParam parameter.
    Take a look at the first part of the window procedure:
    Code:
    0100180A   PUSH EBP
    0100180B   MOV EBP,ESP
    0100180D   SUB ESP,40
    01001810   MOV ECX,DWORD PTR SS:[EBP+C]   <-- ecx is the message (i.e. WM_COMMAND)
    01001813   PUSH EBX
    If we want to catch the click over one of the menu item we need to set a conditional breakpoint (Shift+F2) at 1001810. The condition I have used is:
    [EBP+0Ch]==111H && [EBP+10H]==209H
    where '[EBP+0Ch]==111H' checks for the WM_COMMAND message and '[EBP+10H]==209H' checks whether the 'Beginner' menu item is been clicked (you can use your preferred menu item :-)). Run the program and click on the chosen item, Olly breaks. Steps a little and you will surely find the place where the program checks which menu items is been pressed. This piece of code is what we were looking for; later on we will add a new cmp with the id of the new item when we will patch the program in memory.

    Write the first dll function
    Now that we know all these informations, we can easily write the first function of the dll, I will call it changeItemStatus.
    This function will check/uncheck the menuitem enabling or disabling the special mode, nothing more. To check/uncheck the item I will use CheckMenuItem function:

    DWORD CheckMenuItem(
    HMENU hmenu, // handle to menu
    UINT uIDCheckItem, // menu item to check or uncheck
    UINT uCheck // menu item flags
    );

    An easy function to use. It needs:
    1. the handle of the menu. We don't have the handle but since the function is imported and since some of the items of the menu could be checked/unchecked, the easiest way to retrieve the handle is to put a breakpoint on this function and hit one of the checked items, for example the 'sound' item. Perfect, Olly will break showing us where the handle is stored.
    2. the id of the menu. It's the number we gave to our new item
    3. we are interested in two values:
    MF_CHECKED (08h): sets the check-mark attribute to the checked state.
    MF_UNCHECKED (00h): sets the check-mark attribute to the unchecked state.

    I did write the dll in asm but no one will stop you from writing it in other languages. Here is my partial dll:

    Code:
    .386
    .model flat,stdcall
    option casemap:none
    
    include \masm32\include\windows.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    include \masm32\include\gdi32.inc
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib \masm32\lib\gdi32.lib
    
    .data 
    
    .code
    DllEntry proc hInstance:HINSTANCE, reason:DWORD, reserved1:DWORD
       mov eax, TRUE
       ret
    DllEntry Endp 
    
    ; Change the status of the new item
    changeItemStatus proc
       .IF word ptr [ebp+10h] == 212h   ; 212h is the id I used for the new item
          mov ebx, 10049A2h        ; byte [10049A2] stores the state of the menu item
          xor byte ptr [ebx], 08h
          movzx eax, byte ptr [ebx]
          mov ebx, 10052BCh        ; address where the menu handle is stored
          invoke CheckMenuItem, dword ptr [ebx], 212h, eax
       .ENDIF
    ret 
    changeItemStatus endp 
    
    End DllEntry
    The only thing that requires an explanation is the value stored at 10049A2. This byte is:
    00h if the item is unchecked
    08h if the item is checked

    This is the first function and in my mind I was thinking to add only another function that will unhide a single cell if the special mode in on. We will see later, for the moment it's all...

    ciao,
    ZaiRoN

  9. #9
    Gamehacking was a good way of learning reversing (for me). Cracks alone can be very one-dimensional, but gamehacking forces you to learn a bit of everything.

    ... my 2 cents

  10. #10
    Red wine, not vodka! ZaiRoN's Avatar
    Join Date
    Oct 2001
    Location
    Italy
    Posts
    922
    Blog Entries
    17

    Try to understand how (and where) the program stores the position of the bombs

    We need to find a way to break when a cell is clicked. Exploiting the work we have done in the previous task, I will use another conditional breakpoint at 1001810; the idea is to break when the left mouse button is pressed (and then released).
    When this button is released, a WM_LBUTTONUP (202h) message is posted and so, the new condition will be: [ebp+0Ch]==202h
    Set the new breakpoint and click on a cell; Olly breaks, steps a little until Olly will tell you that you have found the place:
    Code:
    01001C30 XOR EDI,EDI   ; Cases 202 (WM_LBUTTONUP)   <-- thx to Olly :-D
    01001C32 CMP DWORD PTR DS:[1005160],EDI
    01001C38 JE winmine.01001D4C
    01001C3E MOV DWORD PTR DS:[1005160],EDI
    01001C44 CALL DWORD PTR DS:[<&USER32.ReleaseCaptu> ; ReleaseCapture
    01001C4A TEST BYTE PTR DS:[1005010],BL
    01001C50 JE SHORT winmine.01001C5C
    01001C52 CALL winmine.0100373E   ; hmmm...
    01001C57 JMP winmine.01001D4C    ; jump at the end of the procedure
    This is the code that manage the WM_LBUTTONUP command; as you can see there is a call to ReleaseCapture, a jump at the end of the procedure and a suspicious call. Maybe it's the call that will show us where the bombs are...

    At this point I should tell you where the bombs are but, I prefer to signal an interesting article (thx Kayaker) because it is useless to write the same things two times.... The author shows you how to locate the code I posted above and after that, he shows where the bombs are. You can find the article at:
    http://www.codeguru.com/mfc/comments/50642.shtml

    See you on the next step...

    ZaiRoN
    Last edited by ZaiRoN; September 27th, 2003 at 07:07.

  11. #11
    Red wine, not vodka! ZaiRoN's Avatar
    Join Date
    Oct 2001
    Location
    Italy
    Posts
    922
    Blog Entries
    17

    Show where the bombs are...

    In this post we will see how to play with the new dll; as support, I would like to add a new tutorial:
    http://www.woodmann.net/fravia/kayaker_RegmonPlus.htm
    Read it, it's full of interesting informations ;-)


    Now that we know almost everything about the program, we have to show these damned bombs. I will try to explain you how to show them when the mouse pass over a cell; the bombs will remain showed until the end of the game.

    We need to show the bombs when the mouse passes over a cell (that hide a bomb) so, we need to find where the program checks for WM_MOUSEMOVE message. Now, if you read the previous messages, you should not have problems to find the location; as you can see this type of message is not so useful for the original program, it makes a simple jump to the end of the routine.

    When we will patch the program in memory we will need to change this jump into a jump to our code.
    Which are the runtime modifications to apply at the program?
    - a new compare instruction for the new itemmenu (remember the old message...)
    - the jumps to the new code (one for the item menu and one for the wm_mousemove)
    - the code necessary in order to call the dll functions
    I will only speak about the last modification, the other two are very easy; if you have problem do not hesitate to ask.

    How to call a dll? Practically you have to call 3 simple functions: LoadLibrary, GetProcAddress and FreeLibrary.

    LoadLibrary: it's the first function to use and it maps the dll module into the address space of the calling process.
    HINSTANCE LoadLibrary(
    LPCTSTR lpLibFileName // address of the string that names the executable module
    );

    The function returns a handle that can be used in GetProcAddress to get the address of a dll function.

    GetProcAddress: returns the address of the exported dll function.
    FARPROC GetProcAddress(
    HMODULE hModule, // handle to DLL module (the value returned by LoadLibrary)
    LPCSTR lpProcName // address of the string that names the function
    );


    FreeLibrary: unmaps the dll module fro the address space of the calling process
    BOOL FreeLibrary(
    HMODULE hLibModule // handle to DLL module (the value returned by LoadLibrary)
    );


    This is the code I used to call the dll and it's the code you have to inject into a cave of the original program:

    Code:
    010049A2:   ; Initial address
    specialMode BYTE 1h dup(0) ; specialMode=08h if specialMode is enable
                               ; otherwise specialMode=00h
    dllName db "zaiWinmine.dll",0 ; The name of the new DLL
    ; The name of the 2 exported functions:
    changeItemStatus db "changeItemStatus",0 ; Changes the status of the itemmenu     
    revealCell db "revealCell", 0 ; Reveal a bomb under a cell
    
    ; From 'specialMode' item clicked (10018C4)
     push 10019ADh     ; Address from where to return to
     pushad
     push offset changeItemStatus   ; Used by GetProcAddress     
     jmp @go
    
    ; From WM_MOUSEMOVE event (1001b50)
     push 1001DD5h                ; Address from where to return to
     .IF [specialMode] == 00h   ; Is the special mode enable?
      pop eax                     ; specialMode is disable, no need to show the bomb
      jmp eax
     .ENDIF
     pushad
     push offset revealCell        ; Used by GetProcAddress
     jmp @go
    
    @go:
     push offset dllName   ; The name of the dll
     call LoadLibrary
     mov esi, eax
     push eax                 ; Handle to dll module
     call GetProcAddress
     call eax    ; call the exported function
     push esi   ; Handle to dll module
     call FreeLibrary
     popad
     pop eax
     jmp eax      ; Jump back to the original code
    I think there is nothing to add.

    Now we can write the other function of the dll, the one I called revealCell. What this function is supposed to do? Remembering that the function will be called on every single movement of the mouse (and let's suppose specialMode is enable), we have this scheme:

    1. Is the pointer inside the grid?
    No: quit from the function
    Yes: jump to 2

    2. Is the cell hiding a bomb?
    No: quit from the function
    Yes: reveal the bomb

    The point number 1 is necessary because the bombs can not be outside the grid while the point number 2 is the final check.
    The first cell (upper left corner) starts from coordinates 0x0C,0x37 and each cell is 0x10,0x10. Now that we know this information, we are able to implement the point number 1: a simple 'if' based on the coordinates of the point where the mouse has been pressed. How did you know the x and the y coordinates where the mouse has been pressed? WM_MOUSEMOVE will tell you; infact:
    WM_MOUSEMOVE
    fwKeys = wParam; // key flags
    xPos = LOWORD(lParam); // horizontal position of cursor
    yPos = HIWORD(lParam); // vertical position of cursor

    Here is all that you need :-D

    Point number 2: first of all, we have to check whether a cell hides a bomb; this is not a problem because we know where the program stores the grid in memory and, we will easily perform this check but... how can I reveal a bomb under a cell? The answer is inside Graphics Device Interface (GDI) library; in this specific case we will use GDI to display a bitmap. My new version of the game displays the image that has the bomb on the red background (open the program with a resource editor, you will find the image I am talking about under "Bitmap-410-1033"). You can display the image you prefer taken from the proggie or created by you. To display this image I use these functions: GetDC, BitBlt, ReleaseDC.

    GetDC: retrieves a handle of a display Device Context (DC) for the client area of the specified window.
    HDC GetDC(
    HWND hWnd // handle of window
    );

    This is the first function we have to call and it takes a single parameter. How do we know the handle of the window? Simple, these 3 functions are used by MineSweeper and so, the best way to understand how to use them is to bpx them and to look how they are used. This time, put a bpx on GetDC and run again the program. Ollydbg will surely break and the only thing you have to do is to take note of the address that contains the handle...

    BitBlt: it clips an image from a source DC to a destination DC.
    BOOL BitBlt(
    HDC hdcDest,// handle to destination DC, the GetDC returned address
    int nXDest, // x-coordinate of destination rectangle's upper-left corner
    int nYDest, // y-coordinate of destination rectangle's upper-left corner
    int nWidth, // width of destination rectangle
    int nHeight,// height of destination rectangle
    HDC hdcSrc, // handle to source device context
    int nXSrc, // x-coordinate of source rectangle's upper-left corner
    int nYSrc, // y-coordinate of source rectangle's upper-left corner
    DWORD dwRop // raster operation code
    );

    As before, the best way for to understand how to use the function is to bpx it on Ollydbg. If you want to display another image you have to change the 6 parameter: hdcSrc.

    ReleaseDC: the ReleaseDC function releases a device context
    int ReleaseDC(
    HWND hWnd, // handle of window
    HDC hDC // handle of device context
    );


    Ok, it's time to past the source of the revealCell procedure (add it to the code I gave you before):
    Code:
    .data 
    oldRow	db	"01004998"
    oldColumn	db	"0100499C"
    
    ; Display the image under a cell
    revealCell proc
       pushad
    
       ; Is the mouse pointer inside the grid ?
       .IF word ptr [ebp+14h] < 0Ch || word ptr [ebp+16h] < 37h
          jmp @exitRevealCell
       .endif
    	
       xor eax, eax
       mov ax, word ptr [ebp+14h]   ; The x-coord of the mouse
       sub eax, 0Ch	
       shr eax, 4
       add eax, 1   ; The number of the column -inside the grid-  where the mouse is pressed
    
       xor ebx, ebx
       mov bx, word ptr [ebp+16h]	; The y-coord of the mouse
       sub ebx, 37h
       shr ebx, 4
       add ebx, 1   ; The number of the row where the mouse is pressed
    
       mov edi, 1004998h
       .IF ax == word ptr [edi] && bx == word ptr [edi+4]	
          ; It's in the same cell than before, no need to display the same image again
          jmp @exitRevealCell   
       .ENDIF
    
       mov ecx, ebx
       mov edx, ecx
       shl edx, 5
       mov ebx, 1005700h
       add ebx, eax
       add ebx,edx
       ; Reveal the cell if and only if there is an hidden bomb
       .IF byte ptr [ebx]  == 8Fh
          mov edi, 1004998h
          mov dword ptr [edi], eax	; Save the column
          mov dword ptr [edi+4], ecx	; Save the row
          push eax
          push ecx
          mov esi, 10052A8h   ; Pointer to handle of window
          push [esi]   ; Handle of window
          call GetDC
          mov esi, eax
          pop ecx
          pop eax
          shl ecx, 4
          add ecx, 27h
          shl eax, 4
          sub eax, 4
          mov ebx, 1005AE0h
          push 0CC0020h   ; SRCCOPY flag
          push 0
          push 0
          push [ebx+48] ; Source DC, the image to display
          push 10h        ; Height of the rectangle
          push 10h        ; Width of the rectangle
          push ecx        ; y coord
          push eax        ; x coord
          push esi         ; Handle to destination DC
          call BitBlt
          mov ebx, 10052A8h
          push esi               ; Handle of DC
          push dword ptr [ebx]   ; Handle of window
          call ReleaseDC
       .ELSE
          mov dword ptr [edi], 0
          mov dword ptr [edi+4], 0
       .ENDIF	
    	 
       @exitRevealCell:
       popad
    ret
    revealCell endp
    I think that's all...

    Ciao,
    ZaiRoN
    Last edited by ZaiRoN; October 7th, 2003 at 12:31.

  12. #12
    Musician member evaluator's Avatar
    Join Date
    Sep 2001
    Posts
    1,517
    Blog Entries
    1
    because of your good tries for newbies, i done gift for you.
    Attached Files Attached Files

  13. #13
    advant
    Guest

    Injection Tutorial

    What is a good tutorial on learning how to add the DLL into the import table and how to add code to an exe without corrupting the image and static references to code already there?
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  14. #14
    advant
    Guest

    One more thing...

    Also, how do you patch the memory to add a new compare for the WM_COMMAND.

    thanks
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  15. #15
    There is a final tutorial for this project at http://www.woodmann.com/fravia/what_new.htm
    Another tutorial that may help you is http://www.woodmann.com/fravia/kayaker_RegmonPlus.htm

    Foreigner

Similar Threads

  1. old game
    By ronald in forum The Newbie Forum
    Replies: 4
    Last Post: December 22nd, 2011, 00:40
  2. InTether Protection System Reversing...Reversing Kernel Code
    By tHE mUTABLE in forum Advanced Reversing and Programming
    Replies: 1
    Last Post: December 20th, 2007, 10:48
  3. A Clean Sweep on Minesweeper (Botting)
    By L. Spiro in forum Mini Project Area
    Replies: 8
    Last Post: December 7th, 2006, 14:25
  4. game training
    By tdennist in forum The Newbie Forum
    Replies: 7
    Last Post: November 17th, 2004, 06:22
  5. bug in a game
    By Dj Heiko in forum The Newbie Forum
    Replies: 15
    Last Post: February 24th, 2004, 16:29

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •