Пишут, что скрипт надо переписать.
Проверь alloc или загугли allocate neaby.
Сообщения
-
RE: Глюки се
-
RE: Защита Трейнера
Пользователь @Pitronic написал в Защита Трейнера:
Кстати этот вариант мне больше нравится. Нет необходимости во флагах.
Новый прием это хорошо. Еще лучше, если он будет работать. Посмотрю, как будет время в чем там ошибки. Попробуй не использовать aamaker, а генерировать стандартным шаблоном из ce в окне, где создаешь шаблоны aa.
-
RE: Телепорт на 10 слотов и на 3 типа данных (float, double, integer)
Сначала надо найти адрес через скан сигнатуры. Потом подставить адрес в
teleport_address и поставитт тип type_datateleport = Teleport:new(teleport_address, type_data)Потом использовать горячие клавиши для сохранения и загрузки
Управление горячими клавишами. ctrl+X - где X от 0 до 9 сохраняет позицию, shift + X загружает ранее сохраненную позицию
Просто это все писать надо и разбираться. Это жк не все так просто.
А мы сегодня с коллегами много работали на Unity и моя голова сегодня требует отдыха. Сейчас открывать CE и писать скрипты не получится. Наверно, только на выходных, либо на неделе. Но вопрос хороший. Код, который не понятно как применить это не очень хоршо. Поставил в todo.
-
RE: Собираем ссылки на разные источники
Попробуй другой браузер или кеш браузера почистить. Может поможет. Иногда ссылки кешируются и автоматически подставляются неверные.
-
RE: Телепорт на 10 слотов и на 3 типа данных (float, double, integer)
Конечно, возможно. Если заглянуть в документацию, то через чтение массива по адресу address, bytecount - количеству байт, и ReturnAsTable возвращаемая таблица.
readBytes(address,bytecount, ReturnAsTable ) : returns the bytes at the given address. If ReturnAsTable is true it will return a table instead of multiple bytes Reads the bytes at the given address and returns a table containing the read out bytes writeBytes(address, table) : Write the given bytes to the given address from a tableЯ думаю, пример можно найти в Интернете. Только у double байт побольше будет чем у других типов в этом скрипте
-
Заметка. Логи брейкпоинта на структуру размером 0x1000
Примечание. Эти логи мне могут понадобиться для группировки инструкций по типу. Например, булевые типы, по чтению. по записи, по смещениям, локальные структуры по смениям и т.п.
В структуре по смещению 0x2C0 находится здоровье персонажа. На начало этой структуры и был поставлен брейкпоинт .
Ниже будет большой кусок опкодов, который работает со структурой.
Log breakpoint on structure 0x1000.txtМожно посмотреть в каком порядке опкоды исполняются и с какими смещениями, насколько далеко они друг от друга. Некоторые смещения рядом с известными смещениями могут заинтересовать. Одинаковые опкоды в определенном порядке, но по разным RIP тоже могут заинтересовать. Switch-case могут заинтересоваь в виде cmp [x]. число. Инструкции чтения из структуры больше интересуют, т.к. они могут более вероятно, на что-то влиять - из них читается и для чего-то это нужно.
Причем последовательность инструкций идет в порядке вызова, но RIP всегда уникальный (RIP не дублируются). Здесь RIP, т.к. CE 64 разрядный
Если последовательность к данным структуры примерно сохраняется, то можно обратить внимание на обращение к адресам в структуре рядом со здоровьем по смещению 2с0: до обращения к адресу здоровья, во время и после. Я выделил их стрелками. Эти смещения могут быть связаны со здоровьем

Интересные моменты могут быть с так называемыми switch-case операциями. Можно пытаться их подменить

-
RE: CE 6.8 Обзор нового инструмента поиска по структурам
Пользователь @Pitronic написал в CE 6.8 Обзор нового инструмента поиска по структурам:
Разрешаю в этой теме всё что в той дополнить
Спасибо, за твое разрешение. Мне, кажется, это две разные статьи и лучше в новой теме.
@Pitronic публиковать статьи тоже можешь.. Там еще можно добавлять теги и выбирать раздел. -
RE: Поиск в региона памяти модуля
Хм. Ну, да такая функция есть уже

Я думаю, исходники все равно пригодятся в качестве примера, как такой функционал делать. Поставлю метку "обучалка" -
RE: CE 6.8 Обзор нового инструмента поиска по структурам
Прикольная статья, особенно пример работы функции "поиск совпадений". Что-то не помню ее. Надо будет поробовать как-нибудь.
А все, там русский перевод
меня сбил. Знаю эту функцию -
RE: Защита Трейнера
Странно, у меня без ошибок. Версия ce 7.5 с с сайта CE и там же файл туториала. Посмотрю как будет время
-
Крафт в StarsOne
В оригинале, если нет всех компонентов рецепта, то нельзя скрафтить вещь.

Цель: скрафтить без компонетов по нажатию кнопки
Игра на Unity и можно пробовать использовать в dnSpy модифицировать файл Assembly-CSharp.dll
Открываем файлик и смотрим на классы связанные с крафтом
Так находим кнопку, которая создаст указанное количество вещей крафта в CreateItem


Задача скрафтить по имеющемуся рецепту любую вещь. Для этого я добавляю проверку количества вещей и удаляю лишний код. Под сполерами оригинальный и модифицированный код

Модифицированный кодusing System; using System.Collections.Generic; using System.Runtime.CompilerServices; using UnityEngine; public partial class Crafting : MonoBehaviour { public void CreateItem(int curCraft, int craftCount) { if (this.timeBreak >= 0.3f) { // Добавили одну вещь крафта if (craftCount == 0) { craftCount = 1; } if (craftCount != 0) { this.succes = true; CraftRecipe component = this.craftObjects[curCraft].GetComponent<CraftRecipe>(); // Здесь удалили код, который должен расходовать вещи из инвентаря // ... if (this.succes) { this.iks = this.craftObjects[curCraft].GetComponent<CraftRecipe>().countCreate * craftCount; for (int m = 0; m < this.craftObjects[curCraft].GetComponent<CraftRecipe>().countCreate * craftCount; m++) { this.emptyCell = Inventory.inv.FindItemForStack(this.craftObjects[curCraft].name); if (this.emptyCell >= 0) { if (Inventory.inv.items[this.emptyCell].stack + this.iks <= Inventory.inv.items[this.emptyCell].maxStack) { Inventory.inv.items[this.emptyCell].stack += this.iks; break; } this.iks -= Inventory.inv.items[this.emptyCell].maxStack - Inventory.inv.items[this.emptyCell].stack; Inventory.inv.items[this.emptyCell].stack = Inventory.inv.items[this.emptyCell].maxStack; } else { this.emptyCell = Inventory.inv.FindEmptyCell(); if (this.emptyCell >= 0) { this.cloneItem = Inventory.inv.CreateItem(this.craftObjects[curCraft]); if (this.cloneItem.maxStack >= this.iks) { this.cloneItem.stack = this.iks; Inventory.inv.items[this.emptyCell] = this.cloneItem; break; } this.cloneItem.stack = this.cloneItem.maxStack; this.iks -= this.cloneItem.maxStack; Inventory.inv.items[this.emptyCell] = this.cloneItem; } else { if (this.craftObjects[curCraft].GetComponent<Item>().maxStack >= this.iks) { PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.iks, this.craftObjects[curCraft].GetComponent<Item>().health); break; } PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.craftObjects[curCraft].GetComponent<Item>().maxStack, this.craftObjects[curCraft].GetComponent<Item>().health); this.iks -= this.craftObjects[curCraft].GetComponent<Item>().maxStack; } new WaitForEndOfFrame(); } } } } this.timeBreak = 0f; } } }Оригинальный
public void CreateItem(int curCraft, int craftCount) { if (this.timeBreak >= 0.3f) { if (craftCount != 0) { this.succes = true; CraftRecipe component = this.craftObjects[curCraft].GetComponent<CraftRecipe>(); int[] array = new int[7]; int[] array2 = new int[7]; for (int i = 0; i < 7; i++) { if (this.succes && component.ingredients[i] != null) { array2[i] = component.countIngredients[i]; if (array2[i] <= 0) { array2[i] = 1; } array2[i] *= craftCount; for (int j = 0; j < Inventory.inv.items.Length; j++) { if (Inventory.inv.items[j] != null && component.ingredients[i].name == Inventory.inv.items[j].prefName) { array[i] += Inventory.inv.items[j].stack; } } if (array[i] < array2[i]) { this.succes = false; } } } if (this.succes) { for (int k = 0; k < 7; k++) { if (component.ingredients[k] != null) { for (int l = 0; l < Inventory.inv.items.Length; l++) { if (Inventory.inv.items[l] != null && array2[k] > 0 && component.ingredients[k].name == Inventory.inv.items[l].prefName) { this.iks = Inventory.inv.items[l].stack; Inventory.inv.items[l].stack -= array2[k]; array2[k] -= this.iks; if (array2[k] <= 0) { break; } } } } } this.iks = this.craftObjects[curCraft].GetComponent<CraftRecipe>().countCreate * craftCount; for (int m = 0; m < this.craftObjects[curCraft].GetComponent<CraftRecipe>().countCreate * craftCount; m++) { this.emptyCell = Inventory.inv.FindItemForStack(this.craftObjects[curCraft].name); if (this.emptyCell >= 0) { if (Inventory.inv.items[this.emptyCell].stack + this.iks <= Inventory.inv.items[this.emptyCell].maxStack) { Inventory.inv.items[this.emptyCell].stack += this.iks; break; } this.iks -= Inventory.inv.items[this.emptyCell].maxStack - Inventory.inv.items[this.emptyCell].stack; Inventory.inv.items[this.emptyCell].stack = Inventory.inv.items[this.emptyCell].maxStack; } else { this.emptyCell = Inventory.inv.FindEmptyCell(); if (this.emptyCell >= 0) { this.cloneItem = Inventory.inv.CreateItem(this.craftObjects[curCraft]); if (this.cloneItem.maxStack >= this.iks) { this.cloneItem.stack = this.iks; Inventory.inv.items[this.emptyCell] = this.cloneItem; break; } this.cloneItem.stack = this.cloneItem.maxStack; this.iks -= this.cloneItem.maxStack; Inventory.inv.items[this.emptyCell] = this.cloneItem; } else { if (this.craftObjects[curCraft].GetComponent<Item>().maxStack >= this.iks) { PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.iks, this.craftObjects[curCraft].GetComponent<Item>().health); break; } PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.craftObjects[curCraft].GetComponent<Item>().maxStack, this.craftObjects[curCraft].GetComponent<Item>().health); this.iks -= this.craftObjects[curCraft].GetComponent<Item>().maxStack; } new WaitForEndOfFrame(); } } } } this.timeBreak = 0f; } }Изменяем весь класс или метов в этом окне

Если выводит ошибки при компяляции, то скачиваем IlSpy и его код вставляем в код в dnSpy. Или качаем DnSpy 3.2.0 или ранее
Изменения сохраняем в модуль, запускаем игру и крафтим.
Получить все рецепты (не проверял правда, попробуйте если хотите)

Вещи не ломаются. Убрать отнятие "здоровья" у вещи


-
Поиск в региона памяти модуля

c = createComboBox(MainForm.gbScanOptions) c.Style = 'csDropDownList' c.Items.add('All') c.ItemIndex = 0 c.Align = alTop c.BorderSpacing.Left = 6 c.BorderSpacing.Right = 6 c.BorderSpacing.Bottom = 2 local modulelist c.OnDropDown = function(d) --fill the list while c.Items.Count > 1 do c.Items.delete(1) end modulelist = enumModules() local i for i = 1, #modulelist do c.Items.Add(modulelist[i].Name) end end c.OnSelect = function(d) if c.ItemIndex >= 1 then MainForm.FromAddress.Text = string.format("%.16x", modulelist[c.ItemIndex].Address) if modulelist[c.ItemIndex].Size == nil then modulelist[c.ItemIndex].Size = getModuleSize(modulelist[c.ItemIndex].Name) end MainForm.ToAddress.Text = string.format("%.16x", modulelist[c.ItemIndex].Address+modulelist[c.ItemIndex].Size) else MainForm.FromAddress.Text = "0000000000000000" MainForm.ToAddress.Text = "7fffffffffffffff" end end c.Enabled = falseИсточник
ModuleListRegioScan.lua (поместить в папку "autorun") -
RE: Собираем ссылки на разные источники
Ну, пока не знаю. Если руки дотянуться до этого.
У AAMaker сложная история. Во-первых этот инструмент делали двое я и srg. По моей задумке плагин должен был автоматически сам каждый раз ассемблировать по неточной сигнатуре новый АА-код и выполнять его. А сейчас при применении правила он генерируется разого в АА-код вручную. Т.е. это не совсем то, что я хотел. Я его с тех давних пор так и не доделал. Во-вторых нет никакой аналитики и статистики, не на что опереться. В каких случаях неточная сигнатура проходит, а в каких нет. Мне кажется, что пока самый надежный вариант это делать assert сигнатуры на проверку и выводить ошибку. И для каждой новой версии игры делать новую сигнатуру. -
RE: CE 6.8 Обзор нового инструмента поиска по структурам
Если есть видео по этой теме, то можно и тут его запостить
-
CE рисование через дополнительный поток
На видео показано рисование через поток и рисование без потока
Когда происходит рисование без потока, то окно нельзя подвинуть, не работает кнопка и даже не возможно работать с Cheat Engine
function FilledWithPixels() while true do ::begin:: UDF1.repaint() for x=1,UDF1.Canvas.Width do for y=1,UDF1.Canvas.Height do local min = math.random(1, 0xFFFF) local max = math.random(0xFFFF, 0x00FFFFFF) UDF1.Canvas.SetPixel(x,y, math.random (min, max)) if(needReUpdate) then needReUpdate = false goto begin end end end t.suspend() end end t = createNativeThreadSuspended(FilledWithPixels) t.name = 'New thread 1' needReUpdate = true UDF1 = createForm() UDF1.Width = 400 UDF1.Height = 200 btn = createButton(UDF1) btn.OnClick = function (sender) needReUpdate = true t.resume() end -
RE: Создать структуру программно
Решил попробовать написать CE Lua скрипт, который прочесывает структуру и в Dissect data/structures окне создавал бы структуру только со смещениями, с которыми код работает, т.е. читает или пишет.
Например, мой персонаж прогуливается по городу, а каждые 200 мс ставится брейкпоинт на смещение +1 до гипотетической N границы структуры (например до 4096).
Я не успел сделать определение типа, но смещения внутри структуры получить я успел.
Итак, находим начало структуры любой. Запускаем Lua скрипт и просто что-то делаем в игре. Потом вылазит текст с дизассемблированными инструкциями и смещениями. Уже по этим логам можно определить вручную
-
к каким смещением было обращение (адреса по ним мы и будем менять или сравнивать структуры между собой позже)
-
по виду инструкции и соседнему смещению уже примерно можно определить тип данных и их размер

Осталось сделать определение типа, а это не так уж долго сделать и осталось взять код из предыдущих записей в блоге формирования структуры в окне 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) -
-
CE 6.8 Обзор нового инструмента поиска по структурам
- Открываем trainme Dark Byte.
- Проходим первый шаг (там нужно сделать One Hit Kill чит через прогресс бар, количество патронов тоже интересно поломать)
- Так вот на Step2 ищем адрес здоровья нашего космического корабля.
Ставим брейкпоинт на доступ, стреляем.
Видим, три адреса и вот теперь новые функции в контекстном меню как на скриншоте

На "(1)-(2)" - вызываем контекстное меню выделив адрес своего корабля и добавляем его в группу1. Тоже самое делаем для красных адресов кораблей противников
На "(2)" вызываем опцию сканирования и видим "(3)"
На (3) выбираем скан по RAX или по другим значениям. Например, когда по RAX не нашли ничего.
Дальше видим окно и галку ставим "Only find matching groups" и сканим. Видим результат

Т.е. по +70 и другим смещениям можно сделать фильтр свой - чужой.В общем замечательный инструмент для работы со структурами с заданием уровня сканирования по оффестам
-
Создать структуру программно
Создать структуру программно
Пример, что будет в конце записи

Нужен поинтер и процесс.Запустим туториал из 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)