Аризона опять чёт мутит, а так _chat.asi перехватывает сообщение от сервера с item, подменяет там и уже дальше прокидывает как бы копию сообщения.
Lua:
local hooks = require 'hooks'
local ffi = require 'ffi'
local sampev = require 'samp.events'
ffi.cdef [[
void* VirtualAlloc(void* lpAddress, uint32_t dwSize, uint32_t flAllocationType, uint32_t flProtect);
]]
ffi.cdef [[
void* GetModuleHandleA(const char* lpModuleName);
]]
function patternScan(module, pattern)
local base = ffi.cast('uint8_t*', ffi.C.GetModuleHandleA(module))
if base == nil then return nil end
local dos = ffi.cast('uint32_t*', base)
local nt = ffi.cast('uint32_t*', base + dos[15] / 4)
local size = nt[20]
local pat, mask = {}, {}
for byte in pattern:gmatch("%S+") do
if byte == "?" then
table.insert(pat, 0)
table.insert(mask, false)
else
table.insert(pat, tonumber(byte, 16))
table.insert(mask, true)
end
end
for i = 0, size - #pat do
local found = true
for j = 1, #pat do
if mask[j] and base[i + j - 1] ~= pat[j] then
found = false
break
end
end
if found then
return tonumber(ffi.cast('uintptr_t', base + i))
end
end
return nil
end
local STR_LEN_OFFSET = 9
local STR_DATA_OFFSET = 11
local SCRATCH_SIZE = 4096
local ANNOUNCE_TAG = string.char(0xCE, 0xE1, 0xFA, 0xFF, 0xE2, 0xEB, 0xE5, 0xED, 0xE8, 0xE5, 0x3A)
local RULES = {
[":uf280::uf286::uf290:"] = "{d568d5}[PREMIUM]",
[":uf280::uf286::uf291:"] = "{d568d5}[PREMIUM]",
[":uf280::uf286::uf292:"] = "{ffd632}[FOREVER]",
[":uf280::uf286::uf293:"] = "{ffd632}[FOREVER]",
[":uf280::uf286::uf294:"] = "{ffd632}[FOREVER]",
[":uf280::uf286::uf295:"] = "{ffd632}[FOREVER]",
[":uf280::uf286::uf296:"] = "{ffd632}[FOREVER]",
[":uf280::uf286::uf297:"] = "{ffd632}[FOREVER]",
[":uf280::uf286::uf298:"] = "{ffd632}[FOREVER]",
[":uf280::uf286::uf299:"] = "{ffd632}[FOREVER]",
[":uf280::uf287:"] = "{ffd632}[ADMIN]",
[":uf280::uf285:"] = "{6891db}[VIP]",
[":uf280::uf286:"] = "{d568d5}[PREMIUM]",
[":uf230:"] = "{788FD4}[VIP]",
[":uf231:"] = "{B56CFF}[PREMIUM]",
[":uf232:"] = "{B56CFF}[FOREVER]",
[":uf233:"] = "{DF8426}[FOREVER]",
[":uf234:"] = "{D7A926}[FOREVER]",
[":uf235:"] = "{F2C455}[ADMIN]",
[":uf236:"] = "{E75773}[VIP ADV]",
[":uf237:"] = "{E75773}[VIP ADV]",
[":uf238:"] = "{E75773}[VIP ADV]",
[":uf239:"] = "{E75773}[VIP ADV]",
[":uf23a:"] = "{E75773}[VIP ADV]",
-- анонсы
[":uf23b:"] = ":envelope: {079C1C}" .. ANNOUNCE_TAG,
[":uf23c:"] = ":envelope: {FCAA4D}[VIP] " .. ANNOUNCE_TAG,
-- короны
[":uf240:"] = "",
[":uf241:"] = "",
[":uf242:"] = "",
[":uf243:"] = "",
[":uf244:"] = "",
}
function escapePattern(s)
return (s:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1"))
end
function buildRuleList(map)
local list = {}
for from, to in pairs(map) do
list[#list + 1] = { from = from, to = to, pat = escapePattern(from) }
end
table.sort(list, function(a, b) return #a.from > #b.from end)
return list
end
local RULE_LIST = buildRuleList(RULES)
function applyReplacements(text)
for _, rule in ipairs(RULE_LIST) do
text = text:gsub(rule.pat, rule.to)
end
text = text:gsub(" +", " ")
text = text:gsub(" :", ":")
return text
end
local SCRATCH = ffi.cast('uint8_t*', ffi.C.VirtualAlloc(nil, SCRATCH_SIZE, 0x1000, 0x40))
local myHook
function onChatPacket(packet)
local pktPtr = ffi.cast('uint8_t*', packet)
local dataField = ffi.cast('uint8_t**', pktPtr + 0x10)
local sizeField = ffi.cast('uint32_t*', pktPtr + 0x08)
local data, size = dataField[0], sizeField[0]
if data == nil or size < STR_DATA_OFFSET + 1 or data[0] ~= 0xDC or data[1] ~= 0xD2 then
return myHook.call(packet)
end
local oldStrLen = ffi.cast('uint16_t*', data + STR_LEN_OFFSET)[0]
if oldStrLen == 0 or STR_DATA_OFFSET + oldStrLen > size then
return myHook.call(packet)
end
local text = ffi.string(data + STR_DATA_OFFSET, oldStrLen)
local newText = applyReplacements(text)
if newText == text then
return myHook.call(packet)
end
local newStrLen = #newText
local tailLen = size - (STR_DATA_OFFSET + oldStrLen)
local newPktSize = STR_DATA_OFFSET + newStrLen + tailLen
if newPktSize > SCRATCH_SIZE then
return myHook.call(packet)
end
-- [header 9b][uint16 newStrLen][newText][tail]
ffi.copy(SCRATCH, data, STR_LEN_OFFSET)
ffi.cast('uint16_t*', SCRATCH + STR_LEN_OFFSET)[0] = newStrLen
ffi.copy(SCRATCH + STR_DATA_OFFSET, newText, newStrLen)
if tailLen > 0 then
ffi.copy(SCRATCH + STR_DATA_OFFSET + newStrLen, data + STR_DATA_OFFSET + oldStrLen, tailLen)
end
dataField[0] = SCRATCH
sizeField[0] = newPktSize
local result = myHook.call(packet)
dataField[0] = data
sizeField[0] = size
return result
end
--myHook = hooks.jmp.new('void(__cdecl*)(int)', onChatPacket, 0x6B70FEEE, 5, true)
function sampev.onServerMessage(color, text)
print(text)
if text:find(":uf2", 1, true) then
local newText = applyReplacements(text)
if newText ~= text then
return { color, newText }
end
end
end
function main()
while not isSampAvailable() do wait(100) end
wait(2000)
local addr = patternScan("_chat.asi", "68 E4 02 00 00 ? ? ? ? ?")
if addr == nil then
print("hook not found")
return
end
print(string.format("hook found at 0x%X", addr))
myHook = hooks.jmp.new('void(__cdecl*)(int)', onChatPacket, addr, 5, true)
wait(-1)
end
На счёт сигнатуры не уверен что будет работать у всех, не тестил