Перейти к содержанию

MasterGH

Ветераны
  • Постов

    2 999
  • Зарегистрирован

  • Победитель дней

    129

Сообщения, опубликованные MasterGH

  1. Если нужны мои комментарии, то первый твой пример в новинку может быть полезным для многих, а второй можно воспринять как закрепление материала по "активирующим" скриптам :)

    Немного поправлю:

    newmem:

    cmp byte ptr [_Exp],1

    jne short originalcode // корткий прыжок не пишет лишних нопов в теле чит-кода

    add [ecx+60],3E8

    mov [_Exp],0

    originalcode:

    mov eax,[ecx+60]

    ret // эта инструкция "конечная станция" ^_^ поэтому...

    int 3// ...можно было не писать

    jmp returnhere // ...можно было не писать

  2. Ближе к концу на максимальной сложности ... там где зеленые "шары" вылазят из нор. У меня было около 5 патронов дробовика и с сотню от винтовки похожей на СВД с лазерным прицелом и играл без читов по часа два в день начиная где-то с даты создания этой темы.... Короче получалось либо я далеко убегал от напарника бегая от шаров и напарник умирал от них... либо мой герой умирал потому, что я всё защищал напарника. Так что раз 15 - и я забил на игру :D Сегодня нашёл адрес напарника и заморозил его .... и далее ещё около трёх уровней пройти и я лицезрел список авторов игры оповещающих о её конце (не ожидал что она такая короткая). А дальше какая-то непонятная пауза - хоть игру отрубай.

  3. Хм... интересное дело с ножами.

    Можно представить массив указателей объектов которые могут быть на карте. У этих объектов должны быть три координаты и идентификатор типа объекта: это данные должны быть у всех подобных объектов.

    Например:

    Нож:ID1

    Стрелы:ID2

    Массив: ID1,ID1,ID2,ID1,ID2,ID1...

    Есть несколько вариантов как сделать респавн:

    1. Вариант:

    На создание и добавление в этот массив объектов не влияет наш игрок, а влияет только сценарий начала уровня. Т.е. только сценарий создаёт и кладёт в этот массив объекты, а те кто их юзает могут только юзать и максимум выкинуть из массива (уничтожить, но не создать).

    Вопрос здесь стоит только в том, чтобы выйти на место кода игры где происходит создание объекта... а дальше уже будет видно.

    2. Вариант.

    Данный массив используется иначе. Каждый объект игрока создаёт локальные копии объектов, которые он берёт из массива. При этом объекты в этом массиве разрушаются.

    В этом случае можно зациклить сбор нажей с одного "поднимаемого" объекта ножа из массива. Т.е. когда игрок берёт один нож, то мы зацикливаем например на 200 копий, после чего один объект разрушиться из массива, копию которого мы делали. Такой вариант был СТАЛКЕРЕ с патронами.

    Оба варианта сводятся к тому чтобы выйти на массив объектов и понять какой из двух вариантов следует. Мне почему-то кажется, что есть ещё один вариант.

    3. Вариант.

    Он похож на второй. Берём объект из массива "мира" создаём его копию, которую помещаем в создаваемый объект управления ножом. Таким образом Указатель на управление ножом кладём в объект героя...

    Вот такие мысли...

  4. Интересная информация ))

    По поводу бессмертных дружественных NPS у меня есть одна идея. Зацепка от которой можно оттолкнуться, просто мелочь...

    Всем кто играл известно что в дружественных NPS нельзя стрелять - наводишь прицел на "друга" пытаешься выстрелить и не получается. А это значит, что перед выстрелом происходит сравнение свой/чужой. Осталось только найти данные которые задействованы в сравнении, а дальше в инструкцию работающую со здоровьем игроков внедрить условие, которое дружественным NPS пишет постоянное здоровье..

    Пока такие мысли..

  5. Кто-нибудь знает хакнули фильтры от противогаза или нет и что там с гранатами(динамитом)... они как оформлены как объекты? И по какому принципу супер прыжок работает...

    aliast, ты на плейграунде писал, что не смог сделать дружественных игроков бессметрными, а можно узнать узнать поконкретней в чём проблема была?

    На плейграунде нужно подождать с чуть меньше недели, чтобы твой трейнер добавили ))) Те кто добавляют материал "там еле чешутся"

    ----

    Короче, я так понял там гранаты, фильтры и метальные патроны нужно спавнить(создавать) через конструктор. Я месяца два назад научился спавнить патроны в СТАЛКЕРЕ, но всё руки "не доходят" написать как это сделал.

    В Метро можно попробовать найти адрес счётчика метальных патронов и найти инструкции работающие с ним при перезарядке. При перезарядке должно происходить создание объектов в стволе оружия. Самый простой вариант сделать так, чтобы при перезарядке создавались в стволе не существующие патроны, но в этом случае пользователю постоянно придётся перезаряжаться. А нужно сделать так, что при выстреле инициализировалась перезарядка с отсутсвием или с очень быстрой анимацией перезарядки, тогда будет сделан так называемый чит-спавн патронов. Почти аналогично касается предметов которые игрок подбирает с трупов, в этот момент нужно узнать прерывающиеся инструкции, затем узнать в какую функцию они входят и какие параметры этой функции должны быть. Затем задать эти параметры с вызовом функции (либо внутренним потоком игры из некоторого места либо созданным потоком CE через скрпты) и будет спавн динамита или некоторого предмета ^_^ Но это в теории...

    Я сейчас читаю посты темы...

    Ты писал

    movss xmm0,[eax+000001e4]

    comiss xmm0,[_dead] //с этой строкой игра виснет. И без неё тоже (при попытке объявить переменную _dead)

    // comiss xmm0,[agpmeventloggingenabled+3fcff4] //сравнение с нулём - с этой строкой игра не виснет

    Данные (если я не ошибаюсь) должны быть выровнены от начала блока памяти кратно 16 байт, ещё говорят выровнены по 16-му параграфу. Назначь метку _dead, от метки _newmem на расстоянии кратном 16-ти байтам.

  6. Бывают ещё сообщения:

    strhappybirthday='Let''s sing Happy Birthday for Dark Byte today!';

    strXMess='Merry christmas and happy new year';

    strNewyear='And what are your good intentions for this year? ;-)';

    strfuture='Wow,I never imagined people would use Cheat Engine up to today';

    Если в образовательных целях, то сообщение с первоапрельской шуткой вылазит здесь..

    [cod]procedure TMainForm.FormShow(Sender: TObject);

    resourcestring

    strhappybirthday='Let''s sing Happy Birthday for Dark Byte today!';

    strXMess='Merry christmas and happy new year';

    strNewyear='And what are your good intentions for this year? ;-)';

    strfuture='Wow,I never imagined people would use Cheat Engine up to today';

    var reg: tregistry;

    modifier: dword;

    key: dword;

    hotkey: string;

    year,month,day: word;

    temp:string;

    i: integer;

    outputfile: textfile;

    go:boolean;

    loadt: boolean;

    firsttime: boolean;

    x: array of integer;

    begin

    Set8087CW($133f);

    loadt:=false;

    edit2.Text:=format('%.1f',[1.0]);

    reg:=Tregistry.Create;

    try

    Reg.RootKey := HKEY_CURRENT_USER;

    if not Reg.OpenKey('SoftwareCheat Engine',false) then

    begin

    if Reg.OpenKey('SoftwareCheat Engine',true) then

    begin

    //write some default data into the register

    reg.WriteBool('Undo',true);

    reg.writeBool('Advanced',true);

    reg.writeBool('SeperateThread',true);

    reg.writebool('Use Hyperscan if posible',false);

    reg.WriteInteger('ScanThreadpriority',formsettings.combothreadpriority.itemindex);

    end;

    end;

    except

    end;

    if reg.ValueExists('First Time User') then

    firsttime:=reg.ReadBool('First Time User')

    else

    firsttime:=true;

    if firsttime then

    begin

    reg.WriteBool('First Time User',false);

    if messagedlg('Do you want to try out the tutorial?',mtconfirmation,[mbyes,mbno],0)=mryes then

    shellexecute(0,'open','Tutorial.exe','','',sw_show);

    end;

    // animatewindow(mainform.Handle,10000,AW_CENTER);

    //mainform.repaint;

    fronttext:='brings Cheat engine to front';

    if dontrunshow then exit;

    dontrunshow:=true;

    decodedate(now,year,month,day);

    if (month=7) and (day=1) then showmessage(strhappybirthday);

    if (month=12) and ((day=25) or (day=26)) then Showmessage(strXmess);

    if (month=1) and (day=1) then showmessage(strnewyear );

    if (month=1) and (day=1) and (year>=2010) then showmessage(strFuture);

    if (month=4) and (day=1) then aprilfools:=true;

    if aprilfools=true then

    Messagedlg('Your license to use Cheat Engine has expired. You can buy a license to use cheat engine for 1 month for $200, 6 months for only $1000 and for 1 year for only $1800.'+' If you don''t renew your license Cheat Engine will be severely limited in it''s abilities. (e.g: Next scan has been disabled)',mtwarning,[mbok],0);

    LoadSettingsFromRegistry;

    //Load the table if one was suplied

    overridedebug:=false;

    if paramcount>=1 then

    begin

    loadt:=true;

    if uppercase(paramstr(1))='-O' then

    begin

    OverrideDebug:=true;

    loadt:=false;

    end;

    if paramcount>1 then

    begin

    //extra param

    temp:=paramstr(2);

    if length(temp)>4 then

    if temp[1]+temp[2]+temp[3]='/o=' then

    begin

    //output to:

    temp:=copy(temp,4,length(temp)-3);

    assignfile(outputfile, temp);

    rewrite(outputfile);

    for i:=0 to numberofrecords-1 do

    writeln(outputfile,memrec.description+' '+IntToHex(memrec.Address,8));

    closefile(outputfile);

    showmessage(temp+' has been created');

    end;

    end;

    end else

    begin

    end;

    if loadt then

    begin

    LoadTable(paramstr(1),false);

    updatescreen;

    updatelist;

    end;

    if GetSystemType<3 then //not a supported os for hardware breakpoints

    with formsettings do

    begin

    rdWriteExceptions.Checked:=true;

    rbDebugRegisters.Enabled:=false;

    label6.Enabled:=false;

    label7.Enabled:=false;

    rbDebugAsBreakpoint.Enabled:=false;

    rbInt3AsBreakpoint.Checked:=true;

    end;

    if (GetSystemType<4) {or (is64bitos)} then //not nt or later

    begin

    with formsettings do

    begin

    cbKernelQueryMemoryRegion.enabled:=false;

    cbKernelReadWriteProcessMemory.enabled:=false;

    cbKernelOpenProcess.enabled:=false;

    cbProcessWatcher.Enabled:=false;

    cbKDebug.enabled:=false;

    cbGlobalDebug.enabled:=false;

    TauntOldOsUser.Visible:=true;

    label25.Enabled:=false;

    end;

    end;

    vartypechange(vartype);

    adjustbringtofronttext;

    if aprilfools then

    caption:=cenorm+' EXPIRED!';

    if autoattachtimer.enabled then autoattachcheck;

    //SMenu:=GetSystemMenu(handle,false);

    //don't put this in oncreate, just don't

    if memscan=nil then

    memscan:=tmemscan.create(progressbar1);

    memscan.setScanDoneCallback(mainform.handle,wm_scandone);

    FileAccessTest;

    end;[/cod]

    Оно мне уже надоело своим появление и я его кильну на... так же как и предложение потренироваться при первом запуске (при сбросе настроек в реестре)

  7. Все версии можно будет скачивать с нашего сайта.

    ПЕРЕЙТИ

    Cheat Engine 5.6 RUS (1.0)

    1. Модернизированы окна: главное, окно прервавшихся инструкций.

    2. Переведены окна: главное, отладчика, спасибо aliast-у за перевод (настроек, туториала)

    3. Автоматическое выравнивание столбцов в окне отладчика.

    3. Добавлена функция отчётности прервавшихся инструкций там же возможность ставить галочки чтобы отмечать инструкции

    4. Добавлена Функция отключения отладчика

    5. Исправлены ошибки при удалении записей в трейнеросоздателе - ошибка характерна и для оригинальной версии

    6. Шаблон в автоассемблере генерируется с учётом сканирования сигнатур.

    7. Добавлена функция показывающая загруженный игрой и системой файлы (для определения сейв-файлов)

    8. Добавлена функция разложения указателей из CE 5.5

    9. В инсталяторе есть лоадер, который сбрасывает настройки (правда немного он не продуман, из-за него запускается каждый раз предложение пройти тренировку, в будущем исправлю)

    10. Инсталлируемый файл CheatEngine.exe переименован в другой с пометкой что это русская версия и в нём указана версия.

    11. Также вы можете без опасений денисталировать файлы, который были установлены. Ничего не перезаписывается и не удаляется, того что удалять нельзя.

    ps. Эту версию я уже выкладывал, т.к. что скорее кому было надо те скачивали.

    • Плюс 1
  8. Здесь пишем баги.

    Пишу о тех которые я нашёл:

    Статус: не исправлено

    * В окне структур при задании нового типа некотрому смещению - значение в соответсвии с типом не меняется.

    Статус: не исправлено

    * Не работает сгенерируемый трейнер при активации скриптов по горячим клавишам

    Статус: не исправлено

    * Проверить: "А у всех CE перестаёт работать (искать адреса и активировать скрипты) после запуска сканера указателей? шибка возникает вроде бы когда указателей сильно много находится. Иначе всё работает. Наример, в той же операции флэшпоинт или метро 2033 ошибка "Scan error:thread 0:Out of memory""

    Статус: не исправлено

    * Баг в при ассемблировании.

    Я узнал опытным путём, что ассемблирование происходит с добавлением лишних байт

    00D25EA5 - 8d 04 2f - lea eax,[edi+ebp] //оригинальная инструкция

    00D25EA5 - 8d 44 2f 00 - lea eax,[edi+ebp+00]

    Даже если вы не пишите "lea eax,[edi+ebp+00]", а "lea eax,[edi+ebp]", то всё равно у вас будет "lea eax,[edi+ebp+00]".

    А в этом случае меняются первые байты.

    00D6E729 - a3 08 27 9c 02 - mov [029c2708],eax //оригинальная инструкция

    00D6E729 - 89 05 08 27 9c 02 - mov [029c2708],eax

    Ну жесть просто. При отмене чит-кода с такими инструкциями у вас будет "крах игры"

  9. Статья GTA Vice City  - это статья с которой я нулевыми знаниям начал путь в advanced gamehacking. А затем F.E.A.R. - тоже произвела впечатление. Три года прошло и если сравнить знания мои до того как я прочёл эти статьи с теми, что сейчас, то можно посмеяться ))) Тогда я смотрел на ассемблерные инструкции типа этого

    728042d12a82.jpg

    и понятия не имел как с этим работать.... жесть ))) Теперь настало время и я прокомментирую моменты, которые были мне непонятными или которые нужно дополнить. Надеюсь Xipho будет интересно. Комментарии мои могут быть сложным новичкам, но что тут поделаешь, написал как написал...

    Для удобства я все картинки вытащил из под спойлеров, а комментарии я буду писать красным. Поехали...

     

    Скрытый текст
    Цитата
    Бессмертие только для игрока с использованием метода указателей

     

    Сложность: Новичок

    Инструменты: Artmoney, Tsearch.

    Итак, начнем. Запускаем игру, запоминаем количество жизней:

    ff67a9442b37.jpg

    сворачиваем игру и запускаем Artmoney и выбираем игру из списка процессов.

    f5bf85c2b7ac.jpg

    Далее делаем поиск:

    4fc81c6efbce.jpg

    Почему именно так? Да потому, что жизни в вайсе хранятся в переменной с плавающей точкой.

    Позволю себе отметить, что этот финт поиска данных был известен не каждому. Тогда в той ещё Артмани 7.13 также не было корректировок округления вещественных чисел в настройках. Но увидив данный приём однажды, можно было его применять в других играх.

    Далее делаем что-нибудь, чтобы потратить немного жизней, например падаем с крыши невысокого здания (чтобы не насмерть и чтобы жизней осталось на еще два-три таких падения)

    Далее делаем отсев с получившимися жизнями по принципу скриншота… то есть диапазон значений вычисляется так:

    нижний порог диапазона = текущие жизни-1

    верхний порог диапазона = текущие жизни+1

    Повторяем отсев до тех пор, пока не останется ОДИН адрес. Вот что получилось у меня в итоге:

    В игре:

    e559e2a9ed87.jpg

    А в Artmoney:

    a3484f88aec7.jpg

    Как видим, в игре у нас 66 процентов, а в АртМани 66.02 Это потому, что игра просто отбрасывает сотые доли и пишет в жизни тока целую часть. Наверное это сделано для затруднения взлома игры. Ну да нам это не помеха :P

    Запускаем TSearch:

    6ddef1d22c3a.jpg

    Эта программа Хит своего времени (как и MTC) и сейчас может использоваться, но CheatEngine более гибкая и мощнее и также MHS

    и открываем процесс игры. Надеюсь с этим вы справитесь без меня... Далее включаем отладчик:

    d0b2f6b5af14.jpg

    Минус в удобстве TSearch - cпрашивается зачем эти лишние действия, когда отладчик можно было бы включать автоматом при попытке поставить бряк на адресе. Дальнейший путь установки бряка также можно было бы сократить, как это сделано в CE

    и открываем AutoHack window. Тоже надеюсь, что найдете где 

    В этом окне нажимаем зеленую стрелочку:

    203427a6052d.jpg

    Эта стрелочка позволяет установить breakpoint (точку останова) на адрес наших жизней:

    0195a1473bbe.jpg

    Это наш адрес жизней найденный в АртМани, вставляем его в окно установки breakpoint’a:

    d45d80192198.jpg

    Обратите внимание на тип breakpoint’a: он должен быть открытым, то есть срабатывать и на чтение из этого адреса и на запись.

    Многое остаётся за кадром. Почему именно "и на чтение и на запись"?! Ведь сразу после этого идёт следующий абзац и мысль как будто обрывается.

    Пояснение. Бряк и на чтение и на запись, так называемый "открытый" брейкпоинт или бряк на доступ позволит найти предполагаемую частообращаемую инструкцию к адресу здоровья. Обычно, эта инструкция типа чтения, а иногда и на запись. О частоте обращения можно только догадываться, т.к. TSerach не считает кол-во обращений. Однако, обычно, частообращаемые инструкции являются инструкциями чтения, которые работают в игре, когда игрок даже ничего не делает. Руководствуясь данным принципом мы можем найти ту самую частообращаемую инструкцию к адресу здоровья и внедрить чит-код в неё и он будет выполняться создавая эффект постоянного здоровья.

    Мы также могли бы внедрить в некоторую инструкцию записи из появившихся, когда игрок получил урон, но как показала моя практика, проще внедрять так, как тут описано, хотя случаи бывали разные. Перед вами может стоять выбор:

    1. внедрить в одну частообращаему инструкцию,

    2. внедрить в одну или несколько инструкций записи, которые срабатывают обычно при уроне,

    3. внедрить на ваш выбор, куда угодно и что угодно, лишь бы чит работал должным образом

    Далее мы возвращаемся в игру и бегаем пару секунд, но жизни НЕ тратим! Да, и в артмани их не замораживаем!

    После возврата в TSearch видим, что наше breakpoint сработал, и еще как сработал:

    Когда я читал первый раз статью, я точно помню, что задавался вопросом: "Почему именно так нужно поступать?". Как будто Xipho взял да и угадал что нужно сделать.

    Как я уже писал, мы стараемся найти часто обращаемые инструкции (т.к. выбрали этот путь внедрения) и они обычно срабатывают, когда мы просто зашли и вышли из игры. Если мы не будем тратить жизни, то у нас будет меньше инструкций обращения, которые срабатывают только при уроне. Поэтому подмеченное "НЕ" тратим жизни, нужно только для того чтобы не работать с лишними инструкциями (которые срабатывают только при уроне), т.к. нам нужным часто обращаемые.

    728042d12a82.jpg

    Последний из найденных сразу же отсеиваем, так как это сравнение жизней, оно нам не нужно.

    Ну, а тут я могу поспорить. "Сравнение жизней" это не аргумент. Прежде всего это предполагаемая часто обращаемая инструкция и в неё можно внедрить условие и оно должно будет работать не хуже. Роль данной инструкции сравнить некотрое число с точкой со значением здоровья. После сравнения или перед сравнением можно внедрить чит-код.

    Также хочется отменить, что именно сейчас мы имеем возможность охарактеризовать частично структуру героя в игре. Начало структуры является значение регистра, а смещение +0x354 - это велечина от начала структуры по которой находится здоровье.

    Наш игрок или не наш игрок имеет такую же структуру с таким же смещением здоровья. Некторые инструкции которые мы видели, работают как с нашим игроком так и не с нашими. Хотя точно утвержать, пока не установим это, мы не можем.

    Установив какие инструкции работают только со структурой вашего игрока вы можете сделать чит-код с записью постоянного здоровья по смещению +0x354 чем избавите себя от лишних хлопот. Если инструкций работающих только со структурой вашего героя не будет, то придётся изменять инструкции делая фильтр "является ли регистр структурой вашего игрока". Отличить вашу структуру от структуры ботов можно, например, с помощью указателя на структуру вашего героя, который придётся искать далее.

    С этого места можно некоторым образом начать понимать какие инструкции вам необходимо стремиться изменять - часто обращаемые и работающие только со структурой вашего героя. Правда я ещё подстраховываюсь и изменяю также хотябы одну инструкцию урона в случаях, когда урон может отнять всё здоровье героя. Имел ли место быть такой случай в этой игре я без понятия.

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

    Сложно предположить по какому критерию был перебор вручную Все инструкции теоретически вполне подходят под критерий внедрения. Сдаётся мне что на всех инструкциях нужен фильтр, а Xipho искал, ту которая работает без фильтра

    Для начала найдем дырку в коде, для вставки нашей процедуры. Я использую для этой цели CodeCaver:

    Это было давно, сейчас Xipho использует выделение памяти, а не "дырку". Что по сути правильно учитывая разные тонкости, о которых можно узнать поискав по форуму.

    ada177c28703.jpg

    я воспользуюсь отмеченным адресом, так как в нем много пустого места...

    Включаем в TSearch очень удобную фишку Easy Write:

    1f22596dfcc8.jpg

    Затем нажимаем new:

    ccef31a26e69.jpg

    Получаем такое окно:

    68e1018d0382.jpg

    В верхней части окна пишется код для патча адресов игры, а в нижней – для восттановления исходных значений, если вдруг вы решили поиграть честно

    EasyWrite не такой уж Easy в универсальности. Он не сможет понять адрес "Game.dll+5454:", он не приспособлен к выделению памяти, он не может искать адрес внедрения по цепочке байт. И основная фича за которую его любили или до сих пор любят это генерация байт-кода, который на мой взгляд уже утратил свою актуальность. Зачем заниматься компиляцией байт-кода, копипастами и т.п. Берём ассемлерный скрипт, вставляем в трейнер и юзаем без лишней работы с poke-ами. Это можно сделать в скриптах Cheat Engine и непосредственной компиляцией ассемблерных инструкций в среде программирования с их копированием в процесс игры в выделеную память - однако это надо писать особый код трейнера, что не каждый умеет

    В верхней части набираем такой код:

    Сразу даю пояснения…

     


    fld dword ptr [ecx+0x354] – восстанавливаем оригинальную инструкцию
    mov dword ptr [ecx+0x354],0x4479C000 – записываем 999.00 в адрес жизней
    jmp 0x501979 возврат в игровую рутину
    
    
    Offset 0x006E794F --- помните, я выбрал этот адрес для своей процедуры

     

    Здесь более правильнее было бы

    Offset 0x006E794F

    mov dword ptr [ecx+0x354],0x4479C000

    fld dword ptr [ecx+0x354] // загружаем в ST(0) значение 0x4479C000

    jmp 0x501979

     

    jmp 0x006E794F – делаем переход на свою процедуру nop – так как оригинальная инструкция всего 6 байт длиной а переход 5 байт длиной, то нам надо вставить это, для баланса байт, иначе получим вылет из игры.
    
    
    Offset 0x501973 – инструкция по этому адресу читает жизни

     

    А в нижней вставляем это:

     

    fld dword ptr [ecx+0x354]
    
    
    Offset 0x501973

     

    То есть восстановление оригинального кода игры, для честной игры. Включив эту опцию, возвращаемся в игру. Мы стали бессмертными

    Но что это? Все прохожие и менты тоже стали бессмертными. Вот тут и начинается основная часть нашего взлома.

    Ну, вот... похоже нет инструкции, которая работает только с героем. Если вы хотите узнать работает ли инструкция только с вашим героем, то на этой инструкции (Offset 0x501973) нужно определить адрес здоровья врага. Поставить на него также бряк и сравнить какие инструкции срабатывают у него и у вашего героя. Найти отличные и проверить их на практике.  

    Дальеш пойдёт поиск указателя для создания фильтра, чтобы по нему записать здоровье только нашему герою.

     

    Выключаем бессмертие. В окне AutoHack выбираем вкладку Дизассемблера.

    7cce06aaaa7c.jpg

    Затем делаем все четко по скриншотам:

    0a9614b79a92.jpg

    Этим мы заставим TSearch смотреть, что же происходит в регистрах при выполнении данной инструкции. Далее кликаем на Register:

    064efc8a6c3b.jpg

    И видим такое окно:

    a16dff246068.jpg

    Проставляем регистры как на скриншоте и включаем наблюдение (красная рожица слева). Возвращаемся в игру. В игре НИ В КОЕМ СЛУЧАЕ НЕ ВСТУПАЕМ НИ В КАКИЕ РАЗБОРКИ И НЕ ТРАТИМ ЖИЗНИ!!!

    Возможно, что если мы потратим чьи-то жизни, то в регистре ecx будет начало структуры того бота, здоровье которого мы отняли в последнюю очередь. В любом случае это подстраховка.

    Бегаем пару сек и снова возвращаемся в это окно. Вот и нашли значение для поиска указателя (если вы помните, это и есть цель этого тутора):

    846e9c598a5b.jpg

    Далее переводим его в десятичную систему (калькулятором все пользоваться умеют? ). И ищем как обычное число в артмани… А можно сразу искать его в шестнадцатиричном. Вот так:

    7aca70bca72f.jpg

    то есть мы вводим в строку поиска шестнадцатиричное значение, и просто напросто подставляем в конце h чтобы дать АртМани понять, что это шестнадцатиричное значение. Скорее всего адресов найдется много. Выходим из игры, АртМани и TSearch не закрываем! Снова заходим в игру и идем в TSearch. Снова выбираем процесс,  Включаем отладчик в TSearch’e  и переходим в окно Автохака. Оно должно было оставаться открытым. Выключаем наблюдение, снова включаем, переходим в игру, бегаем пару секунд и снова возвращаемся в Автохак

    А вот тут есть сюрпризы.

    1. Указатель может быть в dll - ке, а это не было проверено в статье.

    2. Указатель может быть многоуровневым и должен был быть проверен на статичность. Находится ли этот указатель в статичной памяти? Зелёный ли он в CE или MHS...

    7256d26f5734.jpg

    Видим, что регистр изменился… Делаем отсев по этому значению в АртМани… Повторяем заново, до тех пор, пока не останется только один адрес… Если же после 5-6 отсеиваний адресов все равно несколько, то берем любой

    Здесь я думаю стоило жирным выделить очень полезный финт - способ, которым был найден этот указатель. Именно этот способ помимо реверсинга лежит в основе поиска любого указателя, хоть многоуровневого при этом уровни указателей должны изменять своё положение, чтобы их можно было идентифицировать.

    Я взял адрес 0078F7E4 он мне больше всего понравился:

    Тут надо было обратить внимание, что этот выбор был ориентирован не спроста: 0x201538 лежит ниже 0x00400000, чего не должно быть. Плюс нужно было убедиться в какой памяти лежит 78F7E4 в статической или в dll

    8425be87f884.jpg

    Вот практически и все! Дорабатываем наш код:

    (Объясняю только то, что изменилось)

      Offset 0x006E794F

        fld dword ptr [ecx+0x354]

        push eax – сохраняю регистр на всякий случай

        mov eax,[0x0078F7E4] – считываю из нашего указателя адрес для сравнения

        cmp ecx,eax – сравниваю с текущим указателем

        pop eax – восстанавливаю регистр (а вдруг он используется)

        jne 0x501979 – если указатели не равны, то возвращаюсь без записи

        mov dword ptr [ecx+0x354],0x4479C000 – записываю жизни

        jmp 0x501979 возвращаюсь в игру.

    Можно было написать идеально как-то так:

    Offset 0x006E794F

        fld dword ptr [ecx+0x354]

        cmp ecx,dword ptr[0x0078F7E4]

        jne 0x501979

        mov dword ptr [ecx+0x354],0x4479C000

        jmp 0x501979

    Вообще-то после "mov dword ptr [ecx+0x354],0x4479C000" должна идти "fld dword ptr [ecx+0x354]" и также сохранены и восстановлены флаги pushf и popf. Но раз игра позволяет значит, можно так оставить.

      А это все без изменений

    Offset 0x501973

        jmp 0x006E794F

        nop

    Вот и все!!! Теперь бессмертны только мы!!!

    Я бы ещё уточнил - бессмертны благодаря внедрению чит-кода в инструкцию, в котором был фильтр на указатель структуры игрока. Только поэтому бессмертны только мы.

    Хотел бы отменить ещё одну важную штуку. Указатель на здоровье теперь можно оформить как

    [[0078F7E4]+0x354] = 100.0

    В статье не нашли инструкцию работающую только со здоровьем героя на уровне [xxx+0x354], а

    в этом случае можно поставить бряк на доступ (открытый) на адрес [0078F7E4] и тогда в большинсве случаев можно найти инструкцию, которая работает только со структурой главного героя. Можно внедрить в эту инструкцию без сравнения (без фильтра) с указателем героя как было описано в статье

    Заключение.

    На момент выхода эта статья была актуальна, но сейчас уже появились инструменты, более удобные в использовании. В ближайшем будущем данная статья будет переписана с использованием современных инструментов.

  10. Привет, это вновь MasterGH с занудной, но полезной статьёй )

    Рассмотрим работу с некоторыми FPU инструкциями компилятора Borland C++

    Подопытная программка, которую я написал выглядит так:

    post-3-1295709223,21_thumb.png

    рис.1

    (весит 12 кб в сжатом состоянии.. хе-хе, буду знать)

    Как видите, она умеет уменьшать, увеличивать и уменьшать с условием значение здоровья типа float.

    Основной код, который я добавил в приложение.


    float fhealth = 100.0;
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    fhealth-=20.0;
    updateValue();
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
    fhealth+=20.0;
    updateValue();
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button3Click(TObject *Sender)
    {
    if (fhealth>10) {fhealth-=5;};
    updateValue();
    }

    void TForm1::updateValue()
    {
    Edit1->Text=fhealth;
    }

    //---------------------------------------------------------------------------

    Остальной код писать не буду, т.к. он генерируется автоматически. Ах да updateValue() нужно добавить в приватную область класса формы и больше я никакого кода не писал. А теперь взглянем на ассемблерные инструкции этих действий.

    Буду приводить кусок исходника и описание.

    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    fhealth-=20.0;
    updateValue();
    }

    Это тоже самое что:

    post-3-1295709226,8_thumb.png

    рис.2

    Так как всё тут просто комментировать не буду.

    Идём к следующей инструкции.

    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
    fhealth+=20.0;
    updateValue();
    }

    Почти аналогично, только с инструкцией добавления:

    post-3-1295709230,84_thumb.png

    рис.3

    Ну, а теперь самое интересное:

    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button3Click(TObject *Sender)
    {
    if (fhealth>10) {fhealth-=5;};
    updateValue();
    }

    А теперь разберём инструкции подробнее:

    Unit1.cpp.32: if (fhealth>10) {fhealth-=5;};

    00401CF8 D90598414000 fld dword ptr [$00404198] //грузим в стек FPU 100.0

    00401CFE D9052C1D4000 fld dword ptr [$00401d2c] // грузим в стек FPU 5.0

    //Сейчас ST(0)=10, а ST(1)=100

    00401D04 D9C9 fxch st(1) // меняет местами содержимое регистров

    //Сейчас ST(0)=100, а ST(1)=10

    00401D06 DAE9 fucompp // сравнивание с двойным выталкиванием из стека

    //Сейчас ST(0)=Empty, а ST(1)= Empty (что означает пустые)

    Флаги FPU поменялись

    Было/стало

    post-3-1295709235,95_thumb.png

    рис.4

    00401D08 DFE0 fstsw ax

    Лезу в справку:

    fstsw и fnstsw сохраняют текущее значение слова статуса FPU в указанном месте. Операндом-адресатом может быть либо 16 бит в памяти, либо регистр AX. fstsw перед сохранением слова проверяет на подвешенные немаскируемые прерывания, fnstsw этого не делает

    Короче какие-то флаги FPU загнали в AX

    post-3-1295709240,3_thumb.png

    рис.5

    00401D0A 9E sahf // загружаем ah в младший байт регистра eflags

    post-3-1295709245,17_thumb.png

    рис.6

    00401D0B 7612 jbe $00401d1f // jbe не работает когда 10<100 при флагах CPU: CF=1 и ZF=1

    // а теперь вы полнение записи здоровья

    00401D0D D905301D4000 fld dword ptr [$00401d30] // грузим 5 в ST(0)

    00401D13 D82D98414000 fsubr dword ptr [$00404198] // от здоровья отнимаем ST(0) и сохраняем здоровье в ST(0)

    00401D19 D91D98414000 fstp dword ptr [$00404198] // выталкиваем и записываем вновь здоровье

    Unit1.cpp.33: updateValue();

    00401D1F FF75FC push dword ptr [ebp-$04]

    00401D22 E80D000000 call TForm1::updateValue() // ну, а это уже пошла моя функция обновления…

    00401D27 59 pop ecx

    Заключение.

    Короче говоря, берём на зуб:

    Unit1.cpp.32: if (fhealth>10) {fhealth-=5;};
    00401CF8 D90598414000 fld dword ptr [$00404198]// fhealth
    00401CFE D9052C1D4000 fld dword ptr [$00401d2c]// 10.0
    00401D04 D9C9 fxch st(1)
    00401D06 DAE9 fucompp
    00401D08 DFE0 fstsw ax
    00401D0A 9E sahf
    00401D0B 7612 jbe $00401d1f // if (fhealth>10) {fhealth-=5;};
    00401D0D D905301D4000 fld dword ptr [$00401d30]
    00401D13 D82D98414000 fsubr dword ptr [$00404198]
    00401D19 D91D98414000 fstp dword ptr [$00404198]

    Unit1.cpp.33: updateValue();
    00401D1F FF75FC push dword ptr [ebp-$04]

    Этот шаблон вы можете применить в своих скриптах, когда некоторый параметр не должен быть меньше другого некоторого параметра.

    Не знаю как вы, я подумал сложные скрипты лучше писать на С++ реализованные в dll, которые можно подгрузить скриптами CE, но об этом позже...

  11. Трейнер получился красивым.

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

    ps Я сделал мини-тутор по работе с FPU числами компилятора Borland C++. Заливаю... Надо ещё понять в какой раздел тему создать с этим тутором.

  12. Да, не очень сложен этот FPU. Вообще хорошо бы каждому разобраться с подобными инструкциями окончательно, чтобы как я делать меньше ошибок. Да и мне бы тоже не помешало,поэтому может быть тутор сегодня сделаю, но никому не обещаю.

  13. Я написал по памяти, но могу ошибаться. Обычно, ошибки в логике написания инструкций FPU я сразу вижу и испрвляю при пошаговой отладке со справочником перед глазами, что и советую.

    [sp=Код][ENABLE]

    aobscan(_faddress,f3xxxxxxxx0fxxxxxxxxxxxxxxxx8bxx76xx33xx38xxxxxxxxxx74xxxxxxxxxx)

    alloc(_newmem,2048)

    label(_returnhere)

    label(_originalcode)

    label(_newmem2)

    label(_flag)

    registersymbol(_flag)

    _newmem:

    pushf

    push ecx

    mov ecx,[_flag]

    cmp al,1

    cmp byte ptr [_flag],1

    jne _newmem2

    cmp dword ptr [eax+30],0

    jbe _originalcode

    fld [eax+30] // отнимаем 20

    fld float(20)

    fsubp ST,ST2

    fstp [eax+30]

    mov byte ptr [_flag],0

    jmp _originalcode

    _newmem2:

    cmp al,2

    jne _originalcode

    cmp dword ptr [eax+30],42C80000 //100.0

    jae _originalcode

    fld [ecx+30]

    fld float(20)

    faddp ST,ST2

    fstp [ecx+30]

    mov byte ptr [_flag],0

    _originalcode:

    pop ecx

    popf

    movss xmm0,[eax+30]

    jmp _returnhere

    _flag:

    dd 0

    _faddress: // 006B2965 = JustCause2.exe+2B2965

    jmp _newmem

    _returnhere:

    [DISABLE]

    aobscan(_faddress,0fxxxxxxxxxxxxxxxx8bxx76xx33xx38xxxxxxxxxx74xxxxxxxxxx)

    _faddress-5:

    movss xmm0,[eax+30]

    dealloc(_newmem)

    //Alt: db F3 0F 10 40 30[/sp]

  14. Windows API (application programming interfaces) — общее наименование целого набора базовых функций интерфейсов программирования приложений операционных систем семейств Windows и Windows NT корпорации «Майкрософт». Является самым прямым способом взаимодействия приложений с Windows. Для создания программ, использующих Windows API, «Майкрософт» выпускает SDK, который называется Platform SDK и содержит документацию, набор библиотек, утилит и других инструментальных средств.

    Английская WinApi32: скачать

    Русская справка:

    Краткий вариант: перейти

    Полный вариант: перейти

    Ещё справочник перейти

    Предназначение функций сразу видно из названия, вам нужно запомнить только для чего какая функция нужна, а далее лазить только по справочникам для уточнения.

    Список функций, которые часто используются при создании трейнера:

    GetAsyncKeyState

    TranslateMessage

    DispatchMessage

    FindWindow

    IsWindow

    GetWindowThreadProcessId

    OpenProcess

    ReadProcessMemory

    WriteProcessMemory

    CloseHandle

    Менее используемые

    GetHandleInformation

    Эта функция позволит понять иерархию созданных процессов в том случае если у игры есть запускающий процесс, а надо патчить память дочернего.

    GetLastError

    Возвратит ошибку той или иной операции

    CreateRemoteThread

    Когда требуется создать поток в чужом процессе выполнив некоторый код. Например, загрузки dll и выполнения её функций внутри чужого процесса. Или выполнение какой-то функции игры по заданным параметрам и т.д.

    LoadLibrary

    Загрузка исполняемого модуля в адресное пространство игры.

    Хотел также написать функции которые хорошо бы знать “ВООБЩЕ”, а в итоге понял, что надо посоветовать вам читать полный справочник по WinAPI32. Ссылки можете найти в самом верху.

    А теперь более подробнее с примерами на языке Дельфи. Принцип работы одинаков на других языках программирования для платформы Windows32/64

    Приминение функций:

    FindWindow

    IsWindow

    GetWindowThreadProcessId

    OpenProcess

    ReadProcessMemory

    CloseHandle


    Var
    hWn: HWND;
    PID, hProc, dwReaded,StartAddr,i,r:DWord;
    buf: Byte;
    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 - таблица
    sg.RowCount := SapMap.y;
    sg.Height:=16*sg.RowCount+3;
    sg.Width:=16*sg.ColCount+3;
    form1.Height:=16*sg.RowCount+3+48;
    form1.Width:=16*sg.ColCount+9;

    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;
    procedure TForm1.Button1Click(Sender: TObject);

    Создание трейнера на WinAPI

    Создание трейнера на WinAPI. Пример 1


    {$R-} {проверка диапазона}
    {$S-} {проверка стека}
    {$A+} {"выравнивание слов"}

    program FlatOut;
    uses
    windows, messages, commctrl; //Используемые модули,только самое нужное!

    var
    WinClass : TWndClass; //переменная класса TWndClass для создания главного окна
    hInst : HWND; //Хендл приложения
    Handle : HWND; //локальный хендл
    Com1 : HWND; //TGroupBox
    Com2 : HWND; //TButton
    Com3 : HWND; //TButton
    Com4 : HWND; //TStaticText
    Com5 : HWND; //TStaticText
    Com6 : HWND; //TStaticText
    Msg : TMSG; //сообщения
    hFont : HWND; //хендл шрифта
    win : hwnd; //хендл данного окна

    var
    WindowName : integer; //имя окна
    ProcessId : integer; //ID процесса
    ThreadId : integer; //Поток
    buf : PChar;
    HandleWindow : Integer; //хендл окна игры
    write : cardinal;

    const //id наших контролов
    id_1 = 1; //TGroupBox
    id_2 = 2; //TButton
    id_3 = 3; //TButton
    id_4 = 4; //TStaticText
    id_5 = 5; //TStaticText
    id_6 = 6; //TStaticText

    const
    WindowTitle = 'Flat-Out'; //конец формы, начало формы, точный заголовок игры
    Address = $01B40C64; //адрес нашего значения в памяти игры
    PokeValue = $FFFFFFFF; //значение на которое мы будем менять
    NumberOfBytes = 4; //кол-во байт
    {$R XPMan.res} //Здесь у меня лежит иконка моего трейнера и манифес,

    //это для того что бы все контролы были в стиле XP
    procedure Cheating; //Собственно сама процедура изменения значения
    begin
    WindowName := FindWindow(nil,WindowTitle); //находим окно игры
    If WindowName = 0 then //или,обьясняем пользователю чтобы он запустил игру
    MessageBox(win,'Вначале игра,а потом трейнер.','Ошибка',MB_OK or MB_ICONINFORMATION);
    ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);
    HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);
    GetMem(buf,1);
    buf^ := Chr(PokeValue);
    WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write);//пишем в наш адресс наше значение
    FreeMem(buf);
    CloseHandle(HandleWindow);//конец формы, началоформы, закрываем хэндл, чтобы не вылететь с ошибкой
    end;

    procedure ShutDown; //процедура выхода из программы
    begin
    DeleteObject(hFont); //удаляем шрифт
    UnRegisterClass('Sample Class', hInst); //удаляем окно
    ExitProcess(hInst); //закрываем окно
    Halt; //на всякий случай :)
    end;

    procedure About; //наше окно о программе
    begin
    MessageBox(win, ' [C0DED]: bY g-l-u-k [TeaM - X] ' +#13#10+
    ' ' +#13#10+
    ' GreatZzz....: ' +#13#10+
    ' ' +#13#10+
    ' Baron_Gede,6aHguT,AllexY ' +#13#10+
    ' And all TeaM - X Members ! ' +#13#10+
    ' ' +#13#10+
    ' Write on pure Delphi (WinAPI) ' +#13#10+
    ' Сopyright (g-l-u-k)R 2004-2005 ' +#13#10+
    ' ' +#13#10+
    ' <!-- m -->[url=http://www.team-x.ru]http://www.team-x.ru[/url]<!-- m --> ' +#13#10+
    ' e-mail : <!-- e -->[email=g-l-u-k@rambler.ru]g-l-u-k@rambler.ru[/email]<!-- e --> ' +#13#10+
    ' ' +#13#10+
    ' GEngine v0.1 ' +#13#10+
    ' All Right Reserved ',
    'About',MB_OK or MB_ICONINFORMATION);
    end;

    function WindowProc(hwnd, msg, wparam, lparam: longint): longint; stdcall; //обработчик сообщений
    begin
    Result := DefWindowProc(hwnd, msg, wparam, lparam);
    case Msg of
    WM_COMMAND:
    case LoWord(wParam) of
    id_2 :
    if HiWord(wParam) = bn_Clicked then
    About; //если пользователь нажимает на кнопку "About",получат свой About
    id_3 :
    if HiWord(wParam) = bn_Clicked then
    ShutDown; //если выход то......
    end;
    WM_DESTROY: ShutDown;
    end;
    end;

    // НАЧАЛО ПРОГРАММЫ
    begin
    hInst := GetModuleHandle(nil);

    with WinClass do
    begin
    Style := CS_PARENTDC; //стиль класса главного окна
    hIcon := LoadIcon(hInstance, IDI_APPLICATION); //иконка программы
    lpfnWndProc := @WindowProc; //назначение обработчика сообщений
    hInstance := hInst;
    hbrBackground := COLOR_BTNFACE + 1; //цвет окна
    lpszClassName := 'Sample Class'; //класс окна
    hCursor := LoadCursor(0, IDC_ARROW); //активный курсор
    end;

    InitCommonControls;
    RegisterClass(WinClass); //регистрация класса в сис-ме
    {Создание главного окна программы}

    Handle := CreateWindowEx(0, 'Sample Class', '[FlatOut] Trainer +1',
    WS_OVERLAPPED or WS_SYSMENU or
    WS_VISIBLE,
    503, 345, 234, 222,
    0, 0,
    hInst, nil);
    {Создание шрифта}
    hFont := CreateFont(
    -12, 0, 0, 0, 0, 0, 0, 0,
    DEFAULT_CHARSET,
    OUT_DEFAULT_PRECIS,
    CLIP_DEFAULT_PRECIS,
    DEFAULT_QUALITY,
    DEFAULT_PITCH or FF_DONTCARE, 'Terminal');
    Com1:=CreateWindow(
    'Button',
    'Trainer Options:' ,
    WS_CHILD or BS_GROUPBOX or WS_VISIBLE,
    2,2,222,165, Handle, id_1, hInst,nil);
    SendMessage(Com1,WM_SETFONT,hFont,0);
    Com2 := CreateWindow(
    'Button',
    'About',
    WS_CHILD or BS_TEXT or WS_VISIBLE,
    3, 171, 74, 20,Handle, id_2, hInst, nil);
    SendMessage(Com2,WM_SETFONT,hFont,0);
    Com3 := CreateWindow(
    'Button',
    'Quit',
    WS_CHILD or BS_TEXT or WS_VISIBLE,
    148, 171, 74, 20,Handle, id_3, hInst, nil);
    SendMessage(Com3,WM_SETFONT,hFont,0);
    Com4 :=CreateWindow(
    'Static',
    '[F1] :...: More Money' ,
    WS_CHILD or SS_LEFT or SS_NOTIFY or WS_VISIBLE,
    51,25,117,17,Handle, id_4, hInst,nil);
    SendMessage(Com4,WM_SETFONT,hFont,0);
    Com5:=CreateWindow(
    'Static',
    '[C0DED] :...: g-l-u-k [TeaM - X]' ,
    WS_CHILD or SS_LEFT or SS_NOTIFY or WS_VISIBLE or WS_DISABLED,
    32,145,180,17,Handle, id_5, hInst,nil);
    SendMessage(Com5,WM_SETFONT,hFont,0);
    Com6:=CreateWindow(
    'Static',
    '[R.Mouse] :...: About Box ' ,
    WS_CHILD or SS_LEFT or SS_NOTIFY or WS_VISIBLE,
    26,50,190,17,Handle, id_6, hInst,nil);
    SendMessage(Com6,WM_SETFONT,hFont,0);

    //Цикл сбора сообщений
    while(GetMessage(Msg, Handle, 0, 0)) do
    begin
    TranslateMessage(Msg); //приём сообщений
    if (GetAsyncKeyState(vk_f1 ) <> 0) then Cheating; //если нажата клавиша F1,читим игру
    if (GetAsyncKeyState(vk_RButton) <> 0) then About; //если нажата правая кнопка мыши,то показываем About
    if (GetAsyncKeyState(vk_Escape ) <> 0) then ShutDown;
    DispatchMessage(Msg); //удаление сообщений из очереди
    end;

    end.
    //Немного оптимизации 

    Создание трейнера на WinAPI. Пример 2

    …в блокноте файл trainer.rc,который будет содержать следующие строки:

    ======================trainer.rc============================

    100 DIALOG 0, 0, 173, 69

    STYLE DS_SETFONT | DS_CENTER | WS_CAPTION | WS_SYSMENU

    CAPTION "[FlatOut] Trainer +1"

    FONT 8, "Terminal"

    {

    PUSHBUTTON "About", 102, 2, 52, 36, 15, BS_FLAT

    PUSHBUTTON "Close", 101, 132, 52, 38, 15, BS_FLAT

    GROUPBOX "Trainer options: ", -1, 1, -1, 172, 51

    LTEXT "[C0DED] <--::--> bY g-l-u-k [TeaM - X]", -1, 7, 36, 164, 12, WS_DISABLED

    LTEXT "[F1] :.......: More Money", -1, 7, 9, 126, 12, WS_DISABLED

    }

    ======================trainer.rc============================



    uses
    windows, messages; //Именно по этому наш трейнер должен весить
    //меньше,если помните то в прошлой части учебника мы использовали //ещё и commctrl.

    const
    ID_ABOUT = 102; //Номера контролов нашего ресурса
    ID_EXIT = 101;
    Elapse = 10; //Нужен для таймера
    aboutcap = 'About'; //Наш About Dialog
    aboutmsg = ' [C0DED]: bY g-l-u-k [TeaM - X] ' +#13#10+
    ' ' +#13#10+
    ' GreatZzz....: ' +#13#10+
    ' ' +#13#10+
    ' Baron_Gede,6aHguT,AllexY ' +#13#10+
    ' And all TeaM - X Members ! ' +#13#10+
    ' ' +#13#10+
    ' Write on pure Delphi (WinAPI) ' +#13#10+
    ' copyright (g-l-u-k)R 2004-2005 ' +#13#10+
    ' ' +#13#10+
    ' <!-- m -->[url=http://www.team-x.ru]http://www.team-x.ru[/url]<!-- m --> ' +#13#10+
    ' e-mail : <!-- e -->[email=g-l-u-k@rambler.ru]g-l-u-k@rambler.ru[/email]<!-- e --> ' +#13#10+
    ' ' +#13#10+
    ' GEngine v0.1 ' +#13#10+
    ' All Right Reserved ';

    WindowTitle = 'Flat-Out'; //Название окна игры
    Address = $01B40C64;//Адресс нашего значения
    PokeValue = $FFFFFFFF;//наше значение
    NumberOfBytes = 4;//Кол-во байт

    var
    Msg : TMSG;
    Win : HWND;
    WindowName : Integer;
    ProcessId : Integer;
    ThreadId : Integer;
    hInst : Dword;
    Buf : PChar;
    HandleWindow : Integer;
    Write : Cardinal;

    {$R trainer.res} //Наш ресурс в котором хранится окно трейнера

    //Вот самая интересная часть нашего трейнера,процедура роверки.
    //Если TrainerSPY активен,то мы обломим следящего за нашим //трейнером.
    function IsTrainerSpyActive:bool;
    var
    hProcess,hKernel:dword;
    addr:pointer;
    b:byte;
    dummy:cardinal;
    proc:pchar;
    begin
    result:=false;
    proc:='WriteProcessMemory';

    if FindWindowExA(0,0,nil,'Trainer Spy')<>0 then
    begin
    result:=true;
    exit;
    end;

    hProcess:=GetCurrentProcess;
    hKernel:=LoadLibrary('kernel32.dll');

    if hKernel<>0 then
    begin
    addr:=GetProcAddress(hKernel,proc);
    ReadProcessMemory(hProcess,addr,@b,1,dummy);
    FreeLibrary(hKernel);
    if b=204 then result:=true;
    end;

    end;

    //Процедура взлома игры,описывать полностью не буду,опишу только //самое главное.
    procedure Cheating;
    begin
    if IsTrainerSpyActive then //если TrainerSpy запушен, то вырубаемся
    begin
    MessageBox(0,'Выруби шпион.','Ошибка зашиты',MB_OK or MB_ICONERROR);
    exit;
    end;

    WindowName := FindWindow(nil,WindowTitle);

    If WindowName = 0 then
    MessageBox(win,'Игра должна быть запушенна до трейнера','Ошибка',MB_OK or MB_ICONINFORMATION);

    ThreadId := GetWindowThreadProcessId(WindowName,@ProcessId);
    HandleWindow := OpenProcess(PROCESS_ALL_ACCESS,False,ProcessId);

    GetMem(buf,1);
    buf^ := Chr(PokeValue);
    WriteProcessMemory(HandleWindow,ptr(Address),buf,NumberOfBytes,write);
    FreeMem(buf);
    CloseHandle(HandleWindow);
    end;

    procedure Quit; //процедура выхода из программы
    begin
    EndDialog(win,0);
    Halt;
    end;

    procedure DoTimer; //Дополнительна зашита от шпионов
    begin
    CreateFileA('C:logwmemory.bin',$40000000,1,nil,2,1,0);
    hInst:= GetModuleHandle(nil);
    SetTimer(hInst,1,Elapse,@DoTimer);
    end;

    //Обработчик событий нашего окна
    function SettingsDlgProc(Window : hWnd; Msg,WParam,LParam : Integer): Integer; StdCall;
    begin
    case Msg of
    wm_InitDialog : begin
    end;
    wm_Close : DestroyWindow(Win);
    wm_Destroy : PostQuitMessage(0);
    end;
    Result := 0;
    case Msg of
    WM_COMMAND : begin
    if wParam = ID_EXIT then Quit; //Ели нажата кнопка выхода,выходим
    if wParam = ID_ABOUT then MessageBox(Win,aboutmsg,aboutcap,MB_OK or MB_ICONINFORMATION);//А это наш //about
    end;
    end;
    end;

    //Процедура создания главного окна
    Procedure RunSettings;
    begin
    Win := CreateDialog(hInstance,PCHar(100),0,@SettingsDlgProc);
    Showwindow(Win,SW_SHOW);
    Updatewindow(Win);
    end;

    // Начало программы
    begin
    RunSettings;

    while GetMessage(Msg,0,0,0) do
    begin
    //Цикл сбора сообщений
    TranslateMessage(Msg);
    if (GetAsyncKeyState(VK_F1) <> 0) then Cheating;//Горячая клавиша
    DispatchMessage(Msg);
    end;

    end.
    program FlatOut; //Опять будем ломать FlatOut

    Заключение.

    Можно было заметить как был построен материал. Сначала была дана справочная информация, а затем можно было увидеть применение функций WinApi в коде трейнеров. Как вы понимаете это базовая основа, т.к. некоторые тонкости не освещены. Например, поиск процесса игры по имени процесса, а не по имени окна. Здесь нет функций сканирования сигнатур для поиска адреса внедрения. Нет проверки на повторный запуск трейнера. Нет отмены читов при закрытии трейнера… Читы не выделяются в выделенную память. Байт-код внедряемых игровых инструкций пишется в память игры через байты, которые нужно получать предварительно при компиляции. Я бы эти байты не получал бы таким образом, а получил бы их скомпилировав инструкции в самом трейнере, а затем бы их копировал бы в игровой процесс в выделенную память. Возможно, я ещё что-то забыл указать…

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

  16. В общем Xipho помог мне с инсталлером и он сделал поиск пути по ключу в реестре

    [sp=Ключ][HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionUninstallCheat Engine 5.6_is1]

    "Inno Setup: Setup Version"="5.3.6 (a)"

    "Inno Setup: App Path"="E:ReversingGamehackИнструментыCheat Engine5.6"

    "InstallLocation"="E:ReversingGamehackИнструментыCheat Engine5.6"

    "Inno Setup: Icon Group"="Cheat Engine 5.6"

    "Inno Setup: No Icons"=dword:00000001

    "Inno Setup: User"="_"

    "Inno Setup: Selected Tasks"=""

    "Inno Setup: Deselected Tasks"="desktopicon"

    "DisplayName"="Cheat Engine 5.6"

    "UninstallString"=""E:ReversingGamehackИнструментыCheat Engine5.6unins000.exe""

    "QuietUninstallString"=""E:ReversingGamehackИнструментыCheat Engine5.6unins000.exe" /SILENT"

    "Publisher"="Dark Byte"

    "URLInfoAbout"="http://www.cheatengine.org/"

    "HelpLink"="http://www.cheatengine.org/"

    "URLUpdateInfo"="http://www.cheatengine.org/"

    "NoModify"=dword:00000001

    "NoRepair"=dword:00000001

    "InstallDate"="20100221"[/sp]

    Что-то я не понял. Инсталлер не правильно дописывает путь с существующей оригинальной версией? Подразумевается что у пользователя одна версия оригинальной CE и одна папка :) Делать две отдельных папки для CE RUS и оригинальной думаю не стоит ) всё предпочтительно в одной. Ну а если кто хочет две разные папки, то придётся в ручную делать.

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.