Rework launcher logic
This commit is contained in:
parent
6c94aad9b2
commit
b015c0cce4
@ -112,7 +112,7 @@ void init_injection(HMODULE hModule) {
|
||||
load_mice_config();
|
||||
|
||||
// We're in a new context now, so need to reconfigure
|
||||
setup_logging();
|
||||
setup_logging(GetParentProcessId());
|
||||
log_info(plfBoot, "Handover complete. Now executing within %ls", exeName);
|
||||
|
||||
init_com_devices();
|
||||
|
@ -261,7 +261,7 @@ unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCo
|
||||
jvs_read(gpioByteIndex);
|
||||
jvs_read(gpioByteData);
|
||||
log_warning(plfMxJvs, "GPIO%d Unhandled: [%02x]=%02x",
|
||||
(cmd - JVS_CMD_WRITE_GPIO2) + 1, gpioByteIndex, gpioByteData);
|
||||
(cmd - JVS_CMD_WRITE_GPIO2) + 2, gpioByteIndex, gpioByteData);
|
||||
break;
|
||||
|
||||
case JVS_CMD_COIN_DECREASE:
|
||||
|
@ -6,26 +6,35 @@ const wchar_t* HOOK_BINARIES[] = {
|
||||
L"app\\GmSync.exe",
|
||||
};
|
||||
|
||||
#define DISABLE_PROC_SPAWNING
|
||||
|
||||
BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags, LPVOID lpEnvironment,
|
||||
LPCSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation) {
|
||||
if (dwCreationFlags & CREATE_SUSPENDED) {
|
||||
return TrueCreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes,
|
||||
lpThreadAttributes, bInheritHandles, dwCreationFlags,
|
||||
lpEnvironment, lpCurrentDirectory, lpStartupInfo,
|
||||
lpProcessInformation);
|
||||
}
|
||||
|
||||
log_info(plfProcesses, "CreateProcessA %s %s", lpApplicationName, lpCommandLine);
|
||||
|
||||
return TrueCreateProcessA("mxAuthDisc.bat", "", lpProcessAttributes,
|
||||
lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment,
|
||||
lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
|
||||
// return TrueCreateProcessA("mxAuthDisc.bat", "", lpProcessAttributes, lpThreadAttributes,
|
||||
// bInheritHandles, dwCreationFlags, lpEnvironment,
|
||||
// lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
|
||||
|
||||
HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
SetEvent(fake_evt);
|
||||
// HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
// SetEvent(fake_evt);
|
||||
|
||||
HANDLE hProcess = start_and_inject(INVALID_HANDLE_VALUE, lpApplicationName, lpCommandLine,
|
||||
MICELIB, FALSE, 0, "", 0);
|
||||
|
||||
if (lpProcessInformation) {
|
||||
lpProcessInformation->hProcess = fake_evt;
|
||||
lpProcessInformation->hProcess = hProcess;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
||||
@ -34,61 +43,72 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
|
||||
DWORD dwCreationFlags, LPVOID lpEnvironment,
|
||||
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation) {
|
||||
// #ifdef DISABLE_PROC_SPAWNING
|
||||
// log_error(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
||||
// return FALSE;
|
||||
// #else
|
||||
log_info(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
|
||||
|
||||
// log_info(plfProcesses, "CreateProcessW %ls", lpApplicationName);
|
||||
|
||||
// lpProcessInformation->hThread = GetDummyHandle();
|
||||
// return TRUE;
|
||||
|
||||
CHAR applicationName[MAX_PATH + 1];
|
||||
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName,
|
||||
NULL, NULL);
|
||||
|
||||
HANDLE child;
|
||||
CHAR commandLine[MAX_PATH + 1];
|
||||
WCHAR commandLineW[MAX_PATH + 1];
|
||||
WCHAR micePathW[MAX_PATH + 1];
|
||||
GetModuleFileNameW(NULL, micePathW, MAX_PATH);
|
||||
int nMultiChars = WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, NULL, 0, NULL, NULL);
|
||||
LPSTR commandLine = malloc(nMultiChars);
|
||||
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, nMultiChars, NULL, NULL);
|
||||
|
||||
HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
SetEvent(fake_evt);
|
||||
// WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof
|
||||
// applicationName,
|
||||
// NULL, NULL);
|
||||
|
||||
// HANDLE child;
|
||||
// CHAR commandLine[MAX_PATH + 1];
|
||||
// WCHAR commandLineW[MAX_PATH + 1];
|
||||
// WCHAR micePathW[MAX_PATH + 1];
|
||||
// GetModuleFileNameW(NULL, micePathW, MAX_PATH);
|
||||
|
||||
// HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
// SetEvent(fake_evt);
|
||||
|
||||
// return TrueCreateProcessA(applicationName, commandLine, lpProcessAttributes, lpThreadAttributes,
|
||||
// bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory,
|
||||
// lpStartupInfo, lpProcessInformation);
|
||||
|
||||
HANDLE hProcess = start_and_inject(INVALID_HANDLE_VALUE, applicationName, commandLine, MICELIB,
|
||||
TRUE, 0, NULL, 0);
|
||||
if (lpProcessInformation) {
|
||||
lpProcessInformation->hProcess = fake_evt;
|
||||
lpProcessInformation->hProcess = hProcess;
|
||||
lpProcessInformation->hThread = GetDummyHandle();
|
||||
}
|
||||
|
||||
log_game(plfProcesses, "hP: %08x", hProcess);
|
||||
|
||||
return TRUE;
|
||||
|
||||
if (lpCommandLine != NULL) {
|
||||
log_error(plfProcesses, "!!");
|
||||
return FALSE;
|
||||
// WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL,
|
||||
// NULL);
|
||||
// child = start_and_inject(applicationName, commandLine, MICELIB, false, 0, NULL,
|
||||
// CREATE_NEW_CONSOLE);
|
||||
} else {
|
||||
dwCreationFlags |= CREATE_NEW_CONSOLE;
|
||||
wsprintfW(commandLineW, L"mice -b %ls", lpApplicationName);
|
||||
printf("%ls %ls\n", micePathW, commandLineW);
|
||||
BOOL ret =
|
||||
TrueCreateProcessW(L"mice.cmd", commandLineW, lpProcessAttributes, lpThreadAttributes,
|
||||
bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory,
|
||||
lpStartupInfo, lpProcessInformation);
|
||||
printf("%d\n", ret);
|
||||
return ret;
|
||||
// CHAR commandLine[]
|
||||
// child =
|
||||
// start_and_inject(applicationName, NULL, MICELIB, false, 0, NULL, CREATE_NEW_CONSOLE);
|
||||
}
|
||||
// if (lpCommandLine != NULL) {
|
||||
// log_error(plfProcesses, "!!");
|
||||
// return FALSE;
|
||||
// // WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine,
|
||||
// NULL,
|
||||
// // NULL);
|
||||
// // child = start_and_inject(INVALID_HANDLE_VALUE, applicationName, commandLine, MICELIB,
|
||||
// // false, 0, NULL,
|
||||
// // CREATE_NEW_CONSOLE);
|
||||
// } else {
|
||||
// dwCreationFlags |= CREATE_NEW_CONSOLE;
|
||||
// wsprintfW(commandLineW, L"mice -b %ls", lpApplicationName);
|
||||
// printf("%ls %ls\n", micePathW, commandLineW);
|
||||
// BOOL ret =
|
||||
// TrueCreateProcessW(L"mice.cmd", commandLineW, lpProcessAttributes,
|
||||
// lpThreadAttributes,
|
||||
// bInheritHandles, dwCreationFlags, lpEnvironment,
|
||||
// lpCurrentDirectory, lpStartupInfo, lpProcessInformation);
|
||||
// printf("%d\n", ret);
|
||||
// return ret;
|
||||
// // CHAR commandLine[]
|
||||
// // child =
|
||||
// // start_and_inject(INVALID_HANDLE_VALUE, applicationName, NULL, MICELIB, false, 0,
|
||||
// // NULL, CREATE_NEW_CONSOLE);
|
||||
// }
|
||||
|
||||
return !FAILED(child);
|
||||
// #endif
|
||||
// return !FAILED(child);
|
||||
// // #endif
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeGetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {
|
||||
|
@ -13,6 +13,7 @@ BOOL RemoveDataForHandle(HANDLE hObject, DWORD type);
|
||||
HANDLE GetDummyHandle();
|
||||
void BytesToHex(char* hex_buffer, BYTE* bytes, DWORD nbytes);
|
||||
void PrintStack(void);
|
||||
DWORD GetParentProcessId(void);
|
||||
|
||||
BOOL PathEqual(LPCSTR path1, LPCSTR path2);
|
||||
BOOL PathPrefix(LPCSTR path, LPCSTR prefix);
|
||||
|
@ -1,6 +1,7 @@
|
||||
#define _WIN32_WINNT 0x0600
|
||||
#include <Windows.h>
|
||||
#include <dbghelp.h>
|
||||
#include <tlhelp32.h>
|
||||
|
||||
#include "../hooks/files.h"
|
||||
|
||||
@ -156,15 +157,14 @@ void make_dirs(const char* path) {
|
||||
void* open_mapped_file(LPCWSTR path, DWORD size, HANDLE* file, HANDLE* file_mapping) {
|
||||
make_dirs(path);
|
||||
*file = _CreateFileW(path, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_ALWAYS,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (*file == INVALID_HANDLE_VALUE) {
|
||||
log_error(plfMisc, "Failed to CreateFileW(%ls): %d", path, GetLastError());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*file_mapping =
|
||||
CreateFileMappingW(*file, NULL, PAGE_READWRITE, 0, size, NULL);
|
||||
*file_mapping = CreateFileMappingW(*file, NULL, PAGE_READWRITE, 0, size, NULL);
|
||||
|
||||
if (*file_mapping == INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(*file);
|
||||
@ -179,10 +179,30 @@ void* open_mapped_file(LPCWSTR path, DWORD size, HANDLE* file, HANDLE* file_mapp
|
||||
if (mapping == NULL || GetLastError()) {
|
||||
log_error(plfMisc, "Failed to MapViewOfFileEx: %d", GetLastError());
|
||||
CloseHandle(*file);
|
||||
CloseHandle(*file_mapping);
|
||||
CloseHandle(*file_mapping);
|
||||
*file = INVALID_HANDLE_VALUE;
|
||||
*file_mapping = INVALID_HANDLE_VALUE;
|
||||
return NULL;
|
||||
}
|
||||
return mapping;
|
||||
}
|
||||
|
||||
DWORD GetParentProcessIdFor(DWORD pid) {
|
||||
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
|
||||
PROCESSENTRY32 pe = { 0 };
|
||||
pe.dwSize = sizeof(PROCESSENTRY32);
|
||||
|
||||
if (Process32First(h, &pe)) {
|
||||
do {
|
||||
if (pe.th32ProcessID == pid) {
|
||||
CloseHandle(h);
|
||||
return pe.th32ParentProcessID;
|
||||
}
|
||||
} while (Process32Next(h, &pe));
|
||||
}
|
||||
CloseHandle(h);
|
||||
return (DWORD)-1;
|
||||
}
|
||||
DWORD GetParentProcessId(void) {
|
||||
return GetParentProcessIdFor(GetCurrentProcessId());
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ int boot_delay = 0;
|
||||
char exe_name[MAX_PATH + 1] = "";
|
||||
char commandline[MAX_PATH + 1] = "";
|
||||
|
||||
void print_help(char* exe) {
|
||||
static void print_help(char* exe) {
|
||||
log_info(plfBoot, "Usage: %s [-h] [-t] [-b executable.exe] [-d]", exe);
|
||||
log_info(plfBoot, " -h: Print this help message and exit");
|
||||
log_info(plfBoot, " -b: Specify the game binary to use");
|
||||
@ -19,7 +19,7 @@ void print_help(char* exe) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
bool parse_cmdline(int argc, char* argv[]) {
|
||||
static bool parse_cmdline(int argc, char* argv[]) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0) {
|
||||
print_help(argv[0]);
|
||||
@ -77,9 +77,102 @@ bool parse_cmdline(int argc, char* argv[]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) {
|
||||
// Enable colour support in conhost
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hConsole, &dwMode))
|
||||
SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
|
||||
HANDLE hLogFile = INVALID_HANDLE_VALUE;
|
||||
if (MiceConfig.mice.log_to_file) {
|
||||
hLogFile = CreateFileA(MiceConfig.mice.log_file, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||
CREATE_ALWAYS, 0, NULL);
|
||||
if (hLogFile == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Failed to initialise logging: open %s failed: %d",
|
||||
MiceConfig.mice.log_file, GetLastError());
|
||||
ExitProcess(2);
|
||||
}
|
||||
}
|
||||
|
||||
OVERLAPPED ov;
|
||||
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
ov.Offset = ov.OffsetHigh = 0;
|
||||
ov.hEvent = hEvent;
|
||||
|
||||
char readBuffer[4096];
|
||||
DWORD nRead, nBytes;
|
||||
while (1) {
|
||||
nRead = nBytes = 0;
|
||||
ReadFile(*pSlot, readBuffer, sizeof readBuffer, &nRead, &ov);
|
||||
GetOverlappedResult(*pSlot, &ov, &nBytes, TRUE);
|
||||
DWORD nWrote;
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), readBuffer, nBytes, &nWrote, NULL);
|
||||
|
||||
if (hLogFile != INVALID_HANDLE_VALUE) {
|
||||
// The only VT100 sequences being used are colours, so this lazy approach works
|
||||
BOOL inVt100 = FALSE;
|
||||
for (int i = 0; i < nBytes; i++) {
|
||||
if (readBuffer[i] == '\033') {
|
||||
inVt100 = TRUE;
|
||||
continue;
|
||||
}
|
||||
if (inVt100 && readBuffer[i] == 'm') {
|
||||
inVt100 = FALSE;
|
||||
continue;
|
||||
}
|
||||
if (!inVt100) WriteFile(hLogFile, &(readBuffer[i]), 1, &nWrote, NULL);
|
||||
}
|
||||
FlushFileBuffers(hLogFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL setup_mailslot(void) {
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
char slotName[MAX_PATH + 1];
|
||||
sprintf_s(slotName, MAX_PATH, "\\\\.\\mailslot\\micelog%d", pid);
|
||||
|
||||
HANDLE* pSlot = malloc(sizeof(HANDLE));
|
||||
if (pSlot == NULL) {
|
||||
fprintf(stderr, "malloc(pSlot) failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
*pSlot = CreateMailslotA(slotName, 0, MAILSLOT_WAIT_FOREVER, NULL);
|
||||
if (*pSlot == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Creation of mailslot failed %d\n", GetLastError());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
CreateThread(NULL, 0, MiceMailslotWatcher, pSlot, 0, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Because logging is via a mailslot, we need to give it a chance to flush messages before
|
||||
* terminating. While we could engineer something overly fancy, the only situation this ever occurs
|
||||
* is in the main() function just below.
|
||||
*
|
||||
* I'll let the code speak for itself.
|
||||
*/
|
||||
static int terminate(int err) {
|
||||
Sleep(100);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
HANDLE hGameProc = INVALID_HANDLE_VALUE;
|
||||
HANDLE hJob = INVALID_HANDLE_VALUE;
|
||||
BOOL WINAPI MiceHandlerRoutine(DWORD CtrlType) {
|
||||
if (hJob != INVALID_HANDLE_VALUE) CloseHandle(hJob);
|
||||
// if (hGameProc != INVALID_HANDLE_VALUE) TerminateProcess(hGameProc, 0);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
load_mice_config();
|
||||
setup_logging();
|
||||
if (!setup_mailslot()) return 1;
|
||||
setup_logging(GetCurrentProcessId());
|
||||
|
||||
log_info(plfBoot, "Micetools version: %s", MICE_VERSION);
|
||||
|
||||
@ -87,7 +180,7 @@ int main(int argc, char* argv[]) {
|
||||
GetCurrentDirectory(MAX_PATH, workDir);
|
||||
log_info(plfBoot, "Current directory: %s", workDir);
|
||||
|
||||
if (!parse_cmdline(argc, argv)) return 0;
|
||||
if (!parse_cmdline(argc, argv)) return terminate(0);
|
||||
|
||||
if (exe_name[0] == '\0' && MiceConfig.launcher.game_binary[0] != '\0') {
|
||||
snprintf(exe_name, sizeof exe_name, "%s", MiceConfig.launcher.game_binary);
|
||||
@ -98,13 +191,13 @@ int main(int argc, char* argv[]) {
|
||||
if (exe_name[0] == '\0') {
|
||||
if (!locate_game(exe_name, MAX_PATH + 1)) {
|
||||
log_error(plfBoot, "Fatal: Failed to locate a game");
|
||||
return 0;
|
||||
return terminate(0);
|
||||
}
|
||||
} else {
|
||||
DWORD dwAttrib = GetFileAttributes(exe_name);
|
||||
if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
log_error(plfBoot, "Fatal: %s: no such file found", exe_name);
|
||||
return 0;
|
||||
return terminate(0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -115,19 +208,26 @@ int main(int argc, char* argv[]) {
|
||||
char micepath[MAX_PATH + 1];
|
||||
if (!locate_library(micepath, MAX_PATH + 1)) {
|
||||
log_error(plfBoot, "Fatal: Failed to locate micelib. Check your mice_dll setting!");
|
||||
return 0;
|
||||
return terminate(0);
|
||||
}
|
||||
|
||||
char* extra_injections = MiceConfig.launcher.inject;
|
||||
HANDLE game_proc =
|
||||
start_and_inject(exe_name, commandline, micepath, debug_wait, boot_delay, extra_injections, 0);
|
||||
if (!game_proc) return -1;
|
||||
hJob = CreateJobObject(NULL, NULL);
|
||||
JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
|
||||
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info);
|
||||
|
||||
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {
|
||||
char* extra_injections = MiceConfig.launcher.inject;
|
||||
hGameProc = start_and_inject(hJob, exe_name, commandline, micepath, debug_wait, boot_delay,
|
||||
extra_injections, 0);
|
||||
if (!hGameProc) return terminate(-1);
|
||||
|
||||
SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE);
|
||||
|
||||
if (FAILED(WaitForSingleObject(hGameProc, INFINITE))) {
|
||||
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
|
||||
} else {
|
||||
log_info(plfBoot, "Shutting down");
|
||||
CloseHandle(game_proc);
|
||||
CloseHandle(hGameProc);
|
||||
}
|
||||
return 0;
|
||||
return terminate(0);
|
||||
}
|
||||
|
@ -14,8 +14,7 @@ COMMENT("")
|
||||
SECTION(mice, "General mice settings")
|
||||
COMMENT("Trace logging (6) is intensive, and should only be used when debugging")
|
||||
CFG_int(mice, log_level, 4, "1 = Game\n2 = Error\n3 = Warning\n4 = Info\n5 = Misc\n6 = Trace")
|
||||
CFG_bool(mice, log_to_file, false, "Also log out to log_file")
|
||||
CFG_int(mice, file_log_level, 5, "1 = Game\n2 = Error\n3 = Warning\n4 = Info\n5 = Misc\n6 = Trace")
|
||||
CFG_bool(mice, log_to_file, true, "Also log out to log_file")
|
||||
CFG_str(mice, log_file, "log.txt", "The file to log to if log_to_file is enabled")
|
||||
CFG_bool(mice, apply_patches, true, "Load and apply patches from patches_file at runtime")
|
||||
CFG_str(mice, patches_file, "patches.index", "The file to read patches from")
|
||||
|
@ -2,18 +2,20 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
bool inject_debug_wait(HANDLE process) {
|
||||
BOOL present;
|
||||
|
||||
fprintf(stderr, "Waiting for debugger to attach.\n");
|
||||
log_info(plfBoot, "Waiting for debugger to attach.");
|
||||
do {
|
||||
Sleep(1000);
|
||||
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
|
||||
fprintf(stderr, "Fatal: CheckRemoteDebuggerPresent failed: %03x\n", GetLastError());
|
||||
log_error(plfBoot, "Fatal: CheckRemoteDebuggerPresent failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
} while (!present);
|
||||
fprintf(stderr, "Debugger attached, resuming\n");
|
||||
log_info(plfBoot, "Debugger attached, resuming");
|
||||
return true;
|
||||
}
|
||||
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result) {
|
||||
@ -22,33 +24,33 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result
|
||||
LPVOID arg_addr =
|
||||
VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
||||
if (arg_addr == NULL) {
|
||||
fprintf(stderr, "Fatal: VirtualAllocEx failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: VirtualAllocEx failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
|
||||
fprintf(stderr, "Fatal: WriteProcessMemory failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: WriteProcessMemory failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
HANDLE remote_thread =
|
||||
CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
|
||||
if (remote_thread == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Fatal: CreateRemoteThread failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: CreateRemoteThread failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
|
||||
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: WaitForSingleObject failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(GetExitCodeThread(remote_thread, result))) {
|
||||
fprintf(stderr, "Fatal: GetExitCodeThread failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: GetExitCodeThread failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
if (*result == 0) {
|
||||
fprintf(stderr, "Fatal: GetExitCodeThread failed: result == 0\n");
|
||||
log_error(plfProcesses, "Fatal: GetExitCodeThread failed: result == 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -57,13 +59,13 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result
|
||||
bool inject_dll(HANDLE process, LPCSTR inject) {
|
||||
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32 == NULL) {
|
||||
fprintf(stderr, "Fatal: GetModuleHandleA failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: GetModuleHandleA failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
|
||||
if (addr_LoadLibraryA == NULL) {
|
||||
fprintf(stderr, "Fatal: GetProcAddress failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: GetProcAddress failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -71,8 +73,8 @@ bool inject_dll(HANDLE process, LPCSTR inject) {
|
||||
return remote_call(process, addr_LoadLibraryA, inject, &result);
|
||||
}
|
||||
|
||||
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait, DWORD delay,
|
||||
LPCSTR extra_injections, DWORD flags) {
|
||||
HANDLE start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait,
|
||||
DWORD delay, LPCSTR extra_injections, DWORD flags) {
|
||||
STARTUPINFOA startupInfo;
|
||||
PROCESS_INFORMATION processInformation = { 0 };
|
||||
|
||||
@ -87,27 +89,33 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wa
|
||||
// Does the exe we're starting exist?
|
||||
found = SearchPathA(NULL, path, NULL, 0, NULL, NULL);
|
||||
if (found == 0) {
|
||||
fprintf(stderr, "Fatal: Cannot start %s: not found\n", path);
|
||||
log_error(plfProcesses, "Fatal: Cannot start %s: not found", path);
|
||||
goto abort;
|
||||
}
|
||||
// Does the DLL we want to inject exist?
|
||||
found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
|
||||
if (found == 0) {
|
||||
fprintf(stderr, "Fatal: Cannot inject %s: not found\n", inject);
|
||||
goto abort;
|
||||
if (inject != NULL) {
|
||||
// Does the DLL we want to inject exist?
|
||||
found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
|
||||
if (found == 0) {
|
||||
log_error(plfProcesses, "Fatal: Cannot inject %s: not found", inject);
|
||||
goto abort;
|
||||
}
|
||||
}
|
||||
|
||||
// Start the binary
|
||||
flags |= CREATE_SUSPENDED;
|
||||
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, flags, NULL, NULL, &startupInfo,
|
||||
&processInformation)) {
|
||||
fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: CreateProcessA(%s, %s) failed: %d", path, cmdline,
|
||||
GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
if (hJob != INVALID_HANDLE_VALUE) AssignProcessToJobObject(hJob, processInformation.hProcess);
|
||||
|
||||
if (debug_wait)
|
||||
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
|
||||
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
|
||||
if (inject != NULL)
|
||||
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
|
||||
|
||||
if (extra_injections != NULL && extra_injections[0] != '\0') {
|
||||
char* copy = (char*)malloc(strlen(extra_injections) + 1);
|
||||
@ -125,13 +133,13 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wa
|
||||
}
|
||||
|
||||
if (delay) {
|
||||
fprintf(stderr, "Delaying for %dms\n", delay);
|
||||
log_info(plfBoot, "Delaying for %dms", delay);
|
||||
Sleep(delay);
|
||||
}
|
||||
|
||||
// Injection completed, let the program continue execution
|
||||
if (FAILED(ResumeThread(processInformation.hThread))) {
|
||||
fprintf(stderr, "Fatal: ResumeThread failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: ResumeThread failed: %d", GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
@ -140,14 +148,14 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wa
|
||||
abort:
|
||||
if (processInformation.hProcess && processInformation.hProcess != INVALID_HANDLE_VALUE) {
|
||||
if (!CloseHandle(processInformation.hThread) && GetLastError() != ERROR_INVALID_HANDLE)
|
||||
fprintf(stderr, "Fatal: CloseHandle(hProcess) failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: CloseHandle(hProcess) failed: %d", GetLastError());
|
||||
|
||||
if (!TerminateProcess(processInformation.hProcess, 1))
|
||||
fprintf(stderr, "Fatal: TerminateProcess failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: TerminateProcess failed: %d", GetLastError());
|
||||
}
|
||||
if (processInformation.hThread && processInformation.hThread != INVALID_HANDLE_VALUE) {
|
||||
if (!CloseHandle(processInformation.hThread) && GetLastError() != ERROR_INVALID_HANDLE)
|
||||
fprintf(stderr, "Fatal: CloseHandle(hThread) failed: %03x\n", GetLastError());
|
||||
log_error(plfProcesses, "Fatal: CloseHandle(hThread) failed: %d", GetLastError());
|
||||
}
|
||||
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait, DWORD delay,
|
||||
LPCSTR extra_injections, DWORD flags);
|
||||
HANDLE start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait,
|
||||
DWORD delay, LPCSTR extra_injections, DWORD flags);
|
||||
|
||||
#define MICELIB "mice.dll"
|
||||
|
@ -17,14 +17,14 @@
|
||||
#include "log_facilities.def"
|
||||
#undef _LF
|
||||
|
||||
static BOOL logIsMaster = FALSE;
|
||||
|
||||
extern WCHAR exeName[MAX_PATH + 1];
|
||||
extern DWORD imageOffset;
|
||||
|
||||
extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
|
||||
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
|
||||
|
||||
BOOL HAS_COLOUR = FALSE;
|
||||
|
||||
char _log_prelude[64];
|
||||
char* log_prelude() {
|
||||
time_t rawtime;
|
||||
@ -65,13 +65,12 @@ void __stdcall amLogCallback(DWORD level, char* format) {
|
||||
DWORD pLogcb;
|
||||
DWORD* ppLogcb;
|
||||
|
||||
HANDLE hSlot;
|
||||
|
||||
static char log_buf[1024];
|
||||
int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list args) {
|
||||
// Early-return if we have nothing to do
|
||||
if (MiceConfig.mice.log_level < log_level &&
|
||||
(!MiceConfig.mice.log_to_file || MiceConfig.mice.file_log_level < log_level)) {
|
||||
return 0;
|
||||
}
|
||||
if (MiceConfig.mice.log_level < log_level) return 0;
|
||||
|
||||
// TODO: These are all horrible bodges
|
||||
// if (wcscmp(exeName, L"mxnetwork.exe") == 0) {
|
||||
@ -88,30 +87,21 @@ int _do_log(BYTE log_level, PLOG_FACILITY facility, const char* format, va_list
|
||||
|
||||
char prefix = LOG_PREFIXES[log_level];
|
||||
|
||||
EnterCriticalSection(&logger_lock);
|
||||
|
||||
int col_len = strlen(log_colours[log_level]);
|
||||
|
||||
EnterCriticalSection(&logger_lock);
|
||||
int log_len = snprintf(log_buf, _countof(log_buf), "%s%s%c:%s:", log_colours[log_level],
|
||||
log_prelude(), prefix, facility->m_name);
|
||||
log_len += vsnprintf(log_buf + log_len, _countof(log_buf) - log_len, format, args);
|
||||
log_len += snprintf(log_buf + log_len, _countof(log_buf) - log_len, "%s\n", COLOR_RESET);
|
||||
log_buf[_countof(log_buf) - 1] = '\0';
|
||||
|
||||
if (MiceConfig.mice.log_level >= log_level) {
|
||||
HANDLE sout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
WriteFile(sout, log_buf, log_len, NULL, NULL);
|
||||
// FlushFileBuffers(sout);
|
||||
}
|
||||
|
||||
if (MiceConfig.mice.log_to_file && MiceConfig.mice.file_log_level >= log_level) {
|
||||
if (log_file && log_file != INVALID_HANDLE_VALUE) {
|
||||
// Replace the colour reset with a newline, then skip the prefix when writing
|
||||
log_buf[log_len - col_len] = '\n';
|
||||
log_buf[log_len - col_len + 1] = '\0';
|
||||
WriteFile(log_file, log_buf + col_len, log_len - col_len - sizeof(COLOR_RESET), NULL,
|
||||
NULL);
|
||||
}
|
||||
if (hSlot != INVALID_HANDLE_VALUE) {
|
||||
WriteFile(hSlot, log_buf, log_len, NULL, NULL);
|
||||
} else {
|
||||
// This should never happen, but there's no harm being prepared in case it does
|
||||
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), log_buf, log_len, NULL, NULL);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&logger_lock);
|
||||
@ -178,23 +168,18 @@ int _log_game(PLOG_FACILITY facility, const char* format, ...) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setup_logging() {
|
||||
// Force stdio even for GUI applications
|
||||
// AttachConsole(ATTACH_PARENT_PROCESS);
|
||||
void setup_logging(DWORD slotPid) {
|
||||
char slotName[MAX_PATH + 1];
|
||||
sprintf_s(slotName, MAX_PATH, "\\\\.\\mailslot\\micelog%d", slotPid);
|
||||
|
||||
// Enable colour in CMD
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hConsole, &dwMode))
|
||||
HAS_COLOUR = SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
hSlot = CreateFile(slotName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hSlot == INVALID_HANDLE_VALUE) {
|
||||
fprintf(stderr, "Fatal: Failed to open mailslot %s", slotName);
|
||||
ExitProcess(2);
|
||||
}
|
||||
|
||||
InitializeCriticalSection(&logger_lock);
|
||||
|
||||
if (MiceConfig.mice.log_to_file) {
|
||||
if (log_file == INVALID_HANDLE_VALUE && MiceConfig.mice.log_file[0] != '\0')
|
||||
log_file = CreateFileA(MiceConfig.mice.log_file, GENERIC_WRITE, FILE_SHARE_READ, NULL,
|
||||
CREATE_ALWAYS, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void log_stack(PLOG_FACILITY facility) {
|
||||
|
@ -38,7 +38,7 @@ int vlog_game(PLOG_FACILITY facility, const char* format, va_list args);
|
||||
|
||||
void log_stack(PLOG_FACILITY facility);
|
||||
|
||||
void setup_logging();
|
||||
void setup_logging(DWORD slotPid);
|
||||
|
||||
// Disable some logging entirely at build time for speed
|
||||
#define COMPILE_LOG_LEVEL 6
|
||||
|
Loading…
Reference in New Issue
Block a user