italy 19-1o-2oo3
Minesweeper Reversing
A simple exercize
 
written by ZaiRoN

 
Introduction:
Minesweeper is one of the millions M$ games and in this tutorial I will explain you how to add a new feature on the game. The new feature will give you the ability to view where the bombs are.
 
Literature:
http://www.woodmann.net/fravia/menusspa.htm
http://www.woodmann.net/fravia/TracePlus_MenuPatch.html
http://www.woodmann.net/fravia/kayaker_RegmonPlus.htm
http://www.codeguru.com/mfc/comments/50642.shtml
 
Target:
MineSweeper (English version for WinXP/W2k)
 
Program description:
Don't you ever played with this game in your boring days? I can't believe you :-p
 
Tools:
- a debugger (Ollydbg)
- a disassembler (Ida)
- a resource editor (Resource Hacker)
- Spy++
- c and asm compiler (lcc, masm)
music: Black Sabbath - Black Sabbath
 
Included file (containing files and resources mentioned in this tut):

zaiwinmine.zip

Preamble
We will show where the bombs are as a *mouse-over* effect as the cursor moves over each grid square. We will add all the modifications inside a dll and we will write a loader to patch the program in memory. This is not only a reversing exercize but also a programming exercize because you will have to code a dll, work with GDI and finally write a little loader. This tutorial is a resume (with some differences) of a project at the RCE board, you can find the thread here.
We start finding all the places where we will have to put a jump to our code; after that we will write the code to add to the program, we will write the dll and finally a little loader.
 
Find the point where to add the new menu item
We should be able to pass from normal to cheat mode (and viceversa) therefore the best way is to use a new menu item. I will add the new item inside 'Game' menu, after the 'New' item.
We can use a resource editor but remembering that we need to patch the file in memory, we have to think in a different way. How can I add a new item into an existing menu? We can use the function InsertMenuItem. This function will be placed into a cave with all the other modifications needed by the program. We will see later how to use this function, for the moment you only have to know that InsertMenuITem will be called in the initialization part of the program, exactly after the menu has been loaded (because it needs the menu handle...). 
Now, we should find the place where to insert the jump to the new cave. The program uses LoadMenu to load the menu:
 
:010014B9 push 1F4h   <------- lpMenuName
:010014BE push hInstance   <-- hInstance
:010014C4 call ds:LoadMenuW
:010014CA push 1F5h   <------- lpTableName
:010014CF mov hMenu, eax
:010014D4 push hInstance   <-- hInstance
:010014DA call ds:LoadAcceleratorsW
:010014E0 mov [ebp+hAccTable], eax
:010014E3 call sub_10023DB
:010014E8 mov eax, dword_10052A4
:010014ED mov ecx, yBottom

When the menu has been loaded you can insert the new item, I decided to put a jump to the code that will call the InsertMenuItem directly at 10014E8. I did choose this particular address only because it has the same number of bytes of the new jump instruction...
 
Find the point where the program checks whether a menu item has 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' item, 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:
 
:01001472 mov [ebp+WndClass.style], edi   <----------------------- style param
:01001475 mov [ebp+WndClass.lpfnWndProc], offset sub_100180A   <-- lpfnWndProc param, our address is 100180A
:0100147C mov [ebp+WndClass.cbClsExtra], edi   <------------------ cbClsExtra param
:0100147F mov [ebp+WndClass.cbWndExtra], edi   <------------------ cbWndExtra param
:01001482 mov [ebp+WndClass.hInstance], ecx   <------------------- hInstance param
:01001485 mov [ebp+WndClass.hIcon], eax   <----------------------- hIcon param
:01001488 call ds:LoadCursorW
:0100148E push ebx ; int
:0100148F mov [ebp+WndClass.hCursor], eax   <--------------------- hCursor param
:01001492 call ds:GetStockObject
:01001498 mov [ebp+WndClass.hbrBackground], eax   <--------------- hbrBackground param
:0100149B lea eax, [ebp+WndClass]
:0100149E mov esi, offset AppName
:010014A3 push eax ; lpWndClass
:010014A4 mov [ebp+WndClass.lpszMenuName], edi   <---------------- lpszMenuName param
:010014A7 mov [ebp+WndClass.lpszClassName], esi   <--------------- lpszClassName param
:010014AA call ds:RegisterClassW   <------------------------------ RegisterClassW

Ok, now that we 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 (the one you have clicked on) in the loworder word of the wParam parameter. 
Take a look at the first part of the window procedure:

: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:
 
:010018B7 MOV EAX,111
:010018BC CMP ECX,EAX   <-------------------- Is WM_COMMAND received?
:010018BE JA winmine.01001B3F
:010018C4 JE winmine.010019AD   <------------ We jump if a WM_COMMAND has been received
    ...
:010019AD MOV ECX,DWORD PTR SS:[EBP+10]   <-- ecx is the wParam
:010019B0 MOVZX EAX,CX   <------------------- eax is the item identifier 
:010019B3 CMP EAX,20B   <-------------------- Is "Expert" item clicked?
:010019B8 JG SHORT winmine.01001A30
:010019BA CMP EAX,209   <-------------------- Is "Beginner" item clicked?
:010019BF JGE SHORT winmine.010019EE

This piece of code is what we were looking for; since we will have to check whether the new menu item has been clicked, we will change the jump at 10018C4 into a new jump. We will see later how the code will look like.
 
Find the point where the program checks whether a WM_MOUSEMOVE has been received
This is necessary because from here we will jump to the dll function that shows a possible bomb. In order to find the place where the program checks for WM_MOUSEMOVE message we will change the conditional breakpoint; the new condition will be: [EBP+0Ch]==200H
 
:01001B3F MOV EAX,DWORD PTR SS:[EBP+C]   <-- the received message
:01001B42 MOV ESI,200   <------------------- 200h = WM_MOUSEMOVE
:01001B47 PUSH 1
:01001B49 XOR EDI,EDI
:01001B4B CMP EAX,ESI   <------------------- is WM_MOUSEMOVE received?
:01001B4D POP EBX
:01001B4E JA SHORT winmine.01001BB4
:01001B50 JE winmine.01001DD5   <----------- yes, WM_MOUSEMOVE received

Stepping a little you will see that this type of message is not so useful for the original program therefore we will change the jump at 1001B50.
 
How to modify the Minesweeper process
First of all we have to find a place where we will go to insert the new code; there are many caves inside the file, you must only choose one of them. I will add the new code starting from 10049A5h. What does this new code is supposed to do? It adds the new item menu and then it simply calls a function from our dll.
InsertMenuItem is not imported by the program and so we will have to use the combination of LoadLibrary/GetProcAddress functions. To use these two functions is pretty easy.
 
LoadLibrary: it's the first function to use and it maps the dll module into the address space of the calling process. The function returns a handle that can be used in GetProcAddress to get the address of a dll function.
HINSTANCE LoadLibrary( 
   LPCTSTR lpLibFileName   // address of the string that names the executable module 
);
 
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 
);
 
Now that you know how to call InsertMenuItem we can see how this function looks like:
 
BOOL WINAPI InsertMenuItem(
   HMENU hMenu,           // Handle to the menu in which the new menu item is inserted 
   UINT uItem,            // Identifier or position of the menu item before which to insert the new item 
   BOOL fByPosition,      // If FALSE, uItem is a menu item identifier. Otherwise, it is a menu item position 
   LPMENUITEMINFO lpmii   // Pointer to a MENUITEMINFO structure that contains information about the new menu item 
);
 
and:
 
typedef struct tagMENUITEMINFO { 
   UINT cbSize;             // Size of structure, in bytes  
   UINT fMask;              // Members to retrieve or set
   UINT fType;              // Menu item type  
   UINT fState;             // Menu item state  
   UINT wID;                // Application-defined 16-bit value that identifies the menu item 
   HMENU hSubMenu;          // Handle to the drop-down menu or submenu associated with the menu item 
   HBITMAP hbmpChecked;     // Handle to the bitmap to display next to the item if it is checked 
   HBITMAP hbmpUnchecked;   // Handle to the bitmap to display next to the item if it is not checked  
   DWORD dwItemData;        // Application-defined value associated with the menu item 
   LPTSTR dwTypeData;       // Content of the menu item 
   UINT cch;                // Length of the menu item text 
} MENUITEMINFO, FAR *LPMENUITEMINFO;
 
Even if there are alot of parameters, the use of this function is pretty easy.
This is the code you have to inject into the Minesweeper program: 

:010049A5 ; Initial address of the cave I chose 
:010049A5 dword_10049A5   dd 0                  ; specialMode=08h if specialMode is enable otherwise specialMode=00h
:010049A6 aZaiwinmine_dll db 'zaiWinmine.dll',0 ; The name of the new DLL
:010049B5 aUser32_dll     db 'User32.dll',0     ; InsertMenuItem is inside USer32.dll
; The name of the 2 exported functions:
:010049C0 aChangeitemstat db 'changeItemStatus',0 ; Changes the status of the itemmenu
:010049D1 aRevealcell     db 'revealCell',0       ; Reveals a bomb under a cell
:010049DC dword_10049DC   dd 0                    ; Stores the address of changeItemStatus function
:010049E0 dword_10049E0   dd 0                    ; Stores the address of revealCell function
:010049E4 aInsertmenuitem db 'InsertMenuItemA',0
:010049F4 aSpecialMode    db 'Special Mode',0     ; Text to be place in the new menu item
; MENUITEMINFO structure:
:01004A01 dd 2Ch      ; Size of structure: 11 dwords = 2Ch bytes
:01004A05 dd 42h      ; MIIM_ID + MIIM_STRING
:01004A09 dd 0        ; MFT_STRING, displays the menu item using a text string
:01004A0D dd 0        ; Default state
:01004A11 dd 212h     ; Id of the new item
:01004A15 dd 0        ; NULL because the item does not open a drop-down menu or submenu
:01004A19 dd 0        ; NULL, default check mark
:01004A1D dd 0        ; NULL
:01004A21 dd 0        ; NULL
:01004A25 dd 10049F4h ; The pointer to a null-terminated string that defines the text of the new item
:01004A29 dd 4        ; The length of the string 
 
