MasterGH

Отладка в Lua. Снятие показаний регистров

9 сообщений в этой теме

В этом коротком туторе я покажу пример снятия данных регистров.

post-3-1305873036,47_thumb.png


pmAddress=getAddress("1F72152C")
max = 10
count = 0

function debugger_onBreakpoint() -- срабатывает всегда, когда срабатывает брейкпоинт
count = count + 1
-- если понадобятся все регистры или некоторые, то вы можете исправить код ниже
s = string.format("%3d) 0x%08X: EAX = 0x%08X EBX = 0x%08X ECX = 0x%08X",count, EIP, EAX, EBX, ECX)
print(s)
if count>=max then
debug_removeBreakpoint(pmAddress);
end
--Breakpoint continue methods: co_run=0, co_stepinto=1, co_stepover=2
debug_continueFromBreakpoint(co_run)
-- return 1 --I handled it so dont tell the user
-- return 0 --unexpected breakpoint, show the the user
end

--Breakpoint triggers: bptExecute=0, bptAccess=1, bptWrite=2
--Variable types: (ref http://ce.colddot.nl/browser/Cheat%20Engine%206/bin/defines.lua)
debug_setBreakpoint(pmAddress, vtDword, bptWrite)

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

Так же обращу внимание на "частоты" срабатываний тех или иных инструкций, это тоже можно вести в логе.

В нужный момент можно "не отпускать процесс" и проанализировать ситуацию.

Можно вести трассировку...

Сравнение структур!

И т.п. что вам в голову придёт.

И ещё. Если вам надо снять брейкпоинты установленные через LUA, то это можно сделать вручную в функциях окна меню дизассемблера.

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

В моем примере выводятся инструкции, которые записывают значение 1080 типа Integer по адресу "Test.exe+5B5A4". Дальше смотрите код.


Автор: MasterGH 2011

Скрпит для
идентификации инструкции работающием с адресом, когда в нём оказывается определённое значения.

Требования:
- предварительно приаттачить 32-х разрядный процесс игры через иконку Компьютера в главном окне CE
- Если тип данных сравниваемого значения не Integer, то изменить в скрипте "readInteger"

Информация по Lua поддержке: http://ce.colddot.nl/browser/Cheat%20Engine%206/bin/main.lua
Информация по Lua константам: http://ce.colddot.nl/browser/Cheat%20Engine%206/bin/defines.lua

Хотите доработать скрипт?
-- Вы можете создать графический интерфейс пользователя
-- Вы можете сделать так чтобы не выводились повторяющиеся инструкции

]]--

-- Значения для настройки

local myValue = 1080 -- сравниваемое значение, в моем случае 1080типа Integer
local myValueSize = 4 -- размер данных по адресу, в моём случае Integer, значит "4"
local myAddress = getAddress("Test.exe+5B5A4") -- получение адреса в целочисленный тип, мой адрес "Test.exe+5B5A4"

-- тип бряка "ставим на запись"
local typeBreak = 2 --( другие: bptExecute=0, bptAccess=1, bptWrite=2)

-- Если игра вылетает, то попробовать типы отладки: VEHDebug и Kerneldebug
local typeDebug = 1 -- тип отладки (0=default, 1=windows debug, 2=VEHDebug, 3=Kerneldebug)

local criticalCount = 5000 -- если лог постоянно показыватеся, что его нельзя остановить, то этот предел остановит отладку
local count = 0
-----------------------------------

-- Вызвать в консоли эту функцию если нужно удалить бряк и преркатить слежение
-- В этой функции ничего менять не надо
function RemoveBreakpoint()
debug_removeBreakpoint(myAddress);
end

-----------------------------------

-- Функция обработки события точки останова
-- В этой функции можно поменять readInteger на нужный тип данных
function debugger_onBreakpoint()
-- если значение по адресу равно 1080, то выводить инструкции в лог
if readInteger(myAddress)== myValue then
print(disassemble(getPreviousOpcode(EIP)))
count = count + 1
if (count > criticalCount) then
RemoveBreakpoint()
end
end
return 1 -- не показывать отладчик, если 0 - то показывать
end

-- Далее ничего менять не надо
debugProcess(typeDebug) -- установка режима отладки

-- Утановка брейкпоинта
-- В этой функции ничего менять не надо
debug_setBreakpoint(myAddress, myValueSize, typeBreak) -- установка самого брякак
--[[

Скриншот на котором показано как работать с этим скриптом:

post-3-1311013361,7_thumb.png

Желаю успехов!

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Заготовка скрипта для ведения лога данных на функции TranslateMessage.

Функция TranslateMessage переводит сообщения виртуальных клавиш в символьные сообщения. Символьные сообщения помещаются в очередь сообщений вызывающего потока для прочтения в следующий раз, когда поток вызовет функцию GetMessage или PeekMessage.

Теория (на практике всю теорию не проверял, только где-то как-то кусками)

В игре подгружаются модули dll, которые вызывают translateMessage. Например directXInput8 dll-ка вызывала эту функцию когда я кликнул левой кнопкой мыши по области окна игры. Я мог бы остановить текущую отладку в этот момент и повесить условный бряк уже на функцию обработки именно этого уже оттранслированного сообщения. Ведь именно его обработка это начало пути определённых действий в коде... концом пути уже будет бряк на некотором адресе.

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


Скрипт установки условного брейкпоинта на функции TranslateMessage.

В параметрах сравнения участвует код сообщения "UINT message"
Если сообщение равно сравниваемому, то отладчик прервётся и в поле лога выведет параметры структуры MSG

BOOL TranslateMessage(
const MSG* lpMsg // Указатель на структуру MSG, которая содержит информацию о сообщении извлеченную из очереди сообщений вызывающего потока при помощи использования функции GetMessage или PeekMessage.
);

typedef struct {
HWND hwnd; // Дескриптор окна, оконная процедура которого принимает сообщение.
UINT message; // Определяет код сообщения. Приложения могут использовать только младшее слово; старшее слово зарезервировано системой.
WPARAM wParam; // Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
LPARAM lParam; // Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
DWORD time; // Определяет время, в которое сообщение было помещено в очередь.
POINT pt; // Устанавливает позицию курсора, в экранных координатах, в момент, когда сообщение было помещено в очередь.
} MSG, *PMSG;


Пример использования.

Пример1. Установка условного брейкпоинта функции TranslateMessage в сравнении с параметром MSG:
-- Сработает когда пользователь отпустит левую кнопку мышки

WM_LBUTTONUP = 0x202 (другие коды сообщени ищите в Интернете)
StartDebug_TranslateMessageCondition_onMSG(WM_LBUTTONUP)

Пример2. Установика безусловного брейкпоинта с логировнием всех сообщений:

StartDebug_TranslateMessage()

Пример3. Если необходимо только прерваться на некоторой функции без сбора параметров:

StartDebugSomeFunction(functionName)

Пример4. Если необоходимо остановить отладку, то вызывать:

StopDebug()
]]--

local mode = 0
local addressesBreakPoint = {}
local countAddressesBreakPoint = 0

function AddBreakPointExecut(addressFunction)
countAddressesBreakPoint = table.getn(addressesBreakPoint)
countAddressesBreakPoint = countAddressesBreakPoint + 1
addressesBreakPoint[countAddressesBreakPoint] = addressFunction
debug_setBreakpoint(addressFunction, 1, bptExecute)
end

function DeleteAllBreakPoint()
for i=1, countAddressesBreakPoint do
debug_removeBreakpoint(addressesBreakPoint[i])
end
countAddressesBreakPoint = 0
end

-- Единая функция обработки сообщений о прерывании
function debugger_onBreakpoint()

local withIn = false
for i=1, countAddressesBreakPoint do
if (EIP == addressesBreakPoint[i]) then
withIn = true
break
end
end

if (not withIn) then
return 1
end

if ( (mode == 1) or (mode == 2) ) then
local pMSG = readInteger(ESP+0x4)
local MSG = readInteger(pMSG+0x4)

if ((mode == 1) and (MSG ~= _iMSGBreak)) then
return 1
end

local s = string.format(" • Call to %s from \"%s\" •\n\r\n>> hWnd = %X\n\r\n>> MSG = %X\n\r\n>> wParam = %X\n\r\n>> lParam = %08X\n\r\n>> Time = %X\n\r\n>> Point = %i x %i\n\r\n", getNameFromAddress(EIP), getNameFromAddress(readInteger(ESP)),
readInteger(pMSG),
MSG,
readInteger(pMSG+0x8),
readInteger(pMSG+0xC),
readInteger(pMSG+0x10),
readInteger(pMSG+0x14), readInteger(pMSG+0x18))

if (mode == 1) then -- WM_LBUTTONUP
print(s) -- записываем в лог LuaEngine текст из loglist
return 0 -- ставим бряк
else -- в случае если условие не выполнено
print(s) -- записываем в лог LuaEngine текст из loglist при не выполненом условии
return 1 -- продолжаем без бряка
end
end

return 0
end

function StartDebug_TranslateMessageCondition_onMSG(iMSGBreak)
DeleteAllBreakPoint()
mode = 1
_iMSGBreak = iMSGBreak
local addressFunction = getAddress("TranslateMessage")
AddBreakPointExecut(addressFunction)
print(string.format("Включен режим остановки на фунции TranslateMessage с условием: MSGBreak == %X",iMSGBreak))
end

function StartDebug_TranslateMessage()
DeleteAllBreakPoint()
mode = 2
local addressFunction = getAddress("TranslateMessage")
AddBreakPointExecut(addressFunction)
print("Включен режим остановки на фунции TranslateMessage без условий")
end

function StartDebugSomeFunction(functionName)
mode = 0
local addressFunction = getAddress(functionName)
AddBreakPointExecut(addressFunction)
end

function StopDebug()
DeleteAllBreakPoint()
_iMSGBreak = 0
end
--[[

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Собственно, Lua и надо учить )))

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

И долго ли надо учить его, или весь. Или много не надо учить

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Учить вообще ничего не надо и стоит ли задаваться такими вопросами?. Надо сразу писать код по примерам и пытаться писать свой код. В это время голова будет запоминать то, что надо.

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

если нужно удалить бряк и преркатить слежение

function RemoveBreakpoint()

debug_removeBreakpoint(myAddress);

end

столкнулся с ситуациями когда некоторые участки кода не реагируют на функцию

debug_removeBreakpoint(myAddress);

интуитивно предполагаю что это связано с "высокочастотными" участками кода.

иногда помогает выйти из ситуации простая приостановка процесса.

debug_removeBreakpoint(myAddress)

pause()

unpause()

....

но не всегда.

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

независимо от типа отладки (0=default, 1=windows debug, 2=VEHDebug, 3=Kerneldebug)

В связи с этим, два вопроса.

1. Если кто-то сталкивался с похожей ситуацией, то какими способами решается проблема?

2. Неплохо-бы попросить ДаркБайта обогатить набор функций Lua в СЕ

неким способом "жёсткого" безусловного выхода из режима "debug"

но это к Андрею, думаю вопрос.

*прим. наблюдалось на версиях CE 6,1 и 6,2 , на разных компах и версиях Win.

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

>> 1. Если кто-то сталкивался с похожей ситуацией, то какими способами решается проблема?

Я к сожалению не сталкивался

>>неким способом "жёсткого" безусловного выхода из режима "debug"

Выход из отладки

1) detachIfPossible() - вообще вырубить отладчик (функция должна работать в CE 6.2)

2) debug_removeBreakpoint(address) лишь удаляет брейкпоинты (можно постараться удалить все). Поэтому это не совсем выход из отладочного режима.

Возможно функцию

debug_removeBreakpoint(address)

не стоит вызывать в недрах debugger_onBreakpoint(), когда debugger_onBreakpoint() работает очень часто, а вызывать из чего-то другого. Из функции таймера или потока. Да-да =), На Lua можно работать с потоками существует специальный класс Thread Class.

К сожалению я не могу помочь примерами кода как работать с потоками или как с таймером. Мне лень. Я могу что-то подправить или подсказать.

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас