--
if not _cutsomJumpCall then
_pidContext = _pidContext or {now=os.clock()+3; reset=os.clock()+60}
function getPidContext()
local p, pid, now = _pidContext, getOpenedProcessID(), os.clock()
if now > p.reset then
p.reset = now + 60
local ps = getProcessList()
for k,v in pairs(p)do
if type(k)=='number' and (not ps[k] or ps[k]~=v[1]) then p[k] = nil end
end
end
if now > p.now and not readInteger(process)then
return {}
elseif p[pid] and now<p.now and p.pid == pid and p.process==process then
return p[pid][2]
elseif not readInteger(process) then
return {}
end
p.now, p.pid, p.process = now+3, pid, process
if not p[pid] or p[pid][1]~=process then
local px = enumModules()[1]
p[pid] = {process,{PID=pid,PROCESS=process,ExeBase=px.Address, ExeFile=px.PathToFile,ExeSize=getModuleSize(process)}}
end
return p[pid][2]
end
getPidContext()
local EMPTY = {}
local function toInt(n)return type(n)=='number'and math.tointeger(n)end
function GetTrampoline(target, hint, noNewAlloc)
if not toInt(target)or not toInt(hint) then return nil end
local p = getPidContext()
p.Trampoline = p.Trampoline or {}
local t,tcnt, diff = p.Trampoline,0
for from, to in pairs(t) do
diff = from - hint
if diff>-0x7ffffffb and diff<0x80000005 then
if to==target then return from end
if to==EMPTY then
local bs, r = string.pack('I8I8',0xb8480000000225ff ,target),{}
for c in bs:gmatch'.'do r[1+#r]=c:byte()end
if writeBytes(from, r)==16 then
t[from] = target
return from
end
end
end
end
-- no previous allocation, make new one
if not noNewAlloc then
local addr = allocateMemory(0x1000,hint)
diff = addr and addr - hint
if not diff or diff<=-0x7ffffffb or diff>=0x7ffff005 then
if addr then deAlloc(addr)end
return nil,'fail allocate trampoline'
end
p.TrmpAllocCnt = not p.TrmpAllocCnt and 1 or p.TrmpAllocCnt + 1
for i=0,255 do t[addr+i*16]=EMPTY end
return GetTrampoline(target, hint, true)
end
end
if _cutsomJumpCall then
_cutsomJumpCall = nil,unregisterAssembler(_cutsomJumpCall)
end
_cutsomJumpCall = registerAssembler(function (addr, inst)
local force, target, isJmp, forceShort, forceNear, forceLong =
inst:match'^%s*[jJ][mM][pP]!(%a*)%s+(.-)%s*$'
if target then isJmp = true else
force, target = inst:match'^%s*[cC][aA][lL][lL]!(%a*)%s+(.-)%s*$'
end
if not target then return end
target = target and target:len()>1 and GetAddressSafe(target)
if target and force:len()>1 then
force=force:lower()
if force=='short' then forceShort = true-- should be redundancy?
elseif force=='near' then forceNear = true
elseif force=='long' then forceLong = true
else target = nil end -- unknown jump distance modifier, error
end
if not target then
return --nil,'invalid :'..inst
else
local cmd = isJmp and {0xeb,0xe9,0x25ff} or {0xe8,0xe8,0x08eb0000000215ff}
local diff, r, bs = target - addr, {}
if isJmp and (forceShort or not forceNear and not forceLong) and diff>-0x7e and diff <0x82 then
bs = string.pack('Bb',cmd[1], diff-2)
elseif not targetIs64Bit() or not forceLong and diff>-0x7ffffffb and diff<0x80000005 then
bs = string.pack('Bi4',cmd[2],diff-5)
elseif not forceNear or addr<0x1000 then
if isJmp then
bs = string.pack('I6I8',cmd[3],target)
else
bs = string.pack('I8I8',cmd[3],target)
end
elseif diff<=-0x7ffffffb or diff>=0x80000005 then
local trmp, errmsg = GetTrampoline(target, addr)
if not trmp then return nil,(errmsg or '!')..', no trampoline:'..inst end
bs = string.pack('Bi4',cmd[2], trmp - addr -5)
end
if bs then
for c in bs:gmatch'.' do r[1+#r]=c:byte()end
return r
end
end
end)
end --- cutsomJumpCall