• Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы
    • Зарегистрироваться
    • Войти
    1. Главная
    2. Популярные
    Авторизуйтесь, чтобы написать сообщение
    • За всё время
    • За день
    • За неделю
    • За месяц
    • Все темы
    • Новые темы
    • Отслеживаемые темы
    • Неотвеченные темы

    • Все категории
    • MasterGHM

      Выполить текст, как код

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео фишки ce lua loadstring
      1
      0 Голоса
      1 Сообщения
      75 Просмотры
      MasterGHM
      Функция loadstring исполняет строку кода как функцию. f = loadstring ("print 'hello, world'") f () --> hello, world Есть еще и такая функция как string.dump. Она создает строку из функции function f () print "hello, world" end s = string.dump (f) \-- Можно строку тут же запустить как код loadstring (s) () --> hello, world Если по обратной связи строить и исполнять строку кода, то предположительно можно генерировать код другим кодом и учитывать гораздо больше условий, чем это может сделать человек. Пригодится для ИИ отладки и для ИИ бота. Код пишет другой код по обратной связи. Реальность?
    • MasterGHM

      Считаем размер инъекции в байтах

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео ce lua фишки ce aa
      1
      2
      0 Голоса
      1 Сообщения
      75 Просмотры
      MasterGHM
      Можно подхватить разные моменты активации и деактивации записи в таблице CE и рассчитать размер кода между метками По шаблону вставляем АА код для туториала Cheat Engine Регистрируем метки-маркеры в АА коде Этими метками в Lua считаем и выводим ""endCode - startCode" размер байтов Пример, который подсчитал 15 байтов Пример скрипта {$lua} memrec.OnActivate = function (memoryrecord, before, currentstate) if currentstate and not before then print("Bytes: " .. getAddress("endCode - startCode")) end return before end {$ASM} [ENABLE] //code from here to '[DISABLE]' will be used to enable the cheat aobscanmodule(INJECT,Tutorial-i386.exe,81 BB 80 04 00 00 E8 03 00 00) // should be unique alloc(newmem,$1000) label(code) label(endCode) label(startCode) registerSymbol(startCode) registerSymbol(endCode) newmem: code: startCode: cmp [ebx+00000480],000003E8 jmp return endCode: INJECT: jmp newmem nop nop nop nop nop return: registersymbol(INJECT) [DISABLE] //code from here till the end of the code will be used to disable the cheat INJECT: db 81 BB 80 04 00 00 E8 03 00 00 unregistersymbol(startCode) unregistersymbol(endCode) unregistersymbol(INJECT) dealloc(newmem) { // ORIGINAL CODE - INJECTION POINT: "Tutorial-i386.exe"+23FE3 "Tutorial-i386.exe"+23FD1: C9 - leave "Tutorial-i386.exe"+23FD2: C3 - ret "Tutorial-i386.exe"+23FD3: 00 00 - add [eax],al "Tutorial-i386.exe"+23FD5: 00 00 - add [eax],al "Tutorial-i386.exe"+23FD7: 00 00 - add [eax],al "Tutorial-i386.exe"+23FD9: 00 00 - add [eax],al "Tutorial-i386.exe"+23FDB: 00 00 - add [eax],al "Tutorial-i386.exe"+23FDD: 00 00 - add [eax],al "Tutorial-i386.exe"+23FDF: 00 53 89 - add [ebx-77],dl "Tutorial-i386.exe"+23FE2: C3 - ret // ---------- INJECTING HERE ---------- "Tutorial-i386.exe"+23FE3: 81 BB 80 04 00 00 E8 03 00 00 - cmp [ebx+00000480],000003E8 // ---------- DONE INJECTING ---------- "Tutorial-i386.exe"+23FED: 75 2C - jne Tutorial-i386.exe+2401B "Tutorial-i386.exe"+23FEF: 8B 83 68 04 00 00 - mov eax,[ebx+00000468] "Tutorial-i386.exe"+23FF5: B2 01 - mov dl,01 "Tutorial-i386.exe"+23FF7: 8B 8B 68 04 00 00 - mov ecx,[ebx+00000468] "Tutorial-i386.exe"+23FFD: 8B 09 - mov ecx,[ecx] "Tutorial-i386.exe"+23FFF: FF 91 20 02 00 00 - call dword ptr [ecx+00000220] Документация кому интересно MemoryRecord Class: The memoryrecord objects are the entries you see in the addresslist properties ID: Integer - Unique ID Index: Integer - The index ID for this record. 0 is top. (ReadOnly) Description: string- The description of the memory record Address: string - Get/set the interpretable address string. Useful for simple address settings. AddressString: string - Get the address string shown in CE (ReadOnly) OffsetCount: integer - The number of offsets. Set to 0 for a normal address Offset[] : integer - Array to access each offset OffsetText[] : string - Array to access each offset using the interpretable text style CurrentAddress: integer - The address the memoryrecord points to VarType: ValueType (string) - The variable type of this record. See vtByte to vtCustom Type: ValueType (number) - The variable type of this record. See vtByte to vtCustom If the type is vtString then the following properties are available: String.Size: Number of characters in the string String.Unicode: boolean String.Codepage: boolean If the type is vtBinary then the following properties are available Binary.Startbit: First bit to start reading from Binary.Size : Number of bits If the type is vtByteArray then the following properties are available Aob.Size : Number of bytes CustomTypeName: String - If the type is vtCustom this will contain the name of the CustomType Script: String - If the type is vtAutoAssembler this will contain the auto assembler script Value: string - The value in stringform. Selected: boolean - Set to true if selected (ReadOnly) Active: boolean - Set to true to activate/freeze, false to deactivate/unfreeze Color: integer ShowAsHex: boolean - Self explanatory ShowAsSigned: boolean - Self explanatory AllowIncrease: boolean - Allow value increasing, unfreeze will reset it to false AllowDecrease: boolean - Allow value decreasing, unfreeze will reset it to false Collapsed: boolean - Set to true to collapse this record or false to expand it. Use expand/collapse methods for recursive operations. IsGroupHeader: boolean - Set to true if the record was created as a Group Header with no address or value info. (ReadOnly) IsReadable: boolean - Set to false if record contains an unreadable address. NOTE: This property will not be set until the value property is accessed at least once. (ReadOnly) Options: String set - a string enclosed by square brackets filled with the options seperated by a comma. Valid options are: moHideChildren, moActivateChildrenAsWell, moDeactivateChildrenAsWell, moRecursiveSetValue, moAllowManualCollapseAndExpand, moManualExpandCollapse DropDownLinked: boolean - if dropdown list refers to list of another memory record eg. (memrec name) DropDownLinkedMemrec: string - Description of linked memrec or emptystring if not linked DropDownList : StringList - list of "value:description" lines, lists are still separate objects when linked, read-write DropDownReadOnly: boolean - true if 'Disallow manual user input' is set DropDownDescriptionOnly: boolean - self explanatory DisplayAsDropDownListItem: boolean - self explanatory DropDownCount: integer - equivalent to .DropDownList.Count DropDownValue[index] : Array to access values in DropDownList (ReadOnly) DropDownDescription[index] : Array to access Descriptions in DropDownList (ReadOnly) Count: Number of children Child[index] : Array to access the child records [index] = Child[index] Parent: MemoryRecord - self explanatory HotkeyCount: integer - Number of hotkeys attached to this memory record Hotkey[] : Array to index the hotkeys Async: Boolean - Set to true if activating this entry will be asynchronious. (only for AA/Lua scripts) AsyncProcessing: Boolean - True when async is true and it's being processed AsyncProcessingTime: qword - The time that it has been processing in milliseconds OnActivate: function(memoryrecord,before,currentstate):boolean - The function to call when the memoryrecord will change (or changed) Active to true. If before is true, not returning true will cause the activation to stop. OnDeactivate: function(memoryrecord,before,currentstate):boolean - The function to call when the memoryrecord will change (or changed) Active to false. If before is true, not returning true will cause the deactivation to stop. OnDestroy: function() - Called when the memoryrecord is destroyed. OnGetDisplayValue: function(memoryrecord,valuestring):boolean,string - This function gets called when rendering the value of a memory record. Return true and a new string to override the value shown DontSave: boolean - Don't save this memoryrecord and it's children methods getDescription() setDescription() getAddress() : Returns the interpretable addressstring of this record. If it is a pointer, it returns a second result as a table filled with the offsets setAddress(string) : Sets the interpretable address string, and if offsets are provided make it a pointer getOffsetCount(): Returns the number of offsets for this memoryrecord setOffsetCount(integer): Lets you set the number of offsets getOffset(index) : Gets the offset at the given index setOffset(index, value) : Sets the offset at the given index getCurrentAddress(): Returns the current address as an integer (the final result of the interpretable address and pointer offsets) appendToEntry(memrec): Appends the current memory record to the given memory record getHotkey(index): Returns the hotkey from the hotkey array getHotkeyByID(integer): Returns the hotkey with the given id reinterpret() createHotkey({keys}, action, value OPTIONAL): Returns a hotkey object disableWithoutExecute(): Sets the entry to disabled without executing the disable section global events function onMemRecPreExecute(memoryrecord, newstate BOOLEAN): If above function is defined it will be called before action* has been performed. Active property is about to change to newState. function onMemRecPostExecute(memoryrecord, newState BOOLEAN, succeeded BOOLEAN): If above function is defined it will be called after action*. Active property was supposed to change to newState. If 'succeeded' is true it means that Active state has changed and is newState. newState and succeeded are read only. *action can be: running auto assembler script (ENABLE or DISABLE section), freezing and unfreezing.
    • MasterGHM

      Обработка исключения в Cheat Engine AA

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео фишки ce aa exception
      1
      0 Голоса
      1 Сообщения
      74 Просмотры
      MasterGHM
      Новые директивы 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
    • MasterGHM

      Обработка исключения в Cheat Engine Lua

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео ce lua exception
      1
      0 Голоса
      1 Сообщения
      133 Просмотры
      MasterGHM
      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, что остановит скрипт.
    • MasterGHM

      FPU инструкция FINCSTP. Очистка ST(0)

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Справочники ce aa fincstp
      1
      1
      0 Голоса
      1 Сообщения
      99 Просмотры
      MasterGHM
      Команда FINCSTP добавляет единицу (без переноса) к трехбитному полю TOP слова состояния FPU. Эффект действия команды FINCSTP заключается во вращении стека. Она не изменяет регистров тэгов и не перемещает данные. Она не эквивалентна операции выталкивания из стека, потому что, она не устанавливает тэг старой вершины стека в значение пустой. Флаги C0, C2, C3 регистра SW после выполнения команды не определены, флаг C1 устанавливается равным 0. Похожа на FSTP, также вращает стек регистров FPU (я кстати не знал, увидел при тестах в CE), но только не перемещает значение по адресу. FSTP [здесь указывается адрес или регистр] FINCSTP Если нужно вытолкнуть значение из ST(0), а адрес куда его выталкивать не нужен, то можно сделать так FINCSTP Или аналог FSTP ST(0) При использовании стоит обратить внимание на флаги, возможно их состояние будет влиять на исполнение кода. *Вообще не помню почему я пишу "выталкивать значение" через fstp, когда оно появляется снизу в ST(8). Т.е. не выталкивается по сути.
    • MasterGHM

      Lua ООП конспект

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Справочники ce lua oop
      1
      0 Голоса
      1 Сообщения
      80 Просмотры
      MasterGHM
      Пригодится для создания больших плагинов в 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 Вася ref
    • MasterGHM

      Работа с системой контроля версий в команде разработчиков

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Справочники git-flow версионирование
      1
      0 Голоса
      1 Сообщения
      104 Просмотры
      MasterGHM
      Инфа по совместной работе с гитом. Может быть пригодится кому, а может и нет. Такую систему я использую на работе недавно. Можно совместно работать над одним большим проектом через 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. МИНОРНУЮ версию, когда вы добавляете новый функционал, не нарушая обратной совместимости. ПАТЧ-версию, когда вы делаете обратно совместимые исправления. Дополнительные обозначения для предрелизных и билд-метаданных возможны как дополнения к МАЖОРНАЯ.МИНОРНАЯ.ПАТЧ формату. git-flow заметки Семантическое версионирование
    • MasterGHM

      CE Script Editor [Notepad+]

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена CE Plugins todo ce plugin notepad++
      1
      0 Голоса
      1 Сообщения
      75 Просмотры
      MasterGHM
      Расширение для Notepad+ Там все файлы и ссылки: перейти Пару картинок запосчу, чтобы иметь представление что это Не хватает изменения размеров картинок. Не хватает спойлеров (добавил в todo) Не хватает цвета для текста
    • MasterGHM

      [dnSpy + Unity ] Пошаговая отладка

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео unity dnspy decompile debug блог
      1
      5
      0 Голоса
      1 Сообщения
      682 Просмотры
      MasterGHM
      Эта статья позволит отлаживать игры на Unity в Runtime и при этом видеть декомпилированный код. Это, конечно, не для всех игр на Unity. Пошаговая отладка в dnSpy позволяет ставить брейкпоинты на C# код во время работы игры, перемещаться по коду, просматривать значения переменных. Сэкономит кучу времени при поиске и отладке игрового кода, Страница загрузки dnSpy Скачиваем dnSpy и все архивы с mono.dll файлами Unity-debugging-4.x-win32.zip Unity-debugging-4.x-win64.zip Unity-debugging-win32.zip Unity-debugging-win64.zip Смотрим свойства exe файла игры и определяем по нему версию Unity. Например, "Версия продукта 5.5.0.3120186" или версия "файла 5.50.39994" может указывать на версию Unity 5.5. Определяем разрядность приложения через Process Explorer Т.к. версия Unity 5.5 и приложение 32 разрядное, то открываем Unity-debugging-win32.zip ищем там версию Unity и заменяем mono.dll в директории игры Запускаем игру и dnSpy x86 (игра 32 разрядная поэтому x86). Открываем файл "...\Managed\Assembly-CSharp.dll" Запускаем отладку нажав F5 или кнопку Play Настраиваем соединение и жмем ок Ставим брейкпоинты, смотрим перемененные, перемещаемся по коду, пишем свой код и так далее После изменения кода, нужно перезаписать модуль предварительно сохранив его О других способах подключения пошаговой отладки есть на английском руководство. Как работать в пошаговой отладке Работать можно почти также как и в Cheat Engine в пошаговой отладке или в среде разработки программ. Начать стоит с обзора названия пространств имен, названия классов, методов и полей, Названия могут подсказать логическую связь с читом, который хотим сделать. Стоит обратить внимание на такие названия как "IsPlayer, Player, Character, CharacterController, MainCharacter, Health, Inventory, Craft" и другие. Чтобы не искать вручную можно задействовать поиск сборкам. Поиск стандартного тега "Player" в виде в строки кода (в Unity выше версии 5.0) или свойства "IsPlayer" может помочь найти игрока или отличить от чужих. Важно представлять иерархию игровых объектов, которую мы не видим в dnSpy. Программист работая в Unity видит это окошко много лет и эту иерархию всегда представляет смотря на скрипты в dnSpy Скрипты наследники от MonoBehavior могут находиться на игровом объекте и могут работать как с ним так и с другими объектами. Получается такая штука, что игровой объект всегда имеет Transform компонент с полями позиций, углами и scale. Классы Transform и GameObject самые основные. Методами этих классов можно разместить объект в мире, создать или удалить его. В идеале удалив объект со сцены не должно быть никаких ошибок связанных с пустыми ссылками, потерей объекта. Также и клонировав объект, тоже не должно быть ошибок. Но не всегда так просто отспавнить игровой объект. Если это сделать методами UnityEngine, то другие классы ничего не будут знать о появлении игрового объекта. Нужно ставить брейкпоинт в функции Start или Awake в классе и трейсить по Shift+11 чтобы выйти на функцию разработчиков спавна этого GameObject. Функции Start или Awake (в классе наследника от MonoBehavior) срабатывают один раз при включении скрипта и инициализации. По ним можно выйти на строку кода, которая создает объекты в мире. Отдельно стоит сказать про количество скриптов. Практически в любой игре, которая мне попадалась в dnSpy много скриптов или очень много. Иногда и не будет понятных названий у типов (из-за обфускации). В любом случае при пошаговой отладке можно найти требующиеся участки кода для создания чита и использовать их по другой логике. Основные приемы В Update можно обновлять параметры только своего игрока. Например, в Character классе сделать сравнения в Update по IsPlayer свойству (если оно там есть) и у тебя за каждый кадр рендеринга будет максимум характеристик. В Update с классом Input можно считывать хоткеи. В Start и Awake можно подгружать свои ассеты с внутриигровым user interface. Код скриптов перед загрузкой ассетов должен быть внедрен через dnSpy Иерархию игровых объектов и инспектор, если очень нужно, то можно отрисовать в user interface. Обычно не требуется. (поищите по форуму в игрострое) В заключении Пока нет времени делать трейнер или таблицу на CE для включения опций в играх Unity. Для меня пока подходит способ через перезапись модуля в dnSpy вручную. Вместо трейнера можно сделать программу патчер, который будет проверять версию игры и перезаписывать модуль с возможностью вернуть оригинальный модуль
    • MasterGHM

      [The Escapists 2 + Unity + dnSpy] Спавн итемов

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео unity cheats dnspy csharp блог
      1
      2
      0 Голоса
      1 Сообщения
      106 Просмотры
      MasterGHM
      Спавн итемов удалось сделать через dnSpy При клике на любой предмет на меню крафта он создается в инвентаре, а если там занято, то выкидывается на карту. Я переписал метод клика на рецепт, вот он оригинальный // Token: 0x060069FA RID: 27130 RVA: 0x00254874 File Offset: 0x00252A74 private void OnRecipeSlotClicked(int recipeSlotID) { if (recipeSlotID == this.m_CurrentClickedRecipeID) { if (!T17RewiredStandaloneInputModule.IsCurrentActiveModuleUsingController()) { this.m_CurrentClickedRecipeID = -1; } return; } if (!this.CheckHasItemsForRecipe(recipeSlotID)) { this.m_CurrentClickedRecipeID = -1; return; } CraftManager.Recipe recipeByID = CraftManager.GetInstance().GetRecipeByID(recipeSlotID); if (recipeByID != null && (!recipeByID.m_bHidden || recipeByID.m_bDiscovered)) { this.FillSlots(recipeSlotID); this.m_CurrentClickedRecipeID = recipeSlotID; return; } this.m_CurrentClickedRecipeID = -1; } На этот private void OnRecipeSlotClicked(int recipeSlotID) { int itemDataID = CraftManager.GetInstance().GetCurrentRecipes()[recipeSlotID].m_Product.m_ItemDataID; Character character = base.CurrentGamePlayer.GetComponent(); ItemManager.GetInstance().AssignItemRPC(character.m_NetView.ownerId, itemDataID, new ItemManager.ItemManagerEvent(this.OnStandingAnimItemSpawn), ref character.m_StandingStillEquipID, -1); } private void OnStandingAnimItemSpawn(Item item, int eventID) { if (base.CurrentGamePlayer.GetComponent().m_StandingStillEquipID == eventID) { Player player = base.CurrentGamePlayer; bool flag = false; if (player.GetEquippedItem() == null) { flag = player.SetEquippedItem(item, true, false, RPC_CallContexts.Master); } if (!flag) { item.DropItemInLevel(player, player.transform.position); } } } Для спавна заменить Assembly-CSharp.dll из архива, сделав копию предварительно Assembly-CSharp.rar
    • MasterGHM

      Sikulix-скрипт сравнения изображений в играх

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео sikulix распознавание todo блог
      1
      0 Голоса
      1 Сообщения
      110 Просмотры
      MasterGHM
      Вполне читерская программа Sikulix Помощник для нахождения отличий К сожалению, эту стать невозможно восстановить. Надо искать исходники. Игра Sikulix Документация Туториалы Sikulix умеет: ждать появления или исчезновения элемента, просто ждать, периодически просматривать область в background (например игрового чата); читать (и писать) текст в(/из) поля ввода, "нажимать на клавиатуру", подсвечивать области, кликать по элементам, удерживать и перетаскивать; перемещаться по окнам по названию процессов; сохранять скриншоты в том числе определенные области; показывать много разных диалогов: ввода, тултипов, сообщений; сравнивать изображения и находить отличные области (пример выше); поиск элементов по маске; поиск групп элементов и перебор их; создание гайдов или руководств с анимациями Из наиболее интересных применений: в играх где необходим поиск графических элементов с действиями (кликеры, поиск отличий или поиск/подсчет элементов, маджонги и другие); нажать на найденных элементы(кнопки, чек-боксы); найти текстовое значение, перевести в число, посчитать; ожидает выхода человека из скайпа (или что-то вроде мониторинга чатов); Ну и так далее...
    • MasterGHM

      Большой брейкпоинт page exceptions

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео breakpoint фишки ce lua
      1
      4
      0 Голоса
      1 Сообщения
      110 Просмотры
      MasterGHM
      Наткнувшись на тему вспомнил, что не все написал. В прошлом посте блога рассматривал бряк через DBVM. К сожалению, та версия dbvm из поста блога пропускала очень много инструкций и практически смысла нет её юзать. Например она определяла 16 инструкций, когда их было несколько тысяч, т.е. например 500 оффестов и на каждой по 10 инструкций. По DBVM надо, конечно, писать Дарк Байту, но желания нет. Так вот. Не только с DBVM можно ставить бряки на участок памяти. Есть еще тип брейкпоинтов page exceptions. О нем давно-давно известно и он как на ладони, но почему-то я пропустил его, когда искал оффсеты в структурах С ним можно работать с lua и без. Ловит огромное количество инструкций. Желательно мощное железо, т.к. игра скорее всего будет очень тормозить по 2-5 fps. Но на короткий запуск сойдет. 5 секунд и достаточно для снятия логов. На пару действий в игре тоже сойдет: выстрел или пермещение персонажа, прыжок или вообще ничего не делаем просто снимаем логи. способ поставить бряк из окна памяти. Подопытная программа "Tutorial-x86_64.exe" Здесь видно, что размер 720 байт Логи из окна инструкций CE 1000259AE - 48 8B 00 - mov rax,[rax] 1000259C3 - 48 8B 00 - mov rax,[rax] 10001D70C - F7 40 50 10000000 - test [rax+50],00000010 10001D734 - 48 8B 00 - mov rax,[rax] 1000AAB40 - 48 83 78 70 00 - cmp qword ptr [rax+70],00 10001D809 - F7 40 50 10000000 - test [rax+50],00000010 10000D452 - 48 8B 0A - mov rcx,[rdx] 10005AE70 - 83 40 68 01 - add dword ptr [rax+68],01 1000A4CF5 - F7 40 50 10000000 - test [rax+50],00000010 1000A4EB8 - 48 8B 00 - mov rax,[rax] 10000DA76 - 4C 8B 32 - mov r14,[rdx] 10005AE90 - 83 68 68 01 - sub dword ptr [rax+68],01 100139C13 - F7 40 50 10000000 - test [rax+50],00000010 100139C32 - 48 8B 48 60 - mov rcx,[rax+60] 100139C46 - 48 8B 40 60 - mov rax,[rax+60] 10009CEFB - 48 8B 00 - mov rax,[rax] 100098850 - 8B 80 80010000 - mov eax,[rax+00000180] 1000A4E81 - 81 88 00010000 00200000 - or [rax+00000100],00002000 1000A4E98 - 48 8B 00 - mov rax,[rax] 1000AD685 - F7 40 50 08000000 - test [rax+50],00000008 10009BFB8 - 8B 40 50 - mov eax,[rax+50] 10009816F - F7 40 50 08000000 - test [rax+50],00000008 100098236 - 48 8B 00 - mov rax,[rax] 10001BECE - 48 8B 00 - mov rax,[rax] 100098419 - F7 40 50 08000000 - test [rax+50],00000008 1000A2A28 - 48 8B 00 - mov rax,[rax] 1000A29F4 - 48 8B 12 - mov rdx,[rdx] 1000A4CC8 - 81 A0 00010000 FFDFFFFF - and [rax+00000100],FFFFDFFF 10001CC58 - F7 40 50 10000000 - test [rax+50],00000010 10000DB13 - 48 8B 00 - mov rax,[rax] 100095C65 - 48 8B 48 60 - mov rcx,[rax+60] 100095C75 - 48 8B 40 60 - mov rax,[rax+60] 10001CB04 - F7 40 50 10000000 - test [rax+50],00000010 10009BF35 - 8B 40 50 - mov eax,[rax+50] 10009932D - 48 8B 00 - mov rax,[rax] 10001F5C8 - F7 40 50 08000000 - test [rax+50],00000008 10001F638 - 8B 40 50 - mov eax,[rax+50] 100021803 - F7 40 50 08000000 - test [rax+50],00000008 100021923 - F7 40 50 08000000 - test [rax+50],00000008 10001ACB1 - 8B 41 50 - mov eax,[rcx+50] 10001B850 - 48 8B 48 60 - mov rcx,[rax+60] 10001B85C - 48 8B 40 60 - mov rax,[rax+60] 1000A2AC0 - 48 8B 00 - mov rax,[rax] 10013A2A3 - F7 40 50 10000000 - test [rax+50],00000010 10013A336 - 48 8B 00 - mov rax,[rax] 100098AC4 - 4C 8B 02 - mov r8,[rdx] 100098AD9 - 48 8B 00 - mov rax,[rax] 10013A35C - 48 8B 00 - mov rax,[rax] 10008A0C1 - 48 8B 00 - mov rax,[rax] 1000192A9 - 48 8B 12 - mov rdx,[rdx] 1000A3B99 - 48 8B 12 - mov rdx,[rdx] 100096636 - 8B 82 D0010000 - mov eax,[rdx+000001D0] 10008A0ED - 48 8B 00 - mov rax,[rax] 100097DF9 - 48 8B 00 - mov rax,[rax] 1000A4325 - 81 B8 80010000 FF7F0000 - cmp [rax+00000180],00007FFF 1000A6218 - F7 40 50 10000000 - test [rax+50],00000010 1000A6240 - 48 8B 00 - mov rax,[rax] 1000A6254 - 48 8B 00 - mov rax,[rax] 100097727 - 48 8B 48 60 - mov rcx,[rax+60] 100097733 - 48 8B 40 60 - mov rax,[rax+60] 10018E4D9 - F7 40 50 10000000 - test [rax+50],00000010 1000AA369 - F7 80 58010000 00400000 - test [rax+00000158],00004000 1000AA394 - 48 8B 00 - mov rax,[rax] 1000AA600 - 48 83 B8 B0020000 00 - cmp qword ptr [rax+000002B0],00 100097E3B - 48 8B 00 - mov rax,[rax] 1000A74A9 - 48 8B 00 - mov rax,[rax] Способ через Lua (подробнее в документации) debug_setBreakpoint(structure_address, sizeMemory, bptAccess, bpmException, onBreakpoint) P.S. Я написал про два способа установки брейкпоинта на множество адресов без DBVM. Вручную можно ставить такие брейкпоинты, но дальше уже кропотливый просмотр на предмет того чем это может помочь. Это может помочь определить типы данных и помочь прикинуть размер структуры, а также найти активные оффсеты. Можно на Lua автоматически определять активные offsets по базовому адресу структуры и эту структуру создать и заполнить в dessectData. Если будет время напишу скрипт.
    • MasterGHM

      Cheat Engine и Lua. Старт

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео ce lua
      1
      0 Голоса
      1 Сообщения
      308 Просмотры
      MasterGHM
      Где писать Lua код? Lua Engine окно, которое вызывается из главного окна CE. Lua Console окно, которое вызывается из окна отладки CE. Окно Autoassembler скрипта с вставки {$lua}, {$asm} Lua Engine окно и Autoassembler-ные скрипты могут сохраняться в файлах Cheat Engine *.CT. *.CETRAINER, *.EXE Lua Console для пошаговой отладки Lua кода и просмотров результатов ошибок и функции print() Моя первая программа Сначала узнаем версию для CE 6.7 и это будет первая программа Запускаем CE и жмем ctrl+alt+L и Lua Engine, вводим print(_VERSION) \-->> Lua 5.3 Вторая программа showMessage('Hello World!') Следующий шаг — собрать справочные материалы и практические руководства. Неважно какими они будут по сложности и объему. Всегда можно будет обратиться к ним позже, когда потребуется что-то найти. Справочные материалы Если CE использует версию Lua 5.3, то нужен официальный справочник по этой версии. Ищем Lua 5.3 (https://www.lua.org/manual/5.3/) Cheat Engine Lua Basics (http://wiki.cheatengine.org/index.php?title=Lua_Basics ) Category:Assembler(http://wiki.cheatengine.org/index.php?title=Category:Assembler) Lua Functions and Classes (http://wiki.cheatengine.org/index.php?title=Lua) Introduction to Lua using Cheat Engine: Beginner to Basic Script Writer! (http://dsasmblr.com/introduction-to-lua-using-cheat-engine-beginner-to-basic-script-writer/) Setup a Lua auto attach script (http://wiki.cheatengine.org/index.php?title=Tutorials:Lua:Setup_Auto_Attach) Lua Debugging (http://wiki.cheatengine.org/index.php?title=Lua_Debugging) Практические руководства Tables Tutorial (http://lua-users.org/wiki/TablesTutorial) Learn Lua in 15 Minutes (http://tylerneylon.com/a/learn-lua/) Lua за 60 минут (https://zserge.wordpress.com/2012/02/23/lua-за-60-минут/) Я обращаюсь к celua.txt и defines.lua. Находятся в директории Cheat Engine. В этих файлах краткое справочное руководство. Стоит также отметить, что Cheat Engine 6.7 написана на Lazarus. Написав, например программу по рисованию фигур, линий на форме на Lazarus или Delphi можно будет понять, как сделать также классами и функциями на CE Lua. А что нельзя сделать CE Lua, то решается внедрением и исполнения кода в саму Cheat Engine. Продолжение следует...
    • MasterGHM

      CE рисование через дополнительный поток

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео ce thread ce lua ce draw ce видео
      1
      0 Голоса
      1 Сообщения
      85 Просмотры
      MasterGHM
      На видео показано рисование через поток и рисование без потока CE Native Thread Когда происходит рисование без потока, то окно нельзя подвинуть, не работает кнопка и даже не возможно работать с 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
    • MasterGHM

      Крафт в StarsOne

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео unity dnspy блог
      1
      8
      0 Голоса
      1 Сообщения
      90 Просмотры
      MasterGHM
      В оригинале, если нет всех компонентов рецепта, то нельзя скрафтить вещь. Цель: скрафтить без компонетов по нажатию кнопки Игра на 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 или ранее Изменения сохраняем в модуль, запускаем игру и крафтим. Получить все рецепты (не проверял правда, попробуйте если хотите) Вещи не ломаются. Убрать отнятие "здоровья" у вещи
    • PitronicP

      функции трейнера открыть игру и добавление адреса в форму.

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Не решенные Вопросы, обсуждения и предложения
      1
      1
      0 Голоса
      1 Сообщения
      105 Просмотры
      PitronicP
      Для начала, чтоб было понятно что мне нужно, скриншот ниже. На первом скриншоте видно что можно запустить игру трейнером(Для этого трейнер должен быть в одной папке с игрой). На втором скрншоте окошки где вписываешь значение. Понятно что в форму трейнера добавлены адреса, которые можно в вести в ручную из значение. Я общался с автором трейнер был написан на сишарп. А можно ли в се это реализовать? Кнопка запуска игры, и окошки для значений адресов привязанные к конкретным адресам?
    • MasterGHM

      Заметка. Логи брейкпоинта на структуру размером 0x1000

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Вопросы, обсуждения и предложения
      1
      2
      0 Голоса
      1 Сообщения
      87 Просмотры
      MasterGHM
      Примечание. Эти логи мне могут понадобиться для группировки инструкций по типу. Например, булевые типы, по чтению. по записи, по смещениям, локальные структуры по смениям и т.п. В структуре по смещению 0x2C0 находится здоровье персонажа. На начало этой структуры и был поставлен брейкпоинт . Ниже будет большой кусок опкодов, который работает со структурой. Log breakpoint on structure 0x1000.txt Можно посмотреть в каком порядке опкоды исполняются и с какими смещениями, насколько далеко они друг от друга. Некоторые смещения рядом с известными смещениями могут заинтересовать. Одинаковые опкоды в определенном порядке, но по разным RIP тоже могут заинтересовать. Switch-case могут заинтересоваь в виде cmp [x]. число. Инструкции чтения из структуры больше интересуют, т.к. они могут более вероятно, на что-то влиять - из них читается и для чего-то это нужно. Причем последовательность инструкций идет в порядке вызова, но RIP всегда уникальный (RIP не дублируются). Здесь RIP, т.к. CE 64 разрядный Если последовательность к данным структуры примерно сохраняется, то можно обратить внимание на обращение к адресам в структуре рядом со здоровьем по смещению 2с0: до обращения к адресу здоровья, во время и после. Я выделил их стрелками. Эти смещения могут быть связаны со здоровьем Интересные моменты могут быть с так называемыми switch-case операциями. Можно пытаться их подменить
    • MasterGHM

      Рубрика "Lua код сегодня" №6 (проверка по md5)

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Статьи и видео md5 ce lua speak важно обучалка фишки
      1
      0 Голоса
      1 Сообщения
      258 Просмотры
      MasterGHM
      Получить md5 открытого процесса и записать его в MD5_CHEKING вручную \-- Функция для ручного вывода md5 ранее подключенного процесcа. Для установки MD5_CHEKING PrintMd5CurrentProcess() Пример проверки md5 function onOpenProcess(processid) reinitializeSymbolhandler() local md5Process = GetMd5Process(processid) PrintMd5Process(process, md5Process) local isSupportedVersion = CheckingMd5CurrentProcess(md5Process) local lineResult = isSupportedVersion and 'Is supported version.' or 'Is not supported version.' if not isSupportedVersion then speakEnglish(lineResult, false) messageDialog('Error', lineResult, mtError, mbClose) end end ce_md5.lua md5 - это алгоритм некоторой суммы байтов exe-шника. Позволит точно идентифицировать exe-шник, для которого будет сделана .CT таблица с указателями или сигнатурами. В случае несоответствия будет показан диалог сообщения и звуковое оповещение проговаривания текста ошибки. Будет необходимо проверять md5, чтобы смещения у структур точно не поменялись.
    • MasterGHM

      CE Lua API

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Справочники
      1
      0 Голоса
      1 Сообщения
      58 Просмотры
      MasterGHM
      CE 7.5.0.7431 (в репозитории файл с кратким описанием API celua.txt, который можно найти рядом с CE) Wiki: Lua - Cheat Engine (содержит более полное описание классов с примерами)
    • MasterGHM

      CE Auto Assembler API

      Отслеживается Игнорируется Запланировано Прикреплена Закрыта Перенесена Справочники
      1
      0 Голоса
      1 Сообщения
      113 Просмотры
      MasterGHM
      Auto Assembler Auto Assembler - Commands - Cheat Engine (описание команд Autoassebler c примерами). Там же вставки C-языка {$CCODE playerbase=RCX newhealth=RBX} int isplayer=*(*int)(playerbase+0xb8); if (isplayer) ​newhealth=100000; else ​newhealth=0; {$ASM} Руководство по C языку (https://www.geeksforgeeks.org/c-programming-language/) Там же вставки Lua языка {$LUACODE playerbase=RCX newhealth=RBX} if readInteger(playerbase+0xb8)==1 then newhealth=100000 else ​newhealth=0 end {$ASM} Руководство по Lua (https://www.lua.org/manual/5.4/) Lua классы в CE (https://wiki.cheatengine.org/index.php?title=Cheat_Engine:Lua)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 4 / 7