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