-
Постов
2 999 -
Зарегистрирован
-
Победитель дней
129
Тип контента
Профили
Форумы
Загрузки
Блоги
Сообщения, опубликованные MasterGH
-
-
Не забывайте, что одновременно с Cheat Engine есть инструменты OllyDbg(удобный отладчик в пошаговой отладке и установки условных бряков), IDA + Hex-Rays(анализирование дизассемблерного кода и декомпилирование), RecSudio(декомпилирование), Function Hacker (перехват тех или иных функций), MHS... В последней программе есть удобная функция просматривания и составления цепочек указателей....
В Cheat Engine есть LUA engine, который поможет ставить бряки и удобно снимать показания регистров в лог...
Так же в CE есть инструмент трассировщика с условием прерывания. Этот трейсер может показать огромное дерево иерархии вызовов кода...
В CE есть сканер указателей и dessect data tool позволит просматривать и сравнивать структуры.
Так же повторюсь, если очень трудно искать всю цепочку указателя и нужно найти лишь частичный путь это цепочки, то важно определять сколько и какие адреса проскакивают в квадратных скобках инструкций работающие с указателями уровней. Cheat Engine это умеет делать, пример этого я приводил выше.
Сами понимаете, что учиться овладеть этим далеко непросто. Можно использовать только OllyDbg, ставив условные бряки при выходе из call-а, по методу из статьи Never Winter Nigth.
У Cheat Engine есть сканер указателей. Его лучше не использовать, потому что он может найти неправильный указатель руководствуясь поиском указателей через вычитание и сложение смещений, когда могут быть и другие операции... и быть на 100% уверенным в том, что этот указатель будет всегда работать нельзя. У некоторого пользователя в какой-то момент этот указатель может "сбиться".
-
Путь адреса будет меняться с каждым запуском. Сделать этот путь постоянным практически не возможно. Поэтому требуется найти этот путь: словно такой-то город, такая-то улица, такой-то дом, такая-то квартира... "о здрасте, а вот и ты Адрес здоровья моего героя!" .
Некоторая машинная инструкция может работать с более коротким путём и может позволить быстрее добраться до адреса. Поэтому лучше не искать цепочки указателей, а искать адреса, ставить на них бряки и искать инструкции которые ближе к этому пути...Данное занятие невероятное муторное, запутанное и сложное для тех кто никогда этим не занимался. Но у нас есть много информации на форуме, которая может направить в нужном направлении.
-
Там гед я писал слово "уровень" это относилось к некоторому указателю в цепочки указателей...
Код игры прекрасно знает кто пользователь, а кто Бот. Это нужно всегда помнить.
Ищите зацепки в коде, в бряках на уровнях указателей, в структурах указателей. По крайне мере ищите цепочку указателей до статического адреса (он должен быть зелёным в CE) и не проиграйте.
Ещё один вариант это просто сравнивать структуры по адресам уровней указателей своих выбранных отрядов и отрядов бота. Выясните какие данные позволяют Вам передвигать Ваших юнитов и не позволяют командовать отрядами ботов. Я говорю сейчас про условную карту Мира, а не карту где войска могут захватывать замок...
Могу посоветовать установить игру по которой я делал статью и попытаться сделать также. Понимаю, наверно, это сложно, но ничего более точного и толкового подсказать не могу. Просто сейчас у меня нет возможность установить игру.
-
Ты мне не смог помочь (даже не указал где это видно)... макросы меня путают. Я вытягивать информацию не люблю. Буду сам разбираться.
-
Наверно, тогда не ID модели, а название модели машины. Должна быть функция дать игроку машину определённого названия...
-
Я вот всё равно не пойму, когда исключение срабатывает при обращении к несуществующему адресу, то как определяется чему должен установиться EIP? Есть быстрый ответ?
-
В посте номер 4. Есть строка кода:
58D5DD9F - 88 8E C4000000 - mov [esi+000000C4],cl
Определите какие адреса проскакивают в квадратных скобках. Это можно сделать из меню дизассемблера функцией "Find out what addresses this code accesses".
Если адрес будет проскакивать один, то это хорошо. Если больше двух, то ищем указатель уровня выше (который что-то писал в esi). На адрес указателя "уровня выше" ставим бряк на доступ и определяем прервавшиеся инструкции. На них также определяем проскакивающие адреса... Если найдётся один адрес, то к нему можно обращаться как фильтру...
Может быть я запутанно написал, но пока ничем больше помочь не могу.
-
Трейнер я так понимаю будет лучше делать на LUAEnigne?
Не увидел этот вопрос... Это уже второстепенный вопрос. Сначала надо понять что нужно реализовать, а затем уже думать на чём делать. Так что такой вопрос задавать без исследования рано. Возможно и на АА сделать можно.
Не факт. Если этот ID в разные загрузки игры один и тот же, возможно, это не дескриптор уже созданного объекта, а как бы одна из характеристик (модель машины). Тут может быть два варианта, если это ID заполняется один раз при создании объекта машины - тогда да, это сложно сделать, но, опять таки, исследуя код, реализующий встроенный в игру чит спавна машины, можно выйти на конструктор этого объекта и прореверсить передаваемые ему параметры. Я склоняюсь к тому, что именно этот подход применен, ибо он наиболее логичен. Второй вариант - при каждом обращении к объекту считывается его ID и подставляется нужная модель машины.
Я думаю ты запутался Вот попробуй найти указатель на машину, когда герой в неё садиться и выходит. Сесть в другую машину, чтобы найти указатель другой машины. Сравнивать структуры машин в поисках ID. Затем если найдёшь эти ID и поставишь бряк на доступ, то на конструктор ты не выйдешь, даже если поднимешься до корневого элемента в дереве вызовов...
C бОльшей уверенностью скажу что 2 Способ от MasterGH верный
PS Если найду исходники моего давнего трейнера для GTA IV выложу тут, спавн тачек присутствует
Когда найдёшь и покажешь, тогда тебе и поверим... иначе всё останется туманной теорией
-
Я ни разу не делал обработку исключений (SEH) на Ассемблере. Xipho, может быть ты делал и знаешь быстрое решение? Я знаю есть мануалы, но пока мне их некогда читать.
Вот пример АА на CE (в комментариях указано где нужно обработать SEH):
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(_cmpString)
label(_valueString)
label(_pValueString)
label(_pCmpString)
newmem:
pushfd
pushad
push ecx //+44(4 + 4*9 + 4) или 11 двордов
lea eax, [esp+4*B+0ac]
lea ebx,[_cmpString]
mov [_pCmpString], ebx
lea ebx,[_pCmpString]
// прооверка строки "GetPlayerFaction" по [esp+ac]
cld
mov ecx,#16
lds esi,[eax] //<<< здесь нужна обработка исключения в случае если по eax нет указателя на строку
les edi,[ebx]
cmpsb
jnz short originalcode
// если строки совпали, то записать по [esp] "999999"
lea ebx,[_valueString]
mov [_pValueString], ebx
lea ebx,[_pValueString]
mov ecx,7
lds esi,[ebx]
les edi,[esp] //<<< здесь нужна обработка исключения в случае если по esp нет указателя на строку
cld
rep movsb
originalcode:
pop ecx
popad
popfd
mov eax,[ecx]
mov edx,7EFEFEFF
jmp returnhere
db 90 90 90 90 90
_pCmpString:
dd 0
_pValueString:
dd 0
_cmpString: //"GetPlayerFaction"
db 47 65 74 50 6C 61 79 65 72 46 61 63 74 69 6F 6E 00
_valueString: // "999999"
db 39 39 39 39 39 39 00
"SpazGame.exe"+157790:
jmp newmem
nop
nop
returnhere:
[DISABLE]
"SpazGame.exe"+157790:
mov eax,[ecx]
mov edx,7EFEFEFF
dealloc(newmem)Есть ещё один вариант "не париться" с ассемблером, а сделать dll-инжект на языке высокого уровня с обработкой исключений в секциях try ... catch. Но всё-таки может быть кто-то в курсе обработки на ассемблере?
-
Xipho
ID машины в гараже нашел, а процедуру вызова машины по координатам нельзя из этого сделать?
Нельзя. Этот ID уже появился. Конструктор (инструкции машинного кода) уже создал этот ID. Конструктор для этого ID уже отработал своё и более работать не будет. По этому ID ты не выйдешь на конструктор поставив бряк.
Чтобы сделать чит надо быть серьёзным реверсером - программистом с багажом практики у которого есть время копаться в этом.
-
Спасибо за оформленный вопрос (мне понравилось).
Сегодня я не смогу ответить... так что наверно до завтра.
-
Почему я не мог раньше догадаться до такой простой вещи - аттач к процессу сделать по горячей клавише! В этом случае пользователь не увидит, что форма подвисает при AObscan-е.
-
Нашел чит в GTA III, как его вызвать?
add [ecx+009416D8],bh
00490F35 - push 01
00490F37 - push 005F62A0 : ["CHEAT3"]
00490F3C - call 0052C7E0
00490F41 - push eax
00490F42 - call 005052C0
00490F47 - pop ecx
00490F48 - pop ecx
00490F49 - call 004A1240
00490F4E - mov [eax+000002C0],42C80000 //Тут устанавливается количество жизней
00490F58 - call 004A11B0
00490F5D - test eax,eax
00490F5F - je 00490F92
00490F61 - call 004A11B0
00490F66 - mov [eax+00000200],447A0000
00490F70 - call 004A11B0
00490F75 - mov eax,[eax+00000284]
00490F7B - test eax,eax
00490F7D - jne 00490F92
00490F7F - push 00
00490F81 - call 004A11B0
00490F86 - add eax,00000288
00490F8B - mov ecx,eax
00490F8D - call 00545B40
00490F92 - retЭтот код по идее должен вызываться при сравнении с адресом.
Если в адресе значение "1", то код приведённый выше будет выполняться.
Соответственно надо найти в памяти этот адрес сканером памяти, когда чит включен или выключен.
Ну а дальше, поскольку ты хочешь каким-то странным способом создать чит уже думай сам. Стандартный же вариант о котором написали уже несколько человек это найти адрес здоровья, затем инструкцию которая работает с адресом и внедрить в неё свой чит-код.
-
1) По-моему некрасиво показывать "смех" типа "нафига ты написал так много, когда можно было сделать проще". Ничего смешного нет. Хотя бы потому, что я вложил свой труд в создание статьи.
2) Не все игры поддерживают параметры запуска оконного режима: ни -w, ни "-win", ни "window", ни другие могут не работать. Тогда кому-то возможно будет полезна именно эта статья особенно в случае, когда один процес запускает другой с параметрами... и дочерний процесс можно запустить минуя родительский с установлением оконного режима. Польза от статьи я думаю есть.
-
Это возможно, это совершенно точно. Но решения у меня нет, т.к. я этим читом не занимался. Могу дать только подсказки.
Решение твой задачи может быть очень даже непростым делом. По поводу идеи, даже если ты найдёшь адрес некоторого ID (кстати непонятно какого так как их, скорее всего, может быть несколько у машины), то скорее это не прокатит, т.к. ты не разберёшься с рутиной дизассемблерного кода.
1. Способ.
Насколько я помню, у игры есть читы чтобы получить ту или иную машину. Поэтому есть вариант проследить в отладке как это происходит. Здесь уже должен быть некоторый участок кода, который обрабатывает ввод от пользователя. Можно определить этот ввод в отладчике (как делать объяснять не буду, это долго) и выйти на нужный код, который создаёт машину. Главное добраться до этого кода, а там уже можно что-нибудь придумать.
2. Способ.
Могу предположить с большой вероятностью, что создание того или иного объекта в этой игре зависит от данных - сценариев (некоторого формата в оперативной памяти подгружаемых при начале уровня) и кода обрабатывающий эти сценарии (некоторые сценарии должны постоянно обрабатываться на истинность тех или иных условий)... Если в некотором сценарии для уровня будет директива "создать такую-то тачку по таким-то координатам после того как произойдёт что-то", то код "создаст такую-то тачку". Понять весь этот процесс возможно будет довольно тяжело. У тебя должно быть как минимум два сложных пути создания спавна. Изменить сценарий в памяти или изменить машинный код обработки сценариев. Что будет сложнее это уже зависит от игры. Изменив сценарий это ещё не значит, что его часть поступит на обработку, поэтому сценарий надо менять определённым образом (я без понятия каким). Оба способа должны вывести на функцию принимающую аргументы создания того или иного объекта в игре по тем или иным параметрам. Эту функцию предположительно надо чётко выполнить и тачка должна появиться.
Конечно, я не знаю как в этой игре всё на самом деле, но в своих предположениях я опирался на логику разработки игры. Если в игре что-то должно происходить, то это гораздо легче описывается сценариями и эти сценарии должны обрабатываться с вызовом функций.
-
Эту функцию можно использовать относительно игры для замены предполагаемых случайных величин постоянными. Не факт, что предполагаемые величины будут рандомными и не факт что будет работать функция Антирандома. Но можно попробовать включить эту функцию и если повезёт, то случайные значения будут постоянными.
-
Ничего присоединять не надо ))
Запустил CE.
Открыл LUA-консоль вставил код выше и выполнил его.
Запустил игру в моём случае "UT3.exe"
Начал играть.
Нажимаю F2 - увеличить скорость,F3 - уменьшить, F4 - сбросить до нормальной.
Скрипт этот только пример.
В настройках CE можно зайти и поставить свои хот-кеи на увеличение и уменьшение скорости, или на установку определённой скорости. Я совсем забыл про эти установки... Мне не надо было Lua скрипт писать оказывается... Ну пускай останется в качестве образовательных целей - написания кода на Lua.
-
Если Вам кажется что в игре какие-то действия происходят слишком медленно или слишком быстро, то почему бы не увеличить или не уменьшить скорость. Герой будет быстрее передвигаться, быстрее стрелять... или же этот процесс можно замедлить. А вдруг в игре Вы что-то долго ждёте: медленные разворачивающиеся события... В таких случаях можно использовать следующий скрипт на Lua.
speed = 1.0
function IncSpeed(hotkey)
speed = speed + 1
speedhack_setSpeed(speed)
end
function DecSpeed(hotkey)
speed = speed - 1
speedhack_setSpeed(speed)
end
function ResetSpeed(hotkey)
speed = 1.0
speedhack_setSpeed(1.0)
end
function SetHotKey(func, hotkey)
local objectHotKey = createHotkey(func, hotkey)
generichotkey_setKeys(objectHotKey, hotkey)
generichotkey_onHotkey(objectHotKey, func)
end
function onOpenProcess(processid)
SetHotKey(IncSpeed, VK_F2)
SetHotKey(DecSpeed, VK_F3)
SetHotKey(ResetSpeed, VK_F4)
end
local aalist = getAutoAttachList()
stringlist_add(aalist, "UT3.exe")Измените горячие клавиши и имя процесса на свои данные. Константы горячих клавиш найдёте здесь. Если вам нужно задать комбинацию горячих клавиш таких как "CTRL+1", то посмотрите справку по createHotkey и generichotkey_setKeys. Горячие клавиши записываются через запятую в этих функциях...
- 1
-
Я продолжаю писать код на LUA для генерации трейнеров. Мне понадобилось сохранение пользовательских параметров и восстановление их при следующем запуске Lua файлов CE. Естественно, я не хотел писать то, что возможно уже написано (ссылка)
Для начала мини тутор:
ini_table = {}
ini_table["n"] = {}
ini_table["n"]["n"] = {}
ini_table["n"]["n"]["n"] = 10
for k,v in pairs(ini_table) do
for k1,v1 in pairs(v) do
for k2,v2 in pairs(v1) do
print(k2,v2)
end
end
end
-- Вывод:
-- n 10Если не поняли, то обращаемся к докоментации LUA. Данный приём позволит вывести ключи и значения. Именно этот приём позволит прочитать значения ini - файла. Давайте попробуем создать файл some.ini по пути логического диска D. У вас может быть другой путь.
[Section1]
s1_KEY=Value
[sect2]
s1_KEY=Value
s1_KEY=Value2В консоли LUA Engine попытаемся вывести значения из файла.
return string.format ("%s: %s:%d: %s", msg, filename, line_counter, line)
end
function get(filename) --> (ini_table) or (nil,err)
local f = io.open(filename,'r')
if not f then return nil, "cannot open file: " .. filename end
local line_counter=0
local ini_table = {}
local section, err
for fline in f:lines() do
--set counter for indicate on error
line_counter=line_counter+1
--clean for begin and end spaces
local line = fline:match("^%s*(.-)%s*{:content:}quot;)
--coments
if not line:match("^[%;#]") and #line > 0 then
--section
local sec = line:match("^%[([%w%s]*)%]{:content:}quot;)
if sec then
section = sec
if not ini_table[section] then ini_table[section]={} end
else
--parse key=value and clean for begin and end spaces
local key, value = line:match("([^=]*)%=(.*)")
--check on errors in ini-file
if not key then
err = make_err('key/value absent', filename, line_counter, fline)
break
end
--clean for begin and end spaces
key = key:match("^%s*(%S*)%s*{:content:}quot;)
value = value:match("^%s*(.-)%s*{:content:}quot;)
if not (key and value) then
err = make_err('bad key or value', filename, line_counter, fline)
break
end
if section then
if not ini_table[section][key] then ini_table[section][key]={} end
ini_table[section][key][value] = true
else
err = make_err('key/value outside a section', filename, line_counter, fline)
break
end
end
end
end
f:close()
if err then return nil, err end
return ini_table
end
function set(ini_table, filename)
f = io.open(filename,'w')
if not f then return nil, "cannot open file: " .. filename end
f:write('; Created by inilazy (http://luaforge.net/projects/inilazy/)\n\n')
for secname, sec in pairs(ini_table) do
f:write("[", secname, "]\n")
for keyname, key in pairs(sec) do
for value, _ in pairs(key) do
f:write(keyname, "=", value, "\n")
end
end
f:write "\n"
end
f:close()
return true
end
nriu, err = get("D:\\some.ini")
if (riu == nil) then
print(err)
else
for k,v in pairs(nriu) do
for k1,v1 in pairs(v) do
for k2,v2 in pairs(v1) do
print(k2,v2)
end
end
end
endlocal function make_err (msg, filename, line_counter, line)
Таким образом получим ответ:
Value2
ValueValue
Если вам нужны названия секций, а также запись в файл ini, то думаю уже сами разберётесь.
Я собираюсь использовать файл ini для настроек LUA трейнера.
В частности поддержка перводов на различных языках, пользовательское установленное имя процесса, хранение адресов сигнатур и т.п.
-
ANT' date='19 Июнь 2011 - 10:10' timestamp='1308456642' post='3415']Навеяло темой о "Function Hacker", только чит мне там не понравился.
Цель видео показать как работать с программой по нахождению функций отвечающих за то или иное действие. В другой игре может и не быть адреса от значения которого что-то зависит. Это значение может быть в регистре возвращаемой функции... Может быть какое-то мимолётное время в стеке и поймать значение в стеке сканером памяти будет невозможно.
Потом для обмана игры все средства должны быть "на вооружении". С помощью Function Hacker можно случайно сделать читы о которых даже и не подумаешь.
"Function Hacker" может помочь отсеивать функции которые нужно исследовать. И если повезёт, то ты быстро найдёшь ключевые моменты в дизассемблере от которых зависит тот или иной вызов функции. Ты сможешь определить то или иное условие...
-
SetTimer - установить таймер. Находится в User32.dll
KillTimer - уничтожить таймер. Находится в User32.dll
TimerProc - объявление вызываемой функции в таймере
Подробнее:
Timer Functions
http://msdn.microsof...3(v=VS.85).aspx
About Timers
http://msdn.microsof...0(v=VS.85).aspx
Using Timers
http://msdn.microsof...1(v=VS.85).aspx
--------------
Что-то на русском:
SetTimer http://rusapi.narod.ru/SetTimer.htm
WM_TIMER http://rusapi.narod.ru/WM_TIMER.htm
TimerProc http://rusapi.narod.ru/TimerProc.htm
KillTimer http://rusapi.narod.ru/KillTimer.htm
http://www.firststep.../help/r.php?249
http://www.cyberguru...e-tajmerov.html
В основном надо знать, что таймер создаётся через SetTimer импортируемую из User32.dll. Тамер срабатывает через определённый интервал времени. Количество срабатываний можно идентифицировать увеличивающимся счётчиком и в игре отображать этот счётчик как секунды, минуты или часы. Функцию извлечения системного времени и даты я не рассматриваю.
Если таймер создан, то ему присваивается целочисленный идентификатор, который возвращается функцией SetTimer. Снимая показания именно этого таймера нужно обращаться именно к этому идентификатору в структуре сообщения WM_TIMER или снимать показания внутри функции сигнатуры TimerProc, которая была специально привязана к созданному таймеру. WM_TIMER обрабатывается в оконной процедуре, где снимаются сообщения системы посланные hwnd окна игры... Если создана "специальная функция" для таймера, то она минует функцию оконной процедуры обрабатывающей системные сообщения.
-
Новая версия модуля TrainerGen.lua (версия 1.1)
-- Create by MasterGH
--[[
На будущее:
0) Добавить запуск игры из трейнера из указанного места
1) Сделать отображение читов перед внедрением серым цветом, после вндрения чёрным с бипом
2) Разобраться со скрытыми и не скрытыми читами в группах
3) Сделать отображение читов в виде дерева на основе дерева из главной таблицы Cheat Engine
Читы с префиксом "(+)" отображаются в дереве без префикса
Рядом с именем корневого элемента дерева должен отображаться хот-кей
Корневых элементов может быть не больше 9
4) Обновление формы во время сканирования
5) Возвратить сигнатуру
6) Интеллектуальное внедрение
8) Корректное использование трейнера, при повторном запуске игры.
9) Поодержка русских слов
10) Поддержка файлов перевода
11) Запоминание адресов внедрения, чтобы проивзодить меньше сканирований сигнатур
Раздел1
1) FillnopsInstruction_AndAddInCETable(cheatName, address)
Функция создаёт запись АА-скрипта в главной таблице CE c названием cheatName.
АА-скрипт будет стерать инструкцию по адресу address при активации. При деактивации код будет восстановлен.
2) FillnopsInstructionWithSignature_AndAddInCETable(cheatName, signature, typeMem, signatreOffset)
Функция создаёт запись АА-скрипта в главной таблице CE c названием cheatName.
Тоже что и FillnopsInstruction_AndAddInCETable только по сигнатуре.
Где signature - сигнатура
typeMem - тип сканируемой памяти
signatreOffset - смещение от сигнатуры в виде числа, которое может положительным и отрицательным.
3) GenerateAAscriptPageMem_AndAddInCETable( cheatName, address, injectInstruction, originalcode )
Функция создаёт запись АА-скрипта в главной таблице CE c названием cheatName.
Функция создаёт АА скрипт в новой странице памяти.
Не рекоммендуется использовать эту функцию. Она создана только для тестов из консоли LUA. Используйте альтернативные функции из Раздела 2:
BeginGenerateAA, GenerateAA, EndGenerateAA
4) CreateThread(CEEntryName, callLabel)
Функция создаёт запись АА-скрипта в главной таблице CE c названием CEEntryName.
Функция создания АА-скрипта для потока с добавлением этого скрипта в главную таблицу
Пригодится в случае создания АА исполнения кода находящегося под известной зарегистрированной меткой/
Рекоммендуется использовать эту функцию в особенных редких случаях. Используйте альтернативную функцию из Раздела 2:
BeginGenerateAA, AddCodeThread, EndGenerateAA
5) SetScriptInEntryCETable(cheatName, script)
Функция создаёт запись АА-скрипта в главной таблице CE c названием cheatName.
Добавление скрипта в главную таблицу как записи таблицы с названием cheatName. Если запись уже существует, то будет перезапись.
Рекоммендуется использовать эту функцию в особенных редких случаях. Используйте функциии из Раздела 2, которые добавляют скрипт в CE.
6) DeleteTableEntryes(tableCEEntryesName)
Удаляет записи из главной таблицы Cheat Engine.
tableCEEntryesName имеет формат вида {"имя","имя", ...}
7) GroupAA(nameGRcheat, tableCheats, stateDeleteTableCheats)
Группировка указанных скриптов tableCheats вида {"имя","имя",..} в новый создаваемые или существующий скрипт с названием nameGRcheat.
Группируемые скрипты будут удалены если stateDeleteTableCheats бует равен true
Раздел2
Используйте функции BeginGenerateAA и EndGenerateAA для формирования и исполнения скрипта. Между этими функциями разрешается выполнять другие функции с передачей aggregateMem и возрватом нового сформированного скрипта.
Пример:
script = BeginGenerateAA(script,...)
// Здесь любые функции из раздела 2 например это
script = GenerateAA(script, ...)
script = GenerateAAWithSignature(script, ...)
EndGenerateAA(script,...)
1) BeginGenerateAA(newMemDescription, sizeMem)
Герация начала формирования разметки
2) EndGenerateAA(aggregateMem)
Конец формирования разметки с исполнением АА-скрипта
3) GenerateAA(aggregateMem, cheatName, address, newCode, stateOriginalCode)
Продолжение формирования разметки.
Добавляет запись с названием cheatName в главную таблицу
В АА скрипте формируются метки originalcode_cheatName, где cheatName название из скрипта
4) GenerateAAWithSignature(aggregateMem, cheatName, signature, typeMem, signatureOffset, newCode, stateOriginalCode )
Продолжение формирования разметки по сигнатуре.
Добавляет запись с названием cheatName в главную таблицу
В АА скрипте формируются метки originalcode_cheatName, где cheatName название из скрипта
5) AddCodeThread(aggregateMem, newRegSymbols, AAcode)
Продолжение формирования разметки.
Добавляет запись с названием cheatName в главную таблицу
Регистрируется метка newRegSymbols и добавляется запись в главную таблицу runThread_newRegSymbols
6) AddRegisterSymbols(aggregateMem, tableNewSymbols)
Продолжение формирования разметки. tableNewSymbols вида {"имя","имя","имя","имя",...}
Регистрация пользовательских символа в формирующуюся разметку между началом и концом её формирования
7) AddAllocVariableRegistersymbols(aggregateMem, tableTableSymbols)
где tableTableSymbols может быть вида { {"pId", 4}, {"pRES", 4}, ... }
Продолжение формирования разметки.
Добавление регистрации пользовательского символа для участка памяти определённого размера в формирующуюся разметку между началом и концом её формирования.
8) AddCode(aggregateMem, newRegSymbols, AAcode)
Продолжение формирования разметки.
Добавление участка кода в скрипте в выделенную память. Участок код регистрируется под меткой newRegSymbols. Новый код AAcode
Локальные функции:
CheatAction(indexCheat)
Trainer_Close(sender)
Trainer_SendMessage(message)
Trainer_FormCreate(nameTrainer)
Trainer_CheatsCreateFromCETable()
onOpenProcess(processid)
ByteScan(signature, typeMem)
GetInfoInjection(address)
PreSubScript(script, patternWord, newWords)
DeleteEntryCETable(cheatName)
]]--
local frmTrainer = nil -- форма автоматически создаваемого трейнера
local frmTrainerWidth = 0
local frmTrainerHeigth = 0
local messageLabel = nil -- строка информации в трейнере
local _InitFunction -- указатель на пользовательскую функцию инициализации читов
local countObjectHotKeys = 0 -- countObjectHotKeys равное также кол-ву записей в главной таблице
local adrList = nil
local baseHotKey = "CTRL"
local function CheatAction(indexCheat)
local te = addresslist_getMemoryRecord(adrList, indexCheat-1)
if (memoryrecord_isActive(te)) then
memoryrecord_unfreeze(te)
else
memoryrecord_freeze(te, 0)
end
beep()
end
function onHotkey1(hotkey) CheatAction(1) end
function onHotkey2(hotkey) CheatAction(2) end
function onHotkey3(hotkey) CheatAction(3) end
function onHotkey4(hotkey) CheatAction(4) end
function onHotkey5(hotkey) CheatAction(5) end
function onHotkey6(hotkey) CheatAction(6) end
function onHotkey7(hotkey) CheatAction(7) end
function onHotkey8(hotkey) CheatAction(8) end
function onHotkey9(hotkey) CheatAction(9) end
local arrayFunction = {}
arrayFunction[1] = onHotkey1
arrayFunction[2] = onHotkey2
arrayFunction[3] = onHotkey3
arrayFunction[4] = onHotkey4
arrayFunction[5] = onHotkey5
arrayFunction[6] = onHotkey6
arrayFunction[7] = onHotkey7
arrayFunction[8] = onHotkey8
arrayFunction[9] = onHotkey9
local function Trainer_Close(sender)
closeCE()
return caFree
end
local function Trainer_SendMessage(message)
control_setCaption(messageLabel, message)
end
local function Trainer_FormCreate(nameTrainer)
frmTrainer = createForm(true)
setProperty(frmTrainer, "BorderStyle", "bsDialog")
control_setSize(frmTrainer, frmTrainerWidth, frmTrainerHeigth)
control_setCaption(frmTrainer, nameTrainer)
form_centerScreen(frmTrainer)
form_onClose(frmTrainer, Trainer_Close)
messageLabel = createLabel(frmTrainer)
control_setAlign(messageLabel, alBottom)
Trainer_SendMessage("Trainer is not ready")
end
local function Trainer_CheatsCreateFromCETable()
if (adrList == nil) then
adrList = getAddressList()
end
countObjectHotKeys = addresslist_getCount(adrList)
if (countObjectHotKeys < 1 or countObjectHotKeys > 9) then
showMessage("Cheats group count can not be less than 1 or greater than 9. Trainer will be closed")
Trainer_Close()
end
local x = 20
local y = 10
local yInc = 14
CheatLbl = createLabel(frmTrainer)
control_setPosition(CheatLbl, x, y)
control_setCaption(CheatLbl, "Cheats:")
x = x + 15
for i = 1,countObjectHotKeys do
local te = addresslist_getMemoryRecord(adrList, i-1)
local description = memoryrecord_getDescription(te)
local ObjectHotKeys = createHotkey(arrayFunction[i], VK_CONTROL, VK_0 + i) --string.format("%s",i)
generichotkey_setKeys(ObjectHotKeys, VK_CONTROL, VK_0 + i)
generichotkey_onHotkey(ObjectHotKeys, arrayFunction[i])
CheatLbl = createLabel(frmTrainer)
control_setPosition(CheatLbl, x, (i + 1) * yInc)
local stringHotKey = baseHotKey.."+"..i
control_setCaption(CheatLbl, i..") "..description..": "..stringHotKey)
end
Trainer_SendMessage("Trainer is ready!")
beep()
end
function onOpenProcess(processid)
_InitFunction()
Trainer_CheatsCreateFromCETable()
end
local function ByteScan(signature, typeMem) -- return address
Trainer_SendMessage("Scaning mode... Play in game and wait bell")
local results = nil
-- if (results == nil) then
-- messageDialog("Ошибка. Не найден адрес внедрения.\n\rТрейнер будет закрыт!",1, 2)
-- Trainer_Close()
-- end
repeat
results = AOBScan(signature, typeMem) -- typeMem = "+X-C-W" and any
-- form_show(frmTrainer)
sleep(200)
until (results ~= nil)
local address = stringlist_getString(results, 0)
object_destroy(results);
return address
end
local function GetInfoInjection(address) -- return adressReturnHere, originalCodeString, nopsString
local sumBytes = 0
local originalCodeString = " "
repeat
countBytes = getInstructionSize(address)
extrafield, opcode, bytes, address = splitDisassembledString(disassemble(address))
originalCodeString = originalCodeString.."\n "..opcode
sumBytes = sumBytes + countBytes
until (sumBytes >= 5)
adressReturnHere = string.format("%x", ("0x"..address) + countBytes)
local nopsString = ""
local nopsCount = sumBytes - 5
if (nopsCount>0) then
nopsString = " db"
for i = 1, nopsCount do
nopsString = nopsString.." 90"
end
end
return adressReturnHere, originalCodeString, nopsString
end
local function PreSubScript(script, patternWord, newWords) -- return bufferString
local index = string.find(script, patternWord)
local newscript = string.sub(script, 1, index - 1)..newWords.."\n"..string.sub(script, index)
return newscript
end
local function DeleteEntryCETable(cheatName)
local teSlave = getTableEntry(cheatName)
if (teSlave == nil) then
return
end
memoryrecord_delete(teSlave)
end
-- SECTION 1
function FillnopsInstruction_AndAddInCETable(cheatName, address)
adressReturnHere, originalCodeString, nopsString = GetInfoInjection(address)
local scriptAddMainTable = "[ENABLE]\n-->>address1[DISABLE]\n-->>address2"
local countBytes = getInstructionSize(address)
local nopsString = " db"
for i = 1, countBytes do
nopsString = nopsString.." 90"
end
scriptAddMainTable = PreSubScript(scriptAddMainTable,"-->>address1", address..":\n"..nopsString)
scriptAddMainTable = PreSubScript(scriptAddMainTable,"-->>address2", address..":"..originalCodeString)
scriptAddMainTable = string.gsub(scriptAddMainTable, "-->>address1", "")
scriptAddMainTable = string.gsub(scriptAddMainTable, "-->>address2", "")
SetScriptInEntryCETable(cheatName,scriptAddMainTable)
end
function FillnopsInstructionWithSignature_AndAddInCETable(cheatName, signature, typeMem, signatreOffset)
local workAddress = ByteScan(signature, typeMem)
if (signatureOffset ~=0) then
workAddress = string.format("%x", ("0x"..workAddress) + signatureOffset)
end
FillnopsInstruction_AndAddInCETable(cheatName, workAddress)
end
function GenerateAAscriptPageMem_AndAddInCETable( cheatName, address, injectInstruction, originalcode )
local addressInjection = address
local adressReturnHere = 0
local originalCodeString = ""
local nopsString = ""
adressReturnHere, originalCodeString, nopsString = GetInfoInjection(address)
if (originalcode) then
script =[[
[ENABLE]
alloc(newmem,2048)
label(originalcode)
label(returnhere)
newmem:
]]..injectInstruction..[[
originalcode:]]..originalCodeString.. [[
jmp returnhere
]]..addressInjection..[[:
jmp newmem
]]..nopsString..[[
returnhere:
[DISABLE]
]]..addressInjection..":"..originalCodeString.. [[
dealloc(newmem)
]]
else
script =[[
[ENABLE]
alloc(newmem,2048)
label(returnhere)
newmem:
]]..injectInstruction..[[
jmp returnhere
]]..addressInjection..[[:
jmp newmem
]]..nopsString..[[
returnhere:
[DISABLE]
]]..addressInjection..":"..originalCodeString.. [[
dealloc(newmem)
]]
end
SetScriptInEntryCETable(cheatName, script)
end
function CreateThread(CEEntryName, callLabel)
local bufscript = "%[ENABLE%]\n% createthread("..callLabel..")\n[DISABLE%]"
SetScriptInEntryCETable(CEEntryName, bufscript)
end
function SetScriptInEntryCETable(cheatName, script)
local teSlave = getTableEntry(cheatName)
if (teSlave == nil) then
teSlave = addresslist_createMemoryRecord(addresslist)
memoryrecord_setDescription(teSlave, cheatName)
end
memoryrecord_setType(teSlave, vtAutoAssembler)
memoryrecord_setScript(teSlave, script)
end
function DeleteTableEntryes(tableCEEntryesName)
local sizetable = table.getn(tableCheatsName)
for i=1,sizetable do
DeleteEntryCETable(tableCheatsName[i])
end
end
function GroupAA(nameGRcheat, tableCheats, stateDeleteTableCheats)
if (adrList == nil) then
adrList = getAddressList()
end
countObjectHotKeys = addresslist_getCount(adrList)
mainGRScript = "[ENABLE]-->>marker1\n[DISABLE]\n-->>marker2"
local delIndexes = {}
local count_delIndexes = 0
local zisetable = table.getn(tableCheats)
local description = ""
for i = 1,countObjectHotKeys do
local te = addresslist_getMemoryRecord(adrList, i-1)
description = memoryrecord_getDescription(te)
for j=1,zisetable do
if (tableCheats[j] == description) then
local script = memoryrecord_getScript(te)
local leftPos = 10 -- длина "[ENABLE]\n" 9 символов и плюс переход +1
local rigthPos = string.find(script, "%[DISABLE%]")
mainGRScript = PreSubScript(mainGRScript,"-->>marker1",string.sub(script, leftPos, rigthPos-2))
leftPos = rigthPos + 10 + 1
rigthPos = string.len(script)
mainGRScript = PreSubScript(mainGRScript,"-->>marker2",string.sub(script, leftPos, rigthPos))
count_delIndexes = count_delIndexes + 1
delIndexes[count_delIndexes] = te
break
end
end
end
if (stateDeleteTableCheats) then
for i = 1,count_delIndexes do
memoryrecord_delete(delIndexes[i])
end
end
mainGRScript = string.gsub(mainGRScript, "-->>marker1", "")
mainGRScript = string.gsub(mainGRScript, "-->>marker2", "")
SetScriptInEntryCETable(nameGRcheat,mainGRScript)
end
-- SECTION 2
function BeginGenerateAA(newMemDescription, sizeMem) -- return bufferString
return [[
alloc(]]..newMemDescription..","..sizeMem..[[)
registersymbol(]]..newMemDescription..[[)
->>label]]..newMemDescription..[[:
->>newCode
->>adressessInjected
]]
end
function EndGenerateAA(aggregateMem)
local endScript = string.gsub(aggregateMem, "->>label", "")
endScript = string.gsub(endScript, "->>newCode", "")
endScript = string.gsub(endScript, "->>adressessInjected", "")
autoAssemble(endScript)
end
function GenerateAA(aggregateMem, cheatName, address, newCode, stateOriginalCode) -- return bufferString
local addressInjection = address
local adressReturnHere = 0
local originalCodeString = ""
local nopsString = ""
adressReturnHere, originalCodeString, nopsString = GetInfoInjection(address)
registerSymbol("returnHere_"..cheatName, adressReturnHere)
local script = PreSubScript(aggregateMem,"->>label", "label("..cheatName..")")
script = PreSubScript(script,"->>label", "registersymbol("..cheatName..")")
if (stateOriginalCode) then
script = PreSubScript(script,"->>label", "label(originalcode_"..cheatName..")")
local buf = cheatName..":\n "..newCode.."\noriginalcode_"..cheatName..":"..originalCodeString.."\n jmp returnHere_"..cheatName
script = PreSubScript(script,"->>newCode", buf)
else
script = PreSubScript(script,"->>newCode", cheatName..":\n"..newCode.."\n jmp returnHere_"..cheatName)
end
local scriptAddMainTable = "[ENABLE]\n-->>address1[DISABLE]\n-->>address2"
scriptAddMainTable = PreSubScript(scriptAddMainTable,"-->>address1", addressInjection..":\n jmp "..cheatName.."\n"..nopsString)
scriptAddMainTable = PreSubScript(scriptAddMainTable,"-->>address2", addressInjection..":"..originalCodeString)
scriptAddMainTable = string.gsub(scriptAddMainTable, "-->>address1", "")
scriptAddMainTable = string.gsub(scriptAddMainTable, "-->>address2", "")
SetScriptInEntryCETable(cheatName,scriptAddMainTable)
return script
end
function GenerateAAWithSignature(aggregateMem, cheatName, signature, typeMem, signatureOffset, newCode, stateOriginalCode ) -- return bufferString
local workAddress = ByteScan(signature, typeMem)
if (signatureOffset ~=0) then
workAddress = string.format("%x", ("0x"..workAddress) + signatureOffset)
end
return GenerateAA(aggregateMem, cheatName, workAddress, newCode, stateOriginalCode)
end
function AddCodeThread(aggregateMem, newRegSymbols, AAcode)
newRegSymbols = "threadAA_"..newRegSymbols
local script = PreSubScript(aggregateMem,"->>label", "label("..newRegSymbols..")")
script = PreSubScript(script,"->>label", "registersymbol("..newRegSymbols..")")
script = PreSubScript(script,"->>newCode", AAcode)
local bufscript = "%[ENABLE%]\n% createthread("..newRegSymbols..")\n[DISABLE%]"
SetScriptInEntryCETable("runThread_"..newRegSymbols, bufscript)
return script
end
function AddRegisterSymbols(aggregateMem, tableNewSymbols) -- return bufferString
local sizetable = table.getn(newSymbols)
for i=1,sizetable do
PreSubScript(aggregateMem,"->>label", "label("..tableNewSymbols[i]..")")
PreSubScript(aggregateMem,"->>label", "registersymbol("..tableNewSymbols[i]..")")
end
return aggregateMem
end
function AddAllocVariableRegistersymbols(aggregateMem, tableTableSymbols) --tableTableSymbols = { {"pId", 4}, {"pRES", 4} } -- return bufferString
local sizetable1 = table.getn(tableTableSymbols)
for i=1,sizetable1 do
local inTable = tableTableSymbols[i]
local sizetable2 = table.getn(inTable)
for j=1,sizetable2 do
local regName = inTable[1]
local sizeRegName = inTable[1]
local template = regName..":\n".."db "
for j=1,sizeRegName do
template = sizeRegName.."00"
end
local name
PreSubScript(script,"->>label", "label("..regName..")")
PreSubScript(script,"->>label", "registersymbol("..regName..")")
script = PreSubScript(script,"->>adressessInjected", template)
end
end
return script
end
function AddCode(aggregateMem, newRegSymbols, AAcode)
local script = PreSubScript(aggregateMem,"->>label", "label("..newRegSymbols..")")
script = PreSubScript(script,"->>label", "registersymbol("..newRegSymbols..")")
script = PreSubScript(script,"->>newCode", AAcode)
end
-- SECTION 3
function TrainerShow(nameTrainer, processName, frmWidth, frmHeigth, initFunction)
frmTrainerWidth = frmWidth
frmTrainerHeigth = frmHeigth
local aalist = getAutoAttachList()
stringlist_add(aalist, processName);
Trainer_FormCreate(nameTrainer)
_InitFunction = initFunction
end
--[[
function Initialize()
bufScript = BeginGenerateAA("allocMem", "2048")
bufScript = GenerateAAWithSignature(bufScript, "InfHealth1", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
bufScript = GenerateAAWithSignature(bufScript, "InfHealth2", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
bufScript = GenerateAAWithSignature(bufScript, "InfHealth3", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
bufScript = GenerateAAWithSignature(bufScript, "InfHealth4", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
bufScript = GenerateAAWithSignature(bufScript, "InfHealth5", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
bufScript = GenerateAAWithSignature(bufScript, "InfHealth6", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
bufScript = GenerateAAWithSignature(bufScript, "InfHealth7", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
bufScript = GenerateAAWithSignature(bufScript, "InfHealth8", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
bufScript = GenerateAAWithSignature(bufScript, "InfHealth9", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [ebx+00000758],(float)100", true)
EndGenerateAA(bufScript)
end
TrainerShow("F.E.A.R.XP Ttainer +9, v1.0, {MasterGH}", "FEARXP.exe", 290, 180, Initialize)]]---- Version 1.1
-
Есть скрипт. Надо тупо тормознуть таймер (db 90 90 90) где его записать в скрипте?
Нопить надо что-то другое, а не что-то в скрипте.
Самый простой способ тормознуть таймер это писать постоянно значение в адрес секунд.
И ещё вопрос. Как сделать так, чтобы по нажатии хоткея добавить иное число при этом его не морозить. Например дал себе 100 патронов и при выстреле 99 далее 98 итд. Если можно, то на этом же скрипте.
Вижу множество способов. Один из них следующий.
1) В коде игры найти инструкцию которая работает со всеми патронами для всего оружия.
2) Создаёшь первый АА скрипт (активирующий). Сделать инъекцию в инструкцию на сохранение текущего адреса патронов. А также дописываешь код записи по этому адресу для потока.
3) Создаёшь второй АА скрипт после активации первого (иначе будет ошибка) в котором под [ENABLE] записывается выполнение потока.
4) Потом устанавливаешь хоткеии.
Один хот-кей на активирующий скрипт. Его нужно активировать один раз в начале игры.
Другой хот-кей на второй АА скрипт.
Активирующий:
[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)
label(pAmmo)
label(threadmem)
registersymbol(threadmem)
newmem:
push eax
lea eax,[esi+79]
mov [pAmmo],eax
pop eax
originalcode:
mov al,[esi+79]
test al,al
exit:
jmp returnhere
threadmem:
mov eax, [pAmmo]
mov [eax],#99
ret
pAmmo:
dd 0
005A5A04:
jmp newmem
returnhere:
[DISABLE]
005A5A04:
mov al,[esi+79]
test al,al
//Alt: db 8A 46 79 84 C0
dealloc(newmem)Второй скрипт:
[ENABLE]
createthread(threadmem)
[DIASBLE]Может быть я где-то ошибся, так что надо проверять.
-
Разработки будущего
В этом конкретном примере рассмотрю формирование трейнера для игры Dark Sector.
45 строк против 175 строк, а самое главное более понятнее. АА скрипты для Dark Sector я плохо написал. А вот на LUA гораздо лучше на мой взгляд.
Если читов будет гораздо больше, то эффект будет ещё сильнее.
require("TrainerGen")
function Initialize()
bufScript = BeginGenerateAA("allocMem", "2048")
AllocVariableRegistersymbols({ {"pId", 4}, {"pRES", 4} })
bufScript = GenerateAAWithSignature(bufScript, "getPtrHeroID", "83xxxxxxxxxxxx0fxxxxxxxxxx8dxxxxxxxx8dxxxxxxe8xxxxxxxx80", "+X-C-W", 0, "mov [pId],edx", true)
bufScript = GenerateAAWithSignature(bufScript, "getPtrHeroRes", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [pRES],eax", true)
ExtraCreateCheat("Health", bufScript, "getPtrHeroID",[[
mov [edx+468],#100000
mov [edx+464],#100000
]])
ExtraCreateCheat("Money", bufScript, "getPtrHeroRes",[[
mov eax,[eax]
mov [eax+1d4],#1000000
]])
HideCheats({"getPtrHeroID", "getPtrHeroRes"})
bufScript = GenerateAAWithSignature(bufScript, "MaxAmmo", "8bxxxxxxxxxxxx74xxxxxx8dxxxxxxxxxxbfxxxxxxxx8bxx85xx74xx83xxxx74", "+X-C-W", 0, [[
pushf
push eax
mov eax,[pRES]
or eax,eax
jz short no_MaxAmmo
cmp ecx,[eax]
jne short no_MaxAmmo
mov [ecx+ebp*8+00000394],#99999
no_MaxAmmo:
pop eax
popf
mov ebx,[ecx+ebp*8+394]
]], false)
bufScript = GenerateAAWithSignature(bufScript, "NoReload", "8bxx8bxxxxxxxxxx8dxxxxxxxx8bxxbbxxxxxxxxffxx8bxx8bxxe8xxxxxxxx84xx75xx83", "+X-C-W", 0, [[
mov eax,[eax]
mov byte [eax+3e8],#30
]], true)
EndGenerateAA(bufScript)
end
TrainerShow("Dark Sector Ttainer +4, v1.0, {MasterGH}", "FEARXP.exe", 290, 180, Initialize)Так же в более далёком будущем сделать автоматическое исправление регистров и смещений, если в игре с патчем они будут разные. Например, инструкция в которой будет внедрение будет не mov [ecx+ebp*8+00000394],#99999, а mov [ecx+ebp*7+00000344],#99999. В этом случае будет автоматической исправления первой инструкции на вторую.
Можно увидеть новую функцию пока не реализованную
mov [edx+468],#100000
mov [edx+464],#100000
]])ExtraCreateCheat("Health", bufScript, "getPtrHeroID",[[
Здесь новый принцип. ExtraCreateCheat добавляет каскад безусловных прыгов в то место кода, где была запись поинтера на структуру. Каскад позволит записывать внутрь структуры данные забив прыг нопами. В примере выше нет каскадов, а всего лишь создаётся по одному прыгу для двух поинтеров. Вот один из них
Вырезка из АА скрипта:
mov [_pId],edx
_cheatHealth:
jmp short _Aoriginalcode
mov [edx+468],#100000
mov [edx+464],#100000_newmem1:
--------------
Обновлено...
Всё-таки не пойдут так дела. Смещения от поинтера могут смещаться в играх с новыми патчами. Поэтому надо привязываться к инструкциями работающими со смещениями структуры, а не к инструкциям которые работают с поинтерами. Так что всё что я выше написал не берите в голову. Для игры нужно написать новые "правильные" АА-скрипты. Функция ExtraCreateCheat не потребуется, а остальное всё актуально...
function Initialize()
bufScript = BeginGenerateAA("allocMem", "2048")
AllocVariableRegistersymbols({ {"pId", 4}, {"pRES", 4} })
bufScript = GenerateAAWithSignature(bufScript, "getPtrHeroID", "83xxxxxxxxxxxx0fxxxxxxxxxx8dxxxxxxxx8dxxxxxxe8xxxxxxxx80", "+X-C-W", 0, "mov [pId],edx", true)
bufScript = GenerateAAWithSignature(bufScript, "getPtrHeroRes", "d9xxxxxxxxxx8bxxe8xxxxxxxx2bxx8bxxxx33xx2bxx83xxxx7dxx8axxxxxx84", "+X-C-W", 0, "mov [pRES],eax", true)
-- здесь добваить GenerateAAWithSignature с сравнениями с поинтерами для читов здоровья и возможно денег, если на деньги не будет инструкции типа А
HideCheats({"getPtrHeroID", "getPtrHeroRes"})
bufScript = GenerateAAWithSignature(bufScript, "MaxAmmo", "8bxxxxxxxxxxxx74xxxxxx8dxxxxxxxxxxbfxxxxxxxx8bxx85xx74xx83xxxx74", "+X-C-W", 0, [[
pushf
push eax
mov eax,[pRES]
or eax,eax
jz short no_MaxAmmo
cmp ecx,[eax]
jne short no_MaxAmmo
mov [ecx+ebp*8+00000394],#99999
no_MaxAmmo:
pop eax
popf
mov ebx,[ecx+ebp*8+394]
]], false)
bufScript = GenerateAAWithSignature(bufScript, "NoReload", "8bxx8bxxxxxxxxxx8dxxxxxxxx8bxxbbxxxxxxxxffxx8bxx8bxxe8xxxxxxxx84xx75xx83", "+X-C-W", 0, [[
mov eax,[eax]
mov byte [eax+3e8],#30
]], true)
EndGenerateAA(bufScript)
end
TrainerShow("Dark Sector Ttainer +4, v1.0, {MasterGH}", "FEARXP.exe", 290, 180, Initialize)require("TrainerGen")
[Shogun 2: Total War] Бесконечный ход
in Вопросы по созданию читов в одиночных играх
Опубликовано
>>OllyDbg у меня выдает ошибку ntdll.DbgBreakPoint на винде Win 7 64bit
У меня OllyDbg запускается под Win7 64. У меня две версии OllyDbg, та которая с нашего сайта и последняя с официального сайта OllyDbg. И та и та запускается. Сначала надо запустить игру в конном режиме,а после аттачить его из OllyDbg из меню файла. Если будут остановки из-за исключений, то пропускать их по подсказкам внизу окна Olly или же настроить пропуск исключение из настроек Olly.
По повод IDA, всё-таки советую с ним разобраться... он может гораздо удобнее показать код стрелками и связанными блоками, но только после того как будет проанализирован весь исполняемый файл... Так декомпиляция Arrays по горячей клавише F5 покажет псевдокод в удобном представлении. Можно довольно быстро сориентироваться поступает ли указатель прямо из функции или указатель извлекается внутри функции. Тоже самое правда с ошибками делает RecStudio.
По поводу DBVM и ошибок из-за виртуальных машин ничего сказать не могу. У меня DBVM не работал лишь один раз при комиляции Cheat Engine из SDK...