Rework launcher logic

This commit is contained in:
Bottersnike 2023-03-30 15:48:11 +01:00
parent 6c94aad9b2
commit b015c0cce4
Signed by: Bottersnike
SSH Key Fingerprint: SHA256:3g0ghwd4dNX1k1RX8qazbiT+3RIYn/daeBevHZVCiU0
11 changed files with 268 additions and 135 deletions

View File

@ -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();

View File

@ -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:

View File

@ -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) {

View File

@ -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);

View File

@ -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());
}

View File

@ -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);
}

View File

@ -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")

View File

@ -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;

View File

@ -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"

View File

@ -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) {

View File

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