juntalis Newbie cheater
  Reputation: 2
  Joined: 13 Mar 2013 Posts: 12
 
  | 
		
			
				 Posted: Sun Dec 07, 2014 12:04 pm    Post subject: Lua FFI Plugin | 
				        | 
			 
			
				
  | 
			 
			
				Edit: Not sure when or what changed, but it looks like this plugin is no longer needed, as the ffi C-extension loads and works fine when the binaries are placed in the clibs32/clibs64 folders. I went ahead and added a new release containing the FFI binaries built against CE's customized Lua 5.3. (Up to date as of CE 6.5)
 
 
Original Post
 
 
 	  | Quote: | 	 		  
 
I wrote (using the word loosely) this plugin sometime back in 2013, and ended up losing interest in the project before I ever got around to making it release-worthy. Furthermore, I took a strange approach when loading in the Lua extension, and I don't really remember why. Regardless, it's worked for the last year, and I probably won't ever go back and clean it up, so I figured I'd go ahead and release it.
 
 
I've gone ahead and thrown the project up on github, but since I'm unable to post urls at this time, you'll have to navigate there on your own: juntalis/ce-luacontrib
 
 
Examples
 
 
 	  | Code: | 	 		  
 
local ffi = require('ffi')
 
 
-- Load all of our DLLs
 
local ntdll = ffi.load('ntdll.dll')
 
local kernel32 = ffi.load('kernel32.dll')
 
local user32 = ffi.load('user32.dll')
 
local msvcrt = ffi.load('msvcrt.dll')
 
 
--[[--
 
  CRT Declarations (msvcrt.dll)
 
--]]--
 
ffi.cdef[[
 
unsigned int wcstombs(char* s, const wchar_t* w, unsigned int c);
 
unsigned int mbstowcs(wchar_t* w, const char* s, unsigned int c);
 
unsigned int wcslen(const wchar_t* s);
 
unsigned int strlen(const char* s);
 
char *strcpy(char* d, const char* s);
 
]]
 
 
--[[--
 
  Lua wrapper functions for the above declarations.
 
--]]--
 
 
function wcslen(ws)
 
   return tonumber(
 
      msvcrt.wcslen(
 
         ffi.cast('const wchar_t*', ws)
 
      )
 
   )
 
end
 
 
function wstr2str(ws, length)
 
   local szbuf = length or wcslen(ws)
 
   local buf = ffi.new('char[?]', szbuf+1)
 
   if msvcrt.wcstombs(buf, ffi.cast('const wchar_t*', ws), szbuf) == -1 then
 
      return nil
 
   end
 
   return ffi.string(buf, szbuf)
 
end
 
 
function str2wstr(s)
 
   local szbuf = s:len()
 
   local buf = ffi.new('wchar_t[?]', szbuf+1)
 
   if msvcrt.mbstowcs(buf, s, szbuf) == -1 then
 
      return nil
 
   end
 
   return buf
 
end
 
 
function str2cstr(s)
 
   local szbuf = s:len()
 
   local buf = ffi.new('char[?]', szbuf+1)
 
   msvcrt.strcpy(buf, s)
 
   return buf
 
end
 
 
--[[--
 
  Native Declarations (ntdll.dll)
 
--]]--
 
ffi.cdef[[
 
typedef union _LARGE_INTEGER {
 
   struct
 
   {
 
      unsigned long   LowPart;
 
      long         HighPart;
 
   } s;
 
   struct
 
   {
 
      unsigned long   LowPart;
 
      long         HighPart;
 
   } u;
 
   long long   QuadPart;
 
} LARGE_INTEGER;
 
 
typedef struct _UNICODE_STRING {
 
   unsigned short   Length;
 
   unsigned short   MaximumLength;
 
   wchar_t         ***Buffer;
 
} UNICODE_STRING;
 
 
typedef struct _SYSTEM_PROCESS_INFORMATION_DETAILD {
 
   unsigned long   NextEntryOffset;
 
   unsigned long   NumberOfThreads;
 
   LARGE_INTEGER   SpareLi1;
 
   LARGE_INTEGER   SpareLi2;
 
   LARGE_INTEGER   SpareLi3;
 
   LARGE_INTEGER   CreateTime;
 
   LARGE_INTEGER   UserTime;
 
   LARGE_INTEGER   KernelTime;
 
   UNICODE_STRING   ImageName;
 
   long         BasePriority;
 
   void         *UniqueProcessId;
 
   unsigned long   InheritedFromUniqueProcessId;
 
   unsigned long   HandleCount;
 
   unsigned char   Reserved4[4];
 
   void         *Reserved5[11];
 
   unsigned long   PeakPagefileUsage;
 
   unsigned long   PrivatePageCount;
 
   LARGE_INTEGER   Reserved6[6];
 
} SYSTEM_PROCESS_INFORMATION_DETAILD, *PSYSTEM_PROCESS_INFORMATION_DETAILD;
 
 
long NtQuerySystemInformation(unsigned long, void*, unsigned long, unsigned long*);
 
]]
 
 
-- Constants
 
local SystemProcessInformation = 5
 
 
--[[--
 
  Given a process's PID, return the filename of the executable.
 
--]]--
 
function pid2name(pid)
 
   local status, result, psinfo, retlength =
 
        0, nil,
 
        ffi.cast('PSYSTEM_PROCESS_INFORMATION_DETAILD', ffi.new('unsigned char[?]', 102400)),
 
        ffi.new('unsigned long[1]')
 
   
 
   status = tonumber(ntdll.NtQuerySystemInformation(
 
      SystemProcessInformation,
 
      ffi.cast('void*', psinfo),
 
      102400,
 
      result
 
   ))
 
   
 
   if status ~= 0 then return result end
 
   while (status == 0) and (tonumber(psinfo.NextEntryOffset) > 0) do
 
      if pid == tonumber(psinfo.UniqueProcessId) then
 
         result = cutil.wstr2str(psinfo.ImageName.Buffer, psinfo.ImageName.Length - 4)
 
         status = 1
 
      else
 
         psinfo = ffi.cast(
 
            'PSYSTEM_PROCESS_INFORMATION_DETAILD',
 
            tonumber(ffi.cast('void*', psinfo)) + psinfo.NextEntryOffset
 
         )
 
      end
 
   end
 
   
 
   return result
 
end
 
 
--[[--
 
  Win32 API Declarations (user32.dll, kernel32.dll)
 
--]]--
 
ffi.cdef[[
 
typedef void* HWND, *LPARAM;
 
typedef signed long BOOL;
 
typedef unsigned long DWORD;
 
typedef DWORD* LPDWORD;
 
typedef BOOL(__stdcall* WNDENUMPROC)(HWND hWnd, LPARAM lParam);
 
 
typedef struct _ENUMPARAM {
 
   HWND hWnd;
 
   DWORD PID;
 
} ENUMPARAM, *PENUMPARAM;
 
 
HWND SetFocus(HWND hWnd);
 
DWORD GetCurrentThreadId(void);
 
HWND GetForegroundWindow(void);
 
BOOL BringWindowToTop(HWND hWnd);
 
BOOL SetForegroundWindow(HWND hWnd);
 
BOOL EnumWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam);
 
DWORD GetWindowThreadProcessId(HWND hWnd, LPDWORD lpdwProcessId);
 
BOOL AttachThreadInput(DWORD idAttach, DWORD idAttachTo, BOOL fAttach);
 
]]
 
 
-- Constants & Explicit Imports
 
local TRUE,FALSE = 1,0
 
local GetCurrentThreadId = kernel32.GetCurrentThreadId
 
local SetFocus = user32.SetFocus
 
local GetForegroundWindow = user32.GetForegroundWindow
 
local BringWindowToTop = user32.BringWindowToTop
 
local SetForegroundWindow = user32.SetForegroundWindow
 
local EnumWindows = user32.EnumWindows
 
local GetWindowThreadProcessId = user32.GetWindowThreadProcessId
 
local AttachThreadInput = user32.AttachThreadInput
 
 
local enumWndsProc = ffi.cast('WNDENUMPROC', function(hWnd, lParam)
 
   local lpdwPID = ffi.new('DWORD[1]')
 
   local ep = ffi.cast('PENUMPARAM', lParam)
 
   GetWindowThreadProcessId(hWnd, lpdwPID)
 
   if ep[0].PID == lpdwPID[0] then
 
      ep[0].hWnd = hWnd
 
      return FALSE
 
   end
 
   return TRUE
 
end)
 
 
-- Obviously this function suffers a few serious
 
-- flaws. It only returns the first window found
 
-- for a particular PID, so if your target has more
 
-- than one window open, there's no guarantee that
 
-- you're finding the window you're looking for.
 
pid2hwnd = function(pid)
 
   pid = pid or getOpenedProcessID()
 
   local ep = ffi.new('ENUMPARAM[1]')
 
   ep[0].hWnd = nil
 
   ep[0].PID  = pid
 
   EnumWindows(enumWndsProc, ffi.cast('LPARAM', ep))
 
   return ep[0].hWnd
 
end
 
 
setForegroundWindow = function(hWnd)
 
   local dwFgPID = ffi.new('DWORD[1]')
 
   local hWndFg = GetForegroundWindow()
 
   local dwFgTID = GetWindowThreadProcessId(hWndFg, dwFgPID)
 
   local dwMyTID = GetCurrentThreadId()
 
   AttachThreadInput(dwMyTID, dwFgTID, TRUE)
 
   SetForegroundWindow(hWnd)
 
   BringWindowToTop(hWnd)
 
   SetFocus(hWnd)
 
   AttachThreadInput(dwMyTID, dwFgTID, False)
 
end
 
 | 	  
 
 
One of the ways I've been using it:
 
 
 	  | Code: | 	 		  
 
--[[--
 
  Code below is in its own file under the lua folder.(startup.lua)
 
--]]--
 
function _M.onOpenProcess(pid)
 
   local procname = ntdll.pid2name(pid)
 
   while (pid == 0) or (procname == nil) do
 
      sleep(500)
 
      pid = getOpenedProcessID()
 
      procname = ntdll.pid2name(pid)
 
   end
 
   
 
   startAutoChecks()
 
   for i,fn in ipairs(getpriv('onstartup')) do fn() end
 
   setpriv('onstartup', nil)
 
end
 
 
--[[--
 
  Code found in my main autorun script.
 
--]]--
 
onOpenProcess = require('startup').onOpenProcess
 
 | 	  
 
 
 
Note: Not sure why noblanks.exe is in this project's folder, but here's the source for that, too: (The executable was compiled using pypy translators)
 
 
 	  | Code: | 	 		  
 
import os, sys
 
 
 
def entry_point(argv):
 
   #stdin = os.open(0, os.O_RDONLY, 0777)
 
   stdin = 0
 
   app_running = True
 
   while app_running:
 
      # Readline implementation.
 
      line = ""
 
      count = 0
 
      while True:
 
         c = os.read(stdin, 1)
 
         if len(c) == 0:
 
            app_running = False
 
            break
 
         elif c == '\n':
 
            break
 
         elif c == "\r":
 
            continue
 
         elif c != ' ' and c != '\t':
 
            count += 1
 
         line += c
 
      
 
      # Check count. If 0, skip the line.
 
      if count == 0:
 
         continue
 
      print line
 
   return 0
 
 
def target(*args):
 
   return entry_point, None
 
 
if __name__ == "__main__":
 
   entry_point(sys.argv)
 
 | 	 
  | 	  [/quote]
 | 
			 
		  |