-
Постов
2 999 -
Зарегистрирован
-
Победитель дней
129
Тип контента
Профили
Форумы
Загрузки
Блоги
Сообщения, опубликованные MasterGH
-
-
Заготовка скрипта для ведения лога данных на функции TranslateMessage.
Функция TranslateMessage переводит сообщения виртуальных клавиш в символьные сообщения. Символьные сообщения помещаются в очередь сообщений вызывающего потока для прочтения в следующий раз, когда поток вызовет функцию GetMessage или PeekMessage.
Теория (на практике всю теорию не проверял, только где-то как-то кусками)
В игре подгружаются модули dll, которые вызывают translateMessage. Например directXInput8 dll-ка вызывала эту функцию когда я кликнул левой кнопкой мыши по области окна игры. Я мог бы остановить текущую отладку в этот момент и повесить условный бряк уже на функцию обработки именно этого уже оттранслированного сообщения. Ведь именно его обработка это начало пути определённых действий в коде... концом пути уже будет бряк на некотором адресе.
В OllyDbg можно найти развилку между начальным и конечным путями при автоматическом трейсинге по ретам. И уже на этой развилке хорошо думать, почему именно эта развилка кода имела место быть...
Скрипт установки условного брейкпоинта на функции TranslateMessage.
В параметрах сравнения участвует код сообщения "UINT message"
Если сообщение равно сравниваемому, то отладчик прервётся и в поле лога выведет параметры структуры MSG
BOOL TranslateMessage(
const MSG* lpMsg // Указатель на структуру MSG, которая содержит информацию о сообщении извлеченную из очереди сообщений вызывающего потока при помощи использования функции GetMessage или PeekMessage.
);
typedef struct {
HWND hwnd; // Дескриптор окна, оконная процедура которого принимает сообщение.
UINT message; // Определяет код сообщения. Приложения могут использовать только младшее слово; старшее слово зарезервировано системой.
WPARAM wParam; // Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
LPARAM lParam; // Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
DWORD time; // Определяет время, в которое сообщение было помещено в очередь.
POINT pt; // Устанавливает позицию курсора, в экранных координатах, в момент, когда сообщение было помещено в очередь.
} MSG, *PMSG;
Пример использования.
Пример1. Установка условного брейкпоинта функции TranslateMessage в сравнении с параметром MSG:
-- Сработает когда пользователь отпустит левую кнопку мышки
WM_LBUTTONUP = 0x202 (другие коды сообщени ищите в Интернете)
StartDebug_TranslateMessageCondition_onMSG(WM_LBUTTONUP)
Пример2. Установика безусловного брейкпоинта с логировнием всех сообщений:
StartDebug_TranslateMessage()
Пример3. Если необходимо только прерваться на некоторой функции без сбора параметров:
StartDebugSomeFunction(functionName)
Пример4. Если необоходимо остановить отладку, то вызывать:
StopDebug()
]]--
local mode = 0
local addressesBreakPoint = {}
local countAddressesBreakPoint = 0
function AddBreakPointExecut(addressFunction)
countAddressesBreakPoint = table.getn(addressesBreakPoint)
countAddressesBreakPoint = countAddressesBreakPoint + 1
addressesBreakPoint[countAddressesBreakPoint] = addressFunction
debug_setBreakpoint(addressFunction, 1, bptExecute)
end
function DeleteAllBreakPoint()
for i=1, countAddressesBreakPoint do
debug_removeBreakpoint(addressesBreakPoint[i])
end
countAddressesBreakPoint = 0
end
-- Единая функция обработки сообщений о прерывании
function debugger_onBreakpoint()
local withIn = false
for i=1, countAddressesBreakPoint do
if (EIP == addressesBreakPoint[i]) then
withIn = true
break
end
end
if (not withIn) then
return 1
end
if ( (mode == 1) or (mode == 2) ) then
local pMSG = readInteger(ESP+0x4)
local MSG = readInteger(pMSG+0x4)
if ((mode == 1) and (MSG ~= _iMSGBreak)) then
return 1
end
local s = string.format(" • Call to %s from \"%s\" •\n\r\n>> hWnd = %X\n\r\n>> MSG = %X\n\r\n>> wParam = %X\n\r\n>> lParam = %08X\n\r\n>> Time = %X\n\r\n>> Point = %i x %i\n\r\n", getNameFromAddress(EIP), getNameFromAddress(readInteger(ESP)),
readInteger(pMSG),
MSG,
readInteger(pMSG+0x8),
readInteger(pMSG+0xC),
readInteger(pMSG+0x10),
readInteger(pMSG+0x14), readInteger(pMSG+0x18))
if (mode == 1) then -- WM_LBUTTONUP
print(s) -- записываем в лог LuaEngine текст из loglist
return 0 -- ставим бряк
else -- в случае если условие не выполнено
print(s) -- записываем в лог LuaEngine текст из loglist при не выполненом условии
return 1 -- продолжаем без бряка
end
end
return 0
end
function StartDebug_TranslateMessageCondition_onMSG(iMSGBreak)
DeleteAllBreakPoint()
mode = 1
_iMSGBreak = iMSGBreak
local addressFunction = getAddress("TranslateMessage")
AddBreakPointExecut(addressFunction)
print(string.format("Включен режим остановки на фунции TranslateMessage с условием: MSGBreak == %X",iMSGBreak))
end
function StartDebug_TranslateMessage()
DeleteAllBreakPoint()
mode = 2
local addressFunction = getAddress("TranslateMessage")
AddBreakPointExecut(addressFunction)
print("Включен режим остановки на фунции TranslateMessage без условий")
end
function StartDebugSomeFunction(functionName)
mode = 0
local addressFunction = getAddress(functionName)
AddBreakPointExecut(addressFunction)
end
function StopDebug()
DeleteAllBreakPoint()
_iMSGBreak = 0
end--[[
-
Dark_XSM, вот Lua-код заготовка для решения твоей задачи.
-
Ведение лога инструкций, которые работают с адресом, если в момент срабатывания бряка по адресу находится заданное вами значение.
В моем примере выводятся инструкции, которые записывают значение 1080 типа Integer по адресу "Test.exe+5B5A4". Дальше смотрите код.
Автор: MasterGH 2011
Скрпит для
идентификации инструкции работающием с адресом, когда в нём оказывается определённое значения.
Требования:
- предварительно приаттачить 32-х разрядный процесс игры через иконку Компьютера в главном окне CE
- Если тип данных сравниваемого значения не Integer, то изменить в скрипте "readInteger"
Информация по Lua поддержке: http://ce.colddot.nl/browser/Cheat%20Engine%206/bin/main.lua
Информация по Lua константам: http://ce.colddot.nl/browser/Cheat%20Engine%206/bin/defines.lua
Хотите доработать скрипт?
-- Вы можете создать графический интерфейс пользователя
-- Вы можете сделать так чтобы не выводились повторяющиеся инструкции
]]--
-- Значения для настройки
local myValue = 1080 -- сравниваемое значение, в моем случае 1080типа Integer
local myValueSize = 4 -- размер данных по адресу, в моём случае Integer, значит "4"
local myAddress = getAddress("Test.exe+5B5A4") -- получение адреса в целочисленный тип, мой адрес "Test.exe+5B5A4"
-- тип бряка "ставим на запись"
local typeBreak = 2 --( другие: bptExecute=0, bptAccess=1, bptWrite=2)
-- Если игра вылетает, то попробовать типы отладки: VEHDebug и Kerneldebug
local typeDebug = 1 -- тип отладки (0=default, 1=windows debug, 2=VEHDebug, 3=Kerneldebug)
local criticalCount = 5000 -- если лог постоянно показыватеся, что его нельзя остановить, то этот предел остановит отладку
local count = 0
-----------------------------------
-- Вызвать в консоли эту функцию если нужно удалить бряк и преркатить слежение
-- В этой функции ничего менять не надо
function RemoveBreakpoint()
debug_removeBreakpoint(myAddress);
end
-----------------------------------
-- Функция обработки события точки останова
-- В этой функции можно поменять readInteger на нужный тип данных
function debugger_onBreakpoint()
-- если значение по адресу равно 1080, то выводить инструкции в лог
if readInteger(myAddress)== myValue then
print(disassemble(getPreviousOpcode(EIP)))
count = count + 1
if (count > criticalCount) then
RemoveBreakpoint()
end
end
return 1 -- не показывать отладчик, если 0 - то показывать
end
-- Далее ничего менять не надо
debugProcess(typeDebug) -- установка режима отладки
-- Утановка брейкпоинта
-- В этой функции ничего менять не надо
debug_setBreakpoint(myAddress, myValueSize, typeBreak) -- установка самого брякак--[[
Скриншот на котором показано как работать с этим скриптом:
Желаю успехов!
-
Я думаю, что так лучше:
[ENABLE]
alloc(newmem,2048)
label(originalcode)
label(returnhere)
newmem:
cmp esi,[gta3.exe+4F609C]
jne originalcode
mov [esp+28],(float)0
originalcode:
fcomp dword ptr [esp+28]
fnstsw ax
jmp returnhere
"gta3.exe"+151C05:
jmp newmem
nop
returnhere:
[DISABLE]
"gta3.exe"+151C05:
fcomp dword ptr [esp+28]
fnstsw ax
dealloc(newmem) -
Я сделал фильтр на себя(он работает),но появился вопрос: "ecx меня" - A3ED730, это и есть структура игрока?
Да, это теоретически всегда "структура Игрока" или структура которая относится к Игроку. Обычно, я так и называю структуру в таких случаях - "Структура игрока". Она может быть твоего игрока, игроков-врагов и дружественных игроков.
Структура - структура данных. Сама по себе она никому не нужна и ничего не делает. Это просто кусок или пласт данных бесхозно валяющихся в виртуальном адресном пространстве процесса игры. Самое важно то, как код процесса игры работает со структурой, тогда она уже не является бесхозной. При чём если заметна связь с твоим игроком, то скорее всего это основная структура данных Игрока. В сложном случае - не основная.
-
Трейнермекеры (Разработчики) сталкиваются с ограничением. Им разрешено заливать за раз не более 2 мб данных на форум и файловый лимит 50 Мб. Почему такое ограничение и что делать в этом случае?
В моей компетенции ответить только на последний вопрос - "что делать?".
Если вы поклонник exe-трейнеров генерируемых на Cheat Engine, то Вам остаётся пользоваться архиваторами, а возможно ещё и CE 5.6.x версиями. В этом случае трейнер в архиве получается меньше 2 мб. И вы его можете заливать на хостинг форума.
Тем не менее у вас остаётся следующая проблема. Что делать если Вы подошли к границе 50 Мб ведь это может случится. В этом случае вы можете:
1) Обратиться к Администрации (возможно мы увеличим предел)
2) Выкладывать ссылки на файлы сторонних хостингов (посоветовать какие-то конкретные хостинги я не могу)
3) Удалить/переделать часть ваших файлов (по себе знаю, это тягомотина)
Сторонние хостинги обычно не хранят свои файлы бесконечно и могут их удалить. В этом случае наш хостинг более надежней.
Подходя к концу этого поста подразумеваю, что каждый пользователь из группы трейнероделов один на один столкнётся с этой проблемой идеальное решение которой в принципе найти сложно.
От себя советую все читы как минимум делать на АА-скриптах Cheat Engine файлами формата *.CT. Если есть опыт, то на Lua - формат *.CETRAINER. Последний формат более предпочтителен. Почему именно этот формат, то я об этом много раз писал и мне уже надоело.
Если человек захочет чит, то он установит Cheat Engine и будет ей пользоваться. Ему надо сделать для этого несколько кликов мышкой. Остаётся проблема с картинками и музыкой, т.к. они занимают много места в трейнере. И в этом случае, пользователю важно не это. Ему важно запустить чит в игре. Тем не менее вы сами решайте что должно быть в вашем трейнере и как это будет выглядеть. К сожалению, легче справиться с этой проблемой тем у кого есть хорошие знания в создании скриптов и трейнеров.
-
Пользователи теперь могут:
- удалять свои сообщения
- удалять свои темы
- закрывать свои темы и открывать, если "случайно" закрыли
-
Из текстового 16-ричного формата я перевожу.
А там уже возможна ещё другая ошибка, нужно объявить переменную возвращающую значение:
Dim lpNumberOfBytesWritten
WriteProcessMemory(HL2WriteProcess.Handle, Convert.ToUInt32(AddressWith0X.Text, 16) as IntPtr, pBytes, pBytes.Length, lpNumberOfBytesWritten)На скрине ошибка по поводу pBytes. Я плохо знаю VB у меня он не установлен. Разберись почему pBytes вызывает ошибку. Поищи примеры... Я VB не использую и могу много чего насоветовать и это может быть неправильно.
-
Я перепутал с другим языком и забыл параметр 16.
Попробуй так.
WriteProcessMemory(HL2WriteProcess.Handle, Convert.ToUInt32(AddressWith0X.Text, 16) as IntPtr, pBytes, pBytes.Length, 0)
-
VAM.WriteByte((IntPtr)BaseAddress.text, byte.Parse(NewValue.Text.ToString())):
Нельзя "(IntPtr)" приводить к объекту класса "String".
Так должно быть правильно, если имеем дело с 32-разрядной адресацией:
VAM.WriteByte((IntPtr)(Convert.ToUInt32(BaseAddress.text)), byte.Parse(NewValue.Text.ToString()));
Для кода ниже для AddressWith0X.Text аналогично:
WriteProcessMemory(HL2WriteProcess.Handle, AddressWith0X.Text, pBytes, pBytes.Length, 0)
WriteProcessMemory(HL2WriteProcess.Handle, (IntPtr)(Convert.ToUInt32(AddressWith0X.Text)), pBytes, pBytes.Length, 0)
-
"repe movsd" циклически перемещает данные 4-х байт из адреса EDI+ecx*4 в адрес ESI+ecx*4 уменьшая указанный ecx на единицу до тех пор пока ecx не будет равен нулю.
-
Если ты это знаешь, тогда странно что ты не уверен в своих предположениях. Проверь их и ты узнаешь ответ по результату. Я твоей конечной цели не знаю и не вижу кода, и не могу сказать правильно или нет.
-
Правильно я понял? Ты делал два дампа в режиме гибернации. Первый во время игры. Второй без игры. Первый тебе удалось сохранить. А когда ты делал второй, то ты не будил систему и подменил дампы. Затем включил и загрузился со второго дампа - с места где ты играл.
Думаю здесь необходимо писать драйвер с прямым доступом к устройству жёсткого диска и оперативной памяти. Функции драйвера: создание "спячих" дампов так и их подмена. При чём получится так что система будет засыпать и просыпаться с другим дампом словно при изменении видео режима. Да-да, теоритически это можно сделать. Но я с драйверами операционной системы не имел практического опыта. И я этим заниматься не буду, т.к. всё моё время занято.
Поищи информацию по поводу копирования и подмены системных файлов. Может быть уже кто-то написал драйвер с "программой" общения с этим драйвером...
-
Вообще, по большому счету, достаточно замены лишь одного байта, но иногда несоблюдение баланса опкодов (даже если нопать ничего не надо) приводит к вылету из игры...
Действительно одного байта достаточно. Я не углядел. Что имелось ввиду под понятием "баланса" я не понял. К вылету приведёт, если код запишет не туда и не то, что надо.
Тем кто не знает где прочитать информацию по цепочкам байтов - ссылка.
-
В 11.07.2011в21:53, Izmalkoff сказал:
Я absoscan ставить не умею
На форуме написано по каким правилам составляется цепочка байт, там написано как пользоваться aobscan. Им можно пользоваться в Автоассемблере, а можно на Lua.
Скрипт
Скрытый текст[ENABLE] aobscan(_faddress,74xxxxxxxx8bxxxxxxxxxxe8xxxxxxxx8bxx85xx7cxxf6xxxx74xx8bxxe8) _faddress: // 6CCF13AA = xlive.dll+F13AA db EB 14 [DISABLE] aobscan(_faddress,8bxxxxxxxxxxe8xxxxxxxx8bxx85xx7cxxf6xxxx74xx8bxxe8) _faddress-5: db 74 14
Можно переделать на этот:
Скрытый текст[ENABLE] aobscan(_faddress,74xxxxxxxx8bxxxxxxxxxxe8xxxxxxxx8bxx85xx7cxxf6xxxx74xx8bxxe8) label(xliveLabel) registersymbol(xliveLabel) _faddress: // 6CCF13AA = xlive.dll+F13AA xliveLabel: db EB 14 [DISABLE] xliveLabel: db 74 14
А можно и на этот на Lua (но я не проверял):
Скрытый текстlocal function ByteScan(signature, typeMem) -- return address local results = nil results = AOBScan(signature, typeMem) -- typeMem = "+X-C-W" and any if (results == nil) then messageDialog("Ошибка. Не найден адрес внедрения.\n\rТрейнер будет закрыт!",1, 2) closeCE() return caFree end local address = stringlist_getString(results, 0) object_destroy(results); return address end local AA_XLIVEcodeEnable = "" local AA_XLIVEcodeDisable = "" function DisableXLIVE() autoAssemble(AA_XLIVEcodeEnable) end function EnableXLIVE() autoAssemble(AA_XLIVEcodeDisable) end function InitAndDisableXLIVE() -- Если "+X-C-W" не точно, то поставить свои правила local xliveAddr = ByteScan("74xxxxxxxx8bxxxxxxxxxxe8xxxxxxxx8bxx85xx7cxxf6xxxx74xx8bxxe8", "+X-C-W") AA_XLIVEcodeEnable = [[ ]]..xliveAddr..[[: // 6CCF13AA = xlive.dll+F13AA db EB 14 ]] AA_XLIVEcodeDisable = [[ ]]..xliveAddr..[[: // 6CCF13AA = xlive.dll+F13AA db 74 14 ]] DisableXLIVE() end
-
bronis добавлен в группу разработчиков, может ставить "плюсы и минусы", заливать файлы, публиковать трейнеры, повышен рейтинг...
По поводу оконного режима может быть когда-нибудь я напишу тузлу.
-
О, не плохо. Если ты сам написал описание "_call()", то даже я не знал про то, что так можно динамически определять аргументы функции...
// как реализовать его в CE без скрипта мне не довелось узнать
_call(0x006A6374, 1, curscreen);Это можно реализовать и на автоассемблере, и на Lua, и на том и другом вместе. Я подумаю как сделать удобнее... Возможно стоит просто вызывать AddMsg() из скриптов CE по горячим клавишам... посмотрим.
-------------
Кстати по той же теме, может кому будет полезно, мой набросок одной инъекции. Её предназначение сохранять базу данных из одного формата в другой в файл. Код не был доработан, но можно понять что делать чтобы сохранить что-то и как-то в файл.
// dllmain.cpp: определяет точку входа для приложения DLL.
#include "stdafx.h"
void AddRecord(ofstream *DBFile, long int i, char name[], char cheat[])
{
*DBFile << " <Names>\n";
*DBFile << " <Key>"<< i << "</Key>\n";
*DBFile << " <Name>"<< name <<"</Name>\n";
*DBFile << " </Names>\n";
*DBFile << " <Cheats>\n";
*DBFile << " <Key>"<< i << "</Key>\n";
*DBFile << " <Cheat>"<< cheat << "</Cheat>\n";
*DBFile << " </Cheats>\n";
}
void Code()
{
ofstream DBFile;
DBFile.open ("D:\\DB.txt");
if (DBFile.is_open())
{
cout << "Files opens:\n\n";
DBFile << "<?xml version=\"1.0\" standalone=\"yes\"?>\n<DataSet1 xmlns=\"http://tempuri.org/DataSet1.xsd\">\n";
_asm
{
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
}
long int maxCount = 50;
for(long int i=0; i < maxCount; i++)
{
char name[100] = "Name";
char cheat[100] = "Cheats";
AddRecord(&DBFile, i, name, cheat);
}
DBFile << "</DataSet1>";
DBFile.close();
}
else
cout << "Unable to open file\n\n";
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
} -
int (сокращённое от "Integer") - это тип данных для определения переменой числа. У числа типа int может быть положительный и отрицательный знак. Размер 4 байта. Более подробно в поисковике по запросу "типы данных Integer"
-
Для тех кто хочет использовать этот компонент, а также другие на этом примере с setProperty не из дизайнера создания форм.
В данном примере создаётся ListView с 3 столбцами и 3 строками.
f=createForm()
lv=createListView(f)
setProperty(lv, 'ViewStyle', 'vsReport') --non lua exported property but you can access it with this
setProperty(lv, 'RowSelect', 'True')
setProperty(lv, 'ReadOnly', 'True')
lvc=listview_getColumns(lv)
column1=listcolumns_add(lvc)
column2=listcolumns_add(lvc)
column3=listcolumns_add(lvc)
listcolumn_setCaption(column1, 'a')
listcolumn_setCaption(column2, 'b')
listcolumn_setCaption(column3, 'c')
lvi=listview_getItems(lv);
row1=listitems_add(lvi)
listitem_setCaption(row1, 'Row 1'); --rw 1 column a
row1_subitems=listitem_getSubItems(row1) --returns a Strings object
strings_add(row1_subitems, 'r1_cb') --row 1 column b
strings_add(row1_subitems, 'r1_cc') --row 1 column c
row2=listitems_add(lvi)
listitem_setCaption(row2, 'Row 2');
row2_subitems=listitem_getSubItems(row2)
strings_add(row2_subitems, 'r2_cb')
strings_add(row2_subitems, 'r2_cc')
row3=listitems_add(lvi)
listitem_setCaption(row3, 'Row 3');
row3_subitems=listitem_getSubItems(row3)
strings_add(row3_subitems, 'r3_cb')
strings_add(row3_subitems, 'r3_cc')Источник форум CE.
-
MasterGH а реально вызывать процедуры из CE по горячей клавише? Допустим при внедрении DLL можно вызвать фунцию из неё ... хотелось бы без DLL так же вызывать произвольную функцию в игре
Да, реально. Предвижу несколько способов. Покажу на мой взглядлучший из них, но не проверенный и не полный, поэтому могут быть ошибки.
function FunctionSpawnCar(hotkey)
autoAssemble("CREATETHREAD(SpawnCar)")
end
function SetHotKey(func, hotkey)
local objectHotKey = createHotkey(func, hotkey)
generichotkey_setKeys(objectHotKey, hotkey)
generichotkey_onHotkey(objectHotKey, func)
end
function Deinitialization()
autoAssemble([[
unregistersymbol(SpawnCar)
dealloc(SpawnCar)
]])
end
function Initialization()
local address = ... // получить адрес вызываемой функции
local AAscript = [[
alloc(SpawnCar,2048)
registersymbol(SpawnCar)
label(stringCar)
SpawnCar:
push ...
push ...
push stringCar
call ]]..address..[[
ret
stringCar:
db ... 00 // hex-строка машины оканчивающаясь нулевым символом
]]
autoAssemble(AAscript)
--создание формы трейнера
-- ...
--привязка функции Deinitialization() к закрытию формы
-- ...
--Назначение хоткеев
setHotKey(FunctionSpawnCar, VK_F2) -- спавн некоторой машины
end
function onOpenProcess(processid)
Initialization()
end
local aalist = getAutoAttachList()
stringlist_add(aalist, "gta4.exe")Как видно здесь Lua код вперемешку с Автоассемблером. Есть инициализация, деинициализация, првязка горячей клавиши, создание потока на АА. Могут быть проблемы с поточной синхронизацией или другие, надо проверять на практике...
1. Можно ли на Lua делать удобнее не знаю. Для каждого человека своё видение удобства.Понял.
И ещё вопрос возник. Не совсем по этой теме...
Я так понял, на LUA можно несколько удобнее сделать?
Там же во время выполнения можно менять переменные по горячим клавишам, таким образом включая/отключая разные секции кода?
Тогда получается что в моём случае можно было бы менять сразу несколько переменных, включая и отключая любые из них, не трогая остальные(записывающиеся в адреса), а в автоассемблере есть только варианты вкл/выкл вообще всего...
Жаль что из программирования я тока про Паскаль чего-то помню, и про Java Script
2. По горячим клавишам можно выполнять Lua функцию, которая могла бы на АА скриптах что-то делать... создавать новые "секции кода" и уничтожать старые.
3. Переменные можно менять и без Lua. Зарегистрируй их в АА через registersymbol. Создай другой АА который бы менял значения по зарегистрированным меткам.
4. Когда Lua поддержки в CE не было у меня была та же проблема. Lua я не знал, но учился на примерах.
-
1
-
-
Увы для меня 5ый шаг сложен
Надо учиться, потому что без этого ты вынужден просчитывать в уме все возможные ошибки. Даже больше скажу в сложных ситуациях лучше это делать в OllyDbg, когда отладчик в CE не подключен, но может включать скрипты.
-
2. Случай.
Увлёкшись написанием длинного скрипта можно забыть о корректности типов данных. В этом примере не учтено, что cmp без указания типа данных сравнивает данные как dword. Это касается 32-х разрядных приложений.
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048) //2kb should be enough
label(GM1)
label(GM2)
label(nocops)
label(returnhere)
label(originalcode)
//label(pBuffer)
label(money)
label(god)
label(armor)
label(cops)
//registersymbol(pBuffer)
registersymbol(money)
registersymbol(god)
registersymbol(armor)
registersymbol(cops)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
cmp ebx,0 //первый фильтр на буфер с розыском
jne originalcode
cmp edx,2000 //второй фильтр на буфер с розыском
jne originalcode
//mov [pBuffer],ecx
cmp esi,3 //третий фильтр на буфер с розыском
jne originalcode
cmp [money],01 //+1000000$?
jne GM1
mov [ecx+90],#100000
GM1:
cmp [god],01 //беск. здоровье вкл.?
jne GM2
//mov [ecx+22D0],(float)10000 //столько здоровья хватит, чтобы не взрываться в машинах
mov [ecx+510],(float)10000
GM2:
cmp [armor],01 //беск. броня вкл.?
jne nocops
//mov [ecx+2290],(float)1000
nocops:
cmp [cops],01 //убрать звезды розыска вкл.?
jne originalcode
mov [ecx+10],00 //нет звёзд
originalcode:
lea eax,[esp]
push eax
push 00
exit:
jmp returnhere
//pBuffer:
//db 0
money:
db 0
god:
db 0
armor:
db 0
cops:
db 0
"EFLC.exe"+8F1E3:
jmp newmem
nop
returnhere:
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
//unregistersymbol(pBuffer)
unregistersymbol(money)
unregistersymbol(god)
unregistersymbol(armor)
unregistersymbol(cops)
"EFLC.exe"+8F1E3:
lea eax,[esp]
push eax
push 00
//Alt: db 8D 04 24 50 6A 00[ENABLE]
Для того чтобы скрипт работал как надо, проще объявить сравниваемый тип данных не как db, а как dd.
-
Izmalkoff, давай я не буду гадать, а просто буду учить как проверять свои скрипты.
1) Перед активацией скрипта (игра должна быть в оконном режиме), надо зайти по адресу 038B0013 в дизассемблер.
2) Нужно выделить инструкцию левым кликом мышки с которой будет переход на инструкцию по адресу 038B0013
3) Нажать на F5 чтобы поставить бряк на выполнение (чтобы снять нажать ещё раз)
4) Зайти в игру и что-то сделать, чтобы игра прервалась в отладчике
5) Затем выполняешь отладку по шагам c заходом в call и смотришь за регистрами (кнопки F7 шаг с заходом в call, F8 - шаг без захода в call), Таким образом ты определишь что в регистрах сранивается, что не сравнивается, почему выполняются или не выполняются прыжки.
-
Лучше меня и Xipho Шефами не величать, а использовать никнеймы. Мы будем рады если называть нас по никнеймам
По поводу способа ничего против не имею так как я с ним не работал и тонкостей не узнавал.
Как в Lua-Engine работать с формами?
in Создание трейнеров в специальных студиях
Опубликовано
Создал дефолтную форму UDF1, едит и кнопку. И повесил обработчик на кнопку при клике (код ниже). При клике в лог выводиться текст из едита:
UDF1 в этом случае это объект формы. Если объект формы неизвестен, то нужно использовать перебор форм по индексам от нуля до количества индексов всех форм связанных с Cheat Engine.
getPropertyList(obj_class) создаёт список публичных свойств, среди которых можно найти свойство Text. Можно и не искать таким образом, а поискать названия свойств в дизайнере компонентов.