Guest User

Untitled

a guest
Jun 7th, 2011
360
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. local ffi = require"ffi"
  2. -- We write our own machine code, which is currently only done for x86.
  3. assert(ffi.arch == "x86")
  4. -- The definitions we want to use.
  5. ffi.cdef[[
  6.   typedef void* HWND;
  7.   typedef bool (*WNDENUMPROC)(HWND, long);
  8.   bool EnumChildWindows(HWND hWndParent, WNDENUMPROC lpEnumFunc, long lParam);
  9.   int GetWindowTextA(HWND hWnd, char* lpString, int nMaxCount);
  10. ]]
  11. -- Extra definitions we need for performing contortions with fibers.
  12. ffi.cdef[[
  13.   void* ConvertThreadToFiber(void* lpParameter);
  14.   void SwitchToFiber(void* lpFiber);
  15.   typedef void (*LPFIBER_START_ROUTINE)(void*);
  16.   void* CreateFiber(size_t dwStackSize, LPFIBER_START_ROUTINE lpStartAddress, void* lpParameter);
  17.   uint32_t GetLastError(void);
  18.   void* VirtualAlloc(void* lpAddress, size_t dwSize, uint32_t flAllocationType, uint32_t flProtect);
  19. ]]
  20.  
  21. local EnumChildWindows
  22. do
  23.   local GetLastError = ffi.C.GetLastError
  24.   local contortion_fiber
  25.   local procs
  26.   local transfer_slot
  27.   local init_callbacks
  28.   init_callbacks = function()
  29.     -- Ensure that the thread is a fiber, converting if required.
  30.     local our_fiber = ffi.C.ConvertThreadToFiber(nil)
  31.     if our_fiber == nil and GetLastError() ~= 1280 then
  32.       error("Unable to convert thread to fiber")
  33.     end
  34.     transfer_slot = ffi.new("void*[2]")
  35.     -- fiber_proc: for(;;) {
  36.     --               EnumChildWindows(transfer_slot[0], enum_proc, 0);
  37.     --               transfer_slot[1] = 0; // to mark end of iteration
  38.     --               SwitchToFiber(our_fiber);
  39.     --             }
  40.     local asm = "\x6A\x00" -- push 0
  41.              .. "\x68????" -- push ????
  42.              .. "\xA1????\x50" -- mov eax, dword ptr [????], push eax
  43.              .. "\xE8????" -- call ????
  44.              .. "\xC7\x05????\x00\x00\x00\x00" -- mov dword ptr [????], 0
  45.              .. "\x68????" -- push ????
  46.              .. "\xE8????" -- call ????
  47.              .. "\xEB\xD8" -- jmp $-40
  48.     -- enum_proc: transfer_slot[0] = *(esp+4); // the HWND
  49.     --            SwitchToFiber(our_fiber);
  50.     --            return TRUE;
  51.              .. "\x8B\x44\x24\x04" -- mov eax, dword ptr [esp+4]
  52.              .. "\x3E\xA3????" -- mov dword ptr [????], eax
  53.              .. "\x68????" -- push ????
  54.              .. "\xE8????" -- call ????
  55.              .. "\x33\xC0\x40" -- mov eax, 1
  56.              .. "\xC2\x08" -- retn 8 (*)
  57.     procs = ffi.C.VirtualAlloc(nil, #asm + 1, 0x3000, 0x40)
  58.     if our_fiber == nil then
  59.       -- GetCurrentFiber()
  60.       ffi.copy(procs, "\x64\xA1\x10\x00\x00\x00\xC3") -- return __readfsdword(0x10)
  61.       our_fiber = ffi.cast("void*(*)(void)", procs)()
  62.     end
  63.     ffi.copy(procs, asm)
  64.     local function fixup(offset, ptr, isrelative)
  65.       local dst = ffi.cast("char*", procs) + offset
  66.       ptr = ffi.cast("char*", ptr)
  67.       if isrelative then
  68.         ptr = ffi.cast("char*", ptr - (dst + 4))
  69.       end
  70.       ffi.cast("char**", dst)[0] = ptr
  71.     end
  72.     fixup( 3, ffi.cast("char*", procs) + 40)
  73.     fixup( 8, transfer_slot)
  74.     fixup(14, ffi.C.EnumChildWindows, true)
  75.     fixup(20, transfer_slot + 1)
  76.     fixup(29, our_fiber)
  77.     fixup(34, ffi.C.SwitchToFiber, true)
  78.     fixup(46, transfer_slot)
  79.     fixup(51, our_fiber)
  80.     fixup(56, ffi.C.SwitchToFiber, true)
  81.     contortion_fiber = ffi.C.CreateFiber(1024, ffi.cast("LPFIBER_START_ROUTINE", procs), nil)
  82.     init_callbacks = function() end
  83.   end
  84.   EnumChildWindows = function(wnd)
  85.     init_callbacks()
  86.     transfer_slot[0] = wnd
  87.     transfer_slot[1] = ffi.cast("void*", 1)
  88.     local results = {}
  89.     while true do
  90.       ffi.C.SwitchToFiber(contortion_fiber)
  91.       if transfer_slot[1] == nil then
  92.         return results
  93.       else
  94.         results[#results + 1] = transfer_slot[0]
  95.       end
  96.     end
  97.   end
  98. end
  99.  
  100. -- Example of using EnumChildWindows()
  101. -- it takes a HWND and returns a table of HWNDs
  102. local namebuf = ffi.new("char[300]")
  103. for _, wnd in ipairs(EnumChildWindows(nil)) do
  104.   local len = ffi.C.GetWindowTextA(wnd, namebuf, 300)
  105.   if len ~= 0 then
  106.     print(ffi.string(namebuf, len))
  107.   end
  108. end
RAW Paste Data