From 463d94f1ee808232e13d9136bac333bd45bb0ed2 Mon Sep 17 00:00:00 2001 From: Bottersnike Date: Tue, 14 Jun 2022 13:30:36 +0900 Subject: [PATCH] Bunch of driver work, and json-based patching --- Makefile | 1 + src/micetools/dll/com.c | 100 +++++++-- src/micetools/dll/com.h | 2 +- src/micetools/dll/dllmain.c | 124 +++-------- src/micetools/dll/drivers/columba.c | 36 +++- src/micetools/dll/drivers/mx.h | 1 + src/micetools/dll/drivers/mxjvs.c | 45 +++- src/micetools/dll/drivers/mxsmbus.c | 6 +- src/micetools/dll/drivers/mxsram.c | 7 +- src/micetools/dll/drivers/mxsuperio.c | 8 +- src/micetools/dll/files.c | 58 +++--- src/micetools/dll/files.h | 3 +- src/micetools/dll/meson.build | 2 + src/micetools/dll/network.c | 59 ++++++ src/micetools/dll/network.h | 14 ++ src/micetools/dll/processes.c | 27 +++ src/micetools/dll/processes.h | 11 + src/micetools/dll/setupapi.c | 2 +- src/micetools/launcher/exe.h | 4 - src/micetools/launcher/locate.c | 9 +- src/micetools/launcher/main.c | 1 - src/micetools/launcher/meson.build | 1 - src/micetools/lib/dmi/dmi.c | 125 ++++++------ src/micetools/lib/dmi/dmi.h | 30 +-- src/micetools/lib/meson.build | 6 +- src/micetools/{launcher => lib/mice}/exe.c | 3 +- src/micetools/lib/mice/exe.h | 12 ++ src/micetools/lib/mice/log.c | 44 ++++ src/micetools/lib/mice/log.h | 8 +- src/micetools/lib/mice/meson.build | 5 + src/micetools/lib/mice/mice.h | 2 + src/micetools/lib/mice/patch.c | 224 ++++++++++++++++++++ src/micetools/lib/mice/patch.h | 39 ++++ src/micetools/micepatch/main.c | 227 ++------------------- src/micetools/micepatch/meson.build | 1 - src/patches/ALLNetProc.patch.json | 93 +++++++++ src/patches/Game.patch.json | 98 +++++++++ src/patches/maimai_dump_.patch.json | 149 ++++++++++++++ src/patches/mxnetwork.patch.json | 16 ++ src/patches/mxsegaboot.patch.json | 163 +++++++++++++++ src/patches/patches.json | 51 +++++ 41 files changed, 1348 insertions(+), 469 deletions(-) create mode 100644 src/micetools/dll/network.c create mode 100644 src/micetools/dll/network.h create mode 100644 src/micetools/dll/processes.c create mode 100644 src/micetools/dll/processes.h delete mode 100644 src/micetools/launcher/exe.h rename src/micetools/{launcher => lib/mice}/exe.c (99%) create mode 100644 src/micetools/lib/mice/exe.h create mode 100644 src/micetools/lib/mice/patch.c create mode 100644 src/micetools/lib/mice/patch.h create mode 100644 src/patches/ALLNetProc.patch.json create mode 100644 src/patches/Game.patch.json create mode 100644 src/patches/maimai_dump_.patch.json create mode 100644 src/patches/mxnetwork.patch.json create mode 100644 src/patches/mxsegaboot.patch.json create mode 100644 src/patches/patches.json diff --git a/Makefile b/Makefile index 46b066a..1f73157 100644 --- a/Makefile +++ b/Makefile @@ -53,3 +53,4 @@ dist: @xcopy /E /H /C /R /Q /Y src\system "$(DIST_DIR)\system/*" @xcopy /E /H /C /R /Q /Y src\tools "$(DIST_DIR)\tools/*" + @xcopy /E /H /C /R /Q /Y src\patches "$(DIST_DIR)\patches/*" diff --git a/src/micetools/dll/com.c b/src/micetools/dll/com.c index c6de1cf..6109c92 100644 --- a/src/micetools/dll/com.c +++ b/src/micetools/dll/com.c @@ -1,5 +1,7 @@ #include "com.h" +#include "../lib/mice/mice.h" + com_hook_t* com_hook_list = NULL; com_hook_t* new_com_hook(BYTE port) { com_hook_t* hook = (com_hook_t*)malloc(sizeof *hook); @@ -19,9 +21,11 @@ com_hook_t* new_com_hook(BYTE port) { return hook; }; + void hook_com(com_hook_t* hook) { hook->next = NULL; - hook->virtual_handle = NULL; + hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE)); + *hook->virtual_handle = NULL; if (com_hook_list == NULL) { com_hook_list = hook; return; @@ -33,97 +37,155 @@ void hook_com(com_hook_t* hook) { }; BOOL WINAPI FakeGetCommState(HANDLE hFile, LPDCB lpDCB) { - log_misc("comm", "GetCommState(0x%p, 0x%p)", hFile, lpDCB); + log_misc(COMM_LOGGER, "GetCommState(0x%p, 0x%p)", hFile, lpDCB); com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->GetCommState != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->GetCommState == NULL) { + log_error(COMM_LOGGER, "GetCommState(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->GetCommState(hook->data, lpDCB); } + hook = hook->next; } return TrueGetCommState(hFile, lpDCB); } + BOOL WINAPI FakeSetCommState(HANDLE hFile, LPDCB lpDCB) { - log_misc("comm", "SetCommState(0x%p, 0x%p)", hFile, lpDCB); + log_misc(COMM_LOGGER, "SetCommState(0x%p, 0x%p)", hFile, lpDCB); com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->SetCommState != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->SetCommState == NULL) { + log_error(COMM_LOGGER, "SetCommState(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->SetCommState(hook->data, lpDCB); } + hook = hook->next; } + return TrueSetCommState(hFile, lpDCB); } + BOOL WINAPI FakeGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { - log_misc("comm", "GetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts); + log_misc(COMM_LOGGER, "GetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts); + com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->GetCommTimeouts != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->GetCommTimeouts == NULL) { + log_error(COMM_LOGGER, "GetCommTimeouts(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->GetCommTimeouts(hook->data, lpCommTimeouts); } + hook = hook->next; } return TrueGetCommTimeouts(hFile, lpCommTimeouts); } + BOOL WINAPI FakeSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) { - log_misc("comm", "SetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts); + log_misc(COMM_LOGGER, "SetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts); + com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->SetCommTimeouts != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->SetCommTimeouts == NULL) { + log_error(COMM_LOGGER, "SetCommTimeouts(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->SetCommTimeouts(hook->data, lpCommTimeouts); } + hook = hook->next; } return TrueSetCommTimeouts(hFile, lpCommTimeouts); } + BOOL WINAPI FakeSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) { - log_misc("comm", "SetupCom(0x%p, 0x%08x, 0x%08x)", hFile, dwInQueue, dwOutQueue); + log_misc(COMM_LOGGER, "SetupCom(0x%p, 0x%08x, 0x%08x)", hFile, dwInQueue, dwOutQueue); + com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->SetupComm != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->SetupComm == NULL) { + log_error(COMM_LOGGER, "SetupComm(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->SetupComm(hook->data, dwInQueue, dwOutQueue); } + hook = hook->next; } return TrueSetupComm(hFile, dwInQueue, dwOutQueue); } + BOOL WINAPI FakePurgeComm(HANDLE hFile, DWORD dwFlags) { - log_misc("comm", "PurgeComm(0x%p, 0x%08x)", hFile, dwFlags); + log_misc(COMM_LOGGER, "PurgeComm(0x%p, 0x%08x)", hFile, dwFlags); + com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->PurgeComm != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->PurgeComm == NULL) { + log_error(COMM_LOGGER, "PurgeComm(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->PurgeComm(hook->data, dwFlags); } + hook = hook->next; } return TruePurgeComm(hFile, dwFlags); } + BOOL WINAPI FakeGetCommModemStatus(HANDLE hFile, LPDWORD lpModelStat) { - log_misc("comm", "GetCommModemStatus(0x%p, 0x%p)", hFile, lpModelStat); + log_misc(COMM_LOGGER, "GetCommModemStatus(0x%p, 0x%p)", hFile, lpModelStat); com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->GetCommModemStatus != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->GetCommModemStatus == NULL) { + log_error(COMM_LOGGER, "GetCommModemStatus(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->GetCommModemStatus(hook->data, lpModelStat); } + hook = hook->next; } return TrueGetCommModemStatus(hFile, lpModelStat); } + BOOL WINAPI FakeWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) { - log_misc("comm", "WaitCommEvent"); + log_misc(COMM_LOGGER, "WaitCommEvent"); com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->WaitCommEvent != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->WaitCommEvent == NULL) { + log_error(COMM_LOGGER, "WaitCommEvent(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->WaitCommEvent(hook->data, lpEvtMask, lpOverlapped); } + hook = hook->next; } return TrueWaitCommEvent(hFile, lpEvtMask, lpOverlapped); } + BOOL WINAPI FakeClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) { - log_misc("comm", "ClearCommError"); + log_misc(COMM_LOGGER, "ClearCommError"); com_hook_t* hook = com_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile && hook->ClearCommError != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->ClearCommError == NULL) { + log_error(COMM_LOGGER, "ClearCommError(%ls) unimplemented", hook->wName); + return FALSE; + } return hook->ClearCommError(hook->data, lpErrors, lpStat); } + hook = hook->next; } return TrueClearCommError(hFile, lpErrors, lpStat); } diff --git a/src/micetools/dll/com.h b/src/micetools/dll/com.h index 9360979..16ba7a0 100644 --- a/src/micetools/dll/com.h +++ b/src/micetools/dll/com.h @@ -23,7 +23,7 @@ typedef BOOL(FnWaitCommEvent)(void* com, LPDWORD lpEvtMask, LPOVERLAPPED lpOverl typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat); typedef struct com_hook { - HANDLE virtual_handle; + LPHANDLE virtual_handle; WCHAR wName[7]; // max is COM255 BYTE com; diff --git a/src/micetools/dll/dllmain.c b/src/micetools/dll/dllmain.c index 6bb2d7d..8741f41 100644 --- a/src/micetools/dll/dllmain.c +++ b/src/micetools/dll/dllmain.c @@ -1,4 +1,5 @@ #include +#include #include #pragma comment(lib, "Shlwapi.lib") @@ -6,107 +7,52 @@ #include "../lib/mice/mice.h" #include "drivers/mx.h" -#include "files.h" -#include "com.h" #include "micesetupapi.h" +#include "network.h" +#include "processes.h" WCHAR exePath[MAX_PATH + 1]; void enable_traces() { - if (wcscmp(exePath, L"Game.exe") == 0) { - *(DWORD*)(0x008717a0) = 1; - *(DWORD*)(0x00871728) = 1; - *(DWORD*)(0x00871cd8) = 1; - *(DWORD*)(0x00872660) = 1; - *(DWORD*)(0x0087297c) = 1; // LOG_EN_EEPROM - *(DWORD*)(0x00872980) = 1; - *(DWORD*)(0x00872988) = 1; - *(DWORD*)(0x00873540) = 1; - *(DWORD*)(0x00873538) = 1; - *(DWORD*)(0x0087f890) = 1; - *(DWORD*)(0x00882ce4) = 1; - *(DWORD*)(0x00882cec) = 1; - *(DWORD*)(0x00883018) = 1; - *(DWORD*)(0x00886ff8) = 1; - *(DWORD*)(0x0088b1b8) = 1; - *(DWORD*)(0x0088b1c0) = 1; - } else if (wcscmp(exePath, L"ALLNetProc_Win.exe") == 0) { - *(DWORD*)(0x004f48b0) = 1; // LOG_EN_DONGLE - *(DWORD*)(0x004f989c) = 1; // LOG_EN_PCP - *(DWORD*)(0x004f7d04) = 1; // LOG_EN_EEPROM - *(DWORD*)(0x004f7d08) = 1; // LOG_EN_BACKUP - *(DWORD*)(0x004f8118) = 1; // LOG_EN_RTC - *(DWORD*)(0x004f96dc) = 1; // LOG_EN_GFETCHER - *(DWORD*)(0x004f8338) = 1; // LOG_EN_NETWORK - *(DWORD*)(0x004f88c0) = 1; // LOG_EN_MASTER - *(DWORD*)(0x004f88b0) = 1; // LOG_EN_HM - *(DWORD*)(0x004f8330) = 1; // LOG_EN_SRAM - *(DWORD*)(0x004f9728) = 1; // LOG_EN_PLATFORM - - //*(DWORD*)(0x004f9e7c) = 5; // LOG_EN_ASSERTS (handled by the bellow - // instead) - *(DWORD*)(0x004e884c) = 10; // ALPB_LOG_LEVEL (0=None, 1=Error, - // 2=Warning, 3=Most, 4=Debug) - } else if (wcscmp(exePath, L"ORIG_mxsegaboot.exe") == 0 || wcscmp(exePath, L"mxsegaboot.exe") == 0) { - // start of am - *(DWORD*)(0x0054fcd8) = 1; // LOG_EN_JVS_DRIVER - *(DWORD*)(0x00538810) = 1; // LOG_EN_DIPSW - *(DWORD*)(0x0054afc8) = 1; // LOG_EN_ATA - *(DWORD*)(0x00544b78) = 1; // LOG_EN_DONGLE - *(DWORD*)(0x00536c98) = 1; // LOG_EN_EEPROM - *(DWORD*)(0x00537834) = 1; // LOG_EN_GCATCHER - *(DWORD*)(0x00537d4c) = 1; // LOG_EN_GDELIVER - *(DWORD*)(0x0053828c) = 1; // LOG_EN_GFETCHER - *(DWORD*)(0x00547fd0) = 1; // LOG_EN_HWRESET - *(DWORD*)(0x00547fd8) = 1; // LOG_EN_PLATFORM - *(DWORD*)(0x00548268) = 1; // LOG_EN_HM - *(DWORD*)(0x00536f30) = 1; // LOG_EN_BACKUP - *(DWORD*)(0x00547fcc) = 1; // LOG_EN_CMOS - *(DWORD*)(0x005382d8) = 1; // LOG_EN_INSTALL - *(DWORD*)(0x00538818) = 1; // LOG_EN_JVS - *(DWORD*)(0x00544b68) = 1; // LOG_EN_JVSP - *(DWORD*)(0x0054b3d8) = 1; // LOG_EN_MASTER - *(DWORD*)(0x00548280) = 1; // LOG_EN_NETWORK - *(DWORD*)(0x00548050) = 1; // LOG_EN_RTC - *(DWORD*)(0x00536c94) = 1; // LOG_EN_SRAM - *(DWORD*)(0x005487f8) = 1; // LOG_EN_STORAGE - *(DWORD*)(0x00536c90) = 1; // LOG_EN_SYS - // end of am - *(DWORD*)(0x00536c70) = 1; // LOG_EN_PCPT - } else if (wcscmp(exePath, L"maimai_dump_.exe") == 0) { - *(DWORD*)(0x00c8ab7c) = 1; // LOG_EN_SRAM - *(DWORD*)(0x00f406f0) = 1; // LOG_EN_CABINET_DL - *(DWORD*)(0x00c88680) = 1; // LOG_EN_INSTALL - *(DWORD*)(0x00c8ab78) = 1; // LOG_EN_EEPROM - *(DWORD*)(0x00c88608) = 1; // LOG_EN_PLATFORM - *(DWORD*)(0x00c88dd0) = 1; // LOG_EN_STORAGE - *(DWORD*)(0x00ca25ec) = 1; // LOG_EN_PCP - *(DWORD*)(0x00c96ed0) = 1; // LOG_EN_HM - *(DWORD*)(0x00f406ec) = 1; // LOG_EN_HTTP - *(DWORD*)(0x00c89ca8) = 1; // LOG_EN_DIPSW - *(DWORD*)(0x00c96ed8) = 1; // LOG_EN_DONGLE - *(DWORD*)(0x00c9a83c) = 1; // LOG_EN_JVSP - *(DWORD*)(0x00c89730) = 1; // LOG_EN_NETWORK - *(DWORD*)(0x00c9a440) = 1; // LOG_EN_JVST_THREAD - *(DWORD*)(0x00c8ab80) = 1; // LOG_EN_JVS - *(DWORD*)(0x00c89fc8) = 1; // LOG_EN_MASTER - *(DWORD*)(0x00c88bb8) = 1; // LOG_EN_RTC - *(DWORD*)(0x00c9e420) = 1; // LOG_EN_JVST_DRIVER - *(DWORD*)(0x00c89320) = 1; // LOG_EN_BACKUP - *(DWORD*)(0x00c88bb4) = 1; // LOG_EN_HWRESET - *(DWORD*)(0x00c830e8) = 1; // LOG_EN - } else if (wcscmp(exePath, L"mxnetwork.exe") == 0) { - *(DWORD*)(0x004438e0) = 1; // LOG_EN_PCP - *(DWORD*)(0x004433f8) = 1; // LOG_EN_UTL + patches_t patches; + char error[256]; + if (!load_patches(&patches, "patches.json", error)) { + log_error(BOOT_LOGGER, "Failed to load patches file: %s", error); } else { - log_warning("traces", "No known traces for %ls", exePath); + char exePathC[MAX_PATH + 1]; + WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL); + + for (int i = 0; i < patches.nopatchsets; i++) { + patchset_t* patchset = patches.patchsets[i]; + + // Require the binary explicitly named + if (patchset->binary_name == NULL || strcmp(patchset->binary_name, exePathC) != 0) { + continue; + } + if (!patchset->apply) continue; + + for (int j = 0; j < patchset->nopatches; j++) { + patch_t patch = patchset->patches[j]; + + if (memcmp(patch.from, (void*)patch.offset, patch.count) != 0) { + log_error(BOOT_LOGGER, "Patch %s[%d] failed! from-value missmatch", patchset->name, j); + continue; + } + + memcpy((void*)patch.offset, patch.to, patch.count); + log_misc(BOOT_LOGGER, "Patched %d bytes at %08x", patch.count, patch.offset); + } + } } + free_patches(&patches); } void prebind_hooks() { hook_setupapi(); hook_commio(); hook_io(); + hook_processes(); + hook_network(); } void init_injection() { @@ -114,8 +60,6 @@ void init_injection() { setup_logging(); log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exePath); - dmi_build_default(); - enable_traces(); setup_columba(); diff --git a/src/micetools/dll/drivers/columba.c b/src/micetools/dll/drivers/columba.c index 3e3265f..4041396 100644 --- a/src/micetools/dll/drivers/columba.c +++ b/src/micetools/dll/drivers/columba.c @@ -4,6 +4,17 @@ #include "../lib/mice/mice.h" #include "files.h" +// Much easier than pulling in winddk.h +typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; +typedef struct { + PHYSICAL_ADDRESS addr; + DWORD data_type; + DWORD bytes; +} columba_request; + +#define DMI_HEADER_START 0x000f0000 +#define DMI_TABLES_START 0x000f1000 + BOOL columba_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { switch (dwIoControlCode) { @@ -12,15 +23,23 @@ BOOL columba_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn "DeviceIoControl(, , 0x%p, 0x%x, -, " "0x%x, -, -)", lpInBuffer, nInBufferSize, nOutBufferSize); + columba_request* request = (columba_request*)lpInBuffer; + log_info("columba", "Physical read: 0x%04x %ss at %08X", request->bytes, + request->data_type == 1 ? "byte" + : request->data_type == 2 ? "short" + : request->data_type == 4 ? "long" + : "void", + request->addr); + DWORD requested_size = request->data_type * request->bytes; memset(lpOutBuffer, 0, nOutBufferSize); - if (((LPWORD)lpInBuffer)[0] == 0x0000) { + if (request->addr.QuadPart == DMI_HEADER_START) { DMI_HEADER dmi = { .Signature = {'_', 'D', 'M', 'I', '_'}, .Checksum = 0, .StructLength = dmi_size, - .StructAddr = 0xdeeabeef, + .StructAddr = DMI_TABLES_START, .NumberOfStructs = 0x20, .BCDRevision = 0, .Reserved = 0, @@ -28,10 +47,13 @@ BOOL columba_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn dmi.Checksum = dmi_calc_checksum((char*)&dmi, 15); memcpy(lpOutBuffer, &dmi, sizeof(DMI_HEADER)); - if (lpBytesReturned) *lpBytesReturned = sizeof(DMI_HEADER); - } else { + if (lpBytesReturned) *lpBytesReturned = requested_size; + } else if (request->addr.QuadPart == DMI_TABLES_START) { memcpy(lpOutBuffer, dmi_table, dmi_size); - if (lpBytesReturned) *lpBytesReturned = dmi_size; + if (lpBytesReturned) *lpBytesReturned = 0x10000; + } else { + log_error("columna", "Request to unmapped memory location: %08x", request->addr); + return FALSE; } break; @@ -40,10 +62,12 @@ BOOL columba_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn return FALSE; } - return FALSE; + return TRUE; } void setup_columba() { + dmi_build_default(); + file_hook_t* columba = new_file_hook(L"\\\\.\\columba"); columba->DeviceIoControl = &columba_DeviceIoControl; diff --git a/src/micetools/dll/drivers/mx.h b/src/micetools/dll/drivers/mx.h index 8254514..04d4f16 100644 --- a/src/micetools/dll/drivers/mx.h +++ b/src/micetools/dll/drivers/mx.h @@ -1,3 +1,4 @@ +#include "../com.h" #include "../files.h" #include diff --git a/src/micetools/dll/drivers/mxjvs.c b/src/micetools/dll/drivers/mxjvs.c index cf1f7e5..ffbcccd 100644 --- a/src/micetools/dll/drivers/mxjvs.c +++ b/src/micetools/dll/drivers/mxjvs.c @@ -3,16 +3,16 @@ #include "../lib/mice/mice.h" #include "mx.h" -BOOL mxjvs_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesReturned, - LPOVERLAPPED lpOverlapped) { +BOOL JVS_SENSE = false; + +BOOL mxjvs_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, + DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { switch (dwIoControlCode) { case IOCTL_MXJVS_EXCHANGE: - log_misc("mxjvs", - "DeviceIoControl(, , 0x%p, 0x%x, -, " - "0x%x, -, -)", - lpInBuffer, nInBufferSize, nOutBufferSize); + log_error("mxjvs", + "DeviceIoControl(, , 0x%p, 0x%x, -, " + "0x%x, -, -)", + lpInBuffer, nInBufferSize, nOutBufferSize); // mxjvsDevice->exchange( // lpbyte(lpInBuffer), nInBufferSize & 0xFFFF, @@ -29,9 +29,38 @@ BOOL mxjvs_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, return TRUE; } +BOOL mxjvs_SetupComm(void* com, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; } +BOOL mxjvs_PurgeComm(void* com, DWORD dwFlags) { return TRUE; } +BOOL mxjvs_GetCommState(void* com, LPDCB lpDCB) { return TRUE; } +BOOL mxjvs_SetCommTimeouts(void* com, LPCOMMTIMEOUTS lpDCB) { return TRUE; } + +BOOL mxjvs_GetCommModemStatus(void* com, LPDWORD lpModelStat) { + *lpModelStat = JVS_SENSE ? MS_DSR_ON : 0; + return TRUE; +} + +BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) { + char PARITY[] = {'N', 'O', 'E', 'M', 'S'}; + char* STOP[] = {"1", "1.5", "2"}; + log_info("mxjvs", "Switching to %d baud (%d%c%s)", lpDCB->BaudRate, lpDCB->ByteSize, PARITY[lpDCB->Parity], + STOP[lpDCB->StopBits]); + return TRUE; +} + void setup_mxjvs() { file_hook_t* mxjvs = new_file_hook(L"\\\\.\\mxjvs"); mxjvs->DeviceIoControl = &mxjvs_DeviceIoControl; + com_hook_t* jvscom = new_com_hook(-1); + jvscom->GetCommState = mxjvs_GetCommState; + jvscom->SetCommState = mxjvs_SetCommState; + jvscom->SetCommTimeouts = mxjvs_SetCommTimeouts; + jvscom->SetupComm = mxjvs_SetupComm; + jvscom->PurgeComm = mxjvs_PurgeComm; + jvscom->GetCommModemStatus = mxjvs_GetCommModemStatus; + hook_file(mxjvs); + hook_com(jvscom); + free(jvscom->virtual_handle); + jvscom->virtual_handle = mxjvs->virtual_handle; } diff --git a/src/micetools/dll/drivers/mxsmbus.c b/src/micetools/dll/drivers/mxsmbus.c index 151d461..1a950ea 100644 --- a/src/micetools/dll/drivers/mxsmbus.c +++ b/src/micetools/dll/drivers/mxsmbus.c @@ -208,15 +208,15 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn case PCA9535_WRITE: switch (i2c_packet->reg) { case PCA9535_OUT1: - log_error("mxsmbus", "pca9535 OUT1: %02x %02x", i2c_packet->data[0], + log_info("mxsmbus", "pca9535 OUT1: %02x %02x", i2c_packet->data[0], i2c_packet->data[1]); break; case PCA9535_INV0: - log_error("mxsmbus", "pca9535 INV0: %02x %02x", i2c_packet->data[0], + log_info("mxsmbus", "pca9535 INV0: %02x %02x", i2c_packet->data[0], i2c_packet->data[1]); break; case PCA9535_INV1: - log_error("mxsmbus", "pca9535 INV1: %02x %02x", i2c_packet->data[0], + log_info("mxsmbus", "pca9535 INV1: %02x %02x", i2c_packet->data[0], i2c_packet->data[1]); break; default: diff --git a/src/micetools/dll/drivers/mxsram.c b/src/micetools/dll/drivers/mxsram.c index 30275ec..411d4a2 100644 --- a/src/micetools/dll/drivers/mxsram.c +++ b/src/micetools/dll/drivers/mxsram.c @@ -34,7 +34,7 @@ BOOL mxsram_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInB switch (dwIoControlCode) { case IOCTL_MXSRAM_PING: // Get version - log_misc("mxsram", + log_info("mxsram", "DeviceIoControl(, , 0x%p, 0x%x, -, 0x%x, " "-, -)", lpInBuffer, nInBufferSize, nOutBufferSize); @@ -43,7 +43,7 @@ BOOL mxsram_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInB if (lpBytesReturned) *lpBytesReturned = 4; break; case IOCTL_DISK_GET_DRIVE_GEOMETRY: - log_misc("mxsram", + log_info("mxsram", "DeviceIoControl(, , 0x%p, " "0x%x, -, 0x%x, -, -)", lpInBuffer, nInBufferSize, nOutBufferSize); @@ -58,7 +58,7 @@ BOOL mxsram_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInB if (lpBytesReturned) *lpBytesReturned = sizeof(DISK_GEOMETRY); break; case IOCTL_MXSRAM_GET_SECTOR_SIZE: - log_misc("mxsram", + log_info("mxsram", "DeviceIoControl(, , 0x%p, " "0x%x, -, 0x%x, -, -)", lpInBuffer, nInBufferSize, nOutBufferSize); @@ -118,6 +118,7 @@ void setup_mxsram() { sram_restore(); file_hook_t* mxsram = new_file_hook(L"\\\\.\\mxsram"); + mxsram->DeviceIoControl = &mxsram_DeviceIoControl; mxsram->SetFilePointer = &mxsram_SetFilePointer; mxsram->ReadFile = &mxsram_ReadFile; mxsram->WriteFile = &mxsram_WriteFile; diff --git a/src/micetools/dll/drivers/mxsuperio.c b/src/micetools/dll/drivers/mxsuperio.c index aff8b52..4c0b281 100644 --- a/src/micetools/dll/drivers/mxsuperio.c +++ b/src/micetools/dll/drivers/mxsuperio.c @@ -32,10 +32,10 @@ BOOL mxsuperio_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD n if (lpBytesReturned) *lpBytesReturned = 4; break; case IOCTL_MXSUPERIO_READ: - log_warning("mxsuperio", - "DeviceIoControl(, , 0x%p, 0x%x, -, " - "0x%x, -, -)", - lpInBuffer, nInBufferSize, nOutBufferSize); + log_misc("mxsuperio", + "DeviceIoControl(, , 0x%p, 0x%x, -, " + "0x%x, -, -)", + lpInBuffer, nInBufferSize, nOutBufferSize); /* BYTE chipId = 0|1 diff --git a/src/micetools/dll/files.c b/src/micetools/dll/files.c index c27dfb5..11af159 100644 --- a/src/micetools/dll/files.c +++ b/src/micetools/dll/files.c @@ -19,7 +19,8 @@ file_hook_t* new_file_hook(LPCWSTR filename) { } void hook_file(file_hook_t* hook) { hook->next = NULL; - hook->virtual_handle = NULL; + hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE)); + *hook->virtual_handle = NULL; if (file_hook_list == NULL) { file_hook_list = hook; return; @@ -30,8 +31,9 @@ void hook_file(file_hook_t* hook) { hl->next = hook; }; -drive_redirect_t DRIVE_REDIRECT_TABLE[] = {{"Y:\\", ".\\dev\\Y\\"}, - {"C:\\Documents and Settings\\AppUser\\temp\\", ".\\dev\\temp\\"}}; +drive_redirect_t DRIVE_REDIRECT_TABLE[] = { + {.drive = "Y:\\", .path = ".\\dev\\Y\\"}, + {.drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\"}}; char* redirect_path(char* path) { for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) { @@ -60,30 +62,17 @@ char* redirect_path(char* path) { HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { - // for (int i = 0; i < (sizeof HOOKED_HANDLES) / (sizeof HANDLE_HOOK); - // i++) { HANDLE_HOOK hook = HOOKED_HANDLES[i]; if (lpFileName && - // wcscmp(lpFileName, hook.wName) == 0) { - // log_warning(HOOKS_LOGGER, "CreateFileW intercepting driver file %ls", - // hook.wName); return hook.handle; - // } - // } - - // HANDLE result = TrueCreateFileW(lpFileName, dwDesiredAccess, - // dwShareMode, lpSecurityAttributes, dwCreationDisposition, - // dwFlagsAndAttributes, hTemplateFile); log_misc(HOOKS_LOGGER, - // "CreateFileW(%ls) -> 0x%p", lpFileName, result); - HANDLE handle = NULL; file_hook_t* hook = file_hook_list; while (hook != NULL) { if (wcscmp(lpFileName, hook->filename) == 0) { - if (hook->virtual_handle == NULL) { + if (*hook->virtual_handle == NULL) { // TODO: Assign handles better! - hook->virtual_handle = fake_handle; + *hook->virtual_handle = fake_handle; ((size_t)fake_handle)++; } - handle = hook->virtual_handle; + handle = *hook->virtual_handle; break; } hook = hook->next; @@ -119,18 +108,23 @@ BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lp file_hook_t* hook = file_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hDevice) { + if (*hook->virtual_handle == hDevice) { if (hook->DeviceIoControl) { // TODO: Less jank if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent); return hook->DeviceIoControl(dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); + } else { + log_error(HOOKS_LOGGER, "DeviceIoControl(%ls) unimplemented", hook->filename); + return FALSE; } } hook = hook->next; } + // log_warning(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, -, -, -, -, 0, 0)", hDevice, dwIoControlCode); + return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); } @@ -138,9 +132,12 @@ BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lp DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { file_hook_t* hook = file_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile) { + if (*hook->virtual_handle == hFile) { if (hook->SetFilePointer) { return hook->SetFilePointer(lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod); + } else { + log_error(HOOKS_LOGGER, "SetFilePointer(%ls) unimplemented", hook->filename); + return FALSE; } } hook = hook->next; @@ -153,9 +150,12 @@ DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesT LPOVERLAPPED lpOverlapped) { file_hook_t* hook = file_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile) { + if (*hook->virtual_handle == hFile) { if (hook->WriteFile) { return hook->WriteFile(lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); + } else { + log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", hook->filename); + return FALSE; } } hook = hook->next; @@ -168,9 +168,12 @@ BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRe LPOVERLAPPED lpOverlapped) { file_hook_t* hook = file_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hFile) { - if (hook->WriteFile) { + if (*hook->virtual_handle == hFile) { + if (hook->ReadFile) { return hook->ReadFile(lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); + } else { + log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", hook->filename); + return FALSE; } } hook = hook->next; @@ -190,6 +193,11 @@ BOOL WINAPI FakeCloseHandle(HANDLE hObject) { return TrueCloseHandle(hObject); } +int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) { + path = redirect_path((char*)path); + return True_stat64i32(path, buffer); +}; + void hook_io() { hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl, 5); @@ -201,5 +209,5 @@ void hook_io() { hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile, 6); hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile, 6); - // hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, &True_stat64i32, 5); + hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32, 5); } diff --git a/src/micetools/dll/files.h b/src/micetools/dll/files.h index 856918b..33ecf32 100644 --- a/src/micetools/dll/files.h +++ b/src/micetools/dll/files.h @@ -35,6 +35,7 @@ typedef BOOL(FnWriteFile)(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); typedef BOOL(FnReadFile)(LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); +static int(WINAPIV *True_stat64i32)(const char* path, struct _stat64i32* buffer); #define _WriteFile (TrueWriteFile ? TrueWriteFile : WriteFile) #define _ReadFile (TrueReadFile ? TrueReadFile : ReadFile) @@ -54,7 +55,7 @@ typedef struct file_hook { FnWriteFile* WriteFile; FnReadFile* ReadFile; - HANDLE virtual_handle; + LPHANDLE virtual_handle; struct file_hook* next; } file_hook_t; diff --git a/src/micetools/dll/meson.build b/src/micetools/dll/meson.build index a3e1737..778b6c7 100644 --- a/src/micetools/dll/meson.build +++ b/src/micetools/dll/meson.build @@ -14,6 +14,8 @@ shared_library( 'setupapi.c', 'com.c', 'comdevice.c', + 'processes.c', + 'network.c', ], link_with: [ dmi_lib, diff --git a/src/micetools/dll/network.c b/src/micetools/dll/network.c new file mode 100644 index 0000000..a50f478 --- /dev/null +++ b/src/micetools/dll/network.c @@ -0,0 +1,59 @@ +#include "network.h" + +#include "../lib/mice/mice.h" + +int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) { + ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr); + USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port); + log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, + addr & 0xff, port); + return True_connect(s, name, namelen); +} + +DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) { + DWORD ret = TrueGetIfTable(pIfTable, pdwSize, bOrder); + if (ret == NO_ERROR) { + for (size_t i = 0; i < pIfTable->dwNumEntries; i++) { + pIfTable->table[i].bPhysAddr[0] = 0x00; + pIfTable->table[i].bPhysAddr[1] = 0xD0; + pIfTable->table[i].bPhysAddr[2] = 0xF1; + } + } + return ret; +} +const char* INTERCEPT_DNS[] = { + "naominet.jp", // Startup + "ib.naominet.jp", // Billing + "aime.naominet.jp", // Aime (duh) + "tenporouter.loc", // Routers + "bbrouter.loc", "mobirouter.loc", "dslrouter.loc", +}; + +DNS_RECORDA dummy_record; + +DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra, PDNS_RECORDA* ppQueryResults, + PVOID* pReserved) { + log_misc("dns", "DNS lookup for %s", pszName); + if (ppQueryResults) { + for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) { + if (strcmp(pszName, INTERCEPT_DNS[i]) == 0) { + log_info("dns", "Replacing %s with 10.0.0.4", pszName); + + // We only support replacing at most one address, but that's all we'll ever need to! + (*ppQueryResults) = &dummy_record; + (*ppQueryResults)->pNext = NULL; + (*ppQueryResults)->wType = DNS_TYPE_A; + (*ppQueryResults)->Data.A.IpAddress = 0x0400000a; + + return ERROR_SUCCESS; + } + } + } + return TrueDnsQuery_A(pszName, wType, Options, pExtra, ppQueryResults, pReserved); +}; + +void hook_network() { + hook("Ws2_32.dll", "connect", Fake_connect, (void**)&True_connect, 5); + hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable, 5); + hook("Dnsapi.dll", "DnsQuery_A", FakeDnsQuery_A, (void**)&TrueDnsQuery_A, 5); +} diff --git a/src/micetools/dll/network.h b/src/micetools/dll/network.h new file mode 100644 index 0000000..815a90d --- /dev/null +++ b/src/micetools/dll/network.h @@ -0,0 +1,14 @@ +#include +#include +#include +#include + + +static int(WINAPI* True_connect)(SOCKET s, const SOCKADDR* name, int namelen); + +static DWORD(WINAPI* TrueGetIfTable)(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder); + +static DNS_STATUS(WINAPI* TrueDnsQuery_A)(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra, + PDNS_RECORDA* ppQueryResults, PVOID* pReserved); + +void hook_network(); diff --git a/src/micetools/dll/processes.c b/src/micetools/dll/processes.c new file mode 100644 index 0000000..f624f81 --- /dev/null +++ b/src/micetools/dll/processes.c @@ -0,0 +1,27 @@ +#include "processes.h" + +#include "../lib/mice/mice.h" + +const wchar_t* HOOK_BINARIES[] = { + L"app\\ALLNetProc.exe", + L"app\\CameraUploader.exe", + L"app\\GmSync.exe", +}; + +BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, + BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, + LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, + LPPROCESS_INFORMATION lpProcessInformation) { + log_info("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine); + + CHAR applicationName[MAX_PATH + 1]; + WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName, NULL, NULL); + CHAR commandLine[MAX_PATH + 1]; + WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL, NULL); + + HANDLE child = start_and_inject(applicationName, commandLine, MICELIB); + return child != NULL; +} + +void hook_processes() { hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6); } \ No newline at end of file diff --git a/src/micetools/dll/processes.h b/src/micetools/dll/processes.h new file mode 100644 index 0000000..524a791 --- /dev/null +++ b/src/micetools/dll/processes.h @@ -0,0 +1,11 @@ +#include +#include +#include + +static BOOL(WINAPI* TrueCreateProcessW)(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, + LPSECURITY_ATTRIBUTES lpProcessAttributes, + LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, + DWORD dwCreationFlags, LPVOID lpEnvironment, LPCWSTR lpCurrentDirectory, + LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation); + +void hook_processes(); diff --git a/src/micetools/dll/setupapi.c b/src/micetools/dll/setupapi.c index 5d831a7..716a65d 100644 --- a/src/micetools/dll/setupapi.c +++ b/src/micetools/dll/setupapi.c @@ -68,7 +68,7 @@ BOOL WINAPI FakeSetupDiGetDeviceInterfaceDetailA(HDEVINFO DeviceInfoSet, PSP_DEV FAKE_DEVICE* device = fake_devices; while (device != NULL) { if (device->handle == DeviceInfoSet && (ULONG_PTR)device->path == DeviceInterfaceData->Reserved) { - log_info("setupapi", "Yoinked SetupDiGetDeviceInterfaceDetailA"); + log_info("setupapi", "Intercepted SetupDiGetDeviceInterfaceDetailA"); const WCHAR* res = (WCHAR*)DeviceInterfaceData->Reserved; int new_len = (wcslen(res) + 1) * (sizeof *res); diff --git a/src/micetools/launcher/exe.h b/src/micetools/launcher/exe.h deleted file mode 100644 index 9f53cd0..0000000 --- a/src/micetools/launcher/exe.h +++ /dev/null @@ -1,4 +0,0 @@ -#include -#include - -HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject); diff --git a/src/micetools/launcher/locate.c b/src/micetools/launcher/locate.c index 92177ca..723b274 100644 --- a/src/micetools/launcher/locate.c +++ b/src/micetools/launcher/locate.c @@ -1,4 +1,5 @@ #include "locate.h" +#include "../lib/mice/mice.h" const char* KNOWN_GAMES[] = { // Preferentially use a decrypted dump if present @@ -6,14 +7,6 @@ const char* KNOWN_GAMES[] = { "maimai.exe", }; -#ifndef MICELIB -#ifdef MICE_WIN32 -#define MICELIB "mice86.dll" -#else // MICE_WIN32 -#define MICELIB "mice64.dll" -#endif // MICE_WIN32 -#endif // MICELIB - bool locate_file(char* path, size_t len, const char* exe) { WIN32_FIND_DATA fdFile; HANDLE hFind = NULL; diff --git a/src/micetools/launcher/main.c b/src/micetools/launcher/main.c index a0e707f..3e47ff1 100644 --- a/src/micetools/launcher/main.c +++ b/src/micetools/launcher/main.c @@ -2,7 +2,6 @@ #include #include "../lib/mice/mice.h" -#include "exe.h" #include "locate.h" const char* VERSION = "0.0-pre"; diff --git a/src/micetools/launcher/meson.build b/src/micetools/launcher/meson.build index 2cad1a7..15f4f22 100644 --- a/src/micetools/launcher/meson.build +++ b/src/micetools/launcher/meson.build @@ -4,7 +4,6 @@ executable( win_subsystem: 'console', sources: [ 'locate.c', - 'exe.c', 'main.c', rc, ], diff --git a/src/micetools/lib/dmi/dmi.c b/src/micetools/lib/dmi/dmi.c index 5e7dbd7..0ff68fe 100644 --- a/src/micetools/lib/dmi/dmi.c +++ b/src/micetools/lib/dmi/dmi.c @@ -5,9 +5,9 @@ WORD dmi_size = 0; size_t _dmi_max = 0; DMI_BIOS deafult_dmi_bios = { - .Type = 0x00, - .Length = 0x12, - .Handle = 0x0000, + .Head.Type = 0x00, + .Head.Length = 0x12, + .Head.Handle = 0x0000, .Vendor = 0x00, .Version = 0x00, .StartSegment = 0x0000, @@ -17,9 +17,10 @@ DMI_BIOS deafult_dmi_bios = { }; DMI_SYSTEM default_dmi_system = { - .Type = 0x01, - .Length = 0x08, - .Handle = 0x0000, + .Head.Type = 0x01, + .Head.Length = 0x08, + .Head.Handle = 0x0001, + // TODO: Are these used? .Manufacturer = 0x00, .ProductName = 0x00, .Version = 0x00, @@ -27,84 +28,82 @@ DMI_SYSTEM default_dmi_system = { }; DMI_STRING deafult_dmi_string = { - .Type = 0x0b, - .Length = 0x05, - .Handle = 0x0000, + .Head.Type = 0x0b, + .Head.Length = 0x05, + .Head.Handle = 0x0002, .NoStrings = 0x00, }; static void dmi_init(void) { - if (dmi_table) free(dmi_table); - dmi_table = (LPBYTE)malloc(0xff); - dmi_size = 0; - _dmi_max = 1024; + if (dmi_table) free(dmi_table); + _dmi_max = 0xff; + dmi_table = (LPBYTE)malloc(_dmi_max); + memset(dmi_table, 0, _dmi_max); + dmi_size = 0; } static void dmi_append(void* data, size_t size) { - if (!dmi_table) return; - while (dmi_size + (size + 1) >= _dmi_max) { - LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff); - if (!new_table) return; - dmi_table = new_table; - } - memcpy(dmi_table + dmi_size, &data, size); - dmi_size += size; - dmi_table[dmi_size++] = 0; - dmi_table[dmi_size++] = 0; + if (!dmi_table) return; + while (dmi_size + (size + 1) >= _dmi_max) { + LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff); + if (!new_table) return; + dmi_table = new_table; + } + memcpy(dmi_table + dmi_size, data, size); + dmi_size += size; + dmi_table[dmi_size++] = 0; + dmi_table[dmi_size++] = 0; } static void dmi_append_with_strings(void* data, size_t size, int num_strings, ...) { - va_list args; - va_start(args, num_strings); + va_list args; + va_start(args, num_strings); - dmi_append(data, size); - dmi_size -= 2; - for (int i = 0; i < num_strings; i++) { - char* str = va_arg(args, char*); - int len = strlen(str); -// #pragma warning(disable : 4996) - strcpy((char*)dmi_table + dmi_size, str); - dmi_size += len + 1; - dmi_table[dmi_size - 1] = 0; - } - dmi_table[dmi_size++] = 0; + dmi_append(data, size); + dmi_size -= 2; + for (int i = 0; i < num_strings; i++) { + char* str = va_arg(args, char*); + int len = strlen(str); + strcpy((char*)dmi_table + dmi_size, str); + dmi_size += len + 1; + dmi_table[dmi_size - 1] = 0; + } + dmi_table[dmi_size++] = 0; - va_end(args); + va_end(args); } void dmi_build_default() { - dmi_init(); - dmi_append(&deafult_dmi_bios, sizeof deafult_dmi_bios); - // Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2) - // Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3) + dmi_init(); + dmi_append(&deafult_dmi_bios, sizeof deafult_dmi_bios); + // Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2) + // Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3) dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 1, "Supermicro"); deafult_dmi_string.NoStrings = 3; - dmi_append_with_strings(&deafult_dmi_string, sizeof deafult_dmi_string, - // OEM strings: - // 0: ?? - // 1: ?? - // 2: Platform ID (AAL, AAM) - // AAL = Nvidia drivers - // AAM = AMD drivers - // *** = No dedicated drivers - // 3: ?? - // 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech) - // If present -> makes board = 4 - // AAL = 4 - // AAM = 4 - // Supermicro = 4 - // Advantech = 4 - 5, ".", ".", "AAM", ".", "AAL" - ); + dmi_append_with_strings(&deafult_dmi_string, sizeof deafult_dmi_string, + // OEM strings: + // 0: ?? + // 1: ?? + // 2: Platform ID (AAL, AAM) + // AAL = Nvidia drivers + // AAM = AMD drivers + // *** = No dedicated drivers + // 3: ?? + // 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech) + // If present -> makes board = 4 + // AAL = 4 + // AAM = 4 + // Supermicro = 4 + // Advantech = 4 + 5, ".", ".", "AAM", ".", "AAL"); } BYTE dmi_calc_checksum(const char* buf, int len) { - int sum = 0; - int a; - for (a = 0; a < len; a++) - sum += buf[a]; - return (BYTE)(sum == 0); + int sum = 0; + int a; + for (a = 0; a < len; a++) sum += buf[a]; + return (BYTE)(sum == 0); } \ No newline at end of file diff --git a/src/micetools/lib/dmi/dmi.h b/src/micetools/lib/dmi/dmi.h index 7c93c2b..866e9ef 100644 --- a/src/micetools/lib/dmi/dmi.h +++ b/src/micetools/lib/dmi/dmi.h @@ -7,7 +7,14 @@ extern WORD dmi_size; // #define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop)) #pragma pack(1) -typedef struct DMI_HEADER_ { +typedef struct { + BYTE Type; + BYTE Length; + WORD Handle; +} DMI_SECTION_HEADER; + +#pragma pack(1) +typedef struct { CHAR Signature[5]; BYTE Checksum; WORD StructLength; @@ -18,10 +25,8 @@ typedef struct DMI_HEADER_ { } DMI_HEADER; #pragma pack(1) -typedef struct DMI_BIOS_ { - BYTE Type; - BYTE Length; - WORD Handle; +typedef struct { + DMI_SECTION_HEADER Head; BYTE Vendor; BYTE Version; WORD StartSegment; @@ -31,10 +36,8 @@ typedef struct DMI_BIOS_ { } DMI_BIOS; #pragma pack(1) -typedef struct DMI_SYSTEM_ { - BYTE Type; - BYTE Length; - WORD Handle; +typedef struct { + DMI_SECTION_HEADER Head; BYTE Manufacturer; BYTE ProductName; BYTE Version; @@ -42,17 +45,14 @@ typedef struct DMI_SYSTEM_ { } DMI_SYSTEM; #pragma pack(1) -typedef struct DMI_STRING_ { - BYTE Type; - BYTE Length; - WORD Handle; +typedef struct { + DMI_SECTION_HEADER Head; BYTE NoStrings; } DMI_STRING; static void dmi_init(void); static void dmi_append(void* data, size_t size); -static void dmi_append_with_strings(void* data, size_t size, int num_strings, - ...); +static void dmi_append_with_strings(void* data, size_t size, int num_strings, ...); void dmi_build_default(void); BYTE dmi_calc_checksum(const char* buf, int len); diff --git a/src/micetools/lib/meson.build b/src/micetools/lib/meson.build index 51451a6..2670a41 100644 --- a/src/micetools/lib/meson.build +++ b/src/micetools/lib/meson.build @@ -1,8 +1,8 @@ subdir('util') # This is the only lib that should ever be link_with'd by another lib -subdir('am') -subdir('mice') -subdir('dmi') subdir('json') +subdir('am') +subdir('dmi') +subdir('mice') fs = import('fs') # Handle the fact we aren't distributing the libpcp source diff --git a/src/micetools/launcher/exe.c b/src/micetools/lib/mice/exe.c similarity index 99% rename from src/micetools/launcher/exe.c rename to src/micetools/lib/mice/exe.c index 2ba097e..ac7a118 100644 --- a/src/micetools/launcher/exe.c +++ b/src/micetools/lib/mice/exe.c @@ -1,6 +1,5 @@ #include "exe.h" - -#include "../lib/mice/mice.h" +#include "log.h" bool inject_debug_wait(HANDLE process) { BOOL present; diff --git a/src/micetools/lib/mice/exe.h b/src/micetools/lib/mice/exe.h new file mode 100644 index 0000000..b843373 --- /dev/null +++ b/src/micetools/lib/mice/exe.h @@ -0,0 +1,12 @@ +#include +#include + +HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject); + +#ifndef MICELIB +#ifdef MICE_WIN32 +#define MICELIB "mice86.dll" +#else // MICE_WIN32 +#define MICELIB "mice64.dll" +#endif // MICE_WIN32 +#endif // MICELIB diff --git a/src/micetools/lib/mice/log.c b/src/micetools/lib/mice/log.c index 27f1c0e..63843c3 100644 --- a/src/micetools/lib/mice/log.c +++ b/src/micetools/lib/mice/log.c @@ -146,6 +146,46 @@ int log_error(const char* caller, const char* format, ...) { // return ret; // }; +char* trim_string(char* string) { + size_t len = strlen(string) - 1; + + DWORD oldProt; + while (len > 0 && (string[len] == '\n' || string[len] == '\r')) { + // TODO: Reassess this. Suspect it may be causing issues. + // Make sure we can write! This is a terrible hack, but it does work. + VirtualProtect(string + len, 1, PAGE_EXECUTE_READWRITE, &oldProt); + string[len--] = '\0'; + VirtualProtect(string + len + 1, 1, oldProt, &oldProt); + } + return string; +} + +HANDLE WINAPI FakeRegisterEventSourceA(LPCSTR lpUNCServerName, LPCSTR lpSourceName) { return (HANDLE)0xDEADBEEF; } + +BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, + WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData) { + switch (wType) { + case EVENTLOG_SUCCESS: + case EVENTLOG_AUDIT_SUCCESS: + for (int i = 0; i < wNumStrings; i++) log_misc("evtlog", trim_string((char*)lpStrings[i])); + break; + case EVENTLOG_AUDIT_FAILURE: + case EVENTLOG_ERROR_TYPE: + for (int i = 0; i < wNumStrings; i++) log_error("evtlog", trim_string((char*)lpStrings[i])); + break; + case EVENTLOG_WARNING_TYPE: + for (int i = 0; i < wNumStrings; i++) log_warning("evtlog", trim_string((char*)lpStrings[i])); + break; + case EVENTLOG_INFORMATION_TYPE: + default: + for (int i = 0; i < wNumStrings; i++) log_info("evtlog", trim_string((char*)lpStrings[i])); + break; + } + return TRUE; +}; + +BOOL WINAPI FakeDeregisterEventSource(HANDLE hEventLog) { return TRUE; } + static VOID(WINAPI* TrueOutputDebugStringA)(LPCSTR lpOutputString); VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) { log_info("debug", "%s", lpOutputString); } @@ -165,4 +205,8 @@ void setup_logging() { if (LOG_FILE == NULL) LOG_FILE = CreateFileA("log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); + + hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA, &TrueRegisterEventSourceA); + hook("Advapi32.dll", "ReportEventA", FakeReportEventA, &TrueReportEventA); + hook("Advapi32.dll", "DeregisterEventSource", FakeDeregisterEventSource, &TrueDeregisterEventSource); } diff --git a/src/micetools/lib/mice/log.h b/src/micetools/lib/mice/log.h index 296dfa9..4907d2c 100644 --- a/src/micetools/lib/mice/log.h +++ b/src/micetools/lib/mice/log.h @@ -3,11 +3,17 @@ #include #include -#define LOG_MISC +static HANDLE(WINAPI* TrueRegisterEventSourceA)(LPCSTR lpUNCServerName, LPCSTR lpSourceName); +static BOOL(WINAPI* TrueReportEventA)(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, + WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData); +static BOOL(WINAPI* TrueDeregisterEventSource)(HANDLE hEventLog); + +// #define LOG_MISC #define LOG_INFO #define LOG_WARNING #define LOG_ERROR +#define COMM_LOGGER "comm" #define HOOKS_LOGGER "hooks" #define BOOT_LOGGER "boot" diff --git a/src/micetools/lib/mice/meson.build b/src/micetools/lib/mice/meson.build index 0e87780..3e2e8b6 100644 --- a/src/micetools/lib/mice/meson.build +++ b/src/micetools/lib/mice/meson.build @@ -3,5 +3,10 @@ mice_lib = static_library( sources: [ 'hook.c', 'log.c', + 'exe.c', + 'patch.c', ], + link_with: [ + json_lib, + ] ) diff --git a/src/micetools/lib/mice/mice.h b/src/micetools/lib/mice/mice.h index 6984fcb..93ced2d 100644 --- a/src/micetools/lib/mice/mice.h +++ b/src/micetools/lib/mice/mice.h @@ -1,3 +1,5 @@ #include "hook.h" #include "ioctl.h" #include "log.h" +#include "exe.h" +#include "patch.h" diff --git a/src/micetools/lib/mice/patch.c b/src/micetools/lib/mice/patch.c new file mode 100644 index 0000000..baf5318 --- /dev/null +++ b/src/micetools/lib/mice/patch.c @@ -0,0 +1,224 @@ +#include "patch.h" + +bool fetch(json_value* object, char* name, json_value** value) { + if (object->type != json_object) return false; + for (size_t j = 0; j < object->u.object.length; j++) { + json_object_entry* entry = &(object->u.object.values[j]); + if (strncmp(name, entry->name, entry->name_length) == 0) { + *value = entry->value; + return true; + } + } + return false; +} +bool fetch_string(json_value* object, char* name, char** value) { + json_value* fetched; + if (!fetch(object, name, &fetched)) return false; + if (fetched->type != json_string) return false; + *value = fetched->u.string.ptr; + return true; +} +bool fetch_int(json_value* object, char* name, size_t* value) { + json_value* fetched; + if (!fetch(object, name, &fetched)) return false; + if (fetched->type != json_integer) return false; + *value = fetched->u.integer; + return true; +} +bool fetch_bool(json_value* object, char* name, bool* value) { + json_value* fetched; + if (!fetch(object, name, &fetched)) return false; + if (fetched->type != json_boolean) return false; + *value = fetched->u.boolean; + return true; +} +void free_patches(patches_t* patches) { + if (patches->nopatchsets == 0) return; + for (int i = patches->nopatchsets - 1; i >= 0; i--) { + if (patches->patchsets[i] != NULL) { + for (int j = 0; j < patches->patchsets[i]->nopatches; j++) { + if (patches->patchsets[i]->patches[j].from != NULL) free(patches->patchsets[i]->patches[j].from); + if (patches->patchsets[i]->patches[j].to != NULL) free(patches->patchsets[i]->patches[j].to); + } + free(patches->patchsets[i]); + } + } + patches->nopatchsets = 0; +} + +json_value* load_json_from_file(char* path, char* error) { + FILE* fp = fopen(path, "r"); + if (fp == NULL) { + if (error != NULL) sprintf(error, "Failed to open patch file"); + return NULL; + } + + fseek(fp, 0L, SEEK_END); + size_t sz = ftell(fp); + rewind(fp); + + char* json_buf = (char*)malloc(sz); + if (json_buf == NULL) { + if (error != NULL) sprintf(error, "Failed to allocate file buffer"); + fclose(fp); + return NULL; + } + if (!(sz = fread(json_buf, 1, sz, fp))) { + if (error != NULL) sprintf(error, "Failed to read file"); + fclose(fp); + return NULL; + }; + fclose(fp); + + json_settings settings = {0}; + return json_parse_ex(&settings, json_buf, sz, error); +} + +bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error) { + patches->nopatchsets = set_count; + patches->patchsets = (patchset_t**)malloc(set_count * sizeof(patchset_t*)); + for (int i = 0; i < set_count; i++) patches->patchsets[i] = NULL; + + error[0] = '\0'; + for (int i = 0; i < set_count; i++) { + patchset_t* patchset = (patchset_t*)malloc(sizeof(patchset_t)); + patches->patchsets[i] = patchset; + patchset->name = NULL; + patchset->description = NULL; + patchset->binary_name = NULL; + patchset->apply = false; + patchset->nopatches = 0; + + char *name, *description, *binary_name; + if (!fetch_string(set_json[i], "name", &name)) { + snprintf(error, json_error_max, "'name' missing for patch %d", i); + goto failed; + } + if (!fetch_string(set_json[i], "description", &description)) { + snprintf(error, json_error_max, "'description' missing for patch %d (%s)", i, name); + goto failed; + } + if (!fetch_string(set_json[i], "binary_name", &binary_name)) binary_name = NULL; + + bool apply; + if (!fetch_bool(set_json[i], "apply", &apply)) { + snprintf(error, json_error_max, "'apply' missing for patch %d (%s)", i, name); + goto failed; + } + json_value* set_patches; + if (!fetch(set_json[i], "patches", &set_patches) || set_patches->type != json_array) { + char* patches_file_path; + if (fetch_string(set_json[i], "patches_file", &patches_file_path)) { + char load_error[json_error_max]; + set_patches = load_json_from_file(patches_file_path, load_error); + if (set_patches == NULL) { + log_warning("patcher", "Failed to load '%s': %s", patches_file_path, load_error); + continue; + } + if (set_patches->type != json_array) { + log_warning("patcher", "Failed to load '%s': not an array", patches_file_path); + continue; + } + } else { + snprintf(error, json_error_max, "Neither 'patches' nor 'patchs_file' in patch %d (%s)", i, name); + goto failed; + } + } + + int count = set_patches->u.array.length; + patchset = (patchset_t*)realloc(patchset, sizeof(patchset_t) + (sizeof(patch_t) * count)); + patches->patchsets[i] = patchset; + + patchset->name = name; + patchset->description = description; + patchset->binary_name = binary_name; + patchset->apply = apply; + patchset->nopatches = count; + memset(patchset->patches, 0, count * (sizeof(patch_t))); + + for (int j = 0; j < count; j++) { + json_value* this_patch = set_patches->u.array.values[j]; + size_t at; + char *from, *to; + if (!fetch_int(this_patch, "at", &at)) { + char* at_str; + if (!fetch_string(this_patch, "at", &at_str)) { + snprintf(error, json_error_max, "'at' missing for patch %s[%d]", name, j); + goto failed; + } + + if (strlen(at_str) > 8) { + snprintf(error, json_error_max, "invalid 'at' value for patch %s[%d]", name, j); + goto failed; + } + hex_to_bin(at_str, (void*)&at, 8); + at = _byteswap_ulong(at); // Endianess! + } + if (!fetch_string(this_patch, "from", &from)) { + snprintf(error, json_error_max, "'from' missing for patch %s[%d]", name, j); + goto failed; + } + if (!fetch_string(this_patch, "to", &to)) { + snprintf(error, json_error_max, "'to' missing for patch %s[%d]", name, j); + goto failed; + } + + char* patch_name; + if (!fetch_string(this_patch, "name", &patch_name)) patch_name = NULL; + + patchset->patches[j].name = patch_name; + patchset->patches[j].offset = at; + size_t size = strlen(from); + if (size != strlen(to)) { + snprintf(error, json_error_max, "'from' and 'to' lengths differ in patch %s[%d]", name, j); + goto failed; + } + if (size % 2 != 0) { + snprintf(error, json_error_max, "invalid hex string in patch %s[%d]", name, j); + goto failed; + } + char* bin_from = patchset->patches[j].from = (char*)malloc(size / 2); + char* bin_to = patchset->patches[j].to = (char*)malloc(size / 2); + if (!hex_to_bin(from, bin_from, size)) { + snprintf(error, json_error_max, "invalid hex string in patch %s[%d].from", name, j); + goto failed; + }; + if (!hex_to_bin(to, bin_to, size)) { + snprintf(error, json_error_max, "invalid hex string in patch %s[%d].to", name, j); + goto failed; + }; + + patchset->patches[j].count = size / 2; + } + } + + return true; + +failed: + free_patches(patches); + return false; +} + +bool load_patches(patches_t* patches, char* path, char* error) { + patches->nopatchsets = 0; + + json_value* parsed = load_json_from_file(path, error); + if (parsed == NULL) return false; + + int loaded_patches = 0; + json_value** patches_json; + if (parsed->type == json_array) { + loaded_patches = parsed->u.array.length; + patches_json = parsed->u.array.values; + } else if (parsed->type == json_object) { + loaded_patches = 1; + patches_json = &parsed; + } else { + sprintf(error, "Patch file format error"); + json_value_free(parsed); + return false; + } + + if (!parse_patches(patches, patches_json, loaded_patches, error)) return false; + return true; +} diff --git a/src/micetools/lib/mice/patch.h b/src/micetools/lib/mice/patch.h new file mode 100644 index 0000000..c2741d0 --- /dev/null +++ b/src/micetools/lib/mice/patch.h @@ -0,0 +1,39 @@ +#pragma once +#include +#include + +#include "../json/json.h" +#include "../util/hex.h" + +typedef struct { + size_t offset; + size_t count; + char* name; + unsigned char* from; + unsigned char* to; +} patch_t; + +typedef struct { + char* name; + char* description; + char* binary_name; + bool apply; + size_t nopatches; + patch_t patches[]; +} patchset_t; + +typedef struct { + size_t nopatchsets; + patchset_t** patchsets; +} patches_t; + +// Internal JSON helpers +bool fetch(json_value* object, char* name, json_value** value); +bool fetch_string(json_value* object, char* name, char** value); +bool fetch_int(json_value* object, char* name, size_t* value); +bool fetch_bool(json_value* object, char* name, bool* value); +bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error); + +// Main two exports +void free_patches(patches_t* patches); +bool load_patches(patches_t* patches, char* path, char* error); diff --git a/src/micetools/micepatch/main.c b/src/micetools/micepatch/main.c index db28ae4..bc49d13 100644 --- a/src/micetools/micepatch/main.c +++ b/src/micetools/micepatch/main.c @@ -1,167 +1,18 @@ -#include "../lib/json/json.h" -#include "../lib/util/hex.h" -#include "stdbool.h" -#include "stdio.h" +#include "../lib/mice/mice.h" #include "string.h" -typedef struct { - size_t offset; - size_t count; - unsigned char* from; - unsigned char* to; -} patch_t; - -typedef struct { - char* name; - char* description; - bool apply; - size_t nopatches; - patch_t patches[]; -} patchset_t; - -typedef struct { - size_t nopatchsets; - patchset_t** patchsets; -} patches_t; - -bool fetch(json_value* object, char* name, json_value** value) { - if (object->type != json_object) return false; - for (size_t j = 0; j < object->u.object.length; j++) { - json_object_entry* entry = &(object->u.object.values[j]); - if (strncmp(name, entry->name, entry->name_length) == 0) { - *value = entry->value; - return true; - } - } - return false; -} -bool fetch_string(json_value* object, char* name, char** value) { - json_value* fetched; - if (!fetch(object, name, &fetched)) return false; - if (fetched->type != json_string) return false; - *value = fetched->u.string.ptr; - return true; -} -bool fetch_int(json_value* object, char* name, size_t* value) { - json_value* fetched; - if (!fetch(object, name, &fetched)) return false; - if (fetched->type != json_integer) return false; - *value = fetched->u.integer; - return true; -} -bool fetch_bool(json_value* object, char* name, bool* value) { - json_value* fetched; - if (!fetch(object, name, &fetched)) return false; - if (fetched->type != json_boolean) return false; - *value = fetched->u.boolean; - return true; -} -void free_patches(patches_t* patches) { - if (patches->nopatchsets == 0) return; - for (int i = patches->nopatchsets - 1; i >= 0; i--) { - if (patches->patchsets[i] != NULL) { - for (int j = 0; j < patches->patchsets[i]->nopatches; j++) { - if (patches->patchsets[i]->patches[j].from != NULL) free(patches->patchsets[i]->patches[j].from); - if (patches->patchsets[i]->patches[j].to != NULL) free(patches->patchsets[i]->patches[j].to); - } - free(patches->patchsets[i]); - } - } - patches->nopatchsets = 0; -} - -bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error) { - patches->nopatchsets = set_count; - patches->patchsets = (patchset_t**)malloc(set_count * sizeof(patchset_t*)); - for (int i = 0; i < set_count; i++) patches->patchsets[i] = NULL; - - error[0] = '\0'; - for (int i = 0; i < set_count; i++) { - char *name, *description; - if (!fetch_string(set_json[i], "name", &name)) { - snprintf(error, json_error_max, "'name' missing for patch %d", i); - goto failed; - } - if (!fetch_string(set_json[i], "description", &description)) { - snprintf(error, json_error_max, "'description' missing for patch %d (%s)", i, name); - goto failed; - } - bool apply; - if (!fetch_bool(set_json[i], "apply", &apply)) { - snprintf(error, json_error_max, "'apply' missing for patch %d (%s)", i, name); - goto failed; - } - json_value* set_patches; - if (!fetch(set_json[i], "patches", &set_patches) || set_patches->type != json_array) { - snprintf(error, json_error_max, "'patches' missing for patch %d (%s)", i, name); - goto failed; - } - - int count = set_patches->u.array.length; - patchset_t* patchset = (patchset_t*)malloc(sizeof(patchset_t) + (sizeof(patch_t) * count)); - patches->patchsets[i] = patchset; - patchset->name = name; - patchset->apply = apply; - patchset->description = description; - patchset->nopatches = count; - - for (int j = 0; j < count; j++) { - json_value* this_patch = set_patches->u.array.values[j]; - size_t at; - char *from, *to; - if (!fetch_int(this_patch, "at", &at)) { - snprintf(error, json_error_max, "'at' missing for patch %s[%d]", name, j); - goto failed; - } - if (!fetch_string(this_patch, "from", &from)) { - snprintf(error, json_error_max, "'from' missing for patch %s[%d]", name, j); - goto failed; - } - if (!fetch_string(this_patch, "to", &to)) { - snprintf(error, json_error_max, "'to' missing for patch %s[%d]", name, j); - goto failed; - } - - patchset->patches[j].offset = at; - size_t size = strlen(from); - if (size != strlen(to)) { - snprintf(error, json_error_max, "'from' and 'to' lengths differ in patch %s[%d]", name, j); - goto failed; - } - if (size % 2 != 0) { - snprintf(error, json_error_max, "invalid hex string in patch %s[%d]", name, j); - goto failed; - } - char* bin_from = patchset->patches[j].from = (char*)malloc(size / 2); - char* bin_to = patchset->patches[j].to = (char*)malloc(size / 2); - if (!hex_to_bin(from, bin_from, size)) { - snprintf(error, json_error_max, "invalid hex string in patch %s[%d].from", name, j); - goto failed; - }; - if (!hex_to_bin(to, bin_to, size)) { - snprintf(error, json_error_max, "invalid hex string in patch %s[%d].to", name, j); - goto failed; - }; - - patchset->patches[j].count = size / 2; - } - } - - return true; - -failed: - free_patches(patches); - return false; -} - -void print_patches(patches_t* patches) { +void print_patches(patches_t* patches, char* filename) { for (int i = 0; i < patches->nopatchsets; i++) { patchset_t* patchset = patches->patchsets[i]; - printf("Patch: %s (%s)\n", patchset->name, patchset->apply ? "applied" : "unapplied"); + bool skip = patchset->name != NULL && strcmp(patchset->name, filename) != 0; + + printf("Patch: %s (%s)\n", patchset->name, skip ? "skipped" : patchset->apply ? "applied" : "unapplied"); printf("- %s\n", patchset->description); - for (int i = 0; i < patchset->nopatches; i++) { - printf(":: %d bytes at %08x\n", patchset->patches[i].count, patchset->patches[i].offset); + if (!skip) { + for (int i = 0; i < patchset->nopatches; i++) { + printf(":: %d bytes at %08x\n", patchset->patches[i].count, patchset->patches[i].offset); + } } puts("======================"); } @@ -179,6 +30,11 @@ void apply_patches(patches_t* patches, char* filename) { for (int i = 0; i < patches->nopatchsets; i++) { patchset_t* patchset = patches->patchsets[i]; + + if (patchset->name != NULL && strcmp(patchset->name, filename) != 0) { + continue; + } + for (int j = 0; j < patchset->nopatches; j++) { patch_t patch = patchset->patches[j]; if (patch.offset + patch.count > sz) { @@ -239,65 +95,18 @@ int main(int argc, char** argv) { return -1; } - FILE* fp = fopen(argv[1], "r"); - if (fp == NULL) { - fprintf(stderr, "Failed to open '%s' (%d)\n", argv[1], errno); - return -1; - } - - fseek(fp, 0L, SEEK_END); - size_t sz = ftell(fp); - rewind(fp); - - char* json_buf = (char*)malloc(sz); - if (json_buf == NULL) { - fprintf(stderr, "Failed to allocate %d bytes\n", sz, errno); - fclose(fp); - return -1; - } - if (!(sz = fread(json_buf, 1, sz, fp))) { - fprintf(stderr, "Failed to read from '%s' (%d)\n", argv[1], errno); - fclose(fp); - return -1; - }; - fclose(fp); - - json_settings settings = {0}; char error[json_error_max]; - json_value* parsed = json_parse_ex(&settings, json_buf, sz, error); - - if (parsed == NULL) { - fprintf(stderr, "Parse error: %s\n", error); - return -1; - } - - int loaded_patches = 0; - json_value** patches_json; - if (parsed->type == json_array) { - loaded_patches = parsed->u.array.length; - patches_json = parsed->u.array.values; - } else if (parsed->type == json_object) { - loaded_patches = 1; - patches_json = &parsed; - } else { - fprintf(stderr, "Patch file format error\n"); - json_value_free(parsed); - return; - } - patches_t all_patches; - if (!parse_patches(&all_patches, patches_json, loaded_patches, error)) { - fprintf(stderr, "Patch file format error: %s\n", error); - return; + if (!load_patches(&all_patches, argv[1], error)) { + fprintf(stderr, "%s", error); + return -1; } puts(""); puts("Loaded patches:"); puts("---------------"); - print_patches(&all_patches); - + print_patches(&all_patches, argv[2]); apply_patches(&all_patches, argv[2]); - free_patches(&all_patches); return 0; } diff --git a/src/micetools/micepatch/meson.build b/src/micetools/micepatch/meson.build index f10a6f8..aa9bf7a 100644 --- a/src/micetools/micepatch/meson.build +++ b/src/micetools/micepatch/meson.build @@ -8,7 +8,6 @@ micepatch = executable( ], link_with: [ mice_lib, - json_lib, ], link_args: [ '/MANIFEST:EMBED', diff --git a/src/patches/ALLNetProc.patch.json b/src/patches/ALLNetProc.patch.json new file mode 100644 index 0000000..d8291d9 --- /dev/null +++ b/src/patches/ALLNetProc.patch.json @@ -0,0 +1,93 @@ +[ + { + "name": "LOG_EN_DONGLE", + "at": "004f48b0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_PCP", + "at": "004f989c", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_EEPROM", + "at": "004f7d04", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_BACKUP", + "at": "004f7d08", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_RTC", + "at": "004f8118", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_GFETCHER", + "at": "004f96dc", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_NETWORK", + "at": "004f8338", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_MASTER", + "at": "004f88c0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_HM", + "at": "004f88b0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_SRAM", + "at": "004f8330", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_PLATFORM", + "at": "004f9728", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_ASSERTS (We use ALPB_LOG_LEVEL instead)", + "at": "004f9e7c", + "from": "00000000", + "to": "01000000", + "count": 0 + }, + { + "name": "ALPB_LOG_LEVEL (0=None, 1=Error, 2=Warning, 3=Most, 4=Debug)", + "at": "004e884c", + "from": "01000000", + "to": "0a000000", + "count": 4 + } +] \ No newline at end of file diff --git a/src/patches/Game.patch.json b/src/patches/Game.patch.json new file mode 100644 index 0000000..20bd6c6 --- /dev/null +++ b/src/patches/Game.patch.json @@ -0,0 +1,98 @@ +[ + { + "at": "008717a0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00871728", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00871cd8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00872660", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "0087297c", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00872980", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00872988", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00873540", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00873538", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "0087f890", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00882ce4", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00882cec", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00883018", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "00886ff8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "0088b1b8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "at": "0088b1c0", + "from": "00000000", + "to": "01000000", + "count": 4 + } +] \ No newline at end of file diff --git a/src/patches/maimai_dump_.patch.json b/src/patches/maimai_dump_.patch.json new file mode 100644 index 0000000..12c0a7a --- /dev/null +++ b/src/patches/maimai_dump_.patch.json @@ -0,0 +1,149 @@ +[ + { + "name": "LOG_EN_SRAM", + "at": "00c8ab7c", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_CABINET_DL", + "at": "00f406f0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_INSTALL", + "at": "00c88680", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_EEPROM", + "at": "00c8ab78", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_PLATFORM", + "at": "00c88608", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_STORAGE", + "at": "00c88dd0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_PCP", + "at": "00ca25ec", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_HM", + "at": "00c96ed0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_HTTP", + "at": "00f406ec", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_DIPSW", + "at": "00c89ca8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_DONGLE", + "at": "00c96ed8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_JVSP", + "at": "00c9a83c", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_NETWORK", + "at": "00c89730", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_JVST_THREAD", + "at": "00c9a440", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_JVS", + "at": "00c8ab80", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_MASTER", + "at": "00c89fc8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_RTC", + "at": "00c88bb8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_JVST_DRIVER", + "at": "00c9e420", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_BACKUP", + "at": "00c89320", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_HWRESET", + "at": "00c88bb4", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN", + "at": "00c830e8", + "from": "00000000", + "to": "01000000", + "count": 4 + } +] \ No newline at end of file diff --git a/src/patches/mxnetwork.patch.json b/src/patches/mxnetwork.patch.json new file mode 100644 index 0000000..a90fd3c --- /dev/null +++ b/src/patches/mxnetwork.patch.json @@ -0,0 +1,16 @@ +[ + { + "name": "LOG_EN_PCP", + "at": "004438e0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_UTL", + "at": "004433f8", + "from": "00000000", + "to": "01000000", + "count": 4 + } +] \ No newline at end of file diff --git a/src/patches/mxsegaboot.patch.json b/src/patches/mxsegaboot.patch.json new file mode 100644 index 0000000..d3c7804 --- /dev/null +++ b/src/patches/mxsegaboot.patch.json @@ -0,0 +1,163 @@ +[ + { + "name": "LOG_EN_JVS_DRIVER", + "at": "0054fcd8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_DIPSW", + "at": "00538810", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_ATA", + "at": "0054afc8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_DONGLE", + "at": "00544b78", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_EEPROM", + "at": "00536c98", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_GCATCHER", + "at": "00537834", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_GDELIVER", + "at": "00537d4c", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_GFETCHER", + "at": "0053828c", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_HWRESET", + "at": "00547fd0", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_PLATFORM", + "at": "00547fd8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_HM", + "at": "00548268", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_BACKUP", + "at": "00536f30", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_CMOS", + "at": "00547fcc", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_INSTALL", + "at": "005382d8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_JVS", + "at": "00538818", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_JVSP", + "at": "00544b68", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_MASTER", + "at": "0054b3d8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_NETWORK", + "at": "00548280", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_RTC", + "at": "00548050", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_SRAM", + "at": "00536c94", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_STORAGE", + "at": "005487f8", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_SYS", + "at": "00536c90", + "from": "00000000", + "to": "01000000", + "count": 4 + }, + { + "name": "LOG_EN_PCPT", + "at": "00536c70", + "from": "00000000", + "to": "01000000", + "count": 4 + } +] \ No newline at end of file diff --git a/src/patches/patches.json b/src/patches/patches.json new file mode 100644 index 0000000..d1e37ed --- /dev/null +++ b/src/patches/patches.json @@ -0,0 +1,51 @@ +[ + { + "name": "maimai Finale logs", + "description": "Enable logging facilities", + "binary_name": "maimai_dump_.exe", + "apply": true, + "patches_file": "maimai_dump_.patch.json" + }, + { + "name": "mxnetwork logs", + "description": "Enable logging facilities", + "binary_name": "mxnetwork.exe", + "apply": true, + "patches_file": "mxnetwork.patch.json" + }, + { + "name": "maimai 1.00 logs", + "description": "Enable logging facilities", + "binary_name": "Game.exe", + "apply": true, + "patches_file": "Game.patch.json" + }, + { + "name": "ALLNetProc logs", + "description": "Enable logging facilities", + "binary_name": "ALLNetProc.exe", + "apply": true, + "patches_file": "ALLNetProc.patch.json" + }, + { + "name": "ALLNetProc logs", + "description": "Enable logging facilities (alt filename)", + "binary_name": "ALLNetProc_win.exe", + "apply": true, + "patches_file": "ALLNetProc.patch.json" + }, + { + "name": "mxsegaboot logs", + "description": "Enable logging facilities", + "binary_name": "mxsegaboot.exe", + "apply": true, + "patches_file": "mxsegaboot.patch.json" + }, + { + "name": "mxsegaboot logs", + "description": "Enable logging facilities (alt filename)", + "binary_name": "ORIG_mxsegaboot.exe", + "apply": true, + "patches_file": "mxsegaboot.patch.json" + } +] \ No newline at end of file