1. Sample overview
one point one Application information
Application Name: mine clearance
Size: 119808 bytes
File version: 5.1.2600.0 (xpclient.010817-1148)
Revised on: November 29, 2021, 8:34:38
MD5: 16A4FD569A3EB5CEBEB3DA99EF1D17E1
SHA1: 31A1A89BA067EA95F117754818429D6D8E8E59CF
CRC32: 43242150
Brief function introduction:
Click the chessboard with the left mouse button, and the box will become a number. Infer the number of surrounding mines through the numbers. The right mouse button can mark mines. If you point to mines, you will directly fail. After turning all the numbers, you can win
one point two Analysis environment and tools
Tool: Cheat engine Ollydbg VS2019
one point three Analysis objectives
1. Obtain the coordinates of the mouse. When the mouse hovers over the chessboard, it will display whether the current selection is thunder
2. Click a key to automatically click all non thunder squares and mark thunder with a red flag
2. Specific analysis process
2.1 general idea
1. Dynamic debugging (starting from API)
(1) Break points on the api, and then debug dynamically
(2) Use debugging tools such as OD or x32Dbg to debug
2. Start data analysis based on some data of mine clearance procedure (start with data)
(1) Data analysis, try to find changing data
(2) It is convenient to use CE tools to search data
2.2 collecting information
Open exeinfo and drag the program into exeinfo
vc++7.1 compiler version is 7.0, and the probability is vs2003
Analysis using the pe view tool
It is found that the msvcrt.dll dynamic library is loaded, which is the Microsoft runtime library. Most of the code with this runtime is the SDK program
Obtain key data of mine clearance through CE
Click mine detection to customize the height, width and number of mines, so we use CE to search the data
Through the scanning of ce, we get the basic information, which is helpful for us to write a dll Dynamic Library in the later stage
We speculate that the data is placed in the data segment. Looking at the section table, we find that the data segment is 0x5000(RVA) to 0xB98. The width height thunder number minus the base address (0x01000000 unopened random base address) rva in the above figure hits in the. Data segment
Therefore, we searched the memory and found that each time we clicked smiley face, a large area of memory would change. After analysis, we came to a conclusion
This is the two-dimensional array of the chessboard. After carefully analyzing the elements inside, we can get the following data
2D array first address 0x1005340
40 empty
41 1
42 2
43 3
8f ray
of unselected box
0e is the flag
Cc is the thunder after clicking
According to the preliminary analysis, we have obtained a lot of useful data. Next, let's look at the specific implementation with OD
2.3 OD debugging find callback function
- The SDK program needs to register the window class before creating the window, that is, the RegisterClassW function. Its only parameter is the pointer to the WNDCLASS structure, and the second parameter of this structure is the address of our window callback function
Set the mouse click breakpoint on the callback function
The parameter is assumed to be winproc
Set the conditional breakpoint of left mouse click, because each time you click the mouse to turn the grid
2.4 code for finding screen coordinate to array subscript
Next, we need to clarify what the purpose is. We need to find out how the screen coordinates are converted into array subscripts
Click the mouse and the interface will be broken. See that lparam parameter is the coordinate of our mouse. We should always pay attention to this address and see where to access it
According to the analysis, we found that this place is the code for converting screen coordinates to array subscripts
3. Script mine clearance
3.1 ideas
(1) Using SetWindowLong function to replace the original callback function, we can intercept us in our code
Concerned about the program and do the corresponding processing
(2) Using dynamic library injection technology, we inject our own dll into the target program
(3) Assist us to complete the code according to the information we have collected
// dllmain.cpp: defines the entry point for the DLL application. #include "pch.h" #include <Windows.h> #include <Math.h> //Function pointer of callback function typedef LRESULT(CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM); //Replaced window callback LRESULT CALLBACK MyWindowProc(HWND hwnd, // handle to window UINT uMsg, // message identifier WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ); //Open window handle HANDLE hProcess = NULL; //Own module handle HMODULE g_hMod = NULL; //Original window procedure function WNDPROC g_pfnOldWndProc = NULL; void init();//initialization BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: g_hMod = hModule; init(); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; } //Callback function to inject dll LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch (uMsg) { case WM_KEYDOWN: if (wParam == VK_F5) { //Height of minesweeping array PDWORD hight = (PDWORD)0x1005338; //Width of minesweeping array PDWORD width = (PDWORD)0x1005334; DWORD array = 0x1005340;//Array header address char* szBuf = (char*)array; //Traversing minesweeping array for (int i = 0; i <= *width; i++) { for (int j = 0; j <= *hight; j++) { if ((unsigned char)*((szBuf + j * 32) + i) == 0xf) { int xPos = (i << 4) - 4; int yPos = (j << 4) + 0x27; SendMessage(hwnd, WM_LBUTTONDOWN, 0,MAKELPARAM(xPos, yPos)); SendMessage(hwnd, WM_LBUTTONUP, 0, MAKELPARAM(xPos, yPos)); } if ((unsigned char)*((szBuf + j * 32) + i) == 0x8f) { int xPos = (i << 4) - 4; int yPos = (j << 4) + 0x27; SendMessage(hwnd, WM_RBUTTONDOWN, 0, MAKELPARAM(xPos, yPos)); SendMessage(hwnd, WM_RBUTTONUP, 0, MAKELPARAM(xPos, yPos)); } } } } break; case WM_MOUSEMOVE: { //Corresponding to the code of mouse cursor conversion array subscript in assembly DWORD temp = (DWORD)lParam; DWORD posX = temp & 0xffff; DWORD posY = (temp & 0xffff0000)>>0x10; posX = (posX + 4) >> 4; posY = (posY - 0x27) >> 4; //Take the width and height of the current minesweeping array PDWORD hight = (PDWORD)0x1005338; PDWORD width = (PDWORD)0x1005334; //Determine whether the converted subscript is on our valid grid if ((posX > 0 && posX <= *hight) && (posY > 0 && posY <= *width)) { DWORD array = 0x1005340;//Array header address char* szBuf = (char*)array; //Change window title if ((unsigned char)*((szBuf+ posY *32)+ posX) == 0x8f) { SetWindowText(hwnd, L"Don't cry"); } else { SetWindowText(hwnd, L"Order, order"); } } break; } } return g_pfnOldWndProc(hwnd, uMsg, wParam, lParam); } void init() { HWND hWnd = FindWindow(L"mine clearance", L"mine clearance"); if (hWnd == NULL) { OutputDebugString(L"Handle acquisition failed"); return; } DWORD dwProcid = 0; GetWindowThreadProcessId(hWnd, &dwProcid); hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwProcid); //Replace callback function g_pfnOldWndProc = (WNDPROC)SetWindowLong(hWnd,GWL_WNDPROC,(LONG)MyWindowProc); }