:01004A2D ; From initialization (10014E8): we add the new item and save the address of changeItemStatus and revealCell
:01004A2D push offset loc_10014ED     ; Address from where to return to
:01004A32 pusha
:01004A33 push offset aUser32_dll     ; "User32.dll"
:01004A38 call ds:LoadLibraryA        ; Maps User32.dll
:01004A3E push offset aInsertmenuitem ; "InsertMenuItemA"
:01004A43 push eax                    ; Handle to dll module
:01004A44 call ds:GetProcAddress      ; Get the address of the function
:01004A4A mov ebx, offset hMenu
:01004A4F push offset dword_1004A01   ; Pointer to a MENUITEMINFO structure 
:01004A54 push 0                      ; FALSE
:01004A56 push 0                      ; The position of the item
:01004A58 push dword ptr [ebx]        ; Handle to the menu 
:01004A5A call eax                    ; call InsertMenuItem
:01004A5C push offset aZaiwinmine_dll ; "zaiWinmine.dll"
, the name of the dll
:01004A61 call ds:LoadLibraryA
:01004A67 mov esi, eax
:01004A69 push offset aChangeitemstat ; "changeItemStatus"
:01004A6E push esi
:01004A6F call ds:GetProcAddress
:01004A75 mov ds:dword_10049DC, eax   ; Stores the address of changeItemStatus
:01004A7A push offset aRevealcell     ; "revealCell"
:01004A7F push esi
:01004A80 call ds:GetProcAddress
:01004A86 mov ds:dword_10049E0, eax   ; Stores the address of revealCell
:01004A8B popa
:01004A8C mov eax, dword_10052A4
:01004A91 retn                        ; Jump to the original code 
 
:01004A92 ; From 'specialMode' item clicked (10018C4): we call changeItemStatus  
:01004A92 push offset loc_10019AD     ; Address from where to return to
:01004A97 pusha
:01004A98 call ds:dword_10049DC       ; call changeItemStatus
:01004A9E jmp short loc_1004AB6
 
:01004AA0 ; From WM_MOUSEMOVE event (1001B50): we call revealCell
:01004AA0 push offset loc_1001DD5     ; Address from where to return to
:01004AA5 cmp ds:byte_10049A5, 0      ; Is the special mode enable?
:01004AAC jnz short loc_1004AAF       ; Yes, jump down
:01004AAE retn                        ; specialMode is disable, no need to show the bomb, jump back to the original code
:01004AAF pusha
:01004AB0 call ds:dword_10049E0       ; call revealCell
:01004AB6 popa
:01004AB7 retn                        ; Jump back to the original code

Now, we have to modify the instructions at 10014E8, 10018C4 and at 1001B50 because they have to jump to the new code:
 
:010014E8 jmp loc_1004A2D
:010018C4 jz loc_1004A92
:01001B50 jz loc_1004AA0
 
DLL functions
We have seen all the modifications we will have to add to the program; from now on, we will see how to write the 2 dll functions:
- changeItemStatus, this function will check/uncheck the menuitem enabling or disabling the special mode.
- revealCell, this function reveals a bomb under a cell.
 
changeItemStatus
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 the first function:

; 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

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
Why not 00h and 01h? That is because I use this address for store both the state of the item and the menu item flag.
 
revealCell
Before writing the function we must understand where the bombs are stored.
We need to find a way to break when a cell is clicked. Exploiting the work we have done before, 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:

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 manages 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. Enter the call and take a glance at it:
 
010037F2 MOV EDX,ECX   ; ecx stores the number of the row of the clicked cell, eax stores the column
010037F4 SHL EDX,5
010037F7 MOV DL,BYTE PTR DS:[EDX+EAX+1005700]   ; dl = value stores in the clicked cell
 
As you can see the first row is stored starting from 1005721 and it ends with the character with double value 0x10. Doing some tryes you will sooner understand which is the value that identify the bomb, it's 0x8F. 
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 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 
);
 
Easy. 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:

.data 
oldRow    db "0100499D"
oldColumn db "010049A1"
 
; 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, 100499Dh
   .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, 100499Dh
      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

 
Postamble: conclusion.
The tutorial ends here, you only have to write a loader which will load the program and add the new functionality in memory. I will not tell how to write a simple loader, you will find all the sources inside the attached file.
 
Playing with the new version of the game I have discovered a weird fact; set the special mode feature and make the first click over a bomb. Nothing happens, the bomb disappears; is there something wrong in our work? Eheh, no. Where the bomb has gone? (Hint: it is a specific characteristic of the program.. :-)) 
 
Greetings and thanks.
I would like to thank all the friends at RCE messageboard and all the UIC members. As usual, feel free to mail me for comments, suggestions, bug reports and/or whatever you want...         
ciao,
 
ZaiRoN
zaironcrk(at)hotmail.com 

Disclaimer
All the information given are for educational purposes only.