Advertisement
sheredega

Untitled

Sep 3rd, 2023
697
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.99 KB | None | 0 0
  1. --[[
  2.     AUTHOR: RTD/RutreD(https://www.blast.hk/members/126461/)
  3. ]]
  4. local ffi = require 'ffi'
  5. ffi.cdef[[
  6.     int VirtualProtect(void* lpAddress, unsigned long dwSize, unsigned long flNewProtect, unsigned long* lpflOldProtect);
  7.     void* VirtualAlloc(void* lpAddress, unsigned long dwSize, unsigned long  flAllocationType, unsigned long flProtect);
  8.     int VirtualFree(void* lpAddress, unsigned long dwSize, unsigned long dwFreeType);
  9. ]]
  10. local function copy(dst, src, len)
  11.     return ffi.copy(ffi.cast('void*', dst), ffi.cast('const void*', src), len)
  12. end
  13. local buff = {free = {}}
  14. local function VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect)
  15.     return ffi.C.VirtualProtect(ffi.cast('void*', lpAddress), dwSize, flNewProtect, lpflOldProtect)
  16. end
  17. local function VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect, blFree)
  18.     local alloc = ffi.C.VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
  19.     if blFree then
  20.         table.insert(buff.free, alloc)
  21.     end
  22.     return ffi.cast('intptr_t', alloc)
  23. end
  24. --VMT HOOKS
  25. local vmt_hook = {hooks = {}}
  26. function vmt_hook.new(vt)
  27.     local new_hook = {}
  28.     local org_func = {}
  29.     local old_prot = ffi.new('unsigned long[1]')
  30.     local virtual_table = ffi.cast('intptr_t**', vt)[0]
  31.     new_hook.this = virtual_table
  32.     new_hook.hookMethod = function(cast, func, method)
  33.         jit.off(func, true) --off jit compilation | thx FYP
  34.         org_func[method] = virtual_table[method]
  35.         VirtualProtect(virtual_table + method, 4, 0x4, old_prot)
  36.         virtual_table[method] = ffi.cast('intptr_t', ffi.cast(cast, func))
  37.         VirtualProtect(virtual_table + method, 4, old_prot[0], old_prot)
  38.         return ffi.cast(cast, org_func[method])
  39.     end
  40.     new_hook.unHookMethod = function(method)
  41.         VirtualProtect(virtual_table + method, 4, 0x4, old_prot)
  42.         -- virtual_table[method] = org_func[method]
  43.         local alloc_addr = VirtualAlloc(nil, 5, 0x1000, 0x40, false)
  44.         local trampoline_bytes = ffi.new('uint8_t[?]', 5, 0x90)
  45.         trampoline_bytes[0] = 0xE9
  46.         ffi.cast('int32_t*', trampoline_bytes + 1)[0] = org_func[method] - tonumber(alloc_addr) - 5
  47.         copy(alloc_addr, trampoline_bytes, 5)
  48.         virtual_table[method] = ffi.cast('intptr_t', alloc_addr)
  49.         VirtualProtect(virtual_table + method, 4, old_prot[0], old_prot)
  50.         org_func[method] = nil
  51.     end
  52.     new_hook.unHookAll = function()
  53.         for method, func in pairs(org_func) do
  54.             new_hook.unHookMethod(method)
  55.         end
  56.     end
  57.     table.insert(vmt_hook.hooks, new_hook.unHookAll)
  58.     return new_hook
  59. end
  60. --VMT HOOKS
  61. --JMP HOOKS
  62. local jmp_hook = {hooks = {}}
  63. function jmp_hook.new(cast, callback, hook_addr, size, trampoline, org_bytes_tramp)
  64.     jit.off(callback, true) --off jit compilation | thx FYP
  65.     local size = size or 5
  66.     local trampoline = trampoline or false
  67.     local new_hook, mt = {}, {}
  68.     local detour_addr = tonumber(ffi.cast('intptr_t', ffi.cast(cast, callback)))
  69.     local old_prot = ffi.new('unsigned long[1]')
  70.     local org_bytes = ffi.new('uint8_t[?]', size)
  71.     copy(org_bytes, hook_addr, size)
  72.     if trampoline then
  73.         local alloc_addr = VirtualAlloc(nil, size + 5, 0x1000, 0x40, true)
  74.         local trampoline_bytes = ffi.new('uint8_t[?]', size + 5, 0x90)
  75.         if org_bytes_tramp then
  76.             local i = 0
  77.             for byte in org_bytes_tramp:gmatch('(%x%x)') do
  78.                 trampoline_bytes[i] = tonumber(byte, 16)
  79.                 i = i + 1
  80.             end
  81.         else
  82.             copy(trampoline_bytes, org_bytes, size)
  83.         end
  84.         trampoline_bytes[size] = 0xE9
  85.         ffi.cast('int32_t*', trampoline_bytes + size + 1)[0] = hook_addr - tonumber(alloc_addr) - size + (size - 5)
  86.         copy(alloc_addr, trampoline_bytes, size + 5)
  87.         new_hook.call = ffi.cast(cast, alloc_addr)
  88.         mt = {__call = function(self, ...)
  89.             return self.call(...)
  90.         end}
  91.     else
  92.         new_hook.call = ffi.cast(cast, hook_addr)
  93.         mt = {__call = function(self, ...)
  94.             self.stop()
  95.             local res = self.call(...)
  96.             self.start()
  97.             return res
  98.         end}
  99.     end
  100.     local hook_bytes = ffi.new('uint8_t[?]', size, 0x90)
  101.     hook_bytes[0] = 0xE9
  102.     ffi.cast('int32_t*', hook_bytes + 1)[0] = detour_addr - hook_addr - 5
  103.     new_hook.status = false
  104.     local function set_status(bool)
  105.         new_hook.status = bool
  106.         VirtualProtect(hook_addr, size, 0x40, old_prot)
  107.         copy(hook_addr, bool and hook_bytes or org_bytes, size)
  108.         VirtualProtect(hook_addr, size, old_prot[0], old_prot)
  109.     end
  110.     new_hook.stop = function() set_status(false) end
  111.     new_hook.start = function() set_status(true) end
  112.     new_hook.start()
  113.     if org_bytes[0] == 0xE9 or org_bytes[0] == 0xE8 then
  114.         print('[WARNING] rewrote another hook'.. (trampoline and ' (old hook was disabled, through trampoline)' or ''))
  115.     end
  116.     table.insert(jmp_hook.hooks, new_hook)
  117.     return setmetatable(new_hook, mt)
  118. end
  119. --JMP HOOKS
  120. --CALL HOOKS
  121. local call_hook = {hooks = {}}
  122. function call_hook.new(cast, callback, hook_addr)
  123.     if ffi.cast('uint8_t*', hook_addr)[0] ~= 0xE8 then return end
  124.     jit.off(callback, true) --off jit compilation | thx FYP
  125.     local new_hook = {}
  126.     local detour_addr = tonumber(ffi.cast('intptr_t', ffi.cast(cast, callback)))
  127.     local void_addr = ffi.cast('void*', hook_addr)
  128.     local old_prot = ffi.new('unsigned long[1]')
  129.     local org_bytes = ffi.new('uint8_t[?]', 5)
  130.     ffi.copy(org_bytes, void_addr, 5)
  131.     local hook_bytes = ffi.new('uint8_t[?]', 5, 0xE8)
  132.     ffi.cast('uint32_t*', hook_bytes + 1)[0] = detour_addr - hook_addr - 5
  133.     new_hook.call = ffi.cast(cast, ffi.cast('intptr_t*', hook_addr + 1)[0] + hook_addr + 5)
  134.     new_hook.status = false
  135.     local function set_status(bool)
  136.         new_hook.status = bool
  137.         ffi.C.VirtualProtect(void_addr, 5, 0x40, old_prot)
  138.         ffi.copy(void_addr, bool and hook_bytes or org_bytes, 5)
  139.         ffi.C.VirtualProtect(void_addr, 5, old_prot[0], old_prot)
  140.     end
  141.     new_hook.stop = function() set_status(false) end
  142.     new_hook.start = function() set_status(true) end
  143.     new_hook.start()
  144.     table.insert(call_hook.hooks, new_hook)
  145.     return setmetatable(new_hook, {
  146.         __call = function(self, ...)
  147.             local res = self.call(...)
  148.             return res
  149.         end
  150.     })
  151. end
  152. --CALL HOOKS
  153. --DELETE HOOKS
  154. addEventHandler('onScriptTerminate', function(scr)
  155.     if scr == script.this then
  156.         for i, hook in ipairs(jmp_hook.hooks) do
  157.             if hook.status then
  158.                 hook.stop()
  159.             end
  160.         end
  161.         for i, hook in ipairs(call_hook.hooks) do
  162.             if hook.status then
  163.                 hook.stop()
  164.             end
  165.         end
  166.         for i, addr in ipairs(buff.free) do
  167.             ffi.C.VirtualFree(addr, 0, 0x8000)
  168.         end
  169.         for i, unHookFunc in ipairs(vmt_hook.hooks) do
  170.             unHookFunc()
  171.         end
  172.     end
  173. end)
  174. --DELETE HOOKS
  175.  
  176. return {vmt = vmt_hook, jmp = jmp_hook, call = call_hook}
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement