Создать структуру программно
Пример, что будет в конце записи
Нужен поинтер и процесс.
Запустим туториал из Cheat Engine из меню Health->Cheat Engine Tutorial.
Прохождение туториала подробно описано здесь
Подключаемся к процессу идем на 8-мой шаг. В руководстве есть поинтер
[[[["Tutorial-i386.exe"+XXXXXX]+C]+14]+0]+18
Вместо XXXXXX может быть любое смещение. Поэтому надо бы поискать
Нашил адрес.
Поставили бряк.
Нашли esi
Поставили бряк
Вышли сюда
0042595E - A1 60D65F00 - mov eax,[005FD660] { [0183E9E8] }
00425963 - 8B 40 0C - mov eax,[eax+0C]
00425966 - 8B 40 14 - mov eax,[eax+14]
00425969 - FF 30 - push [eax]
//...
00425F3C - 89 46 18 - mov [esi+18],eax
// Вот такой получили поинтер
[[[[005FD660]+C]+14]+0]+18
Поинтер получили, дальше пойдет Lua.
Открываем Lua консоль и проверяем поинтер
Выведем адрес и его значение
\-- getAddress позволяет получить адрес. Если есть квадратные скобки, то и значение адреса
local address = getAddress("[[[[005FD660]+C]+14]+0]+18")
local value = getAddress("[[[[[005FD660]+C]+14]+0]+18]")
local text = string.format('%X = %s',address,value)
-- Показать диалог. В defines.lua можно посмотреть переменные mtInformation, mbok
messageDialog(text, mtInformation, mbok)
--> Вывод "018250E0 = 3289"
Поинтер верный.
Другой вариант читать значение поинтера примерно такой
local address = getAddress("game.exe")
address = readPointer(address + 0x123)
address = readPointer(address + 0x456)
local value = readFloat(address + 0x789)
Есть и такие варианты
value = readInteger("[[[[[[[[[witcher3.exe + 028F3F60] +0] +18] +20] +40] +40] + 1c0] +10] +28]")
value = readFloat("[[[[[[[[[witcher3.exe + 028F3F60] +0] +18] +20] +40] +40] + 1c0] +10] +28]")
value = readDouble("[[[[[[[[[witcher3.exe + 028F3F60] +0] +18] +20] +40] +40] + 1c0] +10] +28]")
Теперь самое интересное — создание структур с помощью Lua
Построим структуру [[[[005FD660]+C]+14]+0]+18. На +18 будет наш адрес.
Сначала построим один уровень —"005FD660"
\--Создаем пустую структуру и добавляем её в глобальный список
myStructure = createStructure('MyStructure')
myStructure.addToGlobalStructureList()
-- Автоматически заполняем
-- Праметры структуры: адрес, смещение и размер
myStructure.autoGuess('005FD660', 0, 4096)
-- Создать окно и внести поле адреса
local structureFrm = createStructureForm('005FD660')
-- Выбрать структуру на форме. Через UI клик по индексу последней созданной структуры
local structureIndex = getStructureCount() - 1
structureFrm.Menu.Items[2][structureIndex+2].doClick()
Если выполнить скрипт выше, то мы построим структуру одного уровня.
Построим теперь структуру двух уровней "[005FD660]+C". Второй уровень нужно развернуть
Для этого после создания структуры создам дочернюю
myStructure2 = createStructure('MyStructure2')
myStructure2.autoGuess('[005FD660]', 0, 50)
-- И поместим её по индексу
local offset = 0
myStructure.getElementByOffset(offset).setChildStruct(myStructure2)
-- Чтобы развернуть список поитеров. К сожалению разворачивается только два уровня
structureFrm.Menu.Items[1][6].doClick()
Итого получается такой скрипт до второго уровня
\-- Создаем пустую структуру и добавляем её в глобальный список
myStructure = createStructure('MyStructure')
myStructure.addToGlobalStructureList()
-- Автоматически заполняем
-- Праметры структуры: адрес, смещение и размер
myStructure.autoGuess('005FD660', 0, 4096)
\------------------
myStructure2 = createStructure('MyStructure2')
myStructure2.autoGuess('[005FD660]', 0, 50)
local offset = 0
myStructure.getElementByOffset(offset).setChildStruct(myStructure2)
\------------------
-- Создать окно и внести поле адреса
local structureFrm = createStructureForm('005FD660')
-- Выбрать структуру на форме. Через UI клик по индексу последней созданной структуры
local structureIndex = getStructureCount() - 1
structureFrm.Menu.Items[2][structureIndex+2].doClick()
structureFrm.Menu.Items[1][6].doClick()
Создадим и развернем весь указатель [[[[005FD660]+C]+14]+0]+18
Не будем делать через цикл, чтобы не усложнять
myStructure2 = createStructure('MyStructure2')
myStructure2.autoGuess('[005FD660]', 0, 50)
local offset = 0x0
myStructure.getElementByOffset(offset).setChildStruct(myStructure2)
myStructure3 = createStructure('MyStructure3')
myStructure3.autoGuess('[[005FD660]+C]', 0, 50)
offset = 0xC
myStructure2.getElementByOffset(offset).setChildStruct(myStructure3)
myStructure4 = createStructure('MyStructure4')
myStructure4.autoGuess('[[[005FD660]+C]+14]', 0, 50)
offset = 0x14
myStructure3.getElementByOffset(offset).setChildStruct(myStructure4)
myStructure5 = createStructure('MyStructure5')
myStructure5.autoGuess('[[[[005FD660]+C]+14]+0]', 0, 50)
offset = 0x0
myStructure4.getElementByOffset(offset).setChildStruct(myStructure5)
Полный скрипт
\-- Создаем пустую структуру и добавляем её в глобальный список
myStructure = createStructure('MyStructure')
myStructure.addToGlobalStructureList()
-- Автоматически заполняем
-- Праметры структуры: адрес, смещение и размер
myStructure.autoGuess('005FD660', 0, 50)
\------------------
myStructure2 = createStructure('MyStructure2')
myStructure2.autoGuess('[005FD660]', 0, 50)
local offset = 0x0
myStructure.getElementByOffset(offset).setChildStruct(myStructure2)
myStructure3 = createStructure('MyStructure3')
myStructure3.autoGuess('[[005FD660]+C]', 0, 50)
offset = 0xC
myStructure2.getElementByOffset(offset).setChildStruct(myStructure3)
myStructure4 = createStructure('MyStructure4')
myStructure4.autoGuess('[[[005FD660]+C]+14]', 0, 50)
offset = 0x14
myStructure3.getElementByOffset(offset).setChildStruct(myStructure4)
myStructure5 = createStructure('MyStructure5')
myStructure5.autoGuess('[[[[005FD660]+C]+14]+0]', 0, 50)
offset = 0x0
myStructure4.getElementByOffset(offset).setChildStruct(myStructure5)
--[[[[005FD660]+C]+14]+0]+18
\------------------
-- Создать окно и внести поле адреса
local structureFrm = createStructureForm('005FD660')
-- Выбрать структуру на форме. Через UI клик по индексу последней созданной структуры
local structureIndex = getStructureCount() - 1
structureFrm.Menu.Items[2][structureIndex+2].doClick()
structureFrm.Menu.Items[1][6].doClick()
Результат
Ну и на закуску.
Допустим мы знаем что по адресу X будет всегда тип float (как X,Y,Z координаты). Но расструктуризация будет показывать другой тип, дизассемблер будет показывать другой тип — 4 байта. Что делать?
И сразу еще допустим double тип всегда хотим как float тип (в виде комментов в дизассемблере или в расструктуризации)
Воспользоваться следующей функцией
-- Может менять тип адреса x в окне дизассемблере в комментариях, когда в инструкции существует адрес
-- Может менять тип адреса в окне расструктуризации
-- Изменив тип, будет ображаться значение другого типа
onAutoGuess(function) :
Registers an function to be called whenever autoguess is used to predict a variable type
function override (address, ceguess): Return the variable type you want it to be. If no change, just return ceguess
Ну и вот два примера
-- Пример замена типа по типу
function iKnowBetter1(address, ceguess)
if (ceguess==vtDouble) then
return vtDword
else
return ceguess
end
end
-- Пример замена типа по адресу
function iKnowBetter2(address, ceguess)
local someAddress = 0x1424AC6D0
if (address == someAddress) then
return vtSingle
else
return ceguess
end
end
onAutoGuess(iKnowBetter1)
onAutoGuess(iKnowBetter2)