Last active
January 30, 2023 07:33
-
-
Save Youka/0c44171e868377e8d496 to your computer and use it in GitHub Desktop.
Run machine code with LuaJIT (Windows x86)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Load foreign-function-interface handle | |
local ffi = require("ffi") | |
-- Shortcut FFI C namespace | |
local C = ffi.C | |
-- Load Windows kernel32 DLL | |
local kernel32 = ffi.load("kernel32") | |
-- Add C definitions to FFI for usage descriptions of components | |
ffi.cdef([[ | |
// Redefinitions for WinAPI conventions | |
typedef void VOID; | |
typedef VOID* LPVOID; | |
typedef uintptr_t ULONG_PTR; | |
typedef ULONG_PTR SIZE_T; | |
typedef unsigned long DWORD; | |
typedef int BOOL; | |
// Property flags for functions below | |
enum{ | |
MEM_COMMIT = 0x1000, | |
MEM_RESERVE = 0x2000 | |
}; | |
enum{ | |
PAGE_EXECUTE_READWRITE = 0x40 | |
}; | |
enum{ | |
MEM_RELEASE = 0x8000 | |
}; | |
// Function headers for correct Lua->C->Lua conversions | |
LPVOID __stdcall VirtualAlloc(LPVOID, SIZE_T, DWORD, DWORD); | |
BOOL __stdcall VirtualFree(LPVOID, SIZE_T, DWORD); | |
]]) | |
-- Metatable for C function wrapping | |
local func_mt = { | |
__call = function(obj, ...) | |
return obj[1](...) | |
end, | |
__tostring = function(obj) | |
return tostring(obj[1]) | |
end | |
} | |
-- Converts machine code to function | |
local function mem2func(header, code) | |
-- Check arguments | |
if type(header) ~= "string" or type(code) ~= "table" then | |
error("Expected function header as string and machine code as table!", 2) | |
end | |
-- Get code size | |
local code_n = #code | |
-- Allocate memory with executable rights | |
local exec_memory = kernel32.VirtualAlloc(nil, code_n, C.MEM_COMMIT + C.MEM_RESERVE, C.PAGE_EXECUTE_READWRITE) | |
if not exec_memory then | |
error("Couldn't allocate memory with execution rights!", 2) | |
end | |
ffi.gc(exec_memory, function(memory) kernel32.VirtualFree(memory, 0, C.MEM_RELEASE) end) | |
-- Copy code into executable memory | |
ffi.copy(exec_memory, ffi.new("char[?]", code_n, code), code_n) | |
-- Return executable memory as function (packed in table with memory to keep her safe from garbage collection) | |
return setmetatable( | |
{ffi.cast(header, exec_memory), exec_memory}, | |
func_mt | |
) | |
end | |
-- Test | |
local func = mem2func("int (*)(int, int)", {0x8b, 0x44, 0x24, 0x08, 0x03, 0x44, 0x24, 0x04, 0xc3}) | |
--[[ | |
0: 8b 44 24 08 mov 0x8(%esp),%eax | |
4: 03 44 24 04 add 0x4(%esp),%eax | |
8: c3 ret | |
]] | |
print(func(-1, 4)) -- 3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment