скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

Описание метода взлома игры 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 






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook