10 января 2013 г.

Пишем самопальный чит к игре.

Итак, после длительного запоя решил написать небольшой пост как можно самому без помощи артманей и чит энджине делать свои читы к игре. Для примера возьмем один из моих самых любимы скроллеров, который есть практически на любой платформе под названием Open Tyrian.


Я проходил эту игру и с читами и без, так, что отложим моральную сторону, а будем делать маааленький реверс инжинеринг и можно будет посмотреть как вообще работают читы.

Для начала загружаем игру в OllyDbg и смотрим на состояние денег в игре, нам нужно найти количество  перевести его в 16чный формат и поискать в памяти. Изначально денег 10000 прикупив пару вещей доводим его до 6750, так будет проще искать.

Переводим это число в 16чный формат и получаем 1A 5E. Это число и будем искать в памяти, единственное, не забываем, что в x86 числа хранятся наоборот, тоесть искать надо будет 5E 1A. Но таких числе в памяти 2 вязанки, по этому необходимо сузить поиск, предположим, что число хранится в DWORD и значит перед числом будет 2 нуля. Итоговое значение которое ищем получается 00 00 5E 1A.
Переключаем OllyDBG в раздел памяти, нажимая по кнопочке M в верхней панели. По правой кнопки мыши вызываем панель поиска.
Вбиваем предполагаемое число и находим только одну похожу ячейку памяти. Смотрим на скрин ниже.
Очень похоже, что это именно то, что мы ищем. Меняем значение на FF FF FF FF и переключаемся в игру. В игре должно показываться что то типа такого:
Ага, это то что нам нужно, запоминаем адрес где лежит эта ячейка, в моей версии Tyrian она находится по адресу: 004E879E

Ну а теперь нада написать свой чит, который будет работать без правок руками.
Немного говнокода:

start:
    mov        eax, sizeof lprocentry ; вычисляем размер PROCESSENTRY32
    mov        lprocentry.dwSize, eax ; записываем его в PROCESSENTRY32.dwSize
    invoke    CreateToolhelp32Snapshot,TH32CS_SNAPPROCESS OR TH32CS_SNAPMODULE, NULL ; получаем снапшот списка процессов
    .if    eax == NULL
        jmp        errorExit ; если 0, то получить не удалось и выходим
    .endif
    mov        hSnap, eax
    invoke    Process32First, hSnap, offset lprocentry ; получаем название первого процесса
    .if    eax == NULL
        jmp        errorExit ; если 0, то получить не удалось и выходим
    .endif

mainsearch: ; так как касперский посчитал что использование lstrcmp - это троян, изобретаем свой велосипед с дамами и бриджем
    mov        ecx, sizeof processname ; записываем длину имени поцесса
    mov        edi, offset lprocentry.szExeFile ; записываем указатель название процесса который в структуре PROCESSENTRY32
    mov        esi, offset processname ; записываем указатель название процесса который ищем

nextsimb:    
    mov        al, BYTE PTR [esi] ; копируем первый байт из названия процесса в al
    .if        al != BYTE PTR [edi] ; сравниваем с первым байтом в найденом процессе
        jmp        nextproc ; ежели не совпадает идем к следующему процессу
    .endif
    inc        esi ; сдвигаем курсор на 1 в названии процесса
    inc        edi ; сдвигаем курсор на 1 в найденом процессе
    loop    nextsimb ; повторять пока все символы не сойдутся или не кончится строка
    mov        eax, lprocentry.th32ProcessID ; записываем PID найденого процесса в eax
    mov        pid, eax ; а его собственно в переменную pid
    jmp        processfound ; уходим на обработку Pid

nextproc:    
    invoke    Process32Next, hSnap, offset lprocentry ; обрабатываем следующий процесс
    .if    eax == NULL
        jmp        errorExit ; если 0, то получить не удалось и выходим
    .endif
    jmp    mainsearch ; повторяем основной цикл

processfound:
    invoke     OpenProcess, PROCESS_VM_OPERATION OR PROCESS_VM_WRITE, FALSE, pid ; открываем процесс на запись
    .if    eax == NULL
        jmp        errorExit ; если 0, то открыть не удалось и выходим
    .endif
    invoke     WriteProcessMemory, eax, moneycell, offset buf, sizeof buf, NULL ; записываем FF FF FF FF в ячейку памяти
    .if    eax == NULL
        jmp        errorExit ; если 0, то записать не удалось и выходим
    .endif
    invoke     MessageBox, NULL, offset wCheatOk, offset wTitle,MB_OK ; выводим сообщение что чит активирован
    jmp        normalExit ; выходим
errorExit:
    invoke MessageBox, NULL, offset wCheatErr, offset wTitle,MB_ICONERROR ; выводим сообщение что чит активировать не удалось
normalExit:
    invoke    ExitProcess,0
end start

Ну собсно и целиковый код на пастебине - http://pastebin.com/ZNDPLUJN
На сегодня все. :)

Комментариев нет:

Отправить комментарий