• ■ ■ ■ ■ ■ ■
    memapi.lua
     1 +--- @diagnostic disable: param-type-mismatch, undefined-field, cast-local-type
     2 +-- memAPI v.1.0a (by @asdhuman)
     3 +-- Read docs at https://codedune.tech/docs/memapi
     4 +-- lua require docs at https://www.lua.org/pil/8.1.html
     5 +-- Import this library with `` local memapi = require "memapi" ``
     6 + 
     7 +local memapi = {}
     8 + 
     9 +-- Save copied tables in `copies`, indexed by original table.
     10 +local function deepcopy(orig)
     11 + local orig_type = type(orig)
     12 + local copy
     13 + if orig_type == 'table' then
     14 + copy = {}
     15 + for orig_key, orig_value in next, orig, nil do
     16 + copy[deepcopy(orig_key)] = deepcopy(orig_value)
     17 + end
     18 + setmetatable(copy, deepcopy(getmetatable(orig)))
     19 + else -- number, string, boolean, etc
     20 + copy = orig
     21 + end
     22 + return copy
     23 +end
     24 + 
     25 +memapi.convertToHexString = function(number, digits)
     26 + if digits < 1 or digits > 16 then
     27 + error("Number of hexadecimal digits in the resulting string has to be in range [1; 16]")
     28 + return
     29 + end
     30 + 
     31 + if _VERSION:match("5.2") ~= nil then -- Lua 5.2
     32 + local mask = load[[return function(digits) return (1 << (digits * 4)) - 1 end]]()(digits)
     33 + local format = "%0" .. digits .. "X"
     34 + return load[[return function(format, number, mask)
     35 + return string.format(format, number & mask)
     36 + end]]()(format, number, mask)
     37 + else -- Lua 5.3
     38 + local mask = (1 << (digits * 4)) - 1
     39 + local format = "%0" .. digits .. "X"
     40 + return string.format(format, number & mask)
     41 + end
     42 +end
     43 + 
     44 +memapi.get_libbase = function(libname)
     45 + local addresses = gg.getRangesList("*" .. libname .. "*.so")
     46 + local xa_libs = {}
     47 + for k, v in pairs(addresses) do
     48 + if v.state == 'Xa' then table.insert(xa_libs, v) end -- get all in Xa
     49 + end
     50 + if #xa_libs == 1 then
     51 + local ret = {}
     52 + ret.base_offset = xa_libs[1].start
     53 + ret.end_offset = xa_libs[1]["end"] -- "end" is lua keyword
     54 + ret.base_libname = xa_libs[1].name
     55 + return ret
     56 + elseif #xa_libs > 1 then return -1
     57 + else return nil end
     58 +end
     59 + 
     60 +memapi.__attach = function (self)
     61 + local libs = memapi.get_libbase(self.user_libname)
     62 + if type(libs) == "table" then
     63 + self.is_hooked = true
     64 + self.base_offset = libs.base_offset
     65 + self.end_offset = libs.end_offset
     66 + self.libname = libs.base_libname
     67 + return true
     68 + elseif libs == -1 then
     69 + gg.alert("[memAPI] Found more then one library with this string, try to specify more precise")
     70 + return false
     71 + else
     72 + return false
     73 + end
     74 +end
     75 + 
     76 +memapi.__arch = function(self, ...)
     77 + local args = {...}
     78 + if #args == 1 then
     79 + if args[1] == "x32" or args[1] == "32" or args[1] == "armv7" then
     80 + return not self.target_info.x64
     81 + elseif args[1] == "x64" or args[1] == '64' or args[1] == "armv8" then
     82 + return self.target_info.x64
     83 + end
     84 + else
     85 + if self.target_info.x64 then
     86 + return "x64"
     87 + else
     88 + return "x32"
     89 + end
     90 + end
     91 +end
     92 + 
     93 +memapi.__read = function(self, addr, size) -- size in bytes
     94 + local start_clock = os.clock()
     95 + local offset
     96 + if type(addr) == "string" then
     97 + offset = self.base_offset + tonumber(tostring(addr), 16)
     98 + elseif type(addr) == "number" then
     99 + offset = self.base_offset + addr
     100 + end
     101 + local t = {}
     102 + local data = ""
     103 + for i=1, size do
     104 + t[i] = {}
     105 + t[i].address = string.format("0x%X", tostring(offset + (i-1)))
     106 + t[i].flags = gg.TYPE_BYTE
     107 + end
     108 + local d = gg.getValues(t)
     109 + for _, v in pairs(d) do
     110 + data = data .. memapi.convertToHexString(v["value"], 2)
     111 + end
     112 + if self.debug then
     113 + print(string.format("[memAPI] Read %d bytes from 0x%X in %f s", size, offset, os.clock() - start_clock))
     114 + end
     115 + return data
     116 +end
     117 + 
     118 +memapi.__push = function (self, ...)
     119 + local start_clock = os.clock()
     120 + local args = {...}
     121 + if #self.write_buffer < 1 then return end
     122 + 
     123 + if #self.op_buffer > 10 then
     124 + table.remove(self.op_buffer, 1)
     125 + end
     126 + 
     127 + local oldvals = {}
     128 +
     129 + for _, v in pairs(self.write_buffer) do
     130 + if self.rollbacking then -- can make push slower
     131 + table.insert(oldvals, gg.getValues(v))
     132 + end
     133 + gg.setValues(v)
     134 + end
     135 + 
     136 + if self.rollbacking then
     137 + table.insert(self.op_buffer, oldvals)
     138 + end
     139 + 
     140 + if self.debug then
     141 + print(string.format("[memAPI] Pushed %d operations in %f s", #self.write_buffer, os.clock() - start_clock))
     142 + end
     143 + 
     144 + self.write_buffer = {}
     145 +end
     146 + 
     147 +memapi.__rollback = function (self)
     148 + if self.rollbacking then
     149 + -- get last item from write_buffer
     150 + local start_clock = os.clock()
     151 + local last = self.op_buffer[#self.op_buffer]
     152 + 
     153 + for _, v in pairs(last) do
     154 + gg.setValues(v)
     155 + end
     156 + 
     157 + table.remove(self.op_buffer, #self.op_buffer)
     158 + 
     159 + if self.debug then
     160 + print(string.format("[memAPI] Rollbacked %d operations in %f s", #last, os.clock() - start_clock))
     161 + end
     162 + else
     163 + error("Rollbacking not enabled. Use ``hook.rollbacking = true``")
     164 + return
     165 + end
     166 +end
     167 + 
     168 +memapi.__write32 = function (self, offset, val)
     169 + local start_clock = os.clock()
     170 + local t = memapi.__bytesToTable32(val, offset)
     171 + if t ~= false then
     172 + table.insert(self.write_buffer, t)
     173 + if self.debug then
     174 + print(string.format("[memAPI] __write32() %d bytes in %f s", #t, os.clock() - start_clock))
     175 + end
     176 + return true
     177 + else
     178 + return false
     179 + end
     180 +end
     181 + 
     182 +memapi.__write64 = function (self, offset, val)
     183 + local start_clock = os.clock()
     184 + local t = memapi.__bytesToTable64(val, offset)
     185 + if t ~= false then
     186 + table.insert(self.write_buffer, t)
     187 + if self.debug then
     188 + print(string.format("[memAPI] __write64() %d bytes in %f s", #t, os.clock() - start_clock))
     189 + end
     190 + return true
     191 + else
     192 + return false
     193 + end
     194 +end
     195 + 
     196 +memapi.__write = function(self, addr, ...)
     197 + local start_clock = os.clock()
     198 + local args = {...}
     199 + local offset
     200 + if type(addr) == "string" then
     201 + offset = self.base_offset + tonumber(tostring(addr):gsub("0x", ""), 16)
     202 + elseif type(addr) == "number" then
     203 + offset = self.base_offset + addr
     204 + else
     205 + error("[memAPI] Invalid offset type (string or number expected)")
     206 + return
     207 + end
     208 + 
     209 + if #args == 1 then
     210 + if self.is_hooked then
     211 + if self:arch("x32") then
     212 + self:__write32(offset, args[1])
     213 + else
     214 + self:__write64(offset, args[1])
     215 + end
     216 + else
     217 + gg.alert("[memAPI] You have to attach to library first")
     218 + end
     219 + elseif #args > 1 then
     220 + if self.is_hooked then
     221 + if self:arch("x32") then
     222 + local stf = 0
     223 + for i=1, #args do
     224 + self:__write32(offset + stf, args[i])
     225 + stf = stf + memapi.byteslenght(args[i])
     226 + end
     227 + else
     228 + local stf = 0
     229 + for i=1, #args do
     230 + self:__write64(offset + stf, args[i])
     231 + stf = stf + memapi.byteslenght(args[i])
     232 + end
     233 + end
     234 + else
     235 + gg.alert("[memAPI] You have to attach to library first")
     236 + end
     237 + end
     238 + if self.debug then
     239 + print(string.format("[memAPI] __write %d ops in %f s", #args, os.clock() - start_clock))
     240 + end
     241 +end
     242 + 
     243 +memapi.__disasm32 = function(addr, opcode)
     244 + local thumb = gg.disasm(gg.ASM_THUMB, addr, opcode)
     245 + local arm = gg.disasm(gg.ASM_ARM, addr, opcode)
     246 + local t = {}
     247 + t.thumb = thumb
     248 + t.arm = arm
     249 + return t
     250 +end
     251 + 
     252 +memapi.__disasm64 = function(addr, opcode)
     253 + local thumb = gg.disasm(gg.ASM_THUMB, addr, opcode)
     254 + local arm = gg.disasm(gg.ASM_ARM64, addr, opcode)
     255 + local t = {}
     256 + t.thumb = thumb
     257 + t.arm = arm
     258 + return t
     259 +end
     260 + 
     261 +memapi.disasm = function(arch, addr, opcode)
     262 + if type(opcode) == "string" then
     263 + -- remove all spaces, conver to hex
     264 + opcode = string.gsub(opcode, "%s+", "")
     265 + opcode = string.gsub(opcode, " ", "")
     266 + opcode = string.gsub(opcode, "0x", "")
     267 + opcode = string.gsub(opcode, "0X", "")
     268 + 
     269 + -- check if opcode is valid
     270 + if #opcode % 8 ~= 0 then
     271 + gg.alert("4 bytes opcode size required!")
     272 + end
     273 + 
     274 + -- convert to number
     275 + opcode = tonumber(opcode, 16)
     276 + opcode = string.unpack('>I4', string.pack('<I4', opcode))
     277 + end
     278 + 
     279 + if addr == nil then addr = 0x0 end
     280 + if arch == "x32" then
     281 + return memapi.__disasm32(addr, opcode)
     282 + else
     283 + return memapi.__disasm64(addr, opcode)
     284 + end
     285 +end
     286 + 
     287 +memapi.asm = function(code, op_addr)
     288 + if op_addr == nil then op_addr = 0x0 end
     289 + local arm = code
     290 + local addr = gg.getRangesList('libc.so')
     291 + for i, v in ipairs(addr) do
     292 + if v.type:sub(2,2) == 'w' then
     293 + addr = {{address = v.start, flags = gg.TYPE_DWORD}}
     294 + end
     295 + end
     296 + 
     297 + if not addr[1].address then
     298 + gg.alert('Failed to get addr (memapi.asm issues)\n' .. tostring(addr))
     299 + do return end
     300 + end
     301 + do
     302 + local addr = tonumber(op_addr, 16)
     303 + if addr then
     304 + addr = addr & 0xFFFFFFFF
     305 + arm = arm:gsub('( 0[xX](%x+))', function (m, n)
     306 + local num = tonumber(n, 16)
     307 + if not num then return m end
     308 + num = num & 0xFFFFFFFF
     309 + num = num - addr;
     310 + local sign = '+'
     311 + if num < 0 then
     312 + num = -num
     313 + sign = '-'
     314 + end
     315 + return string.format(' %s0x%X', sign, num)
     316 + end)
     317 + end
     318 + end
     319 + 
     320 + local old = gg.getValues(addr)
     321 + addr[1].value = '~A '..arm
     322 + local ok, err = pcall(gg.setValues, addr)
     323 + local out
     324 + if not ok then
     325 + err = err:gsub("^.* '1': ", ''):gsub('\nlevel = 1.*$', '')
     326 + error("-----------------------\n[memAPI] Error: \n" .. tostring(err) .. "\n-----------------------\n")
     327 + out = 'ERR!'
     328 + else
     329 + out = gg.getValues(addr)
     330 + out = out[1].value & 0xFFFFFFFF
     331 +
     332 + gg.setValues(old)
     333 + out = string.unpack('>I4', string.pack('<I4', out))
     334 + out = string.format('%08X', out)
     335 + return out
     336 + end
     337 +end
     338 + 
     339 +memapi.__formatpatch = function(val)
     340 + local ret = ""
     341 + if type(val) == "string" then
     342 + if val == "nop" then
     343 + return "00F020E3" -- nop is 4 bytes "00 F0 20 E3"
     344 + else
     345 + local v = val:gsub("[h]", "")
     346 + v = v:gsub("%s+", "")
     347 + if string.match(v, "^[0-9A-Fa-f]+$") then
     348 + val = val:gsub("[h]", ""); val = val:gsub("%s+", "")
     349 + if string.len(val) % 2 ~= 0 then val = val .. "0" end
     350 + local i2 = 1
     351 + for i=1, string.len(val)/2 do
     352 + ret = ret .. string.sub(val, i2, i2+1)
     353 + i2 = i2 + 2
     354 + end
     355 + else
     356 + local s = memapi.asm(val) -- asm parse
     357 + if s == nil then return false
     358 + else
     359 + for i=1, #s/2 do
     360 + ret = ret .. string.sub(s, (i-1)*2+1, (i-1)*2+2)
     361 + end
     362 + end
     363 + end
     364 + end
     365 + elseif type(val) == "boolean" then
     366 + if val then ret = "h01"
     367 + else ret ="h00" end
     368 + ret = ret .. "00A0E31EFF2FE1"
     369 + elseif type(val) == "number" then -- 0-255 currently
     370 + if val >= 0 then
     371 + if val >= 255 then
     372 + ret = memapi.asm("mov r0, #" .. tostring(val)) -- somekind slower
     373 + ret = ret .. "1EFF2FE1"
     374 + else
     375 + ret = memapi.convertToHexString(val, 2) .."00A0E31EFF2FE1"
     376 + end
     377 + else
     378 + ret = memapi.asm("mov r0, #" .. tostring(val))
     379 + ret = ret .. "1EFF2FE1"
     380 + error("value <0, not implemented")
     381 + return
     382 + -- ret = memapi.convertToHexString(val, 2) -- maybe i will do that later...
     383 + end
     384 + end
     385 + return ret
     386 +end
     387 + 
     388 +memapi.__bytesToTable64 = function(val, offset)
     389 + local t = {}
     390 + if type(val) == "string" then
     391 + if val == "nop" then
     392 + local np = "1F2003D5" -- nop is 4 bytes "1F 20 03 D5"
     393 + for i=1, 4 do
     394 + t[i] = {}
     395 + t[i].address = offset + i - 1
     396 + t[i].flags = gg.TYPE_BYTE
     397 + t[i].value = "h" .. string.sub(np, (i-1)*2+1, (i-1)*2+2)
     398 + end
     399 + else
     400 + local v = val:gsub("[h]", "")
     401 + v = v:gsub("%s+", "")
     402 + if string.match(v, "^[0-9A-Fa-f]+$") then
     403 + val = val:gsub("[h]", ""); val = val:gsub("%s+", "")
     404 + if string.len(val) % 2 ~= 0 then val = val .. "0" end
     405 + local i2 = 1
     406 + for i=1, string.len(val)/2 do
     407 + t[i] = {}
     408 + t[i].address = string.format("0x%X", tostring(offset + (i-1)))
     409 + t[i].flags = gg.TYPE_BYTE
     410 + local bb = "h" .. string.sub(val, i2, i2+1)
     411 + t[i].value = bb
     412 + i2 = i2 + 2
     413 + end
     414 + else
     415 + local s = memapi.asm(val) -- asm parse
     416 + if s == nil then return false
     417 + else
     418 + for i=1, #s/2 do
     419 + t[i] = {}
     420 + t[i].address = string.format("0x%X", tostring(offset + (i-1)))
     421 + t[i].flags = gg.TYPE_BYTE
     422 + t[i].value = "h" .. string.sub(s, (i-1)*2+1, (i-1)*2+2)
     423 + end
     424 + end
     425 + end
     426 + end
     427 + elseif type(val) == "boolean" then
     428 + local s
     429 + if val then s = "200080D2"
     430 + else s = "000080D2" end
     431 + s = s .. "C0035FD6" -- ret
     432 + for i=1, 8 do
     433 + t[i] = {}
     434 + t[i].address = offset + i - 1
     435 + t[i].flags = gg.TYPE_BYTE
     436 + t[i].value = "h" .. string.sub(s, (i-1)*2+1, (i-1)*2+2)
     437 + end
     438 + elseif type(val) == "number" then
     439 + local s
     440 + s = memapi.asm("mov x0, #" .. tostring(val))
     441 + s = s .. "C0035FD6" -- ret
     442 + for i=1, 8 do
     443 + t[i] = {}
     444 + t[i].address = offset + i - 1
     445 + t[i].flags = gg.TYPE_BYTE
     446 + t[i].value = "h" .. string.sub(s, (i-1)*2+1, (i-1)*2+2)
     447 + end
     448 + end
     449 + 
     450 + if #t > 0 then
     451 + return t
     452 + else
     453 + return false
     454 + end
     455 +end
     456 + 
     457 +memapi.__bytesToTable32 = function(val, offset)
     458 + local t = {}
     459 + if type(val) == "string" then
     460 + if val == "nop" then
     461 + local np = "00F020E3" -- nop is 4 bytes "00 F0 20 E3"
     462 + for i=1, 4 do
     463 + t[i] = {}
     464 + t[i].address = offset + i - 1
     465 + t[i].flags = gg.TYPE_BYTE
     466 + t[i].value = "h" .. string.sub(np, (i-1)*2+1, (i-1)*2+2)
     467 + end
     468 + else
     469 + local v = val:gsub("[h]", "")
     470 + v = v:gsub("%s+", "")
     471 + if string.match(v, "^[0-9A-Fa-f]+$") then
     472 + val = val:gsub("[h]", ""); val = val:gsub("%s+", "")
     473 + if string.len(val) % 2 ~= 0 then val = val .. "0" end
     474 + local i2 = 1
     475 + for i=1, string.len(val)/2 do
     476 + t[i] = {}
     477 + t[i].address = string.format("0x%X", tostring(offset + (i-1)))
     478 + t[i].flags = gg.TYPE_BYTE
     479 + local bb = "h" .. string.sub(val, i2, i2+1)
     480 + t[i].value = bb
     481 + i2 = i2 + 2
     482 + end
     483 + else
     484 + local s = memapi.asm(val) -- asm parse
     485 + if s == nil then return false
     486 + else
     487 + for i=1, #s/2 do
     488 + t[i] = {}
     489 + t[i].address = string.format("0x%X", tostring(offset + (i-1)))
     490 + t[i].flags = gg.TYPE_BYTE
     491 + t[i].value = "h" .. string.sub(s, (i-1)*2+1, (i-1)*2+2)
     492 + end
     493 + end
     494 + end
     495 + end
     496 + elseif type(val) == "boolean" then
     497 + for i=1, 8 do
     498 + t[i] = {}
     499 + t[i].address = string.format("0x%X", tostring(offset + (i-1)))
     500 + t[i].flags = gg.TYPE_BYTE
     501 + end
     502 + if val then t[1].value = "h01" else t[1].value = "h00" end
     503 + t[2].value = "h00"; t[3].value = "hA0"
     504 + t[4].value = "hE3"; t[5].value = "h1E"
     505 + t[6].value = "hFF"; t[7].value = "h2F"
     506 + t[8].value = "hE1"
     507 + elseif type(val) == "number" then
     508 + for i=1, 8 do
     509 + t[i] = {}
     510 + t[i].address = string.format("0x%X", tostring(offset + (i-1)))
     511 + t[i].flags = gg.TYPE_BYTE
     512 + end
     513 + if val >= 0 then
     514 + t[1].value = "h" .. memapi.convertToHexString(val, 2)
     515 + else
     516 + t[1].value = "h" .. memapi.convertToHexString(val, 2) -- maybe i will do that later...
     517 + end
     518 + t[2].value = "h00"; t[3].value = "hA0"
     519 + t[4].value = "hE3"; t[5].value = "h1E"
     520 + t[6].value = "hFF"; t[7].value = "h2F"
     521 + t[8].value = "hE1"
     522 + end
     523 + 
     524 + if #t > 0 then
     525 + return t
     526 + else
     527 + return false
     528 + end
     529 +end
     530 + 
     531 +memapi.byteslenght = function(val)
     532 + if type(val) == "string" then
     533 + if val == "nop" then
     534 + return 4 -- nop is 4 bytes "00 F0 20 E3"
     535 + else
     536 + local v = val:gsub("[h]", "")
     537 + v = v:gsub("%s+", "")
     538 + if string.match(v, "^[0-9A-Fa-f]+$") then
     539 + val = val:gsub("[h]", ""); val = val:gsub("%s+", "")
     540 + if string.len(val) % 2 ~= 0 then val = val .. "0" end
     541 + return string.len(val)/2
     542 + else
     543 + local s = memapi.asm(val) -- asm parse
     544 + if s == nil then return false
     545 + else return #s/2 end
     546 + end
     547 + end
     548 + elseif type(val) == "boolean" then
     549 + return 8 -- "mov r0, #0/1; bx lr"
     550 + elseif type(val) == "number" then
     551 + return 8 -- same as bool, #?
     552 + else
     553 + return false
     554 + end
     555 +end
     556 + 
     557 +memapi.__switchconstr = function(hook, offset, patch_to, orig_bytes)
     558 + local handler = {}
     559 + 
     560 + if type(offset) == "string" then
     561 + offset = tonumber(tostring(offset):gsub("0x", ""), 16)
     562 + elseif type(offset) == "number" then
     563 + -- nothing
     564 + else
     565 + error("[memAPI] Invalid offset type (string or number expected)")
     566 + return
     567 + end
     568 + 
     569 + handler.hook = deepcopy(hook) -- memapi obj
     570 + handler.hook.op_buffer = {} -- cleanup
     571 + handler.hook.write_buffer = {} -- cleanup
     572 + handler.hook.rollbacking = false -- we dont need that here
     573 + 
     574 + handler.offset = offset
     575 + handler.patch_to = memapi.__formatpatch(patch_to) -- A0B1C2D3...
     576 + handler.byteslenght = memapi.byteslenght(handler.patch_to)
     577 + 
     578 + local membytes = handler.hook:read(offset, handler.byteslenght) -- to get state
     579 + 
     580 + if orig_bytes then
     581 + if handler.byteslenght ~= memapi.byteslenght(orig_bytes) then
     582 + error("Lenght of patch_to and orig_bytes not equal")
     583 + return
     584 + end
     585 + end
     586 +
     587 + if membytes == handler.patch_to then
     588 + handler.state = true -- already enabled
     589 + if orig_bytes then
     590 + handler.original = orig_bytes -- switch impl
     591 + else
     592 + handler.original = "false" -- bswitch impl
     593 + end
     594 + else
     595 + handler.state = false -- ok
     596 + if orig_bytes then
     597 + handler.original = orig_bytes -- switch
     598 + else
     599 + handler.original = membytes -- bswitch
     600 + end
     601 + end
     602 + 
     603 + handler.enable = function()
     604 + handler.state = true
     605 + handler.hook:write(handler.offset, handler.patch_to)
     606 + handler.hook:push()
     607 + gg.alert("enabled")
     608 + end
     609 + 
     610 + handler.disable = function()
     611 + handler.state = false
     612 + handler.hook:write(handler.offset, handler.original)
     613 + handler.hook:push()
     614 + gg.alert("disabled")
     615 + end
     616 +
     617 + handler.toggle = function()
     618 + if handler.state then
     619 + handler.disable(); return false;
     620 + else
     621 + handler.enable(); return true;
     622 + end
     623 + end
     624 + 
     625 + return handler
     626 +end
     627 + 
     628 +memapi.__bswitch = function(self, offset, patch_to)
     629 + return memapi.__switchconstr(self, offset, patch_to, nil) -- how do we know orig bytes, if patched, lol?
     630 +end
     631 + 
     632 +memapi.__switch = function(self, offset, patch_to, orig_bytes)
     633 + return memapi.__switchconstr(self, offset, patch_to, orig_bytes)
     634 +end
     635 + 
     636 +memapi.__patchconstr = function (hook, offset, ...)
     637 + local args = {...}
     638 + if #args < 1 then
     639 + error("No data specified")
     640 + return
     641 + end
     642 + 
     643 + local handler = {}
     644 + handler.__hook = deepcopy(hook) -- memapi obj
     645 + handler.__hook.op_buffer = {} -- cleanup
     646 + handler.__hook.write_buffer = {} -- cleanup
     647 + 
     648 + handler.offset = offset
     649 + 
     650 + handler.__hook:write(offset, ...)
     651 + handler.__hook:push()
     652 + 
     653 + local mt = {}
     654 + mt.__index = function(self, key)
     655 + if key == "rollbacking" then
     656 + return handler.__hook.rollbacking
     657 + end
     658 + end
     659 + 
     660 + mt.__newindex = function (self, key, value)
     661 + if key == "rollbacking" then
     662 + handler.__hook.rollbacking = value
     663 + else
     664 + handler[key] = value
     665 + end
     666 + end
     667 + 
     668 + handler.rollback = function ()
     669 + handler.__hook:rollback()
     670 + end
     671 + 
     672 + handler.patch = function (...)
     673 + handler.__hook:write(handler.offset, ...)
     674 + handler.__hook:push()
     675 + end
     676 + 
     677 + handler.read = function (num)
     678 + return handler.__hook:read(handler.offset, num)
     679 + end
     680 + 
     681 + setmetatable(handler, mt)
     682 + 
     683 + return handler
     684 +end
     685 + 
     686 +memapi.__patch = function (self, offset, ...)
     687 + return memapi.__patchconstr(self, offset, ...)
     688 +end
     689 + 
     690 +memapi.hook = function(libname) -- you can use shortname, like "l2cpp" instead of "libil2cpp"
     691 + local handler = {}
     692 + handler.target_info = gg.getTargetInfo()
     693 + handler.user_libname = libname
     694 + handler.is_hooked = false
     695 + handler.base_offset = nil
     696 + handler.end_offset = nil
     697 + handler.libname = nil
     698 + handler.op_buffer = {} -- we keep old memory values here (10 last operations) for rollbacking
     699 + handler.write_buffer = {} -- we keep all write operations here, then writing it on :push()
     700 + handler.debug = false
     701 + handler.rollbacking = false
     702 + 
     703 + handler.arch = memapi.__arch
     704 + handler.attach = memapi.__attach
     705 +
     706 + handler.read = memapi.__read
     707 + handler.write = memapi.__write
     708 + handler.push = memapi.__push
     709 + handler.rollback = memapi.__rollback
     710 + handler.__write32 = memapi.__write32
     711 + handler.__write64 = memapi.__write64
     712 + 
     713 + handler.asm = memapi.asm
     714 + handler.disasm = memapi.disasm
     715 + 
     716 + handler.bswitch = memapi.__bswitch
     717 + handler.switch = memapi.__bswitch
     718 + handler.patch = memapi.__patch
     719 + 
     720 + return handler
     721 +end
     722 + 
     723 +return memapi
Please wait...
Page is in error, reload to recover