Сегодня мы будем играть в замечательную игру "Сапер". Правила у нее просты - тыкай пока не проиграешь =))
Я пошутил - играть мы не будем, мы напишем АнтиСапер, т.е. программку, которая будет разминировать минное поле этого самого сапера!
Для начала скопируем из системной папки сам файл winmine.exe. Осмотрим его внешне. Потыкаем по полю наугад .... ты попал на мину - проиграл, ну ладно, не беда! Смотрим верхнее меню, там есть пункт "Новая игра". Нажимаем и видим, что поле заполнено по-новому. Давайте посмотрим, что происходит по выбору этого пункта....
Загружаем Сапера в W32Dasm:
видим, что ID этого пункта меню равен [ID=01FEh]. В поиске вбиваем это значение, ищем... Находим это:
01001DD3 |.3D FE010000 CMP EAX, 1FE 01001DD8 |.0F84 EA000000 JE 01001EC8
именно тут и происходит выбор нашего пункта, идем по этому адресу. А тут:
01001EC8 |>E8 AD170000 CALL 0100367A
Хорошо, идем в эту процедуру... Она начинается так:
0100367A /$A1 AC560001 MOV EAX, DWORD PTR DS:[10056AC] 0100367F |.8B0D A8560001 MOV ECX, DWORD PTR DS:[10056A8]
По этим адресам лежат число клеток по X и Y, они (эти адреса) нам понадобятся!. Шагая по этой подпрограмме можно найти адрес с которого начинается рэндомно заполняющаяся карта... у меня он равен: 01005360h. Ну и начиная с этого адреса идут клетки поля, если в них находиться значение 8F, значит тут мина, иначе стоит FF, а начало и конец строки определяются как 10h, причем строчки находятся друг от друга на интервале 20h.
Этого нам достаточно для написания программы. На форме находится sg: TStringGrid...
Вот код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids;
type
TPole = record
x: Byte;
y: Byte;
End;
type
TForm1 = class(TForm)
Button1: TButton;
sg: TStringGrid;
procedure Button1Click(Sender: TObject);
private
SapMap: Tpole;
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
Var
hWn: HWND;
PID, hProc, dwReaded: DWord;
buf: Byte;
i, r: Dword;
StartAddr: Dword;
begin
hWn := HWND(FindWindow(nil, PChar('Сапер')));
If IsWindow(hWn) Then
Begin
GetWindowThreadProcessId(hWn, PID);
hProc := OpenProcess(PROCESS_VM_READ, False, PID);
Try
If (hProc <> 0) Then
Begin
ReadProcessMemory(hProc, ptr($10056AC), @buf, 1, dwReaded);
SapMap.x := buf;
ReadProcessMemory(hProc, ptr($10056A8), @buf, 1, dwReaded);
SapMap.y := buf;
sg.ColCount := SapMap.x;
sg.RowCount := SapMap.y;
For i := 0 To (sg.ColCount - 1) Do
For r := 0 To (sg.RowCount - 1) Do sg.Cells[i,r] := ' ';
StartAddr := $01005361;
For i := 0 To (SapMap.y - 1) Do
Begin
For r := 0 To (SapMap.x - 1) Do
Begin
ReadProcessMemory(hProc, ptr((i*$20) + StartAddr + r), @buf, 1, dwReaded);
If (buf = $8F) Then sg.Cells[r, i] := 'X';
End;
End;
End;
Finally
CloseHandle(hProc);
End;
End;
end;
end.
А вот результат ее работы:
Удачи!