Написал код для установки 5-и байтового jmp хука. Переводить в библиотеку не вижу смысла, так что нужно просто скопировать его.
upd:или вижу... если хочется вариант с либой - https://www.blast.hk/threads/55743/
Хуки при завершении скрипта сами снимутся
Что нужно для использования?
Для примера установим хук на showDialog
Его прототип
И его адрес
Это все что нужно, для установки хука используем
Эта функция устанавливает хук и возвращает таблицу с управлением над ним, ее методы
Пишем код
Обязательно подключаем библиотеку ffi
Пишем колбэк для хука по прототипу
И ставим хук
Все хук установлен и работает, но диалог не показывается. Чтобы он показался: нужно снять хук, вызвать оригинальную функцию и поставить обратно хук, для этого изменяем калбэк
Можем подменить заголовок диалога
Полный код
При таком хуке для вызова диалога можно использовать sampShowDialog(...) или dialogHook.call(...) (в этом случае нужно еще передать указатель this первым параметром, т.к. функция thiscall, если что, то это sampDialogInfoPtr)
И еще один пример по хук win api функции
upd:или вижу... если хочется вариант с либой - https://www.blast.hk/threads/55743/
Хуки при завершении скрипта сами снимутся
Lua:
--HOOKS
local hook = {hooks = {}}
addEventHandler('onScriptTerminate', function(scr)
if scr == script.this then
for i, hook in ipairs(hook.hooks) do
if hook.status then
hook.stop()
end
end
end
end)
ffi.cdef [[
int VirtualProtect(void* lpAddress, unsigned long dwSize, unsigned long flNewProtect, unsigned long* lpflOldProtect);
]]
function hook.new(cast, callback, hook_addr, size)
jit.off(callback, true) --off jit compilation | thx FYP
local size = size or 5
local new_hook = {}
local detour_addr = tonumber(ffi.cast('intptr_t', ffi.cast('void*', ffi.cast(cast, callback))))
local void_addr = ffi.cast('void*', hook_addr)
local old_prot = ffi.new('unsigned long[1]')
local org_bytes = ffi.new('uint8_t[?]', size)
ffi.copy(org_bytes, void_addr, size)
local hook_bytes = ffi.new('uint8_t[?]', size, 0x90)
hook_bytes[0] = 0xE9
ffi.cast('uint32_t*', hook_bytes + 1)[0] = detour_addr - hook_addr - 5
new_hook.call = ffi.cast(cast, hook_addr)
new_hook.status = false
local function set_status(bool)
new_hook.status = bool
ffi.C.VirtualProtect(void_addr, size, 0x40, old_prot)
ffi.copy(void_addr, bool and hook_bytes or org_bytes, size)
ffi.C.VirtualProtect(void_addr, size, old_prot[0], old_prot)
end
new_hook.stop = function() set_status(false) end
new_hook.start = function() set_status(true) end
new_hook.start()
table.insert(hook.hooks, new_hook)
return setmetatable(new_hook, {
__call = function(self, ...)
self.stop()
local res = self.call(...)
self.start()
return res
end
})
end
--HOOKS
- Знать FFI
- Знать прототип функции
- Знать адрес функции
Для примера установим хук на showDialog
Его прототип
C++:
void(__thiscall *)(void *this, uint16_t wID, uint8_t iStyle, char *szCaption, char *szText, char *szButton1, char *szButton2, bool bSend)
Lua:
getModuleHandle('samp.dll') + 0x6B9C0
Lua:
tableHook = hook.new(прототип, калбэк, адрес, размер) --Размер по умолчанию = 5
Lua:
tableHook.status --статус хука(true/false)
tableHook.start() -- устанавливает хук
tableHook.stop() -- снимает хук
res = tableHook.call(...) --вызывает оригинальную функцию, если не void - возвратит результат
res = tableHook(...) --снимает хук, вызывает оригинальную ф-ю и ставит обратно
--То есть tableHook(...) = stop() call(...) start()
Обязательно подключаем библиотеку ffi
Lua:
local ffi = require 'ffi'
Lua:
--void(__thiscall *)(void *this, uint16_t wID, uint8_t iStyle, char *szCaption, char *szText, char *szButton1, char *szButton2, bool bSend)
function dialogHook(this, id, style, caption, text, button1, button2, send)
print(id, style, ffi.string(caption), ffi.string(text), ffi.string(button1), ffi.string(button2), send) --выводим параметры с которыми была вызвана оригинальная функция
end
Lua:
function main()
dialogHook = hook.new('void(__thiscall *)(void *this, uint16_t wID, uint8_t iStyle, char *szCaption, char *szText, char *szButton1, char *szButton2, bool bSend)', dialogHook, getModuleHandle('samp.dll') + 0x6B9C0)
--Узнать его статус можно так dialogHook.status
end
Lua:
function dialogHook(this, id, style, caption, text, button1, button2, send)
print(id, style, ffi.string(caption), ffi.string(text), ffi.string(button1), ffi.string(button2), send)
dialogHook(this, id, style, caption, text, button1, button2, send)
--Или
--dialogHook.stop()
--dialogHook.call(this, id, style, caption, text, button1, button2, send)
--dialogHook.start()
end
Lua:
function dialogHook(this, id, style, caption, text, button1, button2, send)
dialogHook(this, id, style, ffi.cast('char*', ffi.string(caption)..' | Hooked'), text, button1, button2, send) --К заголовку диалога будет дописываться " | Hooked"
end
Lua:
local ffi = require 'ffi'
--HOOKS
local hook = {hooks = {}}
addEventHandler('onScriptTerminate', function(scr)
if scr == script.this then
for i, hook in ipairs(hook.hooks) do
if hook.status then
hook.stop()
end
end
end
end)
ffi.cdef [[
int VirtualProtect(void* lpAddress, unsigned long dwSize, unsigned long flNewProtect, unsigned long* lpflOldProtect);
]]
function hook.new(cast, callback, hook_addr, size)
jit.off(callback, true) --off jit compilation | thx FYP
local size = size or 5
local new_hook = {}
local detour_addr = tonumber(ffi.cast('intptr_t', ffi.cast('void*', ffi.cast(cast, callback))))
local void_addr = ffi.cast('void*', hook_addr)
local old_prot = ffi.new('unsigned long[1]')
local org_bytes = ffi.new('uint8_t[?]', size)
ffi.copy(org_bytes, void_addr, size)
local hook_bytes = ffi.new('uint8_t[?]', size, 0x90)
hook_bytes[0] = 0xE9
ffi.cast('uint32_t*', hook_bytes + 1)[0] = detour_addr - hook_addr - 5
new_hook.call = ffi.cast(cast, hook_addr)
new_hook.status = false
local function set_status(bool)
new_hook.status = bool
ffi.C.VirtualProtect(void_addr, size, 0x40, old_prot)
ffi.copy(void_addr, bool and hook_bytes or org_bytes, size)
ffi.C.VirtualProtect(void_addr, size, old_prot[0], old_prot)
end
new_hook.stop = function() set_status(false) end
new_hook.start = function() set_status(true) end
new_hook.start()
table.insert(hook.hooks, new_hook)
return setmetatable(new_hook, {
__call = function(self, ...)
self.stop()
local res = self.call(...)
self.start()
return res
end
})
end
--HOOKS
function main()
dialogHook = hook.new('void(__thiscall *)(void *this, uint16_t wID, uint8_t iStyle, char *szCaption, char *szText, char *szButton1, char *szButton2, bool bSend)', dialogHook, getModuleHandle('samp.dll') + 0x6B9C0)
end
function dialogHook(this, id, style, caption, text, button1, button2, send)
dialogHook(this, id, style, ffi.cast('char*', ffi.string(caption)..' | Hooked'), text, button1, button2, send)
end
И еще один пример по хук win api функции
Lua:
function main()
local res, addr = getDynamicLibraryProcedure("MessageBoxA", getModuleHandle('user32.dll'))
if not res then return end
msgBoxHook = hook.new('int (__stdcall *)(void *w, const char *txt, const char *cap, int type)', msgBoxHook, addr)
--Вызываем для теста msgbox
ffi.cdef[[
int MessageBoxA(void *w, const char *txt, const char *cap, int type);
]]
ffi.C.MessageBoxA(nil, "Hello world!", "Test", 0)
--Или просто
msgBoxHook.call(nil, "Hello world!", "Test", 0)
end
function msgBoxHook(w, txt, cap, type)
print(w, ffi.string(txt), ffi.string(cap), type)
return msgBoxHook(w, txt, cap, type) --Т.к. функцию в прототипе указано int, а не void, нужно вернуть результат
end
Последнее редактирование: