local ffi = require("ffi")

ffi.cdef[[
void* GetModuleHandleA(const char* lpModuleName);

// Define IMAGE_DOS_HEADER and IMAGE_NT_HEADERS structures
typedef struct {
    uint16_t e_magic;    // Magic number
    uint16_t e_cblp;     // Bytes on last page of file
    uint16_t e_cp;       // Pages in file
    uint16_t e_crlc;     // Relocations
    uint16_t e_cparhdr;  // Size of header in paragraphs
    uint16_t e_minalloc; // Minimum extra paragraphs needed
    uint16_t e_maxalloc; // Maximum extra paragraphs needed
    uint16_t e_ss;       // Initial (relative) SS value
    uint16_t e_sp;       // Initial SP value
    uint16_t e_csum;     // Checksum
    uint16_t e_ip;       // Initial IP value
    uint16_t e_cs;       // Initial (relative) CS value
    uint16_t e_lfarlc;   // File address of relocation table
    uint16_t e_ovno;     // Overlay number
    uint16_t e_res[4];   // Reserved words
    uint16_t e_oemid;    // OEM identifier (for e_oeminfo)
    uint16_t e_oeminfo;  // OEM information; e_oemid specific
    uint16_t e_res2[10]; // Reserved words
    int32_t e_lfanew;    // File address of new exe header
} IMAGE_DOS_HEADER;

typedef struct {
    uint32_t Signature;
    struct {
        uint16_t Machine;
        uint16_t NumberOfSections;
        uint32_t TimeDateStamp;
        uint32_t PointerToSymbolTable;
        uint32_t NumberOfSymbols;
        uint16_t SizeOfOptionalHeader;
        uint16_t Characteristics;
    } FileHeader;
    struct {
        uint16_t Magic;
        uint8_t MajorLinkerVersion;
        uint8_t MinorLinkerVersion;
        uint32_t SizeOfCode;
        uint32_t SizeOfInitializedData;
        uint32_t SizeOfUninitializedData;
        uint32_t AddressOfEntryPoint;
        uint32_t BaseOfCode;
        uint32_t BaseOfData;
        uint32_t ImageBase;  // This field starts the optional headers
    } OptionalHeader;
} IMAGE_NT_HEADERS;
]]

-- Define SAMP version enumeration
local SAMPVER = {
    SAMP_NOT_LOADED = 0,
    SAMP_UNKNOWN = 1,
    SAMP_037_R1 = 2,
    SAMP_037_R3_1 = 3
}

-- Static address offsets based on version
local samp_addresses = {
    [SAMPVER.SAMP_037_R1] = { 
        0x68610, 0x70F96, 0x68F70, 0x68FA0, 0x21A0FC, 0x66E00, 0x66BD0, 0x12C980, 0x12C940, 0x21A0EC, 0x65F10, 0x9A7D0, 0x70E10, 0x6FD00
    },
    [SAMPVER.SAMP_037_R3_1] = {
        0x6C580, 0x74E8A, 0x6CEE0, 0x6CF10, 0x26E8E4, 0x6AD70, 0x6AB40, 0x140B00, 0x140AC0, 0x26E8D0, 0x69440, 0x9EA80, 0x74CFC, 0x73BEC
    },
}

local function sampGetBase()
    return tonumber(ffi.cast("uintptr_t", ffi.C.GetModuleHandleA("samp.dll")))
end

local function sampGetVersion()
    local sampBase = sampGetBase()
    if not sampBase or sampBase == 0 then
        return SAMPVER.SAMP_NOT_LOADED
    end
    
    local dosHeader = ffi.cast("IMAGE_DOS_HEADER*", sampBase)
    local ntHeader = ffi.cast("IMAGE_NT_HEADERS*", sampBase + dosHeader.e_lfanew)
    local ep = ntHeader.OptionalHeader.AddressOfEntryPoint

    if ep == 0x31DF13 then
        return SAMPVER.SAMP_037_R1
    elseif ep == 0xCC4D0 then
        return SAMPVER.SAMP_037_R3_1
    else
        return SAMPVER.SAMP_UNKNOWN
    end
end

local function sampGetPlayerTagsDrawerCallPtr()
    local version = sampGetVersion()
    local offsets = samp_addresses[version]
    if not offsets then
        error("Unknown or unsupported SAMP version")
    end

    return sampGetBase() + offsets[2]
end

-- Use the function to get the player's tags drawer call pointer
local playerTagsDrawerCallPtr = sampGetPlayerTagsDrawerCallPtr()
print(string.format("Player Tags Drawer Call Ptr: 0x%X", playerTagsDrawerCallPtr))

этот код получает адрес функции. 

Написал код для установки 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 

используя этот код для хука и мой код получающий адрес, напиши код для хука функции

 ?DrawLabel@CPlayerTags@@QAEXPAVCVector@sampapi@@PBDKM_NH@Z ; CPlayerTags::DrawLabel(sampapi::CVector *,char const *,ulong,float,bool,int)