Перейти к содержанию

Условный бряк на функцию TranslateMessage


Гость bronis

Рекомендуемые сообщения

 
local DLL = getAddress("USER32.DLL") -- Адрес DLL
local Function = DLL+0x17809  -- USER32.TranslateMessage
local Condition = 0x202  -- MSG==202  //WM_LBUTTONUP

function debugger_onBreakpoint() -- выполнить если сработал бряк
 local pMSG = readInteger(ESP+0x4)  -- поинтер на параметры функции
 local MSG = readInteger(pMSG+0x4) -- параметр функции - MSG
 s = string.format(">> 0x%08X: MSG = 0x%08X", EIP, MSG) -- форма записи в лог MSG
  if (EIP == Function) then  -- проверяем если бряк сработал на нужной нам функции то
   if (MSG == Condition) then -- проверяем нужные нам параметры
    print(s) -- записываем в лог LuaEngine значение параметра MSG
    return 0 -- ставим бряк
   else -- в случае если условие не выполнено
 -- print(s) -- записываем в лог LuaEngine значение параметра MSG не прошедших условие
    return 1 -- продолжаем без бряка
   end
  end
end

debug_removeBreakpoint(Function) -- убераем старый бряк
debug_setBreakpoint(Function, 4,bptExecute) -- ставим новый бряк

Ищем интересующую нас функцию:

- жмем Ctrl+Alt+S или заходим в View -> Enumerate DLL's and Symbols находясь при этом в коде программы чьи DLL нам нужны

- ищем в списке нужную нам DLL(USER32), кликнув по треугольничку с лева разворачиваем список функций найденой нами DLL-ки

- ищем в этом списке интересующую нас функцию(TranslateMessage) и жмем на нее двойным щелчком левой кнопкой мышки

- жмем Ctrl+M или View -> Show module adresses ставим галочку для того чтобы адрес отображался в виде Модуль+Смещение

ПС: Если адрес отображается не верно то поставьте галочку View -> Kernelmode symbols

Кому лень искать то ее адрес USER32.DLL+17809, в Lua код записывать смещение надо в виде +0x17809.

Заполняем данными Lua код:

- Найденое смещение функции TranslateMessage вписываем в строку

 
local DLL = getAddress("USER32.DLL") -- DLL содержащий нашу функцию
local Function = DLL+0x17809  -- смещение функции относительно DLL

- Вводим условие, например:

 
 local Condition = 0x202  // где 202 - код WM_LBUTTONUP

Делаем условный бряк:

- жмем Ctrl+L или Tools -> Lua Engine

- вставляем Lua код в нижнее поле окна, и жмем кнопку Execute

Читаем логи:

- жмем Ctrl+L и в верхнем поле окна будет вестить лог в формате

- >> 0x"Адрес": MSG = "Параметр"

ПС: Прежде чем включить лог MSG непрошедших условие - советую убрать галочку с параметра в LuaEngine View -> Show on "print"

Выключаем условный бряк:

- Для того что бы выключить условие, снова открываем Lua Engine и прописываем туда

 
function debugger_onBreakpoint()
end
Изменено пользователем imaginary
Указано форматирование кода Lua
Ссылка на комментарий
Поделиться на другие сайты

Актуально:

local Function = getAddress("TranslateMessage")

Для лучшей производительности лучше:

1) cтроку:

local Condition = 0x202  -- MSG==202  //WM_LBUTTONUP

вынести из function debugger_onBreakpoint().

2) строку :

if (EIP == Function) then

заменить на:

 if (EIP ~= Function) then 
return 1
end

3) Возможно лучше использовать объект от Stringlist вместо множественного построчного print(). Метод "strings_getText( твой Stringlist )" может сразу возвратить большую строку лога, которую уже можно обработать через print

Также помимо кодов сообщений можно логировать и адрес возврата по [esp+0]. А также другую информацию:

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;

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

MasterGH: Спасибо за замечания, исправил.


local DLL = getAddress("USER32.DLL") -- local Function = getAddress("TranslateMessage")
local Function = DLL+0x17809 -- USER32.TranslateMessage
local Condition = 0x202 -- MSG==202 //WM_LBUTTONUP

function debugger_onBreakpoint() -- выполнить если сработал бряк
local pMSG = readInteger(ESP+0x4) -- поинтер на параметры функции
local MSG = readInteger(pMSG+0x4) -- параметр функции - MSG
loglist = createStringlist() -- создаем loglist
strings_add(loglist,string.format(' • Call to %s from "%s" • ', getNameFromAddress(EIP), getNameFromAddress(readInteger(ESP)))) -- добавляем в loglist первую строку
strings_add(loglist,string.format('>> hWnd = %X', readInteger(pMSG))) -- Дескриптор окна, оконная процедура которого принимает сообщение.
strings_add(loglist,string.format('>> MSG = %X', MSG)) -- Определяет код сообщения. Приложения могут использовать только младшее слово; старшее слово зарезервировано системой.
strings_add(loglist,string.format('>> wParam = %X', readInteger(pMSG+0x8))) -- Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
strings_add(loglist,string.format('>> lParam = %08X', readInteger(pMSG+0xC))) -- Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
strings_add(loglist,string.format('>> Time = %X', readInteger(pMSG+0x10))) -- Определяет время, в которое сообщение было помещено в очередь.
strings_add(loglist,string.format('>> Point = %i x %i', readInteger(pMSG+0x14), readInteger(pMSG+0x18))) -- Устанавливает позицию курсора, в экранных координатах, в момент, когда сообщение было помещено в очередь.
s = strings_getText(loglist) -- читаем loglist
if (EIP ~= Function) then -- если бряк сработал не на нашей функции то
return 1 -- продолжаем без бряка
end
if (MSG == Condition) then -- проверяем нужные нам параметры
print(s) -- записываем в лог LuaEngine текст из loglist
return 0 -- ставим бряк
else -- в случае если условие не выполнено
print(s) -- записываем в лог LuaEngine текст из loglist при не выполненом условии
return 1 -- продолжаем без бряка
end
end

debug_removeBreakpoint(Function) -- убераем старый бряк
debug_setBreakpoint(Function, 4,bptExecute) -- ставим новый бряк

Пример логов:


• Call to TranslateMessage from "notepad++.exe+9D41E" •
>> hWnd = 3E068C
>> MSG = 113
>> wParam = 1
>> lParam = 00000000
>> Time = 66D51B9
>> Point = 1216 x 889

• Call to TranslateMessage from "notepad++.exe+9D41E" •
>> hWnd = 3E068C
>> MSG = 202
>> wParam = 0
>> lParam = 00180060
>> Time = 66D51B9
>> Point = 1216 x 889

Для отображения адресов в виде Функция+Смещение/Модуль+Смещение необходимо включить опцию в окне отладчика Ctrl+M или View -> Show module adresses.

Для отображения только в виде Модуль+Смещение надо дополнительно включить View -> Kernelmode symbols

Хотелось бы как нибудь конвертировать время

>> Time = 66D51B9

в ЧЧ:ММ:СС:МС есть идеи?

Еще не понятен 1 момент, пытался разделить lParam по 4 байта чтоб выглядело так >> lParam = 0018 0060

Пытался это представить в таком виде

strings_add(loglist,string.format('>> lParam = %04X %04X', readInteger(pMSG+0xC)), readInteger(pMSG+0xE)))

но вместо этого он выдает больше 4 байт.

Было бы не плохо добавить еще комент к дескриптору как в олли, в виде названия окна

К сожалению за не имением необходимых знаний и неудаче в поисках полной документации комант Lua для CE - я не могу реализовать данные идеи =(

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

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

И на будущее createStringlist() в твоём случае постоянно создаёт новый и новый список. Старый при этом не разрушается и происходит "утечка памяти". Достаточно создать список только один раз. Также лучше пользоваться просто print() я что-то "перенасоветовал". Когда я советовал я забыл, что ты ведёшь логи с остановками в Отладчике для пользователя. В этом случае проще использовать print() c длинной строкой (через string.fortmat)... Ладно, как уже писал, позже поправлю.

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


local DLL = getAddress("USER32.DLL") -- local Function = getAddress("TranslateMessage")
local Function = DLL+0x17809 -- USER32.TranslateMessage
local Condition = 0x202 -- MSG==202 //WM_LBUTTONUP
local loglist = createStringlist() -- создаем loglist

function debugger_onBreakpoint() -- выполнить если сработал бряк
local pMSG = readInteger(ESP+0x4) -- поинтер на параметры функции
local MSG = readInteger(pMSG+0x4) -- параметр функции - MSG
strings_clear(loglist) -- чистим старые логи loglist
strings_add(loglist,string.format(' • Call to %s from "%s" • ', getNameFromAddress(EIP), getNameFromAddress(readInteger(ESP)))) -- добавляем в loglist первую строку
strings_add(loglist,string.format('>> hWnd = %X', readInteger(pMSG))) -- Дескриптор окна, оконная процедура которого принимает сообщение.
strings_add(loglist,string.format('>> MSG = %X', MSG)) -- Определяет код сообщения. Приложения могут использовать только младшее слово; старшее слово зарезервировано системой.
strings_add(loglist,string.format('>> wParam = %X', readInteger(pMSG+0x8))) -- Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
strings_add(loglist,string.format('>> lParam = %08X', readInteger(pMSG+0xC))) -- Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
strings_add(loglist,string.format('>> Time = %X', readInteger(pMSG+0x10))) -- Определяет время, в которое сообщение было помещено в очередь.
strings_add(loglist,string.format('>> Point = %i x %i', readInteger(pMSG+0x14), readInteger(pMSG+0x18))) -- Устанавливает позицию курсора, в экранных координатах, в момент, когда сообщение было помещено в очередь.
s = strings_getText(loglist) -- читаем loglist
if (EIP ~= Function) then -- если бряк сработал не на нашей функции то
return 1 -- продолжаем без бряка
end
if (MSG == Condition) then -- проверяем нужные нам параметры
print(s) -- записываем в лог LuaEngine текст из loglist
return 0 -- ставим бряк
else -- в случае если условие не выполнено
-- print(s) -- записываем в лог LuaEngine текст из loglist при не выполненом условии
return 1 -- продолжаем без бряка
end
end

debug_removeBreakpoint(Function) -- убераем старый бряк
debug_setBreakpoint(Function, 4,bptExecute) -- ставим новый бряк

Все, теперь он будет использовать 1 лист на 1 екзекут кода в луа, а то переделывать обратно - получится столько принтов и стрингов что будет не красиво.

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

Вот изменённый вариант:

post-3-1309711951,56_thumb.png


Скрипт установки условного брейкпоинта на функции 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
--[[

Я запустил функцию StartDebug_TranslateMessage() и StopDebug(), а остальные не запускал и поэтому могут быть ошибки, которых я не заметил.

Если будет время сделаю форму с кнопками, полями ввода и т.п., а то через консоль неудобно.

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

Хм, интересно. С помощью этого же приема можно принудительно отправить игру в оконный режим, путем перехвата функции DirectX - CreateDevice. Надо будет вечерком попробовать.

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

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.