CELua[RU]
    • Категории
    • Последние
    • Метки
    • Популярные
    • Пользователи
    • Группы
    • Зарегистрироваться
    • Войти
    1. Главная
    2. MasterGH
    3. Сообщения
    Не в сети
    • Профиль
    • Подписки 1
    • Подписчики 1
    • Темы 134
    • Сообщения 260
    • Группы 4

    Сообщения

    Последние Лучшие сообщения Спорные
    • Рубрика "Lua код сегодня" №3

      1befdd4e-3df6-44c7-b7d6-c916953906e3-изображение.png

      Создать пустую запись чтобы пробовать вывод названия записи через lua

      {$lua}
      print(memrec.Description)
      [ENABLE]
      print('is  on')
      [DISABLE]
      print('is  off')
      

      a351481e-040c-40a1-bb88-b011c5633f53-изображение.png

      Поля memrec многочисленны и описываются в документации. См. MemoryRecord Class: в ...\Cheat Engine 6.8.3\celua.txt

      написал в Обучающие примеры ce memrec ce aa ce lua ce .ct обучалка
      MasterGHM
      MasterGH
    • RE: Защита Трейнера

      У меня другая версия CE

      local aa_script = [[aobscanmodule(INJECT,Tutorial-x86_64.exe,29 93 90 07 00 00) // should be unique
      alloc(newmem,$1000,"Tutorial-x86_64.exe"+2B2D7)
      alloc(newmem2,$1000,"Tutorial-x86_64.exe"+2B2D7)
      registersymbol(flag)
      label(code)
      label(return)
      
      newmem2:
      flag:
      dd 0
      
      newmem:
      
      code:
        sub [rbx+00000790],edx
        jmp return
      
      INJECT:
        jmp newmem
        nop
      return:
      
      registersymbol(INJECT)]]
      
      autoAssemble(aa_script)
      
      написал в Вопросы
      MasterGHM
      MasterGH
    • Принципы управления
      1. Интерфейсный
        Кнопками и графическими элеменами.
        Например, окно CE позволяет удобно ставить галки и переключать скрипты, поведения, сценарии.
        Например, ingame меню. Т.е. отрисовывается внутри окна игры.

      2. Горячими клавишами
        Можно не переключаться между окнами, а активировать нужной комбинацией нужный сценарий. Однако, когда опций будет мноного, можно запросто забыть эти комбинации или подсматривать их.

      3. Через консоль
        Эта консоль может быть в CE или ingame консоль.
        Несморя на малую популярность это очень гибкий инструмент. С его помощью можно давать команды игровому процессу.
        Например, сохранить или загрузить игру, сменить локацию и сцену, добавить ресурсов, создать персонажа, задать команду персонажу и прочее, прочее.
        Сейчас это все в теории и не всегда просто реализуемо, но все это реализумо тем более что это процесс не удаленный и его память доступна.

      4. Программно
        В этом случае создаются некоторые исходники, которые используют способы перечисленные выше.

      Раньше на gamehacklab мы не уделяли внимания способу3. Теперь будем уделять большое внимание консоли. Практически все команды мы будем делать через консоль. И еще один момент исходники мы будем выкладывать в репозиторий, чтобы иметь возможность их корректировать и даже улучшать сохраняя версии.

      написал в Управление управление идея консоль
      MasterGHM
      MasterGH
    • Асинхронное выполнение сценариев

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

      Для этого будем актировать такую опцию
      5a911696-ae56-4772-bf1e-7b32fab46d53-изображение.png

      Если эту опцию поставить на записи, то появляются вот такие часики
      29546916-8f04-4fa5-99df-d43ae5016af3-изображение.png

      АА-шные скрипты могут искать в этот момент сигнатуру.

      Lua скрипты потестить было интересно, узнать действительно ли асинхронно выполняется. Например, один скрипт выполняет счет, второй выполняет счет. По выполнении выводится результат.

      [ENABLE]
      {$lua}
        local _, counter, _, async = memrec.Description:match('(Cunt.=.)(%d*).*(Async.=.)(%w*)')
        memrec.Async = async == 'true'
        for i = 1, counter do end
        local currentTime = os.date("%c"):gsub('/','.')
        print('Finish record:' .. memrec.Description..', at time ' .. currentTime)
        memrec.Active = false
      
        function onMemRecPostExecute(memoryrecord, newState, succeeded)
         if (memoryrecord == memrec and newState == true) then
           memrec.Active = false
         end
        end
      {$asm}
      [DISABLE]
      

      03992ff1-2202-400d-9c53-71d3d71d4163-изображение.png

      После выполнения
      b8fdfa10-52dd-4ad2-8ede-445f363c967c-изображение.png

      Если продублировать 4 скрипта, то видим, что нельзя запустить асинхронно более двух скриптов
      c0aeea14-3aa7-457c-9685-f1fb4bc3859f-изображение.png

      Вот такой вариант еще

      [ENABLE]
      {$Lua}
        function threadFunction(th)
          th.freeOnTerminate(false)
          th.Name = 'myThread'
          for b = 1, 200000000 do
            --checkSynchronize()
          end
          --while not th.Terminated do
          --  myvar=myvar+1
          --  synchronize(function() MainForm.Caption = 'myvar '..myvar end)
           -- sleep(2000)
          --end
          synchronize(function() print("1") end)
        end
      
        --myvar=0
        local myThread = createNativeThreadSuspended(threadFunction)
        myThread.resume()
      {$Asm}
      
      [DISABLE]
      {$Lua}
        if myThread then
           myThread.terminate()
           myThread.waitfor()
           myThread.destroy()
           myThread=nil
        end
      {$Asm}
      

      таблица
      Asynchronous testing.CT

      написал в Приёмы ce .ct ce aa ce async фишки
      MasterGHM
      MasterGH
    • Рубрика "Lua код сегодня" №2
      local address = 0x0170A490
      local x, y, z = 0, 100, 100
      writeDouble(address, x)
      writeDouble(address + 8, y)
      writeDouble(address + 16, z)
      

      Данный код позволяет записать значение координат и переместить персонажа.
      Обычно, адреса координат идут последовательно x,y,z и имеют тип float или double.

      Чтобы переместить персонажа нужно узнать его адрес координат и выполнить код в Lua консоли
      30d5c11d-7b9e-4706-a9c9-221f601d2731-изображение.png

      И убедиться, что данные записались в память процесса
      0e82af37-125b-41b1-9331-fe1bbc2f3042-изображение.png

      Далее мы с вами будем очень много программировать короткими примерами в консоли управляя данными процесса и в том числе связывать это с базами данных. Например, такой-то пользователь, для такого-то персонажа создал таблицу телепортации с локациями и координатами. Этой таблицей можно будет очень удобно пользоваться. Также вы изучите принцип программирования, который используется при работе с СУБД.

      написал в Обучающие примеры ce lua обучалка
      MasterGHM
      MasterGH
    • RE: Сделать большой брейкпоинт на структуру через dbk_useKernelmodeOpenProcess

      Пользователь @Pitronic написал в Сделать большой брейкпоинт на структуру через dbk_useKernelmodeOpenProcess:

      Мы знаем что адрес таймера на выстрел во первых лежит в одной структуре с патронами, во вторых адрес в начале меняется в момент выстрела одновременно с уменьшением патронов и в пределах от одной до 100 миллисекунд возвращается в прежнее значение. может lua скрипт специальный можно сделать?

      Я бы сделал без скриптов.

      1. делаешь dessect structure
        6b8ca47d-ed90-46ea-95e7-cd454196cb74-изображение.png
      2. Далее как обычно. Создаешь структуру. Затем вот это (следить за изменениями)
        17867765-a66b-43e9-9242-482b0b8c7cf3-изображение.png
      3. ну а дальше воспроизводишь свой выстрел
      4. потом создаешь структуру из изменившихся данных (потому что их будешь очень много наверняка)
        783b72ad-84e9-4444-9d5f-c02f5beb20c3-изображение.png
      5. затем делаешь lock на структуру, чтобы значения зафиксирвать
        a8243497-20b9-4ad1-9a14-056b452cace1-изображение.png
      6. затем рядом создаешь второй ряд по ctrl +a и смотрим изменения в реальном времени (игра должна быть в оконном режим, чтобы мы видели как цифры скачут)
        227628c2-13fe-485d-8632-0defed52710b-изображение.png
      7. чтобы увидеть изменения менее 100мс нужно поставить интервал меньше
        5dff820a-cb72-45a6-b625-04112696daec-изображение.png

      По идее это должно сработать

      написал в Приёмы
      MasterGHM
      MasterGH
    • RE: Делаем EFLAGS таблицу

      Ответил

      написал в Приёмы
      MasterGHM
      MasterGH
    • RE: Защита Трейнера

      Пользователь @Pitronic написал в Защита Трейнера:

      Я как понял это скрипт в таблицу

      Этот скрипт не в таблицу. Ты можешь писать свои флаги здесь

      local scriptStr = [[
      [ENABLE]
      // здесь твой флаг
      
      [DISABLE]
      // здесь твой флаг
      ]]
      local enabledOk, disableInfo = autoAssemble(scriptStr)
      
      if enabledOk then
        print('>The auto assembler script was enabled successfully.')
      else
        print('>There was an error enabling the auto assembler script.')
      end
      
      print(disableInfo)
      local disabledOk = autoAssemble(scriptStr, disableInfo)
      
      if disabledOk then
        disableInfo = nil
        print('>The auto assembler script was disabled successfully.')
      else
        print('>There was an error disabling the auto assembler script.')
      end
      
      написал в Вопросы
      MasterGHM
      MasterGH
    • Как загружать картинки

      9b9dbf2b-fdf2-4a7e-8c9f-d504f55c2770-изображение.png

      На скриншоте пример загрузки картинки

      написал в Новости
      MasterGHM
      MasterGH
    • RE: Пошаговая отладка Lua скриптов

      Открываем Lua консоль из дизассемблера

      Пишем Lua скрипт

      Дальше по шагам как на картинке
      e5a13ca4-cfba-4cba-ad07-6e9f2b56197b-изображение.png

      Если мы пишем какую-то функцию и она дает сбой, то её можно отладить как на скриншоте. Это может быть и не функция.

      Например, код прочитал какой-то файл с текстом сохраненных параметров и подсмотрели в пошаговой Lua отладке что происходит дальше.

      *Действуют горячие клавиши. Например, F7— шаг, F9 — запуск без остановки.

      написал в Приёмы
      MasterGHM
      MasterGH
    • Делаем EFLAGS таблицу

      Таблица флагов нужна для определения срабатывания условного прыжка в пошаговой отладке
      8d7c71bd-be7f-45d5-85c8-7065520c965c-изображение.png
      6ad9a581-7655-44b3-a163-52849b60de83-изображение.png

      function ToBits(num, bits)
      	local t = {}
      	for b = bits, 1, -1 do
      		rest = math.fmod(num,2)
      		t[b] = math.floor(rest)
      		num = (num-rest)/2
      	end
      	
      	if num == 0 then
      		return t
      	else
      		return {'Not enough bits to represent this number'}
      	end
      end
      
      local bitsTable = ToBits(EFLAGS, 16)
      
      local tableEFLAGS =
      {
      	OF = bitsTable[17-12],
      	DF = bitsTable[17-11],
      	SF = bitsTable[17-8],
      	ZF = bitsTable[17-7],
      	AF = bitsTable[17-5],
      	PF = bitsTable[17-3],
      	CF = bitsTable[17-1]
      }
      
      for k,v in pairs(tableEFLAGS) do
      	print (k..' = '..v)
      end
      
      print(EFLAGS)
      local s = ''
      for i=1,#bitsTable do
      	s = s..bitsTable[i]
      end
      print(s)
      
      написал в Приёмы шаблоны фишки ce lua
      MasterGHM
      MasterGH
    • Выход из рутины до ближайшего цикла

      собенности

      1. переход на следующий адрес по инструкциям ветвления вычисляется Lua кодом по ret, jmp, jmp condition до исполнения кода
      2. определение опкодов ветвления по readmem без дизассемблериования
      3. по тестам последний брейкпоинт снимается на ближайшем цикле

      Пример лога до близжайшего цикла, когда поднимается из рутины вверх

      > RET    :00454684 - C3 - ret  
      > -->>    :0045468C - 5B - pop ebx
      > RET    :0045468F - C3 - ret  
      > -->>    :00454695 - C3 - ret  
      > RET    :00454695 - C3 - ret  
      > -->>    :00437F36 - 5B - pop ebx
      > RET    :00437F37 - C3 - ret  
      > -->>    :004272EB - 5B - pop ebx
      > RET    :004272EC - C3 - ret  
      > -->>    :004273E9 - 5E - pop esi
      > RET    :004273EA - C3 - ret  
      > -->>    :00437A2E - 5F - pop edi
      > RET    :00437A34 - C3 - ret  
      > -->>    :0043B749 - 5B - pop ebx
      > RET    :0043B74D - C3 - ret  
      > -->>    :00427195 - 5F - pop edi
      > RET    :00427198 - C3 - ret  
      > -->>    :004376BB - 8B 45 FC  - mov eax,[ebp-04]
      > RET    :004376C2 - C2 0400 - ret 0004
      > -->>    :0043B880 - 89 46 0C  - mov [esi+0C],eax
      > RET    :0043B88A - C3 - ret  
      > -->>    :0043BFF4 - 84 C0  - test al,al
      > isCJMP    :0043BFF6 - 75 09 - jne 0043C001
      > RET    :0043C003 - C3 - ret  
      > -->>    :0044DFAD - 5E - pop esi
      > RET    :0044DFAF - C3 - ret  
      > -->>    :00437A2E - 5F - pop edi 
      
      \--[[
      	Версия: 0.01.b1
      	Выход из рутины до близжайшего цикла
      ]]--
      
      mainAddress = 0x0045B5A4 -- адрес некоторого параметра в игре
      nextAddress = nil
      is64bits = targetIs64Bit()
      
      tableInstruction ={}
      tableBreakpointsAddress ={}
      
      
      function ContaintsBeakPoint(address)
      	for i = 1, #tableBreakpointsAddress do
      		if tableBreakpointsAddress[i] == address then
      			return true
      		end
      	end
      	return false
      end
      
      \-- Возвращает адрес по ret
      function GetNextAddressFromRET(address)
      	if is64bits then
      		nextAddress = readPointer(RSP)
      	else
      		nextAddress = readPointer(ESP)
      	end
      	return nextAddress
      end
      \-- Возвращает адрес по Jmp
      function GetNextAddressFromJMP(address)
      	local disassembledstring = nil
      	if is64bits then
      		local disassembledstring = disassemble(RIP)
      	else
      		local disassembledstring = disassemble(EIP)
      	end
      	local _, opcode, _, _ = splitDisassembledString(disassembledstring)
      	return GetAddressFromOpcode(opcode)
      end
      
      
      function ToBits(num, bits)
      	local t = {}
      	for b = bits, 1, -1 do
      		rest = math.fmod(num,2)
      		t[b] = math.floor(rest)
      		num = (num-rest)/2
      	end
      	
      	if num == 0 then
      		return t
      	else
      		return {'Not enough bits to represent this number'}
      	end
      end
      
      
      function GetEFLAGS()
      	local bitsTable = ToBits(EFLAGS, 16)
      
      	local tableEFLAGS =
      	{
      		OF = bitsTable[17-12],
      		DF = bitsTable[17-11],
      		SF = bitsTable[17-8],
      		ZF = bitsTable[17-7],
      		AF = bitsTable[17-5],
      		PF = bitsTable[17-3],
      		CF = bitsTable[17-1]
      	}
      	
      	--for k,v in pairs(tableEFLAGS) do
      	--	print (k..' = '..v)
      	--end
      	--
      	--print(EFLAGS)
      	--local s = ''
      	--for i=1,#bitsTable do
      	--	s = s..bitsTable[i]
      	--end
      	--print(s)		
      	return tableEFLAGS	
      end
      
      \-- Возвращает адрес из опкода jmp dword ptr [edi*4+07895D88] или jmp 07895D88
      \--print(string.format('%08X', newAddress))
      function GetAddressFromOpcode (opcode)
      
      	local rightLine = string.match(opcode, '%S*%s*(%S*)')
      	local isPointer = string.match(opcode, '%[')
      	if isPointer then
      		rightLine = string.match(opcode, '%[(.*)%]')
      		--00454664 - 8B 83 60030000        - mov eax,[ebx+00000360]
      		if string.match(opcode, 'eax') then rightLine = string.gsub(rightLine, 'eax', EAX) end
      		if string.match(opcode, 'ebx') then rightLine = string.gsub(rightLine, 'ebx', EBX) end
      		if string.match(opcode, 'ecx') then rightLine = string.gsub(rightLine, 'ecx', ECX) end
      		if string.match(opcode, 'edx') then rightLine = string.gsub(rightLine, 'edx', EDX) end
      		if string.match(opcode, 'esi') then rightLine = string.gsub(rightLine, 'esi', ESI) end
      		if string.match(opcode, 'edi') then rightLine = string.gsub(rightLine, 'edi', EDI) end
      		if string.match(opcode, 'esp') then rightLine = string.gsub(rightLine, 'esp', ESP) end
      		if string.match(opcode, 'ebp') then rightLine = string.gsub(rightLine, 'ebp', EBP) end
      		
      		if is64bits then
      			if string.match(opcode, 'rax') then rightLine = string.gsub(rightLine, 'rax', RAX) end
      			if string.match(opcode, 'rbx') then rightLine = string.gsub(rightLine, 'rbx', RBX) end
      			if string.match(opcode, 'rcx') then rightLine = string.gsub(rightLine, 'rcx', RCX) end
      			if string.match(opcode, 'rdx') then rightLine = string.gsub(rightLine, 'rdx', RDX) end
      			if string.match(opcode, 'rsi') then rightLine = string.gsub(rightLine, 'rsi', RSI) end
      			if string.match(opcode, 'rdi') then rightLine = string.gsub(rightLine, 'rdi', RDI) end
      			if string.match(opcode, 'rsp') then rightLine = string.gsub(rightLine, 'rsp', RSP) end
      			if string.match(opcode, 'rbp') then rightLine = string.gsub(rightLine, 'rbp', RBP) end
      			
      			if string.match(opcode, 'r8') then rightLine = string.gsub(rightLine, 'r8', R8) end
      			if string.match(opcode, 'r9') then rightLine = string.gsub(rightLine, 'r9', R9) end
      			if string.match(opcode, 'r10') then rightLine = string.gsub(rightLine, 'r10', R10) end
      			if string.match(opcode, 'r11') then rightLine = string.gsub(rightLine, 'r11', R11) end
      			if string.match(opcode, 'r12') then rightLine = string.gsub(rightLine, 'r12', R12) end
      			if string.match(opcode, 'r13') then rightLine = string.gsub(rightLine, 'r13', R13) end
      			if string.match(opcode, 'r14') then rightLine = string.gsub(rightLine, 'r14', R14) end
      			if string.match(opcode, 'r15') then rightLine = string.gsub(rightLine, 'r15', R15) end
      		end
      		
      		return getAddress('%['..rightLine..'%]')
      	end
      	
      	return getAddress(rightLine)
      end
      
      \-- Возвращает адрес по Jmp condition, когда тот выполняется или не выполняется
      function GetNextAddressFromConditionJMP(address, size)
      
      	local _,opcode,_,_ = splitDisassembledString(disassemble(address))
      	local leftString = string.match(opcode, '%S*')
      	local eflags = GetEFLAGS()
      	
      	if (leftString == 'jnz' or leftString == 'jne') 										then	if eflags.ZF == 0 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'je' or leftString == 'jz') 								then if eflags.ZF == 1 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jg' or leftString == 'jnle')								then if eflags.ZF == 0 and eflags.SF == eflags.OF 	then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jb' or leftString == 'jc' or leftString == 'jnae') 	then if eflags.CF == 1 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jae')															then	if eflags.CF == 0											then return GetAddressFromOpcode(opcode) end 
      		elseif (leftString == 'ja') 															then if eflags.CF == 0 and eflags.ZF == 0 				then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jbe') 															then if eflags.CF == 1 and eflags.ZF == 1 				then return GetAddressFromOpcode(opcode) end	
      		elseif (leftString == 'jl' or leftString == 'jnge') 								then if eflags.SF ~= eflags.OF 								then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jle' or leftString == 'jng') 								then if eflags.ZF == 1 or eflags.SF ~= eflags.OF 		then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jna') 															then if eflags.CF == 1 or eflags.ZF == 1 					then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jc') 															then if eflags.CF == 1 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jp' or leftString == 'jpe') 								then	if eflags.PF == 1											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jnp' or leftString == 'jpo') 								then if eflags.PF == 0 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jnb' or leftString == 'jnc') 								then if eflags.CF == 0 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jnbe') 														then if eflags.CF == 0 and eflags.ZF == 0 				then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jno') 															then	if eflags.OF == 0 											then return GetAddressFromOpcode(opcode) end	
      		elseif (leftString == 'jns') 															then	if eflags.SF == 0 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jo') 															then if eflags.OF == 1 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'js') 															then if eflags.SF == 1 											then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jge' or leftString == 'jnl') 								then if eflags.CF == 1 and eflags.OF == 1 				then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jrcxz') 														then if RCX == 0 												then return GetAddressFromOpcode(opcode) end
      		elseif (leftString == 'jecxz') 														then if ECX == 0 												then return GetAddressFromOpcode(opcode) end
      	end
      	return address + size
      end
      
      function IsRet(address)
         local value = readBytes(address,1, false)
         return value == 0xC3 or value == 0xCB or  value == 0xC2 or value == 0xCA
      end
      
      function IsCall(address)
         local value = readBytes(address,1, false)
         return value == 0xFF or value == 0xE8 -- or  value == 0x9A
      end
      
      function IsJMP(address)
      	local value = readBytes (address, 1, false)
      	if value == 0xFF then
      		if readBytes (address + 1, 1, false) == 05 then
      			return false
      		end
      	end
      	return value == 0xEB or value == 0xE9 or  value == 0xFF -- or value == 0xEA
      \--[[
      	078921A8 - EB 38                 		- jmp 078921E2
      	0789242D - E9 E2000000     			- jmp 07892514
      	07894F4C - FF E2                 			- jmp edx
      	07895C67 - FF 24 BD 885D8907     - jmp dword ptr [edi*4+07895D88]
      ]]--	
      end
      
      
      
      
      function IsConditionJMP(address)
      	local value = readBytes (address, 1, false)
      	return  
      		value == 0x77 or value == 0x73 or value == 0x72 or value == 0x76 or
      		value == 0xE3 or value == 0x74 or value == 0x7F or value == 0x7D or
      		value == 0x7C or value == 0x7E or value == 0x75 or value == 0x71 or
      		value == 0x7B or value == 0x79 or value == 0x70 or value == 0x7A or
      		value == 0x78 or value == 0x0F
      end
      
      \-- Возвращает адрес, на который, будет прыжок
      function GetNextAddress(addressXIP)
      	-- Определить на какой инструкции мы находимся, чтобы узнать на какую следующу инструкцию ставить бряк
      	-- ret				- прыжок по смещению ESP/RSP
      	-- jmp				- прыжок без условия
      	-- je, jne, jxx	- прыжок с улосвием
      	
      	-- Определить размер инструкции, тип инструкции на текущем addressXIP
      	local findIndex = -1
      	for i = 1, #tableInstruction do
      		if tableInstruction[i].XIP == addressXIP then
      			findIndex = i
      			break
      		end
      	end
      	
      	local size = 0
      	local isRet = false
      	local isJMP = false
      	local isCJMP = false
      		
      	if findIndex ==  -1 then
      		-- Если нет данных
      		---------------- ЗАПОМИНАТЬ РАЗМЕР ИНСТРУКЦИИ (чтобы не дизассемблировать повторно)
      		size = getInstructionSize(addressXIP)
      		isRet = IsRet(addressXIP)
      		isJMP = IsJMP(addressXIP)
      		isCJMP = IsConditionJMP(addressXIP)
      		table.insert(tableInstruction, {XIP = addressXIP, SIZE = size, ISRET = isRet, ISJMP = isJMP,  ISCJMP = isCJMP})
      	else
      		-- Если данные есть
      		size = tableInstruction[findIndex].SIZE
      		isRet = tableInstruction[findIndex].ISRET
      		isJMP = tableInstruction[findIndex].ISJMP
      		isCJMP = tableInstruction[findIndex].ISCJMP
      	end	
      	---------------
      	
      	if isRet then
      		print('> RET	:' ..disassemble(nextAddress))
      		nextAddress = GetNextAddressFromRET(addressXIP)
      		print('> -->>	:' ..disassemble(nextAddress))
      	elseif isJMP then
      		print('> isJMP	:' ..disassemble(nextAddress))
      		nextAddress =  GetNextAddressFromJMP(addressXIP)
      	elseif isCJMP then
      		print('> isCJMP	:' ..disassemble(nextAddress))
      		nextAddress = GetNextAddressFromConditionJMP(addressXIP, size)
      	else
      		nextAddress = addressXIP + size
      	end
      	
      	return nextAddress
      end
      
      
      function debugger_onBreakpoint()
      
      	local isContaintsBreakPoint = false
      	
      	-- Удалить прошлый брейкпоинт
      	if(nextAddress ~= nil) then
      		 isContaintsBreakPoint = ContaintsBeakPoint(nextAddress)
      		 if isContaintsBreakPoint then
      			debug_removeBreakpoint(nextAddress)
      		end
      	end	
      	
      	-- Поставить брейкпоинт на следующую инструкцию не входя в call-ы
      	local XIP = 0
      	if is64bits then XIP = EIP	else	XIP = RIP end
      	
      	nextAddress = GetNextAddress(XIP)
      	if not ContaintsBeakPoint(nextAddress) then
      		debug_setBreakpoint(nextAddress, 1, bptExecute, bpmDebugRegister)
      		table.insert(tableBreakpointsAddress, nextAddress)
      	end
      	
      	return 1 --1 не показывать дизассемблер
      end
      
      if getOpenedProcessID() == 0 then
        openProcess('test.exe')
      end
      
      
      \--bptWrite
      \--bptAccess
      debug_removeBreakpoint()
      debug_setBreakpoint(mainAddress, 4, bptWrite, bpmDebugRegister)
      

      Справка

      77 cb JA rel8 D Valid Valid Jump short if above (CF=0 and ZF=0).
      73 cb JAE rel8 D Valid Valid Jump short if above or equal (CF=0).
      72 cb JB rel8 D Valid Valid Jump short if below (CF=1).
      76 cb JBE rel8 D Valid Valid Jump short if below or equal (CF=1 or ZF=1).
      72 cb JC rel8 D Valid Valid Jump short if carry (CF=1).
      E3 cb JCXZ rel8 D N.E. Valid Jump short if CX register is 0.
      E3 cb JECXZ rel8 D Valid Valid Jump short if ECX register is 0.
      E3 cb JRCXZ rel8 D Valid N.E. Jump short if RCX register is 0.
      74 cb JE rel8 D Valid Valid Jump short if equal (ZF=1).
      7F cb JG rel8 D Valid Valid Jump short if greater (ZF=0 and SF=OF).
      7D cb JGE rel8 D Valid Valid Jump short if greater or equal (SF=OF).
      7C cb JL rel8 D Valid Valid Jump short if less (SF≠ OF).
      7E cb JLE rel8 D Valid Valid Jump short if less or equal (ZF=1 or SF≠ OF).
      76 cb JNA rel8 D Valid Valid Jump short if not above (CF=1 or ZF=1).
      72 cb JNAE rel8 D Valid Valid Jump short if not above or equal (CF=1).
      73 cb JNB rel8 D Valid Valid Jump short if not below (CF=0).
      77 cb JNBE rel8 D Valid Valid Jump short if not below or equal (CF=0 andZF=0).
      73 cb JNC rel8 D Valid Valid Jump short if not carry (CF=0).
      75 cb JNE rel8 D Valid Valid Jump short if not equal (ZF=0).
      7E cb JNG rel8 D Valid Valid Jump short if not greater (ZF=1 or SF≠ OF).
      7C cb JNGE rel8 D Valid Valid Jump short if not greater or equal (SF≠ OF).
      7D cb JNL rel8 D Valid Valid Jump short if not less (SF=OF).
      7F cb JNLE rel8 D Valid Valid Jump short if not less or equal (ZF=0 and SF=OF).
      71 cb JNO rel8 D Valid Valid Jump short if not overflow (OF=0).
      7B cb JNP rel8 D Valid Valid Jump short if not parity (PF=0).
      79 cb JNS rel8 D Valid Valid Jump short if not sign (SF=0).
      75 cb JNZ rel8 D Valid Valid Jump short if not zero (ZF=0).
      70 cb JO rel8 D Valid Valid Jump short if overflow (OF=1).
      7A cb JP rel8 D Valid Valid Jump short if parity (PF=1).
      7A cb JPE rel8 D Valid Valid Jump short if parity even (PF=1).
      7B cb JPO rel8 D Valid Valid Jump short if parity odd (PF=0).
      78 cb JS rel8 D Valid Valid Jump short if sign (SF=1).
      74 cb JZ rel8 D Valid Valid Jump short if zero (ZF = 1).
      0F 87 cw JA rel16 D N.S. Valid Jump near if above (CF=0 and ZF=0). Not supported in 64-bit mode.
      0F 87 cd JA rel32 D Valid Valid Jump near if above (CF=0 and ZF=0).
      0F 83 cw JAE rel16 D N.S. Valid Jump near if above or equal (CF=0). Not supported in 64-bit mode.
      0F 83 cd JAE rel32 D Valid Valid Jump near if above or equal (CF=0).
      0F 82 cw JB rel16 D N.S. Valid Jump near if below (CF=1). Not supported in 64-bit mode.
      0F 82 cd JB rel32 D Valid Valid Jump near if below (CF=1).
      0F 86 cw JBE rel16 D N.S. Valid Jump near if below or equal (CF=1 or ZF=1). Not supported in 64-bit mode.
      0F 86 cd JBE rel32 D Valid Valid Jump near if below or equal (CF=1 or ZF=1).
      0F 82 cw JC rel16 D N.S. Valid Jump near if carry (CF=1). Not supported in 64-bit mode.
      0F 82 cd JC rel32 D Valid Valid Jump near if carry (CF=1).
      0F 84 cw JE rel16 D N.S. Valid Jump near if equal (ZF=1). Not supported in 64-bit mode.
      0F 84 cd JE rel32 D Valid Valid Jump near if equal (ZF=1).
      0F 84 cw JZ rel16 D N.S. Valid Jump near if 0 (ZF=1). Not supported in 64-bit mode.
      0F 84 cd JZ rel32 D Valid Valid Jump near if 0 (ZF=1).
      0F 8F cw JG rel16 D N.S. Valid Jump near if greater (ZF=0 and SF=OF). Notsupported in 64-bit mode.
      0F 8F cd JG rel32 D Valid Valid Jump near if greater (ZF=0 and SF=OF).
      0F 8D cw JGE rel16 D N.S. Valid Jump near if greater or equal (SF=OF). Not supported in 64-bit mode.
      0F 8D cd JGE rel32 D Valid Valid Jump near if greater or equal (SF=OF).
      0F 8C cw JL rel16 D N.S. Valid Jump near if less (SF≠ OF). Not supported in 64-bit mode.
      0F 8C cd JL rel32 D Valid Valid Jump near if less (SF≠ OF).
      0F 8E cw JLE rel16 D N.S. Valid Jump near if less or equal (ZF=1 or SF≠ OF). Not supported in 64-bit mode.
      0F 8E cd JLE rel32 D Valid Valid Jump near if less or equal (ZF=1 or SF≠ OF). 
      0F 86 cw JNA rel16 D N.S. Valid Jump near if not above (CF=1 or ZF=1). Not supported in 64-bit mode.
      0F 86 cd JNA rel32 D Valid Valid Jump near if not above (CF=1 or ZF=1).
      0F 82 cw JNAE rel16 D N.S. Valid Jump near if not above or equal (CF=1). Not supported in 64-bit mode.
      0F 82 cd JNAE rel32 D Valid Valid Jump near if not above or equal (CF=1).
      0F 83 cw JNB rel16 D N.S. Valid Jump near if not below (CF=0). Not supported in 64-bit mode.
      0F 83 cd JNB rel32 D Valid Valid Jump near if not below (CF=0).
      0F 87 cw JNBE rel16 D N.S. Valid Jump near if not below or equal (CF=0 and ZF=0). Not supported in 64-bit mode.
      0F 87 cd JNBE rel32 D Valid Valid Jump near if not below or equal (CF=0 and ZF=0).
      0F 83 cw JNC rel16 D N.S. Valid Jump near if not carry (CF=0). Not supported in 64-bit mode.
      0F 83 cd JNC rel32 D Valid Valid Jump near if not carry (CF=0).
      0F 85 cw JNE rel16 D N.S. Valid Jump near if not equal (ZF=0). Not supported in 64-bit mode.
      0F 85 cd JNE rel32 D Valid Valid Jump near if not equal (ZF=0).
      0F 8E cw JNG rel16 D N.S. Valid Jump near if not greater (ZF=1 or SF≠ OF). Not supported in 64-bit mode.
      0F 8E cd JNG rel32 D Valid Valid Jump near if not greater (ZF=1 or SF≠ OF).
      0F 8C cw JNGE rel16 D N.S. Valid Jump near if not greater or equal (SF≠ OF). Not supported in 64-bit mode.
      0F 8C cd JNGE rel32 D Valid Valid Jump near if not greater or equal (SF≠ OF). 
      0F 8D cw JNL rel16 D N.S. Valid Jump near if not less (SF=OF). Not supported in 64-bit mode.
      0F 8D cd JNL rel32 D Valid Valid Jump near if not less (SF=OF).
      0F 8F cw JNLE rel16 D N.S. Valid Jump near if not less or equal (ZF=0 and SF=OF). Not supported in 64-bit mode.
      0F 8F cd JNLE rel32 D Valid Valid Jump near if not less or equal (ZF=0 and SF=OF).
      0F 81 cw JNO rel16 D N.S. Valid Jump near if not overflow (OF=0). Not supported in 64-bit mode.
      0F 81 cd JNO rel32 D Valid Valid Jump near if not overflow (OF=0).
      0F 8B cw JNP rel16 D N.S. Valid Jump near if not parity (PF=0). Not supported in 64-bit mode.
      0F 8B cd JNP rel32 D Valid Valid Jump near if not parity (PF=0).
      0F 89 cw JNS rel16 D N.S. Valid Jump near if not sign (SF=0). Not supported in 64-bit mode.
      0F 89 cd JNS rel32 D Valid Valid Jump near if not sign (SF=0).
      0F 85 cw JNZ rel16 D N.S. Valid Jump near if not zero (ZF=0). Not supported in 64-bit mode.
      0F 85 cd JNZ rel32 D Valid Valid Jump near if not zero (ZF=0).
      0F 80 cw JO rel16 D N.S. Valid Jump near if overflow (OF=1). Not supported in 64-bit mode.
      0F 80 cd JO rel32 D Valid Valid Jump near if overflow (OF=1).
      0F 8A cw JP rel16 D N.S. Valid Jump near if parity (PF=1). Not supported in 64-bit mode.
      0F 8A cd JP rel32 D Valid Valid Jump near if parity (PF=1).
      0F 8A cw JPE rel16 D N.S. Valid Jump near if parity even (PF=1). Not supported in 64-bit mode.
      0F 8A cd JPE rel32 D Valid Valid Jump near if parity even (PF=1).
      0F 8B cw JPO rel16 D N.S. Valid Jump near if parity odd (PF=0). Not supported in 64-bit mode.
      0F 8B cd JPO rel32 D Valid Valid Jump near if parity odd (PF=0).
      0F 88 cw JS rel16 D N.S. Valid Jump near if sign (SF=1). Not supported in 64-bit mode.
      0F 88 cd JS rel32 D Valid Valid Jump near if sign (SF=1).
      0F 84 cw JZ rel16 D N.S. Valid Jump near if 0 (ZF=1). Not supported in 64-bit mode.
      0F 84 cd JZ rel32 D Valid Valid Jump near if 0 (ZF=1).
      

      Если трейсить трейслогом 1000 инструкций поверх call, то видим многократное повторение пути внутри цикла между 00437A34 и 0044DFAF.
      1d498e8e-9dce-4fd3-8327-6b8551202bb1-изображение.png
      С помощью скрипта можно выйти на цикл не используя трейслог

      Можно использоваться функции определения куда прыгнет поток, до его выполнения.

      Можно оперировать таблицей адресов с брейкпоинтами в пошаговой отладке.

      написал в Приёмы шаблоны ce lua фишки
      MasterGHM
      MasterGH
    • Регулярки на Lua. Пронумеровать список строк

      Пример задачи. Пронумеровать список

      string
      string.byte
      string.char
      string.dump
      string.find
      string.format
      string.gmatch
      string.gsub
      string.len
      string.lower
      string.match
      string.pack
      string.packsize
      string.rep
      string.reverse
      string.sub
      string.unpack
      string.upper
      
      local text = [[
      string
      string.byte
      string.char
      string.dump
      string.find
      string.format
      string.gmatch
      string.gsub
      string.len
      string.lower
      string.match
      string.pack
      string.packsize
      string.rep
      string.reverse
      string.sub
      string.unpack
      string.upper
      ]]
      
      function EnumerateText(text)
        local count = 0
        local rez = text:gsub('%C+', function (s)
         count = count + 1
         return string.format('%s. %s', count, s)
        end)
      
        showMessage(rez)
        writeToClipboard(rez)
      end
      
      EnumerateText(text)
      

      И получил ответ. В следующий раз только вызывать "EnumerateText([[ текст со строками]])"

      1. string
      2. string.byte
      3. string.char
      4. string.dump
      5. string.find
      6. string.format
      7. string.gmatch
      8. string.gsub
      9. string.len
      10. string.lower
      11. string.match
      12. string.pack
      13. string.packsize
      14. string.rep
      15. string.reverse
      16. string.sub
      17. string.unpack
      18. string.upper
      

      Тут в буфер текст улетит и выведет в мессагу. После закрытия мессаги через CTRL+V вставит текст, куда хотим

      Пронумерованные функции — функции работы со строками последней версии Lua 5.3.x из документации

      На что стоит обратить внимание при регулярках:

      1. Работа с пробелами и не пробелами: "%s" и "%S"
      2. Работа с символами разделяющие строки и не разделяющими строки: "%с" и "%С"
      3. Захват строк "(.+)", "(.-)", "(.)", а также без захвата, т.е. пропуск других символов ".+",".-","."
      4. Узнать как и какая функция из выше перечисленных работает, какая используется с регуляторами.

      Хотим к примеру вывести слово, которое закончится на пробеле (пишу просто "на пробеле" без учета других символов). Это уже "(%w+)", а если хотим второе слово, то это "%W+%w+" (не выводить первое и вывести второе слово) или "%s(%w+)" (после пробела, но чтобы было без пробела, то захватить в круглые скобки), или "^.+%s(%w+)"(начинать с первого символа до пробела и захват до конца слова).

      Если писать на CE Lua, то регулярки знать не обязательно. Но, их желательно знать, чтобы читать чужой код и писать свой. Да и вообще это интересно. Очень короткие выражения позволяют решить некоторую задачу за быстрое время. Основные задачи: поиск текста и замена текста.

      написал в Обучающие примеры ce lua обучалка regular
      MasterGHM
      MasterGH
    • Сравнение времени выполнения двух функций
      function NoOptimizeCode()
         --[[Предположительно не оптимизированный код]]--
      end
      
      function OptimizeCode()
         --[[Предположительно оптимизированный код]]--
      end
      
      local countRepeat = 10000000
      local x1 = 0
      local x2 = 0
      
      x1 = os.clock()
      for i = 1, countRepeat do NoOptimizeCode() end
      x2 = os.clock()
      for i = 1, countRepeat do OptimizeCode() end
      
      local deltaTimeOptimize = (os.clock() - x2)
      local deltaTimeNoOptimize = (x2 - x1)
      
      print(string.format("%.2f\n",  deltaTimeNoOptimize/deltaTimeOptimize))
      

      Пример1. Узнать во сколько раз string.match() медленее string.find()

      function NoOptimize()
         if string.match('mov eax, [edx]', 'edx') then
         end
      end
      
      function Optimize()
         if string.find('mov eax, [edx]', 'edx') then
         end
      end
      

      Пример2. Создание лишней локальной переменной

      local tableA = {'A', 'B', 'C'}
      
      function NoOptimize()
         local t = #tableA
         for i = 1, t do
      
         end
      end
      
      function Optimize()
         for i = 1, #tableA do
      
         end
      end
      

      Ответы: 1.38, 1.04.

      Если значение меньше единицы, то оптимизированный код хуже.
      Если значение больше единицы, то стоит использовать более оптимизированный вариант.

      Для простого поиска лучше использовать string.find чем string.match.

      Еще несколько примеров

      tableA = {'A', 'B', 'C'}
      local tableB = {'A', 'B', 'C'}
      
      function NoOptimize()
         for i = 1, #tableA do
      
         end
      end
      
      function Optimize()
         for i = 1, #tableB do
      
         end
      end
      

      1.14
      К локальной таблице доступ быстрее

      function NoOptimize()
       tableA = {'A', 'B', 'C'}
      end
      
      function Optimize()
       local tableB = {'A', 'B', 'C'}
      end
      

      Создание новой глобальной и новой локальной таблицы.
      1.08

      Для чего может пригодиться. Может пригодиться при оптимизации кода трассировке на брейкпоинтах в пошаговой отладке

      написал в Обучающие примеры обучалка ce lua optimization
      MasterGHM
      MasterGH
    • Оптимизация splitDisassembledString()

      Напишем функцию, которая в 3.2 раз быстрее splitDisassembledString(disassemble(address))

      \-- Линия: 0045464A - FF 05 A4B54500        - inc [0045B5A4] { [000003EA] }
      
      function GetDebugString(address)
        return splitDisassembledString(disassemble(address))
      end
      
      \-- address, bytes, opcode
      function GetDebugString2(address)
        local clearString = string.gsub(disassemble(address), '%s','')
        return string.match(clearString, '^(.-)%-(.-)%-(.-)$')
      end
      
      function NoOptimizeCode()
        GetDebugString(0x0045464A)
      end
      
      function OptimizeCode()
         GetDebugString2(0x0045464A)
      end
      
      local countRepeat = 100000 -- add more cycle
      local x1 = 0
      local x2 = 0
      
      x1 = getTickCount()
      for i = 1, countRepeat do NoOptimizeCode() end
      x2 = getTickCount()
      for i = 1, countRepeat do OptimizeCode() end
      
      print(string.format("%.2f", (x2 - x1)/(getTickCount() - x2)) )
      

      Сравнивая скорости получаем оптимизацию в ~3.20 раза быстрее.
      Пример использования

      function GetDebugString2(address)
        local clearString = string.gsub(disassemble(address), '%s','')
        return string.match(clearString, '^(.-)%-(.-)%-(.-)$')
      end
      
      local address, bytes, opcode = GetDebugString2(0x0045464A)
      
      print(address)
      print(bytes)
      print(opcode)
      

      gsub очищает пробелы, а выражение '^(.-)%-(.-)%-(.-)$' позволит захватить данные между тире в строке.
      Может пригодится, когда трейсим своим Lua кодом.
      Если заинтересовали регулярки: ссылка

      написал в Приёмы ce lua optimization фишки
      MasterGHM
      MasterGH
    • Пошаговая отладка Lua скриптов

      2b109af7-9ce2-40e4-9361-272ec599eaa0-изображение.png
      Пример, который показывает как снять стек вызовов функций

      function A0()
        -- Здесь можно удалить ":gsub('\n','\r\n')", но тогда в консоли текст будет в одну строку
        print(debug.traceback():gsub('\n','\r\n'))
      end
      
      function A1() A0() end
      function A2() A1() end
      function A3() for i=1,3 do A2() end end
      
      A3()
      

      Можно поставить пошаговую отладку в консоли Lua (как на скриншоте) и пройти по шагам

      написал в Приёмы debug ce lua фишки
      MasterGHM
      MasterGH
    • Заполненение таблицы данными по базовому адресу

      Нажали checkbox — заполнились данные по базовому адресу
      5c7004e5-5eed-48f6-8292-2ad642446fe9-изображение.png

      Отжали checkbox — удалились данные
      45a2563e-db72-4c52-9298-5fb1b29c93ee-изображение.png

      [ENABLE]
      {$lua}
      baseAddress = 0x40000000
      
      function FillValues(baseAddress, userValue)
        stringData =
        [[
            Голод                        20
            Болезнь                     -10
            Депрессия                   -40
            Усталость                    8
            Ранения                     -28
            Скрытность                   6c
            Изготовление                 84
            Исследования                 54
            Собирательство               3c
            Охота                        b4
            Рыбалка                      e4
            Сбор                         cc
            Готовка                      9c
            Сила                         114
            Ловкость                     fc
            Телосложение                 144
            Борьба                       12c
            Интелект                     1a4
            Речь                         174
            Медицина                     18c
            Знания                       15c
        ]]
      
        -- Захват данных включая знак
        for name, value in stringData:gmatch('(%S+).-(%S?%x+)') do
      
          local stringPointer = ''
          local indexMinus = value:find('-')
      
          if indexMinus then
            stringPointer = string.format('[%08X - %s]', baseAddress, value:sub(indexMinus + 1))
          else
            stringPointer = string.format('[%08X + %s]', baseAddress, value)
          end
      
          -- Добавить дочерний memrec
            -- memrec это ссылка на memrec, в котором написан этот скрипт
            local newMemRect = getAddressList().createMemoryRecord()
            newMemRect.Description = name
            newMemRect.Address = stringPointer
            newMemRect.Type = vtDword
            newMemRect.appendToEntry(memrec)
        end
      end
      
      \-- Запись userValue по baseAddress
      FillValues(baseAddress, userValue)
      
      [DISABLE]
      {$lua}
      for i = 0, memrec.Count-1 do
        memrec[0].destroy()
      end
      

      Если проще руками забить и поставить опцию раскрытия, то можно и без скрипта.

      написал в Приёмы фишки ce lua ce memrec ce aa
      MasterGHM
      MasterGH
    • Сделать большой брейкпоинт на структуру через dbk_useKernelmodeOpenProcess

      Обычно, дается 4 аппаратных брейкпоинта на адреса памяти. Их можно включать одновременно и найти инструкции, которые в данный момент срабатывают. Так можно определить тип данных у адресов и найти инструкции. По инструкциям найти смещения внутри дизассемблированной инструкции. По смещениям визуально определить структуры в структурах. Расструтуризовать структуру в dessect data и найти много интересных параметров для читов. Вручную с 4мя бряками делать очень хлопотно.

      Начинается все с установки огромного бряка на структуру из туториала CE.

      3931d315-3242-4905-ac49-8dc56de2c6c3-изображение.png

      \-- Tutorial-x86_64.exe+2B3A9 - 81 BB F0070000 E8030000 - cmp [rbx+000007F0],000003E8 { 1000 }
      
      local addressStructure = 0x000001FB07E391B0
      local sizeStrucure = 0x1000
      local TYPE_BREAKPOINT_ACESS = "READ" -- "READ" "WRITE" режимы брейкпоинта
      local scanTIme = 7000   -- через 7 секунд показать результат
      local stopTimee = true  -- остановить таймер после получения результата
      
      if dbkInited == nil or not dbkInited then
        dbkInited = dbk_initialize()
        dbk_useKernelmodeOpenProcess()
        OpenProcess(getOpenedProcessID())
        if not dbkInited then
           print("Can't load DBK")
           return
        end
        -- Появится диалог, жем "ДА"
        dbvm_initialize(true)
      end
      
      string.format('Start watching address: = %016X  size: %X', addressStructure, sizeStrucure)
      
      local physicalAddress = dbk_getPhysicalAddress(addressStructure)
      print (physicalAddress)
      
      if TYPE_BREAKPOINT_ACESS == "WRITE" then
         IDscannerWrites = dbvm_watch_writes(physicalAddress, sizeStrucure)
      elseif TYPE_BREAKPOINT_ACESS == "READ" then
         IDscannerReads = dbvm_watch_reads(physicalAddress, sizeStrucure)
      end
      
      function PrintResult(IDscanner)
         data = dbvm_watch_retrievelog(IDscanner)
      
         if data == nil then
           print('Inforamtion: Data nil')
          return
         end
      
         if #data <= 0 then
           print('Inforamtion: #data <= 0')
          return
         end
      
         for i=1,#data do
           print(string.format('RIP = %016X',data[i].RIP))
           print(disassemble(data[i].RIP))
         end
      
      end
      
      timer = createTimer(nil, false)
      timer.OnTimer = function(timer)
      
        if TYPE_BREAKPOINT_ACESS == "WRITE" then
          print "Result Writes"
          PrintResult(IDscannerWrites)
        elseif TYPE_BREAKPOINT_ACESS == "READ" then
          print "Result Reads"
          PrintResult(IDscannerReads)
        end
      
        if stopTimee then
          print "Stop Timer"
          timer.Enabled = false
          dbvm_watch_disable(IDscannerWrites)
          dbvm_watch_disable(IDscannerReads)
        end
      
      end
      timer.Interval = 10000
      timer.Enabled = true
      

      Логи

      Result Reads 
      RIP = FFFFF8040E9D5320 
      FFFFF8040E9D5320 - 00 00  - add [rax],al 
      RIP = FFFFF8040E9D5300 
      FFFFF8040E9D5300 - 00 00  - add [rax],al 
      RIP = 000000010002B3A9 
      10002B3A9 - 81 BB F0070000 E8030000 - cmp [rbx+000007F0],000003E8 
      RIP = 000000010009D080 
      10009D080 - 48 83 B8 88050000 00 - cmp qword ptr [rax+00000588],00 
      RIP = 000000010002599D 
      10002599D - 80 B8 02040000 00 - cmp byte ptr [rax+00000402],00 
      RIP = 00000001000259AE 
      1000259AE - 48 8B 00  - mov rax,[rax] 
      RIP = 00000001000A429D 
      1000A429D - 8A 81 00040000  - mov al,[rcx+00000400] 
      RIP = 00000001000259C3 
      1000259C3 - 48 8B 00  - mov rax,[rax] 
      RIP = 000000010001D70C 
      10001D70C - F7 40 50 10000000 - test [rax+50],00000010 
      RIP = 000000010001D71D 
      10001D71D - 80 B8 A1050000 00 - cmp byte ptr [rax+000005A1],00 
      RIP = 000000010001D734 
      10001D734 - 48 8B 00  - mov rax,[rax] 
      RIP = 00000001000AAB40 
      1000AAB40 - 48 83 78 70 00 - cmp qword ptr [rax+70],00 
      RIP = 000000010001D741 
      10001D741 - 48 83 B8 98060000 00 - cmp qword ptr [rax+00000698],00 
      RIP = 000000010001D7F8 
      10001D7F8 - 80 B8 A1050000 00 - cmp byte ptr [rax+000005A1],00 
      RIP = 000000010001D809 
      10001D809 - F7 40 50 10000000 - test [rax+50],00000010 
      RIP = 000000010009B630 
      10009B630 - 48 83 B8 70040000 00 - cmp qword ptr [rax+00000470],00
      

      f7c869d2-f790-4ed0-b7da-d7d1a574cac7-изображение.png

      По логам видим, что какие-то инструкции обращаются и скорее всего обращаются к нашей той самой структуре. Проверим так ли это и заодно увидим к каким другим структурам идет обращение
      df5c8aed-7148-49c0-bba8-bb91fe31d947-изображение.png

      Видим, что одна из инструкций действительно обращается к нашей структуре и далеко за пределам диапазона 4 брейкпоинтов. Т.е. это действительно огромный такой брейкпоинт на всю структуру.

      Также видим, что инструкция отработала по другим 4 структурам и это могли быть враги и друзья игрока.

      Также видим, что тип данных автоматически неверно определился в окна DesectData и мы можем его скорективать - это будет 1 байт
      53a9ef34-fbbf-41ab-8c02-505ca89eded1-изображение.png

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

      написал в Приёмы фишки breakpoint ce lua dbk
      MasterGHM
      MasterGH
    • Телепорт на 10 слотов и на 3 типа данных (float, double, integer)
      1. Функции:
      • Три типа данных: float, double, integer
      • 10 слотов сохранение
      • Управление горячими клавишами. ctrl+X - где X от 0 до 9 сохраняет позицию, shift + X загружает ранее сохраненную позицию
      • Озвучивание загрузки или сохранения (смотри функцию speakEnglish ниже)
      teleport_address = "03D2C6DC"	-- "[[address+XX]+XX]" или через registersymbol()
      type_data = 'INTEGER'			-- FLOAT, DOUBLE, INTEGER
      
      \-- ctrl + R - сбросить позицию
      \-- ctrl + X - сохранить в слот X, где X от 0 до 9
      \-- shift + X - сохранить в слот X, где X от 0 до 9
      
      \--класс
      Vector3 = {}
      function Vector3:new(address, type_data)
      
      	local object = {}
      	object.address = address
      	object.x = 0
      	object.y = 0
      	object.z = 0
      	object.type_data = type_data
      	
      	function object:getAddress()
      		return self.address 
      	end
      	
      	function object:read()
      		if object.type_data == 'FLOAT' then
      			object.x = readFloat(object.address)
      			object.y = readFloat(getAddress(object.address) + 4)
      			object.z = readFloat(getAddress(object.address) + 8)
      		elseif object.type_data == 'DOUBLE' then
      			object.x = readDouble(object.address)
      			object.y = readDouble(getAddress(object.address) + 8)
      			object.z = readDouble(getAddress(object.address) + 16)		
      		elseif object.type_data == 'INTEGER' then
      			object.x = readInteger(object.address)
      			object.y = readInteger(getAddress(object.address) + 4)
      			object.z = readInteger(getAddress(object.address) + 8)		
      		end
      		return object
      	end
      	
      	function object:write()
      		if object.type_data == 'FLOAT' then
      			writeFloat(object.address, object.x)
      			writeFloat(getAddress(object.address) + 4, object.y)
      			writeFloat(getAddress(object.address) + 8, object.z)
      		elseif object.type_data == 'DOUBLE' then
      			writeDouble(object.address, object.x)
      			writeDouble(getAddress(object.address) + 8, object.y)
      			writeDouble(getAddress(object.address) + 16, object.z)		
      		elseif object.type_data == 'INTEGER' then
      			writeInteger(object.address, object.x)
      			writeInteger(getAddress(object.address) + 4, object.y)
      			writeInteger(getAddress(object.address) + 8, object.z)		
      		end	
      	end
      	
      	function object:print_vector()
      		print(string.format("%s, %s, %s", object.x, object.y, object.z))
      	end
      	
      	setmetatable(object, self)
      	self.__index = self; 
      	return object
      end
      
      
      
      \--класс
      Teleport = {}
      
      \--тело класса Teleport
      function Teleport:new(address, type_data)
      	
      	local object = {}
      	-- Тип данных
      	object.type_data = type_data
      	-- Адрес
      	object.vector3_position = Vector3:new(address, type_data)
      	-- Адреса для слотов
      	object.vector3_positions = {}
      	
      	function object:getAddress()
      		return self.address 
      	end
      	
      	function object:make_hotkey_reset_position()
      	
      		local genericHotkey = createHotkey(
      				function() 
      					object.vector3_position:write()
      				end,
      				{VK_CONTROL, VK_R}
      			)
      		genericHotkey.DelayBetweenActivate = 2000
      	end
      
      	function object:make_hotkey_save_position(numberKey)
      		
      		local genericHotkey = createHotkey(
      				function()
      					speakEnglish("Save position "..numberKey)
      					object.vector3_positions[numberKey]:read()
      				end, 
      				{VK_CONTROL, VK_0 + numberKey}
      			)
      		genericHotkey.DelayBetweenActivate = 2000
      	end
      
      	function object:make_hotkey_load_position(numberKey)
      		
      		local genericHotkey = createHotkey(
      				function() 
      					speakEnglish("Load position "..numberKey)
      					object.vector3_position:read()
      					object.vector3_positions[numberKey]:write()
      				end,
      				{VK_SHIFT, VK_0 + numberKey}
      			)
      		genericHotkey.DelayBetweenActivate = 2000
      	end
      
      	function object:registry_hot_keys()
      
      		object:make_hotkey_reset_position()
      
      		for numberKey = 0, 9 do
      			local addressPosition = Vector3:new(address, type_data)
      			addressPosition:read()
      			table.insert(object.vector3_positions, addressPosition)
      			object:make_hotkey_save_position(numberKey)
      			object:make_hotkey_load_position(numberKey)		
      		end
      	end	
      	
      	object:registry_hot_keys()
      	
      	setmetatable(object, self)
      	self.__index = self; 
      	return object
      end
      
      local teleport = Teleport:new(teleport_address, type_data)
      
      1. Меняем адрес teleport_address = "03D2C6DC" на тот который нужно.

      Здесь может быть указатель например -"[[address+XX]+XX]" или через registersymbol() в АА скриптах.

      Не тестировалось если адрес еще невалидный, т.е. не существует в памяти. По идее слоты проинициализируются с нулевыми координатами по умолчанию. Поэтому лучше Lua скрипт запускать в момент существования адреса. Проверка на существование адреса - getAddressSafe(string, local OPTIONAL, shallow OPTIONAL): returns the address of a symbol, or nil if not found. Similar to getAddress when errorOnLookup is false, but returns nil instead. Проверку можно делать по таймеру. Запуск скрипта это последняя строка

      1. Меняем тип данных type_data = 'INTEGER' -- FLOAT, DOUBLE, INTEGER

      Справочник по Lua функциям в файле "celua.txt"

      написал в Приёмы ce lua телепорт озвучка шаблоны todo
      MasterGHM
      MasterGH
    • Поиск по формуле

      В таблице поиска есть колонки ссылающиеся на название Lua перменных: "value" и "previousvalue"
      fb6eb5fd-f132-42d3-82e5-da0af262ffde-изображение.png
      35e15012-0c36-4ec5-8a54-7e3ad82a878e-изображение.png

      Сравнивать текущее и предыдущие значения вместе или по отдельности, в том числе на разных вкладках CE
      0be17f93-8b99-49f6-9aae-151493b4a764-изображение.png

      Примеры:

      value == 65
      value == 0x65 (или поставить галку hex)
      value ~= 65 (или поставить галку not)
      

      Можно и такое сравнение сделать после поиска неизвестного используя математические функции:

      math.abs(value - previousvalue) < 10
      

      Можно делать различные комбинации:

      and (логическое И).
      or (логическое ИЛИ).
      not (логическое НЕ).
      
      \+ (сложение);
      \- (вычитание);
      * (умножение);
      / (деление);
      ^ (возведение в степень);
      % (остаток от деления).
      
      == (равно);
      ~= (не равно);
      < (меньше);
      > (больше);
      <= (меньше или равно);
      >= (больше или равно).
      

      Можно написать функцию xor

      function BitXOR(a,b)--Bitwise xor
          local p,c=1,0
          while a>0 and b>0 do
              local ra,rb=a%2,b%2
              if ra~=rb then c=c+p end
              a,b,p=(a-ra)/2,(b-rb)/2,p*2
          end
          if a<b then a=b end
          while a>0 do
              local ra=a%2
              if ra>0 then c=c+p end
              a,p=(a-ra)/2,p*2
          end
          return c
      end
      

      А потом применяем даже отдельные функции как в этом примере

      "value > 0 and BitXOR(value, 100) "
      

      b7e4f839-065d-4d99-8099-fdd6f71a21cf-изображение.png

      А может быть я хочу только 100 первых результатов

      function BitXOR(a,b)--Bitwise xor
          local p,c=1,0
          while a>0 and b>0 do
              local ra,rb=a%2,b%2
              if ra~=rb then c=c+p end
              a,b,p=(a-ra)/2,(b-rb)/2,p*2
          end
          if a<b then a=b end
          while a>0 do
              local ra=a%2
              if ra>0 then c=c+p end
              a,p=(a-ra)/2,p*2
          end
          return c
      end
      
      valueCount = 0
      function CheckCount100()
         valueCount = valueCount + 1
         return valueCount <= 100
      end
      
      CheckCount100() and value > 0 and BitXOR(value, 50)
      

      71a9da57-7807-45a0-8eb0-0584fdea3a17-изображение.png

      Также хочу добавить те адреса, которые предположительно являются указателями

      getAddressSafe('['..value..']')~=nil
      

      2f4e2e22-6f5a-4dcd-8757-85d8ad2744a4-изображение.png

      Или наоборот не являются указателями

      getAddressSafe('['..value..']')==nil
      

      ae76b77f-9eca-4dc1-b175-2f590d9ac3f9-изображение.png

      Еще можно попробовать добавить 50 красных и 50 синих указателей в таблицу CE, но это уже задание кому интересно.

      Можно в теории сравнивать адреса со значениями известных адресов и даже с известными указателями, с метками. Но поиск может затянуться, если адресов очень много.

      Можно попробовать указать условие, что значение адреса должно находиться в X структуре или в её вероятных указателях.

      Или попробовать оставить только одинаковые значения адресов, т.е. повторяющихся более 1 раза.

      Или попробовать искать только те адреса, к которым применимы сразу несколько условий чтобы не кликать их постоянно:

      (изменилось) И (больше 0) И (меньше 10000)
      (не изменилось) И (больше 0) И (меньше 10000)
      
      написал в Приёмы фишки идея scan memory ce lua
      MasterGHM
      MasterGH
    • 1
    • 2
    • 9
    • 10
    • 11
    • 12
    • 13
    • 12 / 13