USER
Написал код для установки 5-и байтового jmp хука. Переводить в библиотеку не вижу смысла, так что нужно просто скопировать его.
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
При таком хуке для вызова диалога можно использовать sampShowDialog(...) или dialogHook.call(...) (в этом случае нужно еще передать указатель this первым параметром, т.к. функция thiscall, если что, то это sampDialogInfoPtr)
И еще один пример по хук 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
Последнее редактирование: 8 Дек 2021
вот код для хука, сам блок HOOKS в свой код НЕ ВКЛЮЧАЙ
вот функция для хуука
// 0x707390
void CShadows::StoreShadowToBeRendered(uint8 type, RwTexture* texture, const CVector& posn, float topX, float topY, float rightX, float rightY, int16 intensity, uint8 red, uint8 green, uint8 blue, float zDistance, bool drawOnWater, float scale, CRealTimeShadow* realTimeShadow, bool drawOnBuildings) {
if (ShadowsStoredToBeRendered >= asShadowsStored.size())
return;
auto& shadow = asShadowsStored[ShadowsStoredToBeRendered];
shadow.m_nType = (eShadowType)type;
shadow.m_pTexture = texture;
shadow.m_vecPosn = posn;
shadow.m_Front.x = topX;
shadow.m_Front.y = topY;
shadow.m_Side.x = rightX;
shadow.m_Side.y = rightY;
shadow.m_nIntensity = intensity;
shadow.m_nRed = red;
shadow.m_nGreen = green;
shadow.m_nBlue = blue;
shadow.m_fZDistance = zDistance;
shadow.m_bDrawOnWater = drawOnWater;
shadow.m_bDrawOnBuildings = drawOnBuildings;
shadow.m_fScale = scale;
shadow.m_pRTShadow = realTimeShadow;
ShadowsStoredToBeRendered++;
}
напиши для нее хук. не используй настоящие структуры, достаточно войдаASSISTANT
Для того чтобы установить хук на функцию `CShadows::StoreShadowToBeRendered`, нужно выполнить аналогичные шаги, как и в предыдущих примерах с использованием FFI и Lua. Вы установите хук в том месте программы, где выполняется вызов этой функции. Ниже представлен пример установки такого хука:
```lua
local ffi = require 'ffi'
-- Определение прототипа функции для FFI
ffi.cdef [[
typedef struct {
float x;
float y;
float z;
} CVector;
typedef void RwTexture;
typedef void CRealTimeShadow;
]]
-- Основной блок для создания и управления хуком
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)
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
-- Определение каллбэка для нашего хука
function storeShadowHook(type, texture, posn, topX, topY, rightX, rightY, intensity, red, green, blue, zDistance, drawOnWater, scale, realTimeShadow, drawOnBuildings)
-- Вывод параметров для отладки
print(type, texture, posn, topX, topY, rightX, rightY, intensity, red, green, blue, zDistance, drawOnWater, scale, realTimeShadow, drawOnBuildings)
-- Далее вызывается оригинальная функция
storeShadowHook(type, texture, posn, topX, topY, rightX, rightY, intensity, red, green, blue, zDistance, drawOnWater, scale, realTimeShadow, drawOnBuildings)
end
-- Основная функция
function main()
-- Укажите фактический адрес функции CShadows::StoreShadowToBeRendered
local function_address = 0x707390 -- поставьте актуальный адрес
-- Установка хука
storeShadowHook = hook.new('void(uint8_t, RwTexture*, CVector, float, float, float, float, int16_t, uint8_t, uint8_t, uint8_t, float, bool, float, CRealTimeShadow*, bool)', storeShadowHook, function_address)
end
```
Не забудьте заменить `0x707390` на фактический адрес в памяти, по которому функция `CShadows::StoreShadowToBeRendered` загружается во время выполнения программы. Также обязательно убедитесь в корректном использовании сигнатуры и структуры данных при вызове hook.new.