Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local ffi = require"ffi"
- -- We write our own machine code, which is currently only done for x86.
- assert(ffi.arch == "x86")
- -- The definitions we want to use.
- ffi.cdef[[
- typedef void* HWND;
- typedef bool (*WNDENUMPROC)(HWND, long);
- bool EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc, long lParam);
- int GetWindowTextA(HWND hWnd, char* lpString, int nMaxCount);
- ]]
- -- Extra definitions we need for performing contortions with fibers.
- ffi.cdef[[
- void* ConvertThreadToFiber(void* lpParameter);
- void SwitchToFiber(void* lpFiber);
- typedef void (*LPFIBER_START_ROUTINE)(void*);
- void* CreateFiber(size_t dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, void* lpParameter);
- uint32_t GetLastError(void);
- void* VirtualAlloc(void* lpAddress, size_t dwSize, uint32_t flAllocationType, uint32_t flProtect);
- ]]
- local EnumChildWindows
- do
- local GetLastError = ffi.C.GetLastError
- local contortion_fiber
- local procs
- local transfer_slot
- local init_callbacks
- init_callbacks = function()
- -- Ensure that the thread is a fiber, converting if required.
- local our_fiber = ffi.C.ConvertThreadToFiber(nil)
- if our_fiber == nil and GetLastError() ~= 1280 then
- error("Unable to convert thread to fiber")
- end
- transfer_slot = ffi.new("void*[2]")
- -- fiber_proc: for(;;) {
- -- EnumChildWindows(transfer_slot[0], enum_proc, 0);
- -- transfer_slot[1] = 0; // to mark end of iteration
- -- SwitchToFiber(our_fiber);
- -- }
- local asm = "\x6A\x00" -- push 0
- .. "\x68????" -- push ????
- .. "\xA1????\x50" -- mov eax, dword ptr [????], push eax
- .. "\xE8????" -- call ????
- .. "\xC7\x05????\x00\x00\x00\x00" -- mov dword ptr [????], 0
- .. "\x68????" -- push ????
- .. "\xE8????" -- call ????
- .. "\xEB\xD8" -- jmp $-40
- -- enum_proc: transfer_slot[0] = *(esp+4); // the HWND
- -- SwitchToFiber(our_fiber);
- -- return TRUE;
- .. "\x8B\x44\x24\x04" -- mov eax, dword ptr [esp+4]
- .. "\x3E\xA3????" -- mov dword ptr [????], eax
- .. "\x68????" -- push ????
- .. "\xE8????" -- call ????
- .. "\x33\xC0\x40" -- mov eax, 1
- .. "\xC2\x08" -- retn 8 (*)
- procs = ffi.C.VirtualAlloc(nil, #asm + 1, 0x3000, 0x40)
- if our_fiber == nil then
- -- GetCurrentFiber()
- ffi.copy(procs, "\x64\xA1\x10\x00\x00\x00\xC3") -- return __readfsdword(0x10)
- our_fiber = ffi.cast("void*(*)(void)", procs)()
- end
- ffi.copy(procs, asm)
- local function fixup(offset, ptr, isrelative)
- local dst = ffi.cast("char*", procs) + offset
- ptr = ffi.cast("char*", ptr)
- if isrelative then
- ptr = ffi.cast("char*", ptr - (dst + 4))
- end
- ffi.cast("char**", dst)[0] = ptr
- end
- fixup( 3, ffi.cast("char*", procs) + 40)
- fixup( 8, transfer_slot)
- fixup(14, ffi.C.EnumChildWindows, true)
- fixup(20, transfer_slot + 1)
- fixup(29, our_fiber)
- fixup(34, ffi.C.SwitchToFiber, true)
- fixup(46, transfer_slot)
- fixup(51, our_fiber)
- fixup(56, ffi.C.SwitchToFiber, true)
- contortion_fiber = ffi.C.CreateFiber(1024, ffi.cast("LPFIBER_START_ROUTINE", procs), nil)
- init_callbacks = function() end
- end
- EnumChildWindows = function(wnd)
- init_callbacks()
- transfer_slot[0] = wnd
- transfer_slot[1] = ffi.cast("void*", 1)
- local results = {}
- while true do
- ffi.C.SwitchToFiber(contortion_fiber)
- if transfer_slot[1] == nil then
- return results
- else
- results[#results + 1] = transfer_slot[0]
- end
- end
- end
- end
- -- Example of using EnumChildWindows()
- -- it takes a HWND and returns a table of HWNDs
- local namebuf = ffi.new("char[300]")
- for _, wnd in ipairs(EnumChildWindows(nil)) do
- local len = ffi.C.GetWindowTextA(wnd, namebuf, 300)
- if len ~= 0 then
- print(ffi.string(namebuf, len))
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement