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]
|
|