Пользовательские метки должны здесь появится.
Если их там нет, значит они не зарегистрировались. Чтобы они зарегистрировались нужно использовать reinitializeSymbolhandler(true)
до autoassemble(...)
Пользовательские метки должны здесь появится.
Если их там нет, значит они не зарегистрировались. Чтобы они зарегистрировались нужно использовать reinitializeSymbolhandler(true)
до autoassemble(...)
Статья "Настройка частного DNS"
ссылка en
перевод ru
Расширение для Notepad+
Там все файлы и ссылки: перейти
Пару картинок запосчу, чтобы иметь представление что это
Не хватает изменения размеров картинок.
Не хватает спойлеров (добавил в todo)
Не хватает цвета для текста
В этой теме собираем все, что понравилось и плюс небольшой комментарий. Можно по CE, можно не по CE. Как угодно. Потом сгруппируем, как больше накопится
Базовые основы CE Auto Assembler Basics
Auto Assembler Basics
Вся справка по CE
Статья из блога по шаблонам CE (сложно, для понимания надо хорошо знать CE Lua)
Сам форум CE (там куча всего). Наиболее интересный для меня раздел по CE Lua плагинам.
Отличный форум "FearLess Cheat Engine"
Лучшие авторы. Можно найти их сообщения. Перейти
Книга программиста из Electronic Arts. Создание игр на C++. Офиц. версия
Семантическое Версионирование 2.0.0. Всегда хотел узнать что означают точки в названии версии? Тогда сюда
Продолжение следует...
Мой вариант был не рабочий. Я толком не проверил, потому что мой бинарник тоториала не подходил.
Рабочий вариант. Если хочешь, то попробуй запустить мой вариант (если нужен, то мой exe туториала там же). А потом из моего примера сделать твой, который заработает на двух бинарниках.
Update:
Если скрипт не запускается, то вызывать reinitializeSymbolhandler(true)
Пример здесь
Бинарник тутораала(шаг1):Tutorial-i386.zip
Смысл в следующем. Нужно активирующий скрипт перенести в Lua. Как оказалось для корректности нужно использовать reinitializeSymbolhandler(true)
aa_script = [[
{ Game : Tutorial-i386.exe
Version:
Date : 2023-04-08
Author : 79777
This script does blah blah blah
}
[ENABLE]
aobscanmodule(INJECT_tut1,Tutorial-i386.exe,81 BB B0 04 00 00 E8 03 00 00)
alloc(newmem,$1000)
alloc(newmem2,$1000)
label(code)
label(return)
label(pointer_ebx)
registersymbol(pointer_ebx)
newmem2:
pointer_ebx:
dd 00
newmem:
mov [pointer_ebx],ebx
code:
cmp [ebx+000004B0],000003E8
jmp return
INJECT_tut1:
jmp newmem
nop 5
return:
registersymbol(INJECT_tut1)
[DISABLE]
//code from here till the end of the code will be used to disable the cheat
INJECT_tut1:
db 81 BB B0 04 00 00 E8 03 00 00
unregistersymbol(INJECT_tut1)
dealloc(newmem)
dealloc(newmem2)
{
// ORIGINAL CODE - INJECTION POINT: Tutorial-i386.exe+25DD3
Tutorial-i386.exe+25DC1: 85 C0 - test eax,eax
Tutorial-i386.exe+25DC3: 74 05 - je Tutorial-i386.exe+25DCA
Tutorial-i386.exe+25DC5: E8 B6 7D FE FF - call Tutorial-i386.exe+DB80
Tutorial-i386.exe+25DCA: 5E - pop esi
Tutorial-i386.exe+25DCB: 5B - pop ebx
Tutorial-i386.exe+25DCC: 89 EC - mov esp,ebp
Tutorial-i386.exe+25DCE: 5D - pop ebp
Tutorial-i386.exe+25DCF: C3 - ret
Tutorial-i386.exe+25DD0: 53 - push ebx
Tutorial-i386.exe+25DD1: 89 C3 - mov ebx,eax
// ---------- INJECTING HERE ----------
Tutorial-i386.exe+25DD3: 81 BB B0 04 00 00 E8 03 00 00 - cmp [ebx+000004B0],000003E8
// ---------- DONE INJECTING ----------
Tutorial-i386.exe+25DDD: 75 2D - jne Tutorial-i386.exe+25E0C
Tutorial-i386.exe+25DDF: 8B 83 9C 04 00 00 - mov eax,[ebx+0000049C]
Tutorial-i386.exe+25DE5: B2 01 - mov dl,01
Tutorial-i386.exe+25DE7: 8B 8B 9C 04 00 00 - mov ecx,[ebx+0000049C]
Tutorial-i386.exe+25DED: 8B 09 - mov ecx,[ecx]
Tutorial-i386.exe+25DEF: FF 91 20 02 00 00 - call dword ptr [ecx+00000220]
Tutorial-i386.exe+25DF5: 8B 83 A8 04 00 00 - mov eax,[ebx+000004A8]
Tutorial-i386.exe+25DFB: 30 D2 - xor dl,dl
Tutorial-i386.exe+25DFD: 8B 8B A8 04 00 00 - mov ecx,[ebx+000004A8]
Tutorial-i386.exe+25E03: 8B 09 - mov ecx,[ecx]
}
]]
function onOpenProcess()
reinitializeSymbolhandler(true)
local checkOk, errMsg = autoAssembleCheck(aa_script, true, false)
if not checkOk then
print('Ошибка в активирующем скрипте')
print(errMsg)
return
end
is_enabled, disabled_info = autoAssemble(aa_script)
if not is_enabled then
print('Ошибка. Не запущен активирующий скрипт')
end
end
getAutoAttachList().add("Tutorial-i386.exe")
Перенос старых тем, постов, блогов, видео по разделам
В ступать и выходить из групп можно самому без админа? (Проверить)
Есть инструкции, которые добавляют мусора больше чем другие.
Показываем объем памяти мусора
print(string.format('Lua memory usage %.1f MiB',collectgarbage('count')/1024))
Ниже код того как попробовать узнать сколько мусора добавил код при парсинге ассемблерной строки двумя способами
local s = " 0045464A - FF 05 A4B54500 - inc [0045B5A4] { [000003EA] }"
function GetDebugString(address)
return splitDisassembledString(s)
end
\-- address, bytes, opcode
function GetDebugString2(address)
local clearString = string.gsub(s, '%s','')
return string.match(clearString, '^(.-)%-(.-)%-(.-)$')
end
function NoOptimizeCode()
GetDebugString2()
end
function OptimizeCode()
GetDebugString()
end
local countRepeat = 500000 -- add more cycle
local x1 = 0
local x2 = 0
x1 = getTickCount()
print(string.format('Lua memory usage %.1f MiB',collectgarbage('count')/1024))
for i = 1, countRepeat do NoOptimizeCode() end
print(string.format('Lua memory usage %.1f MiB',collectgarbage('count')/1024))
x2 = getTickCount()
for i = 1, countRepeat do OptimizeCode() end
print(string.format('Lua memory usage %.1f MiB',collectgarbage('count')/1024))
print(string.format("%.2f", (x2 - x1)/(getTickCount() - x2)) )
Пример результатов могут отличаться. Фиг его знает почему. Возможно работает сборщик мусора в разные моменты времени
Lua memory usage 1.8 MiB
Lua memory usage 1.8 MiB
Lua memory usage 1.8 MiB
1.49Lua memory usage 1.8 MiB
Lua memory usage 2.3 MiB
Lua memory usage 2.3 MiB
1.47Lua memory usage 2.3 MiB
Lua memory usage 2.8 MiB
Lua memory usage 2.8 MiB
1.49
Инфа по совместной работе с гитом. Может быть пригодится кому, а может и нет. Такую систему я использую на работе недавно.
Можно совместно работать над одним большим проектом через git-flow. Возможно, кто-то из форумчан тоже использует git flow на работе.
git-flow — это набор расширений git предоставляющий высокоуровневые операции над репозиторием для поддержки модели ветвления Vincent Driessen.
Кратко. Модель контроля версии построена на 4 ветках
master - релизы
develop - разработка
feature - фичи
hotfix - исравления
С develop начинается разработка через копирования в ветку feature.
Над фичей идет работа, а после завершения feature мержится с develop и feature сразу удаляется.
После запланированных изменений develop мержится с master уходя в релиз.
Если возникли баги, то от master создается ветвь на hotfix . После фиксов hotfix мержится с master.
Доступ к мастер ветки может иметь один человек или его доверенные лица. Ветка Develop открыта для разработчиков. Это значит, что множество разработчиков колдуют в Develop ветке, а мержит изменения с master уже главный разработчик или несколько главных разработчиков.
В мастере создаются теги с обозначением версии.
Учитывая номер версии МАЖОРНАЯ.МИНОРНАЯ.ПАТЧ, следует увеличивать:
МАЖОРНУЮ версию, когда сделаны обратно несовместимые изменения API.
МИНОРНУЮ версию, когда вы добавляете новый функционал, не нарушая обратной совместимости.
ПАТЧ-версию, когда вы делаете обратно совместимые исправления.
Дополнительные обозначения для предрелизных и билд-метаданных возможны как дополнения к МАЖОРНАЯ.МИНОРНАЯ.ПАТЧ формату.
UserData в Lua это пользовательский тип. Точно не знаю, но я думаю в документации в CE Lua (celua.txt или здесь на офф. сайте) тип userData у всех классов или большинства классов. Например, проверим, что главная форма CE это userData тип
local mainFormCE = getMainForm()
print(type(mainFormCE))
> userdata (вывод из консоли)
Выводим список свойств следующим образом через getmetatable функцию. Метатаблица — это особая таблица свойств Lua-переменной
local mainForm = getMainForm()
local listUserData = createStringlist()
for k,_ in pairs(getmetatable(mainForm)) do
listUserData.add(k)
end
local allowCustomInput = false
local id, name = showSelectionList("Title", "Caption", listUserData, allowCustomInput)
print ('Index: '..id..", Name: "..name)
listUserData.destroy()
Результат в виде списка свойство переменной mainForm
Чтобы наглядно было. Свойства эти похожи на свойства из Дельфи. Можно загуглить, они поддробно описываются.
Берем например свойство цвет. Прочитаем оригинальное и запишем свое любое
local mainFormCE = getMainForm()
print(mainFormCE.getColor())
> 536870912 -- в hex-е это 0x20000000. Можно перевести в калькуляторе или через print(string.format("%08X", 536870912))
Случайное свое впишем ради наглядного примера
mainFormCE.setColor(546484)
Пригодится для создания больших плагинов в Cheat Engine. Более ~500 строк
Наследование
ClassX = {}
function ClassX:New(_argument1, _argument2)
local obj = {}
obj.argument1 = _argument1
obj.argument2 = _argument2
-- Через "self"
function obj:GetValue1() return obj.argument1 end
function obj:GetValue2() return obj.argument2 end
setmetatable(obj, self)
obj.__index = ClassX
return obj
end
someObject = ClassX:New("A", "B")
print(someObject.GetValue1())
print(someObject.GetValue2())
Woman = {}
--наследуемся
setmetatable(Woman ,{__index = ClassX})
--проверяем
masha = Woman:New("Марья","Ивановна")
print(masha:GetValue1()) --->результат: Марья
Инкапсуляция
Person = {}
function Person:new(name)
--приватное свойство
local private = {}
private.age = 18
local obj = {}
--публичное свойство
obj.name = name or "Вася" -- "Вася" - это значение по умолчанию
function obj:getAge() return private.age end
setmetatable(obj,self)
self.__index = self
return obj
end
vasya = Person:new()
print(vasya.name) --> результат: Вася
print(vasya.age) --> результат: nil
print(vasya:getAge()) --> результат: 18
Полиморфизм
Person = {}
function Person:New(name)
local private = {}
private.age = 18
local obj = {}
obj.name = name or "Вася"
-- Защищенный от переорпеделения
function obj:GetName() return "Person protected "..self.name end
-- Переопределяемый
function Person:GetName2() return "Person "..self.name end
setmetatable(obj, self)
self.__index = self
return obj
end
--создадим класс, унаследованный от Person
Woman = {}
setmetatable(Woman,{__index = Person})
function Woman:GetName() return "Woman protected "..self.name end
function Woman:GetName2() return "Woman "..self.name end
--проверим
masha = Woman:New()
print(masha:GetName()) --> Person protected Вася
print(masha:GetName2()) --> Woman Вася
Команда FINCSTP добавляет единицу (без переноса) к трехбитному полю TOP слова состояния FPU.
Эффект действия команды FINCSTP заключается во вращении стека. Она не изменяет регистров тэгов и не перемещает данные. Она не эквивалентна операции выталкивания из стека, потому что, она не устанавливает тэг старой вершины стека в значение пустой.
Флаги C0, C2, C3 регистра SW после выполнения команды не определены, флаг C1 устанавливается равным 0.
Похожа на FSTP, также вращает стек регистров FPU (я кстати не знал, увидел при тестах в CE), но только не перемещает значение по адресу.
FSTP [здесь указывается адрес или регистр]
FINCSTP
Если нужно вытолкнуть значение из ST(0), а адрес куда его выталкивать не нужен, то можно сделать так FINCSTP
Или аналог FSTP ST(0)
При использовании стоит обратить внимание на флаги, возможно их состояние будет влиять на исполнение кода.
*Вообще не помню почему я пишу "выталкивать значение" через fstp, когда оно появляется снизу в ST(8). Т.е. не выталкивается по сути.
С точностью до тысячной доли секунды можно посчитать задержку выполнения кода, что можно применить как счет производительности.
local x = os.clock()
local s = 0
for i=1,100000 do s = s + i end
print(string.format("elapsed time: %.3f\n", os.clock() - x))
После выполнения, показывает 2 тысячных секунды или 2 мс
elapsed time: 0.002
Можно посчитать прошедшее время для другой цели. Например, если цикл в отладке выполняется более 3 секунд, то это вероятно корневой цикл, а если менее, то это вложенный цикл. На корневом цикле можно остановить трейслог. Об этом может быть потом напишу.
Функция autoAssemble это Lua функция, которая позволяет скопилировать ассемблерный код активации и деактивации. Пример ниже
\-- Скрипт похожий на таблицу АА
InfiniteHealthScript = [[
[ENABLE]
alloc(InfiniteHealth,2048,BlackOps3.exe)
aobscanmodule(InfiniteHealthAOB,BlackOps3.exe,8B 83 C8 02 00 00 48 8B)
registersymbol(InfiniteHealthAOB)
label(return)
InfiniteHealth:
mov [rbx+000002C8],#999
jmp return
InfiniteHealthAOB:
jmp InfiniteHealth
nop
return:
[DISABLE]
InfiniteHealthAOB:
db 8B 83 C8 02 00 00
unregistersymbol(InfiniteHealthAOB)
dealloc(InfiniteHealth)
]]
\-- Функция активации
function enableInfiniteHealthCheat()
-- Если чит был выключен, то только тогда сработает деактивация
if not InfiniteHealthCheatIsEnabled then
InfiniteHealthCheatIsEnabled,InfiniteHealthCheatDisableinfo = autoAssemble(InfiniteHealthScript)
end
end
\-- Функция деактивации
function disableInfiniteHealthCheat()
-- Если чит был включен, то только тогда сработает активация
if InfiniteHealthCheatIsEnabled then
if autoAssemble(InfiniteHealthScript,InfiniteHealthCheatDisableinfo) then
InfiniteHealthCheatIsEnabled = false
end
end
end
Хотя в последних версиях CE включили чистку памяти (надеюсь, что эта функция была и есть). Но может пригодится очистка памяти. Вдруг?
ИМХО отказываться от CE Lua скриптов из-за утечек памяти не стоит, если такая происходит. Т.е. оперативная память забивается каким-то мусором. Это бывает редко, когда пилишь плагины.
Можно чистить память следующим образом
function startCollectgarbageProcess(interval, showStatus)
local timer1 = createTimer(true)
timer1.Interval = interval
timer1.onTimer = function ()
if (showStatus) then
print(string.format('Lua memory usage %.1f MiB',collectgarbage('count')/1024))
end
collectgarbage("restart")
collectgarbage("collect")
if (showStatus) then
print(string.format('Lua memory usage %.1f MiB',collectgarbage('count')/1024))
end
end
end
\-- Собирать каждую 1 минуту и показать результат
startCollectgarbageProcess(60000, true)
Lazarus — это среда разработки программ под разные операционные системы. Можно найти в Интернете.
На Lazarus создали программу Cheat Engine, собрав исходники в exe. Исходники большие и запутанные.
Исходники CE лежат на официальном сайте и их можно открыть с помощью Lazarus. Но лучше этого не делать без необходимости, т.к. чтобы разобраться в исходниках и уметь их собирать нужно потратить некоторое время, а может и много-много времени.
Просто на Lazarus видно все компоненты в том числе скрытые. А в CE видны только те компоненты, к которым DarkByte явно дал доступ. К компоненту смены цвета доступ можно получить как я писал выше
pcall() функция может вызывать функцию, которая может вызывать исключение.
Возвращает статус в виде булевой о том, есть ли исключение или нет и возвращает текст исключения.
function ThrowException()
-- раскоментировать чтобы зывать ошибку по условию некоторому
-- error("string expected", 2)
-- Пример вывода стека ошибки
print('AAA ->> '..debug.traceback())
-- Исключение делаем
temp[5] = 1
-- До этой строчки не дойдет, т.к. исключение выше будет из-за temp[5] = 1
print('BBB ->> '..debug.traceback())
end
local status, err = pcall(ThrowException)
-- Показать какие типы имеют статус и ошибка (это булевый и строка)
print(type(status))
print(type(err))
if status then
print('No Exception')
else
print('Exception: ' .. err)
end
Как этим пользоваться? Если вдруг знаем, что может произойти ошибка, то можно её обработать и выполнить правильное действие не останавливая работу Lua скрипта.
Подробнее документация
Или например если не выполняется условие, то можем сами создать ошибку с помощью функции error, что остановит скрипт.
Новые директивы try/except
в AA доступны Cheat Engine 6.8 Beta2 и выше
Задача try/except
в AA обработать исключение, не допустить crash. Чтобы игра продолжалась, а чит в лучшем случае не закрыл бы процесс.
В теории возможно определить, что был crash и что-то сделать. Например, отправить логи в свой или иной удаленный сервис аналитики, что такой-то чит не сработал...
Пример от DarkByte для try/except
с счетчиком crashes
[ENABLE]
alloc(newmem,2048)
alloc(crashcount,4)
registersymbol(crashcount)
label(returnhere)
label(originalcode)
label(exit)
newmem:
push eax
{$try}
mov eax,[esi+95c]
cmp [eax+10],0
jmp ok
{$except}
pop eax
add [crashcount],1
jmp originalcode
ok:
pop eax
je aftersub //it is 0
originalcode:
subss xmm0,xmm3
aftersub:
movss [esi+00000164],xmm0
exit:
jmp returnhere
"HomeworldRM.exe"+22AEEA:
jmp newmem
nop
nop
nop
nop
nop
nop
nop
returnhere:
[DISABLE]
dealloc(newmem)
"HomeworldRM.exe"+22AEEA:
subss xmm0,xmm3
movss [esi+00000164],xmm0
//Alt: db F3 0F 5C C3 F3 0F 11 86 64 01 00 00