Лидеры
Популярный контент
Показан контент с высокой репутацией 13.01.2016 во всех областях
-
Demono50601, у меня вопрос - Сколько тебе лет? Судя по формулировкам - лет 12. Vlad2, я думаю Demono50601 ещё не преступал к написанию скриптов, они берут готовые сигны (сигну, которую нужно найти и сигну, на которую нужно заменить и знают как с помощью СЕ сделать из этого трейнер ) В своё время, пока не вышел на наш форум, я насмотрелся в ТЮБЕ псевдо-уроков от таких малышей. Demono50601, если хочешь поучиться чему-нибудь на форуме, сперва научись сдержанности.2 балла
-
"Можете ли вы нарисовать 7 перпендикулярных красных линий? Можете ли нарисовать из линии котёнка? Ведь это было бы здорово! Нет, не перебивай. Ты - эксперт и должен знать как это сделать." Начальство говорит "сделай". О том как придется выкручиваться человеку, от которого требуют невозможное.1 балл
-
ООП состоит на основе трёх концепций: инкапсуляция, наследование и полиморфизм. Но модель ООП на этом не заканчивается. В каждом отдельном языке программирования добавлены свои "прибамбасы" относительно наследования и полиморфизма, что формирует модель ООП соответствующую языку программирования. Из всех языков которых я знаю или сталкивался С++ и его продолжения наиболее сильные в ООП. О концепциях ООП Тоже самое в IDA рис. 3 А вот так выглядит в псевдокоде рис. 4 При обмане игр у нас не будет исходника С++ и нам нужно научится понимать псевдокод. Сделаем немного понятнее псевдокод. Нажмём shift+F9 и опишем структуру класса Player с 3*4 байт рис. 5 Затем в псевдокоде нажмём на Y и определим тип структуры: рис.6 И получим более лучшее представление псевдокода Рис.7 И ещё давайте посмотрим, что будет если мы не иницилизируем некоторые данные объекта. рис 8 Результат такой: рис 9 Переменные x1.x2.x3 не инициализировались и остался мусорный код выделенной памяти. Когда выделяется память, то она не «подчищена», если вы не знали. Подведём итог. Познакомились с С++ (если не были знакомы) увидели на простом примере как оформляется структура объекта в С++ и как она выглядит в памяти и в псевдокоде. Увидели как псевдокод облегчает анализ игровых объектов. Главное научиться проводить аналогии между псевдокодом и дизассемблерным кодом для того чтобы представить как устроен объект. Если у вас возникли трудности в С++ то существует много информации в Интернете, которую вы можете легко найти самостоятельно. Часть2. Дальнейшее исследования игрового объекта в памяти Виртуальные функцииВиртуальные классы и множественное наследование 3.1 Виртуальные функции. Если вы не сталкивались с полиморфизмом ни разу и вообще с ООП знакомы мало, то понять эту тему будет, скорее всего, сложно. Виртуальные функции это одинаково объявленные функции в иерархии наследования, которые позволяют работать с данными объекта в контексте нужного класса. Объяснил как смог.. =) Очень важно понять, как это работает для исследования игровых объектов в дальнейшем, т.к. виртуальные функции попадаются сплошь и рядом. Разберём пример «на пальцах», показывающий выгоду виртуальных функции перед похожими, но не виртуальными одинаковыми функциями. Программа перемещает графические объекты по нажатым клавишам клавиатуры, но писать мне её некогда, поэтому разберу основное. { int x,y; public: Dot() {x=100; y=100;} // просто зададим координаты по умолчанию void show(){сделать пиксел белым}; void hide() {сделать пиксел черным}; void move (int dx,dy){ hide(); x+=dx; y+=dy; show()}; };class Dot Мы создали класс Точки, у которой описаны координаты положения и описаны функции перемещения с угасанием и отображения точки. Ключевое место здесь в том, что в функции перемещения присутствуют локальные вызовы угасания и отображения точки. Именно из-за локальных вызовов появится проблема в производном классе, т.к. в базовом классе будут вызываться свои локальные функции с тем же именем. Выходом будет определение виртуальных функций. Рассмотрим эту проблему. { int radius; public: Ring () {radius=200;}; //зададим радиус круга по умолчанию void show(){сделать окружность белой}; void hide(){сделать окружность чёрной}; };class Ring: public Dot Видим, что Круг наследует функцию перемещения, в которой происходят локальные вызовы hide и show. Т.е. если мы зададим движение Кругу, то двигаться будет Точка, т.к. вызываются локальные функции в контексте класса Точки. Ring *ring=new(Ring); ring->mov(50,60); // вызовет перемещение только точки,а не круга Чтобы решить эту проблему был введен механизм виртуальных функций. Вызов той или иной функции задается смещением (генерируемым компилятором), по которому в созданной таблице виртуальных методов (vftable) выбирается нужная функция, которая и вызовется. { int x,y; public: Dot() {x=100; y=100;} // просто зададим координаты по умлочанию virtual void show(){сделать пиксел белым}; virtual void hide() {сделать пиксел черным}; void move (int dx,dy){ hide(); x+=dx; y+=dy; show()}; }; class Ring: public Dot { int radius; public: Ring () {radius=200;}; // также просто зададим радиус круга void show(){сделать окружность белой}; void hide(){сделать окружность чёрной}; };class Dot Теперь ring->mov(50,60); // вызовет перемещение только круга в заданные координаты 50 и 60 ring->Dot::mov(50,60); // этот метод в принципе бесполезный, т.к. координаты точки уже были равны 50 и 60Ring *ring=new(Ring); Вызывать метод перемещения точки было не обязательно, главное то, что круг наследовал координаты x и y и можно и нужно перемещать только круг. Однако, если вы вызовете ring->Dot::mov(100,100), то это распространится и на круге... т.е. и точка и круг взаимосвязаны и буквально слеплены в одно целое как в симбиозе (кто биологию хорошо знает? ) Как мы увидели механизм «виртуальных функций (полиморфизм)» нужен для правильной работы с данными объекта в требуемых контекстах его описывающих классов. Чаще всего виртуальные функции объявляются без входных параметров, таким образом, их применение наиболее удобно и более расположено к полиморфизму. При полиморфизме в статичной области кода возникает таблица виртуальных функций vftable. Указатель на таблицу виртуальных функций находится по первому адресу объекта (см. рис. 1) рис. 1 Следует отметить, что vftable характерна только для определённого типа класса. Если вы найдёте в памяти игры адрес таблицы виртуальных функций (vftable) некоторого объекта и затем в сканере памяти найдёте 6 указателей на ту же vftable, то можете считать что вы «вышли» ещё на 6 объектов, которые наследовали vftable класса или некоторой иерархии классов. Соответственно по указателю на vftable в чит-кодах можно делать фильтры по изменению данных игровых объектов построенных по описанию конкретного класса или по описанию классовой иерархии. Учитывая всё выше известное, напишем программу с игровыми объектами и проанализируем формирование объектов с vftable. Результат программы будет таким. рис. 2. (Координат нет, это вы поймете на рис 6 ) В данной программе и в случае, кода виртуальные функции наследуются, то vftable сильно усложняется. Нам будет очень полезно рассмотреть случай ниже для обмана игр. Сначала посмотрим расположение данных двух объектов, после того как мы их заполнили. Так мы увидим данные после того как CE сама расструктуризовала их. рис. 3 Как мы видим, структуры объектов заполнены непонятными данными по смещениям 0x18-2С, 4C-0x64, 0x68-0x6C. Адреса по этим смещениям рассмотрим позже. Сейчас важно понять, как устроены таблицы на рисунке по смещениям 0x0, 0x30 и как они работают. Они выглядят вот так (так как и расструктуризавала CE) рис. 4 Для удобства переведём эти значения в hex- вид рис. 5 Я пока не знаю, правильно ли я определил, что по смещению 0хС значение 0х48 указывает на конец таблицы виртуальных функций в контексте всей иерархии классов... 00401017 – это указатель на функцию Player:: GetInfo 0040102B – это указатель на функцию Building::GetInfo Обращение к указателям компилируется в коде (вы это можете посмотреть в дизассемблерном листинге ниже), т.е. в объектах не содержится данных о том к какой именно функции, в каком описании класса в какой момент обращаться. Залезем в псевдокод в функцию main, т.к. именно по нему нам надо учиться обманывать игры и смотрим рис 5 и рис.6 В псевдокоде смещения в структурах объектов десятичные,но там не сложные числа можно перевести в 16-ричную систему в уме для того чтобы соотнести смещения структур на рис. 5 рис. 6 GetInfo в контексте класса control не сработала, из-за виртуальных функций, так и должно быть. Псевдокод показывает всё что необходимо и это гораздо нагляднее, чем смотреть дизассемблерный код в отладке. Для интересующихся (маньяков) привожу дизассемблерный код. Комментировать не буду, т.к. основное всё разобрал. Скопируйте его в отдельное место и можете тщательно разобраться как что и куда. С виртуальными функциями более менее познакомились. Возможно, в следующих статья разберём ещё более тяжёлые случаи (адские ) Продолжение следует. В следующей частях возможно будет рассмотрено. Множественное наследование. Виртуальные функции при множественном наследовании. Виртуальное наследование классов. Виртуальные функции при виртуальном наследовании классов. Статичные данные и функции в объектах. Дружественные функции в объектах. Массивы объектов. Объекты по шаблону. Объекты по стандартному шаблону . Сообщения. Методы дизассемблирования и отладки. Объекты совместно с lua – интерпритатором. Создаём объекты через конструкторы и команды lua. Обход антиотладочных ловушек xlive. Распаковка игровых ресурсов. Обман flash игр. Обман .NET игр. Обман JAVA игр. Обман эмуляторных игр, поиск нулевого адреса.1 балл
-
Обновил его и добавил бесконечный рпг. Дизайн не множко сменил попробовать.1 балл
-
ЗЫ: Кстати забыл написать - выяснил, почему игра вылетала у меня,Dison и у LIRW: Мы делали инъекцию из инструкции на чтение, а на неё есть прыг из различных мест. Так что инъекцию сделал ниже инструкций на запись.1 балл
-
Сделал, теперь без вылетов. 1. Сам скрипт: { Game : game.exe Version: Date : 2016-01-12 Author : Garik66 This script does blah blah blah}[ENABLE]{$LUA}PlaySound(findTableFile([[Activate]])){$ASM}aobscanmodule(INJECT,game.exe,8B 48 08 89 4B 08) // should be uniquealloc(newmem,$1000)label(Fuel)label(code)label(return)label(money)registersymbol(money)label(fuel)registersymbol(fuel)registersymbol(INJECT)newmem: cmp [ebx+08],3 jne code cmp [ebx+18],4 jne code mov ecx,[ebx+10] cmp [ecx+10],656E6F6D jne Fuel cmp byte ptr [ecx+14],79 jne code fld qword ptr [money] fstp qword ptr [ebx] jmp codeFuel: cmp [ecx+10],6C657566 jne code cmp [ecx+14],6C6C6946 jne code cmp [ecx+18],6576654C jne code cmp byte ptr [ecx+1C],6C jne code fld qword ptr [fuel] fstp qword ptr [ebx]code: mov ecx,[eax+08] mov [ebx+08],ecx jmp returnmoney:dq (double)1000000fuel:dq (double)1000INJECT: jmp newmem nopreturn:[DISABLE]{$LUA}PlaySound(findTableFile([[Deactivate]])){$ASM}INJECT: db 8B 48 08 89 4B 08unregistersymbol(money)unregistersymbol(fuel)unregistersymbol(INJECT)dealloc(newmem){// ORIGINAL CODE - INJECTION POINT: "game.exe"+D65C1"game.exe"+D65A5: 33 FF - xor edi,edi"game.exe"+D65A7: EB 02 - jmp game.exe+D65AB"game.exe"+D65A9: 8B F8 - mov edi,eax"game.exe"+D65AB: 85 FF - test edi,edi"game.exe"+D65AD: 0F 85 D3 00 00 00 - jne game.exe+D6686"game.exe"+D65B3: 8B 44 24 24 - mov eax,[esp+24]"game.exe"+D65B7: 8B 08 - mov ecx,[eax]"game.exe"+D65B9: 89 0B - mov [ebx],ecx"game.exe"+D65BB: 8B 50 04 - mov edx,[eax+04]"game.exe"+D65BE: 89 53 04 - mov [ebx+04],edx// ---------- INJECTING HERE ----------"game.exe"+D65C1: 8B 48 08 - mov ecx,[eax+08]"game.exe"+D65C4: 89 4B 08 - mov [ebx+08],ecx// ---------- DONE INJECTING ----------"game.exe"+D65C7: 83 78 08 04 - cmp dword ptr [eax+08],04"game.exe"+D65CB: 0F 8C E5 00 00 00 - jl game.exe+D66B6"game.exe"+D65D1: 8B 10 - mov edx,[eax]"game.exe"+D65D3: F6 42 05 03 - test byte ptr [edx+05],03"game.exe"+D65D7: 0F 84 D9 00 00 00 - je game.exe+D66B6"game.exe"+D65DD: 8A 45 05 - mov al,[ebp+05]"game.exe"+D65E0: A8 04 - test al,04"game.exe"+D65E2: 0F 84 CE 00 00 00 - je game.exe+D66B6"game.exe"+D65E8: 8B 4C 24 18 - mov ecx,[esp+18]"game.exe"+D65EC: 8B 49 10 - mov ecx,[ecx+10]}1 балл