Delphi World - Описание метода взлома игры FlashPoint
Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Описание метода взлома игры FlashPoint

Автор: FreeExec

Проанализировав содержимое файла OperationFlashpoint.exe, я обнаружил, что названия сегментов не содержат не одного символа и экспортируется минимальный набор функций из модулей KERNEL32.DLL, USER32.dll: LoadLibraryA, GetProcAddress, VirtualProtect, ExitProcess, MessageBoxA. Так обычно поступают, чтобы скрыть содержимое файла от всяких дисассемблеров, т.е. когда файл запакован.

Далее запускаю SoftICE и ставлю брекпоинт на функцию определения типа устройства (bpx GetDriveTypeA). Вставляем CD и запускаем игру. Убеждаемся, что функцию вызвала игра, а не explorer.exe. Дальше жму F5 пока эту функцию не вызовут с параметром указывающий путь к CD.


00011E2: lea eax,[ebp][-000C] 
00011E5: push eax 
00011E6: call d,[000407018] ; GetDriveTypeA 
00011EC: mov dl,al ; al=05 тут мы оказались после выхода из функ. 
00011EE: lea edi,[ebp][0FFFFF254] ; ссылка на буфер с меткой тома диска 
00011F4: or ecx,-001 
00011F7: xor eax,eax 
00011F9: repne scasb 
00011FB: not ecx 
00011FD: dec ecx ; ecx равен длине метки 
00011FE: add ecx,esi ; esi соответствует адресу на 4 байта меньше чем адрес буфера, т..е обработке подлежат последние 4 символа 
0001200: mov bl,[eax][ecx] 
0001203: add bl,dl 
0001205: mov [eax][ecx],bl ;увеличивают символы на 5(вернула функ.) позиций дальше 
0001208: inc eax 
0001209: cmp eax,004 ; всего 4 символа 
000120C: jl 000001200 -------- (2) 
000120E: mov ecx,[ebp][-0010] 
0001211: lea edx,[ebp][0FFFFFD1F] 
0001217: push ecx 
0001218: lea eax,[ebp][0FFFFF254] 
000121E: push edx 
000121F: push eax 
0001220: call 0000014C0 -------- (3) ; эта функция сравнивает два буфера переданные ей в параметрах 
0001225: add esp,00C 
0001228: test eax,eax 
000122A: jne 0000012D5 -------- (4) 
Функция (3) возвращает 0, если буфера одинаковые, и значит (4)-ый переход не осуществляется. 
:00401230 lea ecx, dword ptr [ebp-6C] 
:00401233 push ecx 
:00401234 call dword ptr [00407014] ; GetStartupInfoA 
:0040123A xor eax, eax 
:0040123C mov cl, byte ptr [ebp+eax-00000179] ; mrc32.dll 
:00401243 mov byte ptr [ebp+eax-00000DAC], cl 
:0040124A inc eax 
:0040124B test cl, cl 
:0040124D jne 0040123C 
:0040124F lea edi, dword ptr [ebp+FFFFF254] 
:00401255 or ecx, FFFFFFFF 
:00401258 xor eax, eax 
:0040125A mov dx, word ptr [004080C0] 
:00401261 repnz 
:00401262 scasb 
:00401263 or ecx, FFFFFFFF 
:00401266 mov word ptr [edi-01], dx 
:0040126A mov edi, dword ptr [ebp+10] 
:0040126D repnz 
:0040126E scasb 
:0040126F not ecx 
:00401271 sub edi, ecx 
:00401273 lea edx, dword ptr [ebp+FFFFF254] 
:00401279 mov esi, edi 
:0040127B mov ebx, ecx 
:0040127D mov edi, edx 
:0040127F or ecx, FFFFFFFF 
:00401282 repnz 
:00401283 scasb 
:00401284 mov ecx, ebx 
:00401286 dec edi 
:00401287 shr ecx, 02 
:0040128A repz 
:0040128B movsd 
:0040128C mov ecx, ebx 
:0040128E lea eax, dword ptr [ebp-28] 
:00401291 and ecx, 00000003 
:00401294 push eax ; struct _PROCESS_INFORMATION 
:00401295 repz 
:00401296 movsb 
:00401297 lea ecx, dword ptr [ebp-6C] 
:0040129A lea edx, dword ptr [ebp+FFFFF254] 
:004012A0 push ecx ; struct _STARTUPINFO 
:004012A1 push 00000000 
:004012A3 push 00000000 
:004012A5 push 00000004 
:004012A7 push 00000000 
:004012A9 push 00000000 
:004012AB push 00000000 
:004012AD push edx ; mrc32.dll 
:004012AE push 00000000 
:004012B0 call dword ptr [00407010] ; CreateProcess 
:004012B6 test eax, eax 
:004012B8 jne 00401307 
... 
:00401307 mov ecx, dword ptr [ebp+FFFFFCF8] 
:0040130D mov edx, dword ptr [ebp-28] 
:00401310 lea eax, dword ptr [ebp-08] 
:00401313 add ecx, 00400000 
:00401319 push eax ; буфер, сюда вернут старые права 
:0040131A push 00000040 ; новый код доступа, 40h=PAGE_EXECUTE_READWRITE 
:0040131C push 00000100 ; размер 
:00401321 push ecx ; адрес региона для изменения доступа к странице памяти 
:00401322 push edx ; HANDLE hProcess из struct _PROCESS_INFORMATION 
:00401323 call dword ptr [0040700C] ; VirtualProtectEx 
:00401329 test eax, eax 
:0040132B jne 00401348 
… 
:00401348 mov edx, dword ptr [ebp+FFFFFCF8] 
:0040134E lea eax, dword ptr [ebp-08] 
:00401351 push eax ; буфер, сюда вернут количество записанных байт 
:00401352 mov eax, dword ptr [ebp-28] 
:00401355 lea ecx, dword ptr [ebp+FFFFFD70] 
:0040135B push 00000100 ; размер буфера 
:00401360 add edx, 00400000 
:00401366 push ecx ; адрес – откуда скопировать (12FCA4) 
:00401367 push edx ; адрес – куда писать (44CCBF) 
:00401368 push eax ; HANDLE hProcess 
:00401369 call dword ptr [00407008] ; WriteProccessMemory 
:0040136F test eax, eax 
:00401371 je 0040137C 
:00401373 cmp dword ptr [ebp-08], 00000100 
:0040137A je 00401398 ; осуществляется прыжок 
… 
:00401398 mov ecx, dword ptr [ebp-24] 
:0040139B push ecx ; HANDLE hThread 
:0040139C call dword ptr [00407004] ; ResumeThread 
:004013A2 mov edx, dword ptr [ebp-28] 
:004013A5 push FFFFFFFF ; количество миллисикунд 
:004013A7 push edx ; HANDLE hHandle 
:004013A8 call dword ptr [00407000] ; WaitForSingleObject 

Теперь разберемся во всех вызывающихся функциях. GetStartupInfo нужна для получения одноименной структуры, требующейся для функции создания процесса - CreateProcess. Создаем процесс используя файл mrc32.dll, он то и есть ядро игры. Затем функцией VirtualProtectEx назначаем новые права коду загруженного модуля, а именно разрешаем выполнять этот код. Потом туда копируем код из адреса 12FCA4, и передаем управление созданному процессу, функцией WaitForSingleObject. Единственная трудность это получить код который мы копируем для исполнения. Можно было конечно переписать эти 256 байт и руками, но я сделал по другому.

Вставляю CD, ставлю брекпоинт на функцию GetDriveTypeA (bpx GetDriveTypeA), запускаю игру. После вылета в функцию, ставлю еще один брекпоинт (bpx 401355),жму F5. Теперь мне нужны адреса трех функций CreateFileA, WriteFile, ExitProcess. Получаю их поможью команды EXP (exp CreateFileA), в ответ должно быть что-то такое:


exp CreateFileA 
KERNEL32 
001B:77E7A837 CreateFileA 
exp WriteFile 
KERNEL32 
001B:77E79D8C WriteFile 
exp ExitProcess 
KERNEL32 
001B:77E75CB5 ExitProcess 

Затем задаю параметры первой функции, прямо в стек.


d esp ## показать стек 
e ## начать редактировать его 

Должно это выглядеть как-то так. Функция на языке Си выгледит так: CreateFileA(&filename, 0x40000000, 0, 0, 2, 0x80, 0); 8C 9D E7 77 – это адрес возврата (на функцию WriteFile = 77E79D8C), туда попадаем после завершения функции CreateFileA. По адресу 0012E198 (98 E1 12 00) находится имя файла завершающееся нулевым символом. Этот файл должен сущуствовать. Теперь ставим указатель на начало функции CreateFileA.


r eip=77E7A837 # изменяем значение регистра EIP 
bpx WriteFile # что отловить момент когда завершится первая функция 

Жму F5. Если все нормально, то должен остановится на первой команде функции WriteFile, а EAX не равняться FFFFFFFF, потому что это код ошибки. У меня EAX=000007CC, это хэндл на только что созданный файл. Задаю параметры второй функции, прямо в стек.


d esp ## показать стек 
e ## начать редактировать его 

Должно это выглядеть как-то так. Функция на языке Си выгледит так: WriteFile(hHandle, 0x0012FCA4, 100, 0x0012E1C8, 0); где hHandle=0x7CC, 0x0012FCA4 – адрес буфера ради которого все и затеял, 100 его размер, 0x0012E1C8 – сюда напишут сколько реально записали байт. 5B 5C E7 77 – это адрес возврата (на функцию ExitProcess = 77E75CB5), туда попадаем после завершения функции CreateFileA. Теперь у меня есть все чтобы с имитировать запуск игры, т.е. написать загрузчик самому без всяких выкрутасов.

Приведен пример загрузчика:
File calldll.asm


.386 
.model flat, stdcall 
option casemap :none ; case sensitive 
include \masm32\include\windows.inc 
include \masm32\include\user32.inc 
include \masm32\include\kernel32.inc 
includelib \masm32\lib\user32.lib 
includelib \masm32\lib\kernel32.lib 
.data? 
buff db 100h dup (?) 
prin db 100h dup (?) 
.code 
start: 
jmp @F 
libName db "mrc32.dll",0 
include patch.inc 
@@: 

push offset buff 
call GetStartupInfo 
  
push offset prin 
push offset buff 
push 0 
push 0 
push 4 
push 0 
push 0 
push 0 
push offset libName 
push 0 
call CreateProcess 
mov eax, offset [prin+20h] 
push eax 
push 000040h 
push 000100h 
mov ecx, 44CCBFh 
push ecx 
mov eax, dword ptr [prin] 
push eax 
call VirtualProtectEx 
mov eax, offset [prin+20h] 
push eax 
push 000100h 
push offset patch 
push 44CCBFh 
mov eax, dword ptr [prin] 
push eax 
call WriteProcessMemory 
mov eax, dword ptr [prin+4] 
push eax 
call ResumeThread 
push 0000FFh 
mov eax, dword ptr [prin] 
push eax 
call WaitForSingleObject 
invoke ExitProcess,eax 
end start 

file patch.ini


patch: 
db 055h,08Bh,0ECh,06Ah,0FFh,068h,018h,024h,06Eh,000h,068h,0ECh,020h,06Ch,000h,064h 
db 0A1h,000h,000h,000h,000h,050h,064h,089h,025h,000h,000h,000h,000h,083h,0ECh,058h 
db 053h,056h,057h,089h,065h,0E8h,0FFh,015h,00Ch,052h,06Ch,000h,033h,0D2h,08Ah,0D4h 
db 089h,015h,0C8h,070h,077h,000h,08Bh,0C8h,081h,0E1h,0FFh,000h,000h,000h,089h,00Dh 
db 0C4h,070h,077h,000h,0C1h,0E1h,008h,003h,0CAh,089h,00Dh,0C0h,070h,077h,000h,0C1h 
db 0E8h,010h,0A3h,0BCh,070h,077h,000h,033h,0F6h,056h,0E8h,0CAh,052h,0FFh,0FFh,059h 
db 085h,0C0h,075h,008h,06Ah,01Ch,0E8h,06Fh,04Eh,027h,000h,059h,089h,075h,0FCh,0E8h 
db 0B9h,062h,0FFh,0FFh,0FFh,015h,0D8h,051h,06Ch,000h,0A3h,064h,08Bh,077h,000h,0E8h 
db 08Fh,02Ah,0FFh,0FFh,0A3h,0FCh,070h,077h,000h,0E8h,0A3h,0A0h,0FFh,0FFh,0E8h,037h 
db 0A1h,0FFh,0FFh,0E8h,0F4h,036h,0FFh,0FFh,089h,075h,0D0h,08Dh,045h,0A4h,050h,0FFh 
db 015h,010h,052h,06Ch,000h,0E8h,0FEh,0FEh,0FFh,0FFh,089h,045h,09Ch,0F6h,045h,0D0h 
db 001h,074h,006h,00Fh,0B7h,045h,0D4h,0EBh,003h,06Ah,00Ah,058h,050h,0FFh,075h,09Ch 
db 056h,056h,0FFh,015h,0E8h,050h,06Ch,000h,050h,0E8h,099h,087h,0FDh,0FFh,089h,045h 
db 0A0h,050h,0E8h,0F3h,036h,0FFh,0FFh,08Bh,045h,0ECh,08Bh,008h,08Bh,009h,089h,04Dh 
db 098h,050h,051h,0E8h,060h,001h,000h,000h,059h,059h,0C3h,08Bh,065h,0E8h,0FFh,075h 
db 098h,0E8h,0C3h,036h,0FFh,0FFh,083h,03Dh,004h,071h,077h,000h,001h,075h,005h,0E8h 

file compl.bat


@echo off 
e:\masm32\bin\ml /Zf /Zi /c /coff /w calldll.asm 
if errorlevel 1 goto exit 
echo _ 
echo MASM32 OK ************************************************* 
echo _ 
e:\masm32\bin\Link /DEBUG /SUBSYSTEM:WINDOWS calldll.obj 
:exit 
pause 

Весь архив можно скачать (и он вроде даже работает :)

Проект Delphi World © Выпуск 2002 - 2017
Автор проекта: Эксклюзивные курсы программирования