<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Статьи и видео]]></title><description><![CDATA[Статьи]]></description><link>https://celua.ru/category/16</link><generator>RSS for Node</generator><lastBuildDate>Wed, 20 May 2026 04:02:12 GMT</lastBuildDate><atom:link href="https://celua.ru/category/16.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 04 Oct 2025 07:49:59 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Шаблон скрипта для проверки MD5 в Cheat Engine с авто-активацией чита]]></title><description><![CDATA[Шаблон скрипта для проверки MD5 в Cheat Engine с авто-активацией чита
Сначала дается краткий сжатый код.
function onOpenProcess(processid)
  reinitializeSymbolhandler()
  local md5Process = GetMd5Process(processid)
  PrintMd5Process(process, md5Process)
  local isSupportedVersion = CheckingMd5CurrentProcess(md5Process)
  local lineResult = isSupportedVersion and 'Is supported version. Activating cheat...' or 'Is not supported version.'
  if not isSupportedVersion then
    speakEnglish(lineResult, false)
    messageDialog('Error', lineResult, mtError, mbClose)
  else
    speakEnglish(lineResult, true)
    -- Активация простого чита: поиск и заморозка адреса здоровья
    autoAssemble(&lsqb;&lsqb;
      alloc(newmem,2048)
      label(code)
      label(return)
      "Base.exe"+123456:
      code:
        mov [eax],(int)999
      return:
      jmp return
      newmem:
        jmp "Base.exe"+123456
        nop
        jmp return
    &rsqb;&rsqb;)
    messageDialog('Success', 'Cheat activated for health: 999', mtInformation, mbOK)
  end
end

А потом дается объяснение. Все нужно в формате nodebb
ce_md5_cheat.lua
md5 - это алгоритм хэширования exe-файла, который позволяет точно идентифицировать версию игры или приложения. Это критично для .CT таблиц в Cheat Engine, чтобы избежать ошибок из-за обновлений, меняющих смещения структур памяти.
В случае несоответствия MD5 версии показывается диалог ошибки и звуковое оповещение. Если версия поддерживается, скрипт автоматически активирует простой чит (в примере - заморозка здоровья на 999 по смещению "Base.exe"+123456; замените на реальные значения для вашей игры).
Обязательно проверяйте MD5 перед использованием таблиц, чтобы смещения структур не сдвинулись из-за патчей!

Получить md5 открытого процесса и записать его в MD5_CHEKING вручную

\-- Функция для ручного вывода md5 ранее подключенного процесса. Для установки 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. Activating cheat...' or 'Is not supported version.'
  if not isSupportedVersion then
    speakEnglish(lineResult, false)
    messageDialog('Error', lineResult, mtError, mbClose)
  else
    speakEnglish(lineResult, true)
    -- Активация простого чита: поиск и заморозка адреса здоровья
    autoAssemble(&lsqb;&lsqb;
      alloc(newmem,2048)
      label(code)
      label(return)
      "Base.exe"+123456:
      code:
        mov [eax],(int)999
      return:
      jmp return
      newmem:
        jmp "Base.exe"+123456
        nop
        jmp return
    &rsqb;&rsqb;)
    messageDialog('Success', 'Cheat activated for health: 999', mtInformation, mbOK)
  end
end

]]></description><link>https://celua.ru/topic/167/шаблон-скрипта-для-проверки-md5-в-cheat-engine-с-авто-активацией-чита</link><guid isPermaLink="true">https://celua.ru/topic/167/шаблон-скрипта-для-проверки-md5-в-cheat-engine-с-авто-активацией-чита</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 04 Oct 2025 07:49:59 GMT</pubDate></item><item><title><![CDATA[Unity3d. Easing functions в Unity &amp; DoTween]]></title><description><![CDATA[Функции анимации для Unity













FrameWork для UNity3d: https://dotween.demigiant.com/
Документация: https://dotween.demigiant.com/documentation.php
Принцип:

Узнаем, что анимировать. Например, подсветку.
Узнаем, как анимировать. Например, идем https://easings.net/ смотрим график и тип анимации. Например, мне нужна анимация easeOutSine. По ней должна меняться частота цвета подсветки
Далее ищем какой-нибудь пример в поисковике по работе с цветом. Пусть это будет

using DG.Tweening;
using UnityEngine;

public class ColorChanger : MonoBehaviour
{
    [SerializeField] private MeshRenderer meshRenderer;

    private void Awake()
    {
       // меняется цвет материала
        DOVirtual.Color(Color.black, Color.white, 10, (value) =&gt;
        {
            meshRenderer.material.color = value;
        });
    }
}

Смотрим документацию

...В этом примере, material при каждом разе пересоздается с новым цветом в каждом кадре отрисовки, поэтому надо менять на sharedMaterial. Этот пример надо переделать с анимацией


Ищем функцию анимации



Пишем пример. Анимируем мерцание цвета с возрастающей частотой по InQuint


       IEnumerator ShowWriteButton()
       
              {
       
                  Image image = writeButton.GetComponent&lt;Image&gt;();       
                  Color originalColor = image.color;       
                  float frequency = 0;       
                  DOVirtual.Float(0.01f, 0.1f, 1f, v =&gt; frequency = v).SetEase(Ease.InQuint);       
                  var currentTime = Time.time;       
                  yield return new WaitForSeconds(0.5f);       
                  while (Time.time - currentTime &lt;= 1f)       
                  {
                      image.color = originalColor;       
                      yield return new WaitForSeconds(frequency);       
                      image.color = colorWrite;       
                      yield return new WaitForSeconds(frequency);       
                  }       
              }
                    StartCoroutine(ShowWriteButton());


В этом примере происходят параллельно две операции: изменение частоты по InQuint и использование этой частоты для подсветки кнопки. Много примеров в документации...
Dotween библиотека популярна. Её можно использовать для полета камеры, для перемещения объектов, подсветки и т.п.
]]></description><link>https://celua.ru/topic/149/unity3d.-easing-functions-в-unity-dotween</link><guid isPermaLink="true">https://celua.ru/topic/149/unity3d.-easing-functions-в-unity-dotween</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sun, 19 May 2024 11:38:56 GMT</pubDate></item><item><title><![CDATA[Visual Studio. Топ 10 часто используемых горячих клавиш]]></title><description><![CDATA[Предлагаю поделиться своими ТОП горячими клавишами в Visual Studio.


ctrl + ] найти закрывающие скобки функции, класса. С shift можно выбрать внутри.


shift + alt + (. или &lt;) перемещение по выделенными словам как f3 вперед или назад


alt + лев. кнопка мышки   установка мульти курсора. После выбор по shift или в пункт 2, 4.


shift +u или ctl +u  сделать выделенный текст строчными или прописными


ctrl + R + G - удалить неиспользуемые пространства имен


ctrl + shift + v  кольцевой буфер обмена


ctrl + K + S обернуть строки (в регион, namespace, if и т.п.)


ctrl + alt + X  окно элементов (перетаскиваем туда выделенные строки в своим папки. Это для хранения истории своих строк кода)


ctrl + K  поставить закладку
ctrl +K+K				создать/убрать закладку
ctrl +K+N / CTRL+K+P 	перемещение по закладкам
ctrl +K+L 				удалить все закладки


ctrl + T показать список задач.


Перемещение строки или выделенных строк
alt +↑  переместить строку вверх
alt +↓  переместить строку вниз


alt + shift +arrow keys(←,↑,↓,→)   выбор колонок текста


ctrl +arrow keys(←,→)  перемещение по словами


ctrl +arrow keys(↑,↓) движение списка
и т.п.


]]></description><link>https://celua.ru/topic/144/visual-studio-топ-10-часто-используемых-горячих-клавиш</link><guid isPermaLink="true">https://celua.ru/topic/144/visual-studio-топ-10-часто-используемых-горячих-клавиш</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 23 Dec 2023 19:41:53 GMT</pubDate></item><item><title><![CDATA[Безусловные и условные пыжки.]]></title><description><![CDATA[Иногда код ассемблера необходимо с делать с условием пример фильтр свой чужой. Реализовать это можно сравнением двух адресов и задать условие. Сравнение задаётся командой cmp, после которой идёт условие прыжка , после которого выполняется ваш код. пример мы нашли смещение от адреса число которое равно 1 от начала структуры адреса игрока и нам надо если оно равно чтоб здоровье было больше. и так пишем наш код.
cmp [eax+1234],1 // сравнили наш адрес фильтра с единицей
jne code // если не равно прыжок на метку code
mov [eax+40],#99999 // а если равно
кроме метки code могут быть безымянные метки
@F прыжок в перёд
@B прыжок назад
пример
cmp [eax+1234],1 // сравнили наш адрес фильтра с еденицей
jne @F // если не равно прыжок в перёд
mov [eax+40],#99999 // а если равно
также есть чистая безымянная метка которая позволит сделать два условия
@@: безымянная метка
пример с этим же кодом
cmp [eax+1234],1 // сравнили наш адрес фильтра с единицей
jne @F // если не равно прыжок в перёд
mov [eax+40],#99999 // а если равно
@@: // прыжок на безымянную метку
mov [eax+40],0 // если  [eax+1234],1 не равен это наш враг и с метки @@: не наш игрок умирает
Теперь таблица условных прыжков и переходов:
JA прыжок, если выше
JAE прыжок, если выше или равно
JB прыжок, если ниже
JBE прыжок, если меньше или равно
JC Прыгает, если перенос
JCXZ прыжок, если равно нулю
JE прыжок, если равно
JG прыжок, если больше
JGE прыжок, если больше или равно
JL прыжок, если меньше
JLE прыжок, если меньше или равно
Прыжок JNA, если не выше
JNAE прыжок, если не выше или не равно
Прыжок JNB, если не ниже
JNBE прыжок, если не ниже или не равно
Переход JNC, если не выполняется перенос
JNE прыжок, если не равно
Переход JNG, если не больше
JNL прыжок, если не меньше
JNO переходит, если не переполнено
JZ прыжок если равно нулю.
]]></description><link>https://celua.ru/topic/123/безусловные-и-условные-пыжки</link><guid isPermaLink="true">https://celua.ru/topic/123/безусловные-и-условные-пыжки</guid><dc:creator><![CDATA[Pitronic]]></dc:creator><pubDate>Thu, 25 May 2023 12:15:01 GMT</pubDate></item><item><title><![CDATA[Создать структуру программно]]></title><description><![CDATA[Решил попробовать написать CE Lua  скрипт, который прочесывает структуру и в Dissect data/structures окне создавал бы структуру только со смещениями, с которыми код работает, т.е. читает или пишет.
Например, мой персонаж прогуливается по городу, а каждые 200 мс ставится брейкпоинт на смещение +1 до гипотетической N границы структуры (например до 4096).
Я не успел сделать определение типа, но смещения внутри структуры получить я успел.
Итак, находим начало структуры любой. Запускаем Lua скрипт и просто что-то делаем в игре. Потом вылазит текст с дизассемблированными инструкциями и смещениями. Уже по этим логам можно определить вручную


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


по виду инструкции и соседнему смещению уже примерно можно определить тип данных и их размер

Осталось сделать определение типа, а это не так уж долго сделать  и осталось взять код из предыдущих записей в блоге формирования структуры в окне dessect data. Так мы получим структуру только с активными смещениями, (а зачем нам пассивные?) и определим в них тип, я надеюсь определим правильно


Пример кода, который я использовал
addressStructure1 = 0x412E0200 --&gt; адрес начала структуры в любой игре
sizeStructure = 100     --&gt; гипототический размер структуры 100 для быстрых поисков, по умолчанию 4096
indexStructure = 0      --&gt; индекс внутри структуры, который будет перемещаться вместе с breakPointAddress
breakPointAddress = 0   --&gt; адрес, на который сейчас постален брейкпоинт
waitTimeTillBreak = 300 --&gt; частота активности смещеиня
resultText = ''         --&gt; конкатенация частей текста в этой переменной

\-- Функция пытается поставить брейкпоинт на следующий байт в структуре
function TryNextSetBreakPointToAddress()
  debug_removeBreakpoint(breakPointAddress)
  indexStructure = indexStructure + 1
  if indexStructure &gt; sizeStructure then
    debugTimer.Interval = 1000
    debugTimer.Enabled = false
    debugTimer.destroy()
    debug_continueFromBreakpoint(co_run)
    print(resultText) --&gt; вывод результата с завершением отладки
    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)

]]></description><link>https://celua.ru/topic/102/создать-структуру-программно</link><guid isPermaLink="true">https://celua.ru/topic/102/создать-структуру-программно</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sun, 14 May 2023 08:12:44 GMT</pubDate></item><item><title><![CDATA[Как контролировать включение и выключение скриптов в таблице]]></title><description><![CDATA[Как контролировать включение и выключение скриптов в таблице
AA или "Autoassembler code" код похожий на язык программирования ассемблера.

Кратко, он позволяет менять игровой код. Подробнее Cheat Engine:Auto Assembler (http://wiki.cheatengine.org/index.php?title=Cheat_Engine:Auto_Assembler)

Обычный АА-скрипт состоит из двух директив и добавляется в таблицу CE как запись
 // Код срабатывающий как при активации, так и при деактивации
  [ENABLE]
  // Код активации
  [DISABLE]
  // Код деактивации

Чтобы код активировался, нужно включить галку напротив записи в таблице и наоборот выключить.
Есть такие директивы как {$lua} и {$asm}.
Под {$lua} пишут Lua скрипт, под {$asm} пишут АА-скрипт.
Мы можем проверить Lua скриптом любое условие и разрешить включать галку или выключать галку. Например, через "syntaxcheck" — проверку синтаксиса или другое условие .
Если проверка не прошла, то не получится галку включить и не получится выключить, если что-то пойдет не так.
В Lua строка из двух минусов "--", обозначает комментарий.
{$lua}
\-- Расскоментируйте или закоментируйте пару строк ниже
\-- if syntaxcheck then return end
\-- error[666] = 666
\------------------------------ ENABLE ------------------------------
[ENABLE]
\-- Расскоментируйте или закоментируйте пару строк ниже
\-- if syntaxcheck then return end
\-- error[666] = 666
\------------------------------ DISABLE ------------------------------
[DISABLE]
\-- Расскоментируйте или закоментируйте пару строк ниже
\-- if syntaxcheck then return end
\-- error[666] = 666

Попробовав разные варианты вы увидите, что нельзя включать или выключать галку в разных ситуациях. Например в этой получится включить галку, а выключить нет из-за ошибки.
{$lua}
\-- if syntaxcheck then return end
\-- некоторый lua код правильный или не правильный
\-- error[666] = 666
\------------------------------ ENABLE ------------------------------
[ENABLE]
\--if syntaxcheck then return end
\-- некоторый lua код
\-- некоторый lua код правильный или не правильный
\-- error[666] = 666
\------------------------------ DISABLE ------------------------------
[DISABLE]
if syntaxcheck then return end
\-- некоторый lua код
\-- некоторый lua код правильный или не правильный
error[666] = 666

Следующий вариант проверяет открыт ли процесс. Если нет, то покажет сообщение.
Как узнать, что процесс был закрыт после открытия
process - зарезервированное переменная, показывает что процесс открыт

(http://wiki.cheatengine.org/index.php?title=Lua:process)
В комментариях можно увидеть при каких условиях блокируются включение галки

{$lua}
  -- code before either enable/disable section runs for both just like with AA code
  if syntaxcheck then return end
  [ENABLE]
  if process == nil  then
   showMessage('Процесс не подключен. Галка не будет включена')
   return
  end
  if process ~= nil and readInteger(process) == nil  then
   showMessage('Процесс был закрыт. Галка не будет включена')
   return
  end

  [DISABLE]
  -- Галку можно выключить, но код выключения выполнять если процесс подключен
  if process ~= nil and readInteger(process) ~= nil then
    print('Attached to ' .. process)
  else
   showMessage('The process closed')
  end

]]></description><link>https://celua.ru/topic/101/как-контролировать-включение-и-выключение-скриптов-в-таблице</link><guid isPermaLink="true">https://celua.ru/topic/101/как-контролировать-включение-и-выключение-скриптов-в-таблице</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sun, 14 May 2023 08:12:02 GMT</pubDate></item><item><title><![CDATA[Часть1. Lua простые регулярные выражения]]></title><description><![CDATA[Есть такой плагин "AA Maker" и там довольно интересные регулярные выражения на Lua. Разберем некоторые выражения
Выражение ''%[(.*)%]' - захват всего, что в квадратных скобках
Пример
local s = 'mov eax, [ecx + 4]'
print(string.match(s, '%[(.*)%]'))
\--&gt; ecx + 4

Символ "%" нужно всегда ставить перед специальными символами такими как ^$()%.[]*+-?
Символ "%[" и "%]" означают квадратные скобки в строке
Разбирая комбинацию (.*).
Точка означает любой символ, а символ умножить означает повторение любого символа
Круглые скобки означают "подшаблон"

Подшаблоны
В шаблон можно включить подшаблоны, выделив их круглыми скобками. Если найденная строка соответствует шаблону, то ее подстроки, соответствующие подшаблонам, будут доступны для будущего использования. Подшаблоны пронумерованы согласно их левым круглым скобкам. Например, в шаблоне "(a*(.)%w(%s*))", часть строки, соответствующая "a*(.)%w(%s*)" будет зафиксирована как первый подшаблон (и поэтому имеет номер 1); любые символы попавшие под соответствие "." будут зафиксированы как подшаблон номер 2, и часть строки, соответствующая "%s*" получит номер 3.
Специальный вариант использования подшаблонов - получение текущей позиции в строке. Для этого используются пустые подшаблоны (). Например, если мы применим шаблон "()aa()" к строке "flaaap", то получим два результата: 3 и 5.
Шаблон не может содержать вложенные ноли. Используйте %z вместо этого.

Т.е. можем извлечь содержимое инструкции.
Примеры
"(.*)" - захват всей строки
"/(.*)/" - захват всего, что находится между КРАЙНИМИ символами /
"/(.-)/" - захват всего, что находится между ПЕРВЫМИ ДВУМЯ символами /

Пример из ААMaker плагина
local _,_,x = string.find(opcode, '%[(.*)%]') из функции ниже

Функция
string.find("СТРОКА", "ШАБЛОН") возвращает номер позиции начала начала и конца шаблона
Пример
print(string.find('some string', 'me'))
\--&gt; 3 4 

Вся функция с комментариями из AAMaker
\-- Таблица паттернов для нескольких инструкций inc, mov, fld, fstp (ключи таблицы)
\-- Они нужны для создания автоматического АА кода, через замену строк другими строками
\- {$Type} — очевидно для типа byte, word, dword
\- [x] — очевидно обращение к адресу
\- {$Value} — это значение
\- \r\n — переход на следующую строку
\-- Что будем делать с этой таблицой будет видно по коду или смотрите плагин
PATTERN = {
['inc']	 = 'mov{$Type}[x],{$Value}',
['mov']  = 'mov{$Type}[x],{$Value}\r\n{$OriginalCode}',
['fld']	 = 'mov{$Type}[x],{$Value}\r\n{$OriginalCode}',
['fstp'] = '{$OriginalCode}\r\n'..'mov{$Type}[x],{$Value}'
}

\-- Не очень понятно зачем квадратные скобки у ключей. Можно написать не ['inc'], а 'inc'

\-- Функция проверки паттерна
function checkPattern()

	-- Получение имени адреса из адреса dv_address1 (выделенный адрес в дизассемблере)
	local address = getNameFromAddress(dv_address1)

	-- Получение инструкции по имени адреса 
	local _,opcode = splitDisassembledString(disassemble(address))

	-- ComboBox.Text свойство равно "Injection" или "AOBScanModule"
	local choose = getProperty(cmbCheatType,"Text")

	if choose == 'Injection' or choose == 'AOBScanModule' then

		-- Перебор по ключу и значению таблицы PATTERN
		for key,value in pairs(PATTERN) do

			-- Если в опкоде нашли ключ из таблицы паттернов
			-- Где key это inc, mov, fld, fstp (см. выше таблицу PATTERN)
			-- Где opcode это например инструкция 'inc [edx + 4]'
			if string.find(opcode,key) ~= nil then
				local _,_,x = string.find(opcode, '%[(.*)%]')
				if x ~= nil then
					-- В value будет значение 'mov{$Type}[x],{$Value}'
					patternInjectAsmCode = value
					-- Нашли паттерн и вернули его
					return true
				end
			end
		end
	end
	-- Паттерн не нашли в таблице, вернули false
	patternInjectAsmCode = '{$OriginalCode}'
	return false
end

\-- patternInjectAsmCode 
 

Чтобы посмотреть результат, сделал скрин отладки Lua кода

Функции по работе со строками. Link
Используемые источники: link, link, link, link
aamaker.lua
]]></description><link>https://celua.ru/topic/99/часть1-lua-простые-регулярные-выражения</link><guid isPermaLink="true">https://celua.ru/topic/99/часть1-lua-простые-регулярные-выражения</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sun, 14 May 2023 08:05:27 GMT</pubDate></item><item><title><![CDATA[Часть2. Lua простые регулярные выражения]]></title><description><![CDATA[Если нужно найти начало и конец подстроки. Пример
Попробуем найти слово lab в троке gamehacklab.ru
print(string.find('gamehacklab.ru', 'lab'))
&gt;9 11

Если не найдена подстрока, то вернет nil.
С помощью string.match можем выводить не индексы, а строку
print(string.match('gamehacklab.ru', 'lab'))
&gt;lab

С помощью string.gmatch можем выводить последовательно строки
Где 'a.' означает символ 'a' и еще один следующий любой
local result = string.gmatch('gamehacklab.ru', 'a.')
print(result())
print(result())
print(result())

вывод
&gt;am 
&gt;ac 
&gt;ab 

Здесь комбинация символов "%a+" означает искать слово пока оно не закончится
s = "hello world from Lua"
for w in string.gmatch(s, "%a+") do
  print(w)
end

Вывод
&gt; hello 
&gt; world 
&gt; from 
&gt; Lua

А здесь заполняем таблицу ключ — значение из строки, которую можно было бы взять из файла
t = {}
s = "X=0, Y=0, Z=0"
for k, v in string.gmatch(s, "(%w+)=(%w+)") do
  t[k] = v
end

for i, v in pairs(t) do
  print(i..' = '..v)
end

Вывод
&gt;Z = 0 
&gt;X = 0 
&gt;Y = 0 

Пока на этом все... Более сложные примеры в предыдущей части записи
]]></description><link>https://celua.ru/topic/98/часть2-lua-простые-регулярные-выражения</link><guid isPermaLink="true">https://celua.ru/topic/98/часть2-lua-простые-регулярные-выражения</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sun, 14 May 2023 07:59:30 GMT</pubDate></item><item><title><![CDATA[Рубрика &quot;Lua код сегодня&quot; №6 (проверка по md5)]]></title><description><![CDATA[












Получить 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, чтобы смещения у структур точно не поменялись.
]]></description><link>https://celua.ru/topic/86/рубрика-lua-код-сегодня-6-проверка-по-md5</link><guid isPermaLink="true">https://celua.ru/topic/86/рубрика-lua-код-сегодня-6-проверка-по-md5</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sun, 07 May 2023 18:23:54 GMT</pubDate></item><item><title><![CDATA[Крафт в StarsOne]]></title><description><![CDATA[В оригинале, если нет всех компонентов рецепта, то нельзя скрафтить вещь.

Цель: скрафтить без компонетов по нажатию кнопки
Игра на 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 &gt;= 0.3f)
		{
            // Добавили одну вещь крафта
			if (craftCount == 0)
			{
				craftCount = 1;
			}

			if (craftCount != 0)
			{
				this.succes = true;
				CraftRecipe component = this.craftObjects[curCraft].GetComponent&lt;CraftRecipe&gt;();
              
                // Здесь удалили код, который должен расходовать вещи из инвентаря
                // ...
              
				if (this.succes)
				{
					this.iks = this.craftObjects[curCraft].GetComponent&lt;CraftRecipe&gt;().countCreate * craftCount;
					for (int m = 0; m &lt; this.craftObjects[curCraft].GetComponent&lt;CraftRecipe&gt;().countCreate * craftCount; m++)
					{
						this.emptyCell = Inventory.inv.FindItemForStack(this.craftObjects[curCraft].name);
						if (this.emptyCell &gt;= 0)
						{
							if (Inventory.inv.items[this.emptyCell].stack + this.iks &lt;= 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 &gt;= 0)
							{
								this.cloneItem = Inventory.inv.CreateItem(this.craftObjects[curCraft]);
								if (this.cloneItem.maxStack &gt;= 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&lt;Item&gt;().maxStack &gt;= 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&lt;Item&gt;().health);
									break;
								}
								PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.craftObjects[curCraft].GetComponent&lt;Item&gt;().maxStack, this.craftObjects[curCraft].GetComponent&lt;Item&gt;().health);
								this.iks -= this.craftObjects[curCraft].GetComponent&lt;Item&gt;().maxStack;
							}
							new WaitForEndOfFrame();
						}
					}
				}
			}
			this.timeBreak = 0f;
		}
	}
}

Оригинальный
public void CreateItem(int curCraft, int craftCount)
	{
		if (this.timeBreak &gt;= 0.3f)
		{
			if (craftCount != 0)
			{
				this.succes = true;
				CraftRecipe component = this.craftObjects[curCraft].GetComponent&lt;CraftRecipe&gt;();
				int[] array = new int[7];
				int[] array2 = new int[7];
				for (int i = 0; i &lt; 7; i++)
				{
					if (this.succes &amp;&amp; component.ingredients[i] != null)
					{
						array2[i] = component.countIngredients[i];
						if (array2[i] &lt;= 0)
						{
							array2[i] = 1;
						}
						array2[i] *= craftCount;
						for (int j = 0; j &lt; Inventory.inv.items.Length; j++)
						{
							if (Inventory.inv.items[j] != null &amp;&amp; component.ingredients[i].name == Inventory.inv.items[j].prefName)
							{
								array[i] += Inventory.inv.items[j].stack;
							}
						}
						if (array[i] &lt; array2[i])
						{
							this.succes = false;
						}
					}
				}
				if (this.succes)
				{
					for (int k = 0; k &lt; 7; k++)
					{
						if (component.ingredients[k] != null)
						{
							for (int l = 0; l &lt; Inventory.inv.items.Length; l++)
							{
								if (Inventory.inv.items[l] != null &amp;&amp; array2[k] &gt; 0 &amp;&amp; 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] &lt;= 0)
									{
										break;
									}
								}
							}
						}
					}
					this.iks = this.craftObjects[curCraft].GetComponent&lt;CraftRecipe&gt;().countCreate * craftCount;
					for (int m = 0; m &lt; this.craftObjects[curCraft].GetComponent&lt;CraftRecipe&gt;().countCreate * craftCount; m++)
					{
						this.emptyCell = Inventory.inv.FindItemForStack(this.craftObjects[curCraft].name);
						if (this.emptyCell &gt;= 0)
						{
							if (Inventory.inv.items[this.emptyCell].stack + this.iks &lt;= 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 &gt;= 0)
							{
								this.cloneItem = Inventory.inv.CreateItem(this.craftObjects[curCraft]);
								if (this.cloneItem.maxStack &gt;= 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&lt;Item&gt;().maxStack &gt;= 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&lt;Item&gt;().health);
									break;
								}
								PlayerNetwork.inst.CallCmdCreateItem(this.craftObjects[curCraft].name, Inventory.inv.transform.position - Vector3.forward * 2f + FloatingOrigin.offset, Quaternion.identity, this.craftObjects[curCraft].GetComponent&lt;Item&gt;().maxStack, this.craftObjects[curCraft].GetComponent&lt;Item&gt;().health);
								this.iks -= this.craftObjects[curCraft].GetComponent&lt;Item&gt;().maxStack;
							}
							new WaitForEndOfFrame();
						}
					}
				}
			}
			this.timeBreak = 0f;
		}
	}

Изменяем весь класс или метов в этом окне

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

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


]]></description><link>https://celua.ru/topic/74/крафт-в-starsone</link><guid isPermaLink="true">https://celua.ru/topic/74/крафт-в-starsone</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 22:27:07 GMT</pubDate></item><item><title><![CDATA[Поиск в региона памяти модуля]]></title><description><![CDATA[
вот доказательство что старым версиям твой плагин нужен будет.
]]></description><link>https://celua.ru/topic/73/поиск-в-региона-памяти-модуля</link><guid isPermaLink="true">https://celua.ru/topic/73/поиск-в-региона-памяти-модуля</guid><dc:creator><![CDATA[Pitronic]]></dc:creator><pubDate>Sat, 08 Apr 2023 21:41:39 GMT</pubDate></item><item><title><![CDATA[CE рисование через дополнительный поток]]></title><description><![CDATA[На видео показано рисование через поток и рисование без потока







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

]]></description><link>https://celua.ru/topic/72/ce-рисование-через-дополнительный-поток</link><guid isPermaLink="true">https://celua.ru/topic/72/ce-рисование-через-дополнительный-поток</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 12:29:57 GMT</pubDate></item><item><title><![CDATA[CE 6.8 Обзор нового инструмента поиска по структурам]]></title><description><![CDATA[Пользователь @Pitronic написал в CE 6.8 Обзор нового инструмента поиска по структурам:

Разрешаю в этой теме всё что в той дополнить

Спасибо, за твое разрешение. Мне, кажется, это две разные статьи и лучше в новой теме.
@Pitronic публиковать статьи тоже можешь.. Там еще можно добавлять теги и выбирать раздел.
]]></description><link>https://celua.ru/topic/71/ce-6-8-обзор-нового-инструмента-поиска-по-структурам</link><guid isPermaLink="true">https://celua.ru/topic/71/ce-6-8-обзор-нового-инструмента-поиска-по-структурам</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 12:20:43 GMT</pubDate></item><item><title><![CDATA[Cheat Engine и Lua. Старт]]></title><description><![CDATA[Где писать 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)
\--&gt;&gt; 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.
Продолжение следует...
]]></description><link>https://celua.ru/topic/70/cheat-engine-и-lua-старт</link><guid isPermaLink="true">https://celua.ru/topic/70/cheat-engine-и-lua-старт</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 12:08:23 GMT</pubDate></item><item><title><![CDATA[Большой брейкпоинт page exceptions]]></title><description><![CDATA[Наткнувшись на тему вспомнил, что  не все написал. В прошлом посте блога рассматривал бряк через 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. Если будет время напишу скрипт.
]]></description><link>https://celua.ru/topic/69/большой-брейкпоинт-page-exceptions</link><guid isPermaLink="true">https://celua.ru/topic/69/большой-брейкпоинт-page-exceptions</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 12:04:06 GMT</pubDate></item><item><title><![CDATA[Sikulix-скрипт сравнения изображений в играх]]></title><description><![CDATA[Вполне читерская программа Sikulix
Помощник для нахождения отличий
К сожалению, эту стать невозможно восстановить. Надо искать исходники.
Игра
Sikulix
Документация
Туториалы
Sikulix умеет:

ждать появления или исчезновения элемента, просто ждать, периодически просматривать область в background (например игрового чата);
читать (и писать) текст в(/из) поля ввода, "нажимать на клавиатуру", подсвечивать области, кликать по элементам, удерживать и перетаскивать;
перемещаться по окнам по названию процессов;
сохранять скриншоты в том числе определенные области;
показывать много разных диалогов: ввода, тултипов, сообщений;
сравнивать изображения и находить отличные области (пример выше);
поиск элементов по маске;
поиск групп элементов и перебор их;
создание гайдов или руководств с анимациями

Из наиболее интересных применений:

в играх где необходим поиск графических элементов с действиями (кликеры, поиск отличий или поиск/подсчет элементов, маджонги и другие);
нажать на найденных элементы(кнопки, чек-боксы);
найти текстовое значение, перевести в число, посчитать;
ожидает выхода человека из скайпа (или что-то вроде мониторинга чатов);

Ну и так далее...
]]></description><link>https://celua.ru/topic/68/sikulix-скрипт-сравнения-изображений-в-играх</link><guid isPermaLink="true">https://celua.ru/topic/68/sikulix-скрипт-сравнения-изображений-в-играх</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 11:58:51 GMT</pubDate></item><item><title><![CDATA[[The Escapists 2 + Unity + dnSpy] Спавн итемов]]></title><description><![CDATA[Спавн итемов удалось сделать через 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 &amp;&amp; (!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
]]></description><link>https://celua.ru/topic/67/the-escapists-2-unity-dnspy-спавн-итемов</link><guid isPermaLink="true">https://celua.ru/topic/67/the-escapists-2-unity-dnspy-спавн-итемов</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 11:52:12 GMT</pubDate></item><item><title><![CDATA[[dnSpy + Unity ] Пошаговая отладка]]></title><description><![CDATA[Эта статья позволит отлаживать игры на 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 вручную.
Вместо трейнера можно сделать программу патчер, который будет проверять версию игры и перезаписывать модуль с возможностью вернуть оригинальный модуль
]]></description><link>https://celua.ru/topic/66/dnspy-unity-пошаговая-отладка</link><guid isPermaLink="true">https://celua.ru/topic/66/dnspy-unity-пошаговая-отладка</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 11:46:14 GMT</pubDate></item><item><title><![CDATA[Собираем ссылки на разные источники]]></title><description><![CDATA[Попробуй другой браузер или кеш браузера почистить. Может поможет. Иногда ссылки кешируются и автоматически подставляются неверные.
]]></description><link>https://celua.ru/topic/63/собираем-ссылки-на-разные-источники</link><guid isPermaLink="true">https://celua.ru/topic/63/собираем-ссылки-на-разные-источники</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 09:56:18 GMT</pubDate></item><item><title><![CDATA[Запустить активирющий скрипт CE 7.5]]></title><description><![CDATA[Кнопка "^"
]]></description><link>https://celua.ru/topic/62/запустить-активирющий-скрипт-ce-7-5</link><guid isPermaLink="true">https://celua.ru/topic/62/запустить-активирющий-скрипт-ce-7-5</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Sat, 08 Apr 2023 09:27:22 GMT</pubDate></item><item><title><![CDATA[Функция autoAssemble]]></title><description><![CDATA[Пользователь @MasterGH написал в Функция autoAssemble:

// Скрипт похожий на таблицу АА

Маленькое замечание. Два слеша используются для коментариев в асм. На луа используются пунктир не менее двух чёрточек. Если пользователь не разбирается, он не поймёт почему луа выдаёт ошибку. Тему поправил.
]]></description><link>https://celua.ru/topic/55/функция-autoassemble</link><guid isPermaLink="true">https://celua.ru/topic/55/функция-autoassemble</guid><dc:creator><![CDATA[Pitronic]]></dc:creator><pubDate>Fri, 07 Apr 2023 21:19:37 GMT</pubDate></item><item><title><![CDATA[Обработка исключения в Cheat Engine Lua]]></title><description><![CDATA[pcall() функция может вызывать функцию, которая может вызывать исключение.
Возвращает статус в виде булевой о том, есть ли исключение или нет и возвращает текст исключения.
function ThrowException()
      -- раскоментировать чтобы зывать ошибку по условию некоторому
      -- error("string expected", 2)
      
      -- Пример вывода стека ошибки
      print('AAA -&gt;&gt; '..debug.traceback())
      
      -- Исключение делаем
      temp[5] = 1
      
      -- До этой строчки не дойдет, т.к. исключение выше будет из-за temp[5] = 1
      print('BBB -&gt;&gt; '..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, что остановит скрипт.
]]></description><link>https://celua.ru/topic/53/обработка-исключения-в-cheat-engine-lua</link><guid isPermaLink="true">https://celua.ru/topic/53/обработка-исключения-в-cheat-engine-lua</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Fri, 07 Apr 2023 21:05:07 GMT</pubDate></item><item><title><![CDATA[Обработка исключения в Cheat Engine AA]]></title><description><![CDATA[Новые директивы 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 

]]></description><link>https://celua.ru/topic/52/обработка-исключения-в-cheat-engine-aa</link><guid isPermaLink="true">https://celua.ru/topic/52/обработка-исключения-в-cheat-engine-aa</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Fri, 07 Apr 2023 21:03:36 GMT</pubDate></item><item><title><![CDATA[Считаем размер инъекции в байтах]]></title><description><![CDATA[Можно подхватить разные моменты активации и деактивации записи в таблице 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.

]]></description><link>https://celua.ru/topic/51/считаем-размер-инъекции-в-байтах</link><guid isPermaLink="true">https://celua.ru/topic/51/считаем-размер-инъекции-в-байтах</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Fri, 07 Apr 2023 21:00:37 GMT</pubDate></item><item><title><![CDATA[Выполить текст, как код]]></title><description><![CDATA[Функция loadstring исполняет строку кода как функцию.
f = loadstring ("print 'hello, world'")
f ()   --&gt; hello, world

Есть еще и такая функция как string.dump. Она создает строку из функции
function f () print "hello, world" end
s = string.dump (f)
\-- Можно строку тут же запустить как код
loadstring (s) () --&gt; hello, world

Если по обратной связи строить и исполнять строку кода, то предположительно можно генерировать код другим кодом и учитывать гораздо больше условий, чем это может сделать человек.
Пригодится для ИИ отладки и для ИИ бота.
Код пишет другой код по обратной связи. Реальность?
]]></description><link>https://celua.ru/topic/50/выполить-текст-как-код</link><guid isPermaLink="true">https://celua.ru/topic/50/выполить-текст-как-код</guid><dc:creator><![CDATA[MasterGH]]></dc:creator><pubDate>Fri, 07 Apr 2023 20:50:07 GMT</pubDate></item></channel></rss>