CELua[RU]
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы
    • Зарегистрироваться
    • Войти

    Создать структуру программно

    Запланировано Прикреплена Закрыта Перенесена Программирование
    ce structurece lua
    2 Сообщения 1 Posters 49 Просмотры
    Загружаем больше сообщений
    • Сначала старые
    • Сначала новые
    • По количеству голосов
    Ответить
    • Ответить, создав новую тему
    Авторизуйтесь, чтобы ответить
    Эта тема была удалена. Только пользователи с правом управления темами могут её видеть.
    • MasterGHM Не в сети
      MasterGH Администраторы
      отредактировано MasterGH

      Создать структуру программно

      Пример, что будет в конце записи
      изображение.png
      Нужен поинтер и процесс.

      Запустим туториал из Cheat Engine из меню Health->Cheat Engine Tutorial.
      Прохождение туториала подробно описано здесь

      Cheat Engine Tutorial Guide (x32) - Cheat Engine
      Подключаемся к процессу идем на 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()
      

      Результат
      33e4b026-502e-4ddd-809d-e1ca47ed7159-изображение.png

      Ну и на закуску.

      Допустим мы знаем что по адресу 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)
      
      1 ответ Последний ответ Ответить Цитировать 0
      • MasterGHM Не в сети
        MasterGH Администраторы
        отредактировано

        Решил попробовать написать CE Lua скрипт, который прочесывает структуру и в Dissect data/structures окне создавал бы структуру только со смещениями, с которыми код работает, т.е. читает или пишет.

        Например, мой персонаж прогуливается по городу, а каждые 200 мс ставится брейкпоинт на смещение +1 до гипотетической N границы структуры (например до 4096).

        Я не успел сделать определение типа, но смещения внутри структуры получить я успел.

        Итак, находим начало структуры любой. Запускаем Lua скрипт и просто что-то делаем в игре. Потом вылазит текст с дизассемблированными инструкциями и смещениями. Уже по этим логам можно определить вручную

        1. к каким смещением было обращение (адреса по ним мы и будем менять или сравнивать структуры между собой позже)

        2. по виду инструкции и соседнему смещению уже примерно можно определить тип данных и их размер
          a3ea23e7-54e8-46c5-82a5-f3d2a73cc540-изображение.png
          Осталось сделать определение типа, а это не так уж долго сделать и осталось взять код из предыдущих записей в блоге формирования структуры в окне dessect data. Так мы получим структуру только с активными смещениями, (а зачем нам пассивные?) и определим в них тип, я надеюсь определим правильно

        Пример кода, который я использовал

        addressStructure1 = 0x412E0200 --> адрес начала структуры в любой игре
        sizeStructure = 100     --> гипототический размер структуры 100 для быстрых поисков, по умолчанию 4096
        indexStructure = 0      --> индекс внутри структуры, который будет перемещаться вместе с breakPointAddress
        breakPointAddress = 0   --> адрес, на который сейчас постален брейкпоинт
        waitTimeTillBreak = 300 --> частота активности смещеиня
        resultText = ''         --> конкатенация частей текста в этой переменной
        
        \-- Функция пытается поставить брейкпоинт на следующий байт в структуре
        function TryNextSetBreakPointToAddress()
          debug_removeBreakpoint(breakPointAddress)
          indexStructure = indexStructure + 1
          if indexStructure > sizeStructure then
            debugTimer.Interval = 1000
            debugTimer.Enabled = false
            debugTimer.destroy()
            debug_continueFromBreakpoint(co_run)
            print(resultText) --> вывод результата с завершением отладки
            return
          end
          breakPointAddress = addressStructure1 + indexStructure
          debug_setBreakpoint(breakPointAddress, 1, bptAccess, bpmDebugRegister)
          debug_continueFromBreakpoint(co_run)
        end
        
        \-- Любимая функция снятия отладочных данных
        function debugger_onBreakpoint()
          -- проверить обращение к структуре
          prevAddress = getPreviousOpcode(RIP)
          resultText = resultText..string.format('Offset: + %X : %s', indexStructure, disassemble(prevAddress)) .. '\r\n'
          TryNextSetBreakPointToAddress()
          return 1
        end
        
        \-- Простой таймер
        debugTimer = createTimer(nil, false)
        debugTimer.OnTimer = function(timer) TryNextSetBreakPointToAddress() end
        debugTimer.Interval = waitTimeTillBreak
        debugTimer.Enabled = true
        breakPointAddress = addressStructure1 + indexStructure
        debug_setBreakpoint(breakPointAddress, 1, bptAccess, bpmDebugRegister)
        
        1 ответ Последний ответ Ответить Цитировать 0

        • 1 / 1
        • Первое сообщение
          Последнее сообщение
        Powered by NodeBB | Contributors
        СeLua[RU] 2025©