Добавить закладку
#1
Написал код для установки 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




используя этот пример напиши хук для

// 0x726AF0
void CBulletTraces::AddTrace(const CVector& posMuzzle, const CVector& posBulletHit, eWeaponType weaponType, CEntity* fromEntity)
{
    if (FindPlayerPed() == fromEntity || FindPlayerVehicle() && FindPlayerVehicle() == fromEntity) {
        switch (CCamera::GetActiveCamera().m_nMode) {
        case MODE_M16_1STPERSON:
        case MODE_SNIPER:
        case MODE_CAMERA:
        case MODE_ROCKETLAUNCHER:
        case MODE_ROCKETLAUNCHER_HS:
        case MODE_M16_1STPERSON_RUNABOUT:
        case MODE_SNIPER_RUNABOUT:
        case MODE_ROCKETLAUNCHER_RUNABOUT:
        case MODE_ROCKETLAUNCHER_RUNABOUT_HS:
        case MODE_HELICANNON_1STPERSON: {
            if (FindPlayerEntity()->AsPhysical()->m_vecMoveSpeed.Magnitude() < 0.05f) {
                return;
            }
        }
        }
    }

    CVector dir = posBulletHit - posMuzzle;
    const float traceLengthOriginal = dir.Magnitude();
    dir.Normalise();

    const float traceLengthNew = CGeneral::GetRandomNumberInRange(0.0f, traceLengthOriginal);
    const float fRadius = std::min(CGeneral::GetRandomNumberInRange(2.0f, 5.0f), traceLengthOriginal - traceLengthNew);

    CVector from = posMuzzle + dir * traceLengthNew;
    CVector to = from + dir * fRadius;

    AddTrace(
        from,
        to,
        0.01f,
        300,
        70
    );
}