diff --git a/Makefile b/Makefile index 1f73157..9fb600b 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,18 @@ BUILD_DIR_32 := $(BUILD_DIR)/build32 BUILD_DIR_64 := $(BUILD_DIR)/build64 DIST_DIR := dist -BUILD_DRIVE = M: +BUILD_DRIVE := M: -MICE_32 = "$(BUILD_DIR_32)/src\mice.exe" -MICE_64 = "$(BUILD_DIR_64)/src\mice.exe" +MICE_32 := "$(BUILD_DIR_32)/src\mice.exe" +MICE_64 := "$(BUILD_DIR_64)/src\mice.exe" + +VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" +VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat" + +# For windows XP: +# VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" -vcvars_ver=14.16 +# VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat" -vcvars_ver=14.16 -VCVARS_32 = C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat -VCVARS_64 = C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat .ONESHELL: @@ -19,7 +24,7 @@ all: mice86 dist mice86: -@subst $(BUILD_DRIVE) . @cd /D $(BUILD_DRIVE) \ - & "$(VCVARS_32)" \ + & $(VCVARS_32) \ & meson setup --cross cross-32.ini $(BUILD_DRIVE)\$(BUILD_DIR_32) \ & meson compile -C $(BUILD_DRIVE)\$(BUILD_DIR_32) @subst $(BUILD_DRIVE) /D @@ -27,7 +32,7 @@ mice86: mice64: -@subst $(BUILD_DRIVE) . @cd $(BUILD_DRIVE) \ - & "$(VCVARS_64)" \ + & $(VCVARS_64) \ & meson setup --cross cross-64.ini $(BUILD_DRIVE)\$(BUILD_DIR_64) \ & meson compile -C $(BUILD_DRIVE)\$(BUILD_DIR_64) @subst $(BUILD_DRIVE) /D @@ -47,6 +52,8 @@ dist: @copy /Y "$(BUILD_DIR_32)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib" @copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice86.exe" +# @copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.pdb" "$(DIST_DIR)/mice86.pdb" + @copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.pdb" "$(DIST_DIR)/mice86.pdb" @copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice86.dll" # @copy /Y "$(BUILD_DIR_64)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice64.exe" # @copy /Y "$(BUILD_DIR_64)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice64.dll" diff --git a/meson.build b/meson.build index 6d81df6..c1ee10c 100644 --- a/meson.build +++ b/meson.build @@ -1,15 +1,30 @@ -project('micetools', 'c') +project('micetools', 'c', default_options: [ + 'buildtype=minsize', + # ! Tobble /\ and \/ when building for XP (minsize=normal, static=XP) + # 'b_vscrt=static_from_buildtype', + 'warning_level=2', +]) + +winxp = false +subsystem = 'console,5.01' if (host_machine.cpu_family() == 'x86') add_project_arguments('-DMICE_WIN32', language: 'c') endif add_project_arguments( - '-DWIN32_LEAN_AND_MEAN', # Strip out headers we don't really need - '-D_WIN32_WINNT=_WIN32_WINNT_WINXP', # hahahahaha I hate it - # '/O1', # Optimise size + '/DWIN32_LEAN_AND_MEAN', # Strip out headers we don't really need + '/D_WIN32_WINNT=_WIN32_WINNT_WINXP', # hahahahaha I hate it language: 'c', ) +if winxp + add_project_arguments( + '/D_USING_V140_SDK71_', + '/DSFML_STATIC', + '/DYNAMICBASE:NO', + language: 'c', + ) +endif subdir('assets') subdir('src') diff --git a/src/micetools/dll/comdevice.c b/src/micetools/dll/comdevice.c index 0a370bb..6818ccd 100644 --- a/src/micetools/dll/comdevice.c +++ b/src/micetools/dll/comdevice.c @@ -6,7 +6,8 @@ BOOL DevGetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE BOOL DevSetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; } BOOL DevSetupComm(void* data, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; } BOOL DevPurgeComm(void* data, DWORD dwFlags) { - if (dwFlags & PURGE_RXCLEAR) ((com_device_t*)data)->filled = 0; + if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&((com_device_t*)data)->out); + return TRUE; } BOOL DevGetCommModemStatus(void* data, LPDWORD lpModelStat) { @@ -18,13 +19,76 @@ BOOL DevWaitCommEvent(void* data, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent); return TRUE; } -BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) { return TRUE; } +BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) { + if (lpErrors != NULL) *lpErrors = 0; + if (lpStat != NULL) { + lpStat->fCtsHold = FALSE; + lpStat->fDsrHold = FALSE; + lpStat->fRlsdHold = FALSE; + lpStat->fXoffHold = FALSE; + lpStat->fXoffSent = FALSE; + lpStat->fEof = FALSE; + lpStat->fTxim = FALSE; + lpStat->fReserved = 0; + lpStat->cbInQue = ringbuf_available(&((com_device_t*)data)->out); + lpStat->cbOutQue = ringbuf_available(&((com_device_t*)data)->in); + } + return TRUE; +} + +BOOL DevWriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, + LPOVERLAPPED lpOverlapped) { + if (nNumberOfBytesToWrite > 0xffff) return FALSE; + // Ignore overflow + ringbuf_write(&((com_device_t*)file)->in, lpBuffer, nNumberOfBytesToWrite & 0xffff); + if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nNumberOfBytesToWrite; + return TRUE; +} +BOOL DevReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, + LPOVERLAPPED lpOverlapped) { + if (nNumberOfBytesToRead > 0xffff) return FALSE; + + // Make sure we have at least one byte to return + // while (!ringbuf_available(&((com_device_t*)file)->out)) { + // WaitForSingleObject(((com_device_t*)file)->event, INFINITE); + // } + + short read = ringbuf_read(&((com_device_t*)file)->out, lpBuffer, nNumberOfBytesToRead & 0xffff); + if (lpNumberOfBytesRead) *lpNumberOfBytesRead = read; + + if (read != 0) { + // log_info("drf", "%d", read); + // for (int i = 0; i < read; i++) { + // printf("%02x ", ((unsigned char*)lpBuffer)[i]); + // } + // puts(""); + } + return TRUE; +} + +short comdev_read(com_device_t* com, unsigned char* buffer, short bytes) { + return ringbuf_read(&com->in, buffer, bytes); +} +bool comdev_write(com_device_t* com, unsigned char* buffer, short bytes) { + bool ret = ringbuf_write(&com->out, buffer, bytes); + SetEvent(com->event); + return ret; +} +short comdev_available(com_device_t* com) { return ringbuf_available(&com->in); } + +void com_device_thread(com_device_t* com, FnComDeviceThread* thread) { + com->thread = CreateThread(NULL, 0, thread, com, 0, NULL); +} com_device_t* new_com_device(BYTE port) { com_device_t* hook = (com_device_t*)malloc(sizeof *hook); com_hook_t* com = new_com_hook(port); file_hook_t* file = new_file_hook(com->wName); + file->altFilename = com->wDosName; com->data = hook; + file->data = hook; + hook->com = com; + hook->file = file; com->GetCommState = DevGetCommState; com->SetCommState = DevSetCommState; @@ -36,9 +100,17 @@ com_device_t* new_com_device(BYTE port) { com->WaitCommEvent = DevWaitCommEvent; com->ClearCommError = DevClearCommError; - hook->filled = 0; + file->ReadFile = DevReadFile; + file->WriteFile = DevWriteFile; + + ringbuf_purge(&hook->in); + ringbuf_purge(&hook->out); hook->event = CreateEventW(NULL, TRUE, FALSE, hook->com->wName); - hook->com = com; + + hook_file(file); + hook_com(com); + free(com->virtual_handle); + com->virtual_handle = file->virtual_handle; return hook; } diff --git a/src/micetools/dll/comdevice.h b/src/micetools/dll/comdevice.h index 1b908f1..8787c6d 100644 --- a/src/micetools/dll/comdevice.h +++ b/src/micetools/dll/comdevice.h @@ -1,11 +1,23 @@ -#include "com.h" -#include "files.h" +#pragma once +#include "hooks/com.h" +#include "common.h" +#include "hooks/files.h" typedef struct com_device { com_hook_t* com; file_hook_t* file; - BYTE queue[2048]; - DWORD filled; + ring_buffer_t in; + ring_buffer_t out; HANDLE event; + HANDLE thread; } com_device_t; + +typedef DWORD(WINAPI FnComDeviceThread)(com_device_t* com); + +short comdev_read(com_device_t* com, unsigned char* buffer, short bytes); +bool comdev_write(com_device_t* com, unsigned char* buffer, short bytes); +short comdev_available(com_device_t* com); + +void com_device_thread(com_device_t* com, FnComDeviceThread* thread); +com_device_t* new_com_device(BYTE port); \ No newline at end of file diff --git a/src/micetools/dll/common.h b/src/micetools/dll/common.h new file mode 100644 index 0000000..d236d23 --- /dev/null +++ b/src/micetools/dll/common.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include +#include +#pragma comment(lib, "Shlwapi.lib") +#include +#pragma comment(lib, "d3d9.lib") +#include +#pragma comment(lib, "comctl32.lib") +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../lib/mice/mice.h" +#include "./util/_util.h" diff --git a/src/micetools/dll/devices/_devices.c b/src/micetools/dll/devices/_devices.c new file mode 100644 index 0000000..fa2c914 --- /dev/null +++ b/src/micetools/dll/devices/_devices.c @@ -0,0 +1,6 @@ +#include "_devices.h" + +void install_devices() { + install_led_bd(); + install_touch_bd(); +} diff --git a/src/micetools/dll/devices/_devices.h b/src/micetools/dll/devices/_devices.h new file mode 100644 index 0000000..8f5a335 --- /dev/null +++ b/src/micetools/dll/devices/_devices.h @@ -0,0 +1,8 @@ +#pragma once +#include "../comdevice.h" +#include "../common.h" + +void install_led_bd(); +void install_touch_bd(); + +void install_devices(); \ No newline at end of file diff --git a/src/micetools/dll/devices/led_bd.c b/src/micetools/dll/devices/led_bd.c new file mode 100644 index 0000000..ab64a99 --- /dev/null +++ b/src/micetools/dll/devices/led_bd.c @@ -0,0 +1,225 @@ +#include "../hooks/gui.h" +#include "_devices.h" + +/* +[0] = e0 +[1] = dest? +[2] = dst? +[3] = length +[4] = op code +[...] length-1 bytes +[.] = sum + +[0] = e0 +[2] = dst? +[1] = dest? +[3] = length +[4] = status +[5] = op +[6] = report +[...] +[.] = sum + +OP codes: + 3c: FUN_005735c0 (1) + + 10: FUN_00580c00 (1) + 7c: FUN_00580c00 (2) + 3c: FUN_00580c00 (1) + 39: FUN_00580c00 (4) + 3b: FUN_00580c00 (1) + + 31: FUN_00581350 (5) + 32: FUN_005813b0 (8) + 33: FUN_00581430 (8) -> something at [16]?? + 39: FUN_005814b0 (4) + 3f: FUN_00581220 (7) + + 7b: FUN_005812a0 (3) + 7c: FUN_00581310 (2) + +01: was this just an error? +10: + +31: Set button. [button] [r] [g] [b] + 0-7 = buttons + 8 = woofer + 9 = center +32: Set multiple. [00] [idx hi] [idx lo] [r] [g] [b] +33: Fade multiple?. [09] [?] [?] [r] [g] [b] +39: Set body light. [intensity] [-] [-] +3b: +3c: Commit? +3f: + +7c: +7b: + +initial setup: 7c 0-7, 32, 3c, 39, 3f, 3b +*/ + +unsigned char COLOURS[10][3]; +double positions[10][2] = { + { 0.337963, 0.470833 }, { 0.469444, 0.619792 }, { 0.469444, 0.828125 }, { 0.337037, 0.977083 }, + { 0.152778, 0.976042 }, { 0.020370, 0.828125 }, { 0.020370, 0.618750 }, { 0.151852, 0.472917 }, + { 0.5, 0.75 }, { 0.5, 0.5 }, +}; + +typedef struct rs232c_recv_head { + BYTE sync; + BYTE src; + BYTE dst; + BYTE length; + BYTE op; +} rs232c_recv_head_t; + +static DWORD WINAPI led_bd_thread(com_device_t* dev) { + log_warning("led_bd", "%ls woke up", dev->com->wName); + while (1) { + rs232c_recv_head_t head; + if (comdev_available(dev) < sizeof head) { + // Sleep(100); + continue; + } + comdev_read(dev, (char*)&head, sizeof head); + + unsigned char* extra = malloc(head.length); + comdev_read(dev, extra, head.length); + + // log_info("led_bd", "Bound %02x->%02x", head.src, head.dst); + + switch (head.op) { + case 0x01: + log_warning("led_bd", "01"); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x01\x01\x18", 8); + // syn dst src len sts op. rep chk + break; + + case 0x10: + log_warning("led_bd", "10"); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x10\x01\x27", 8); + // syn dst src len sts op. rep chk + break; + + case 0x31: + COLOURS[extra[0]][0] = extra[1]; + COLOURS[extra[0]][1] = extra[2]; + COLOURS[extra[0]][2] = extra[3]; + + log_warning("led_bd", "31: %02x = (%02x %02x %02x)", extra[0], extra[1], extra[2], extra[3]); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x31\x01\x48", 8); + // syn dst src len sts op. rep chk + break; + case 0x32: + log_warning("led_bd", "32: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3], + extra[4], extra[5], extra[6], extra[7]); + + for (unsigned char i = extra[2] - 1; i < extra[1]; i++) { + COLOURS[i][0] = extra[3]; + COLOURS[i][1] = extra[4]; + COLOURS[i][2] = extra[5]; + } + + comdev_write(dev, "\xe0\x01\x11\x03\x01\x32\x01\x49", 8); + // syn dst src len sts op. rep chk + break; + case 0x33: + log_warning("led_bd", "33: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3], + extra[4], extra[5], extra[6], extra[7]); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x33\x01\x4a", 8); + // syn dst src len sts op. rep chk + COLOURS[extra[0]][0] = extra[extra[5]]; + COLOURS[extra[0]][1] = extra[extra[6]]; + COLOURS[extra[0]][2] = extra[extra[7]]; + break; + + case 0x39: + log_warning("led_bd", "39: %02x %02x %02x", extra[0], extra[1], extra[2]); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x39\x01\x50", 8); + // syn dst src len sts op. rep chk + + COLOURS[9][0] = extra[0]; + COLOURS[9][1] = extra[0]; + COLOURS[9][2] = extra[0]; + break; + case 0x3b: + log_warning("led_bd", "3b"); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x3b\x01\x52", 8); + // syn dst src len sts op. rep chk + break; + case 0x3c: + log_warning("led_bd", "3c (I am %ls)", dev->com->wName); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x3c\x01\x53", 8); + // syn dst src len sts op. rep chk + break; + case 0x3f: + log_warning("led_bd", "3f: %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3], + extra[4], extra[5], extra[6]); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x3f\x01\x56", 8); + // syn dst src len sts op. rep chk + break; + + case 0x7c: + // extra[0] goes from 0 to 7 + // Could this be some sort of calibration for the buttons? + log_warning("led_bd", "7c: %02x", extra[0]); + comdev_write(dev, "\xe0\x01\x11\x04\x01\x7c\x01\x00\x94", 9); + // \/ causes 7b to be used + // comdev_write(dev, "\xe0\x01\x11\x04\x01\x7c\x01\x10\xa4", 9); + // syn dst src len sts op. rep --- chk + break; + case 0x7b: + log_warning("led_bd", "7b: %02x %02x %02x", extra[0], extra[1], extra[2]); + comdev_write(dev, "\xe0\x01\x11\x03\x01\x7b\x01\x92", 8); + // syn dst src len sts op. rep chk + break; + + default: + log_error("led_bd", "Unknown op %02x (%d)", head.op, head.length - 1); + break; + } + + free(extra); + } +} + +static DWORD WINAPI led_null_thread(com_device_t* dev) { + while (1) Sleep(10000000); +} + +void led_overlay(IDirect3DDevice9* dev) { + ShowCursor(true); + D3DDEVICE_CREATION_PARAMETERS cparams; + RECT rect; + + dev->lpVtbl->GetCreationParameters(dev, &cparams); + GetClientRect(cparams.hFocusWindow, &rect); + + if (GetAsyncKeyState(VK_LBUTTON) & 1) { + POINT cursor; + GetCursorPos(&cursor); + + // log_info("led_overlay", "x: %d, y: %d", cursor.x, cursor.y); + log_info("led_overlay", "x%: %f, y%: %f", (float)cursor.x / (float)rect.right, + (float)(cursor.y - 26) / (float)rect.bottom); + } + + for (unsigned char i = 0; i < 10; i++) { + int x = rect.right * positions[i][0]; + int y = rect.bottom * positions[i][1]; + draw_rect(dev, x - 25, y - 25, 50, 50, COLOURS[i][0], COLOURS[i][1], COLOURS[i][2]); + } +} + +void install_led_bd() { + register_gui_hook(&led_overlay); + + com_device_t* com5 = new_com_device(5); + com_device_thread(com5, led_null_thread); + com_device_t* leds_1p = new_com_device(6); + com_device_thread(leds_1p, led_bd_thread); + com_device_t* com7 = new_com_device(7); + com_device_thread(com7, led_null_thread); + com_device_t* leds_2p = new_com_device(8); + com_device_thread(leds_2p, led_bd_thread); +} diff --git a/src/micetools/dll/devices/meson.build b/src/micetools/dll/devices/meson.build new file mode 100644 index 0000000..d5fed29 --- /dev/null +++ b/src/micetools/dll/devices/meson.build @@ -0,0 +1,5 @@ +devices_files = files( + '_devices.c', + 'led_bd.c', + 'touch_bd.c', +) \ No newline at end of file diff --git a/src/micetools/dll/devices/touch_bd.c b/src/micetools/dll/devices/touch_bd.c new file mode 100644 index 0000000..acaf57e --- /dev/null +++ b/src/micetools/dll/devices/touch_bd.c @@ -0,0 +1,84 @@ +#include "_devices.h" + +static BYTE read_one(com_device_t* dev) { + while (!comdev_available(dev)) Sleep(50); + BYTE data; + comdev_read(dev, (char*)&data, 1); + return data; +} + +const BYTE TOUCH_ID_LUT[] = "ABCD\0EFGH\0IJKL\0MNOPQRSTU\0VWXY\0"; +static BYTE get_touch_id(BYTE id) { + for (BYTE i = 0; i < sizeof(TOUCH_ID_LUT); i++) { + if (TOUCH_ID_LUT[i] == id) return i; + } + return 0xff; +} + +BOOL touch_is_enabled = false; +BYTE thresh = 0x00; // Lazy caching of single value +DWORD WINAPI touch_bd_thread(com_device_t* dev) { + while (1) { + if (touch_is_enabled && !comdev_available(dev)) { + // Active mode! + comdev_write(dev, "(@@@@@@@@@@@@)", 14); + Sleep(100); + continue; + } + + while (read_one(dev) != '{') continue; + while (comdev_available(dev) < 5) { + log_info("touch", "<. .>"); + Sleep(50); + } + BYTE command[5]; + comdev_read(dev, command, 5); + BYTE response[6]; + memcpy(response, "( )", 6); + + if (memcmp(command, "HALT}", 5) == 0) { + if (touch_is_enabled) + log_info("touch", "Touchscreen left active mode"); + else + log_misc("touch", "Touchscreen not in active mode"); + touch_is_enabled = false; + } else if (memcmp(command, "STAT}", 5) == 0) { + if (!touch_is_enabled) + log_info("touch", "Touchscreen entered active mode"); + else + log_misc("touch", "Touchscreen already in active mode"); + touch_is_enabled = true; + } else if (command[2] == 'k' && command[4] == '}') { + BYTE sensor = get_touch_id(command[1]); + + log_misc("touch", "k-command recieved: %d >=%d", sensor, command[3]); + // Sensor == '@': failed + // ( <> <> ) + response[1] = command[0]; + response[2] = command[1]; + thresh = command[3]; + + comdev_write(dev, response, 6); + } else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') { + BYTE sensor = get_touch_id(command[1]); + + // { t h } + log_misc("touch", "th-command recieved: %d", sensor); + + // Sensor == '@': failed + // ( <> ) + response[1] = command[0]; // 'L' or 'R' + response[2] = command[1]; // Sensor + response[4] = thresh; + + comdev_write(dev, response, 6); + } else { + log_error("touch", "Unhandled: {%.*s", 5, command); + } + } +} + +void install_touch_bd() { + com_device_t* touch = new_com_device(3); + com_device_thread(touch, touch_bd_thread); +} diff --git a/src/micetools/dll/dllmain.c b/src/micetools/dll/dllmain.c index 8741f41..f9f035f 100644 --- a/src/micetools/dll/dllmain.c +++ b/src/micetools/dll/dllmain.c @@ -1,15 +1,7 @@ -#include -#include -#include -#pragma comment(lib, "Shlwapi.lib") - -#include - -#include "../lib/mice/mice.h" +#include "common.h" +#include "devices/_devices.h" #include "drivers/mx.h" -#include "micesetupapi.h" -#include "network.h" -#include "processes.h" +#include "hooks/_hooks.h" WCHAR exePath[MAX_PATH + 1]; @@ -22,7 +14,7 @@ void enable_traces() { char exePathC[MAX_PATH + 1]; WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL); - for (int i = 0; i < patches.nopatchsets; i++) { + for (size_t i = 0; i < patches.nopatchsets; i++) { patchset_t* patchset = patches.patchsets[i]; // Require the binary explicitly named @@ -31,7 +23,7 @@ void enable_traces() { } if (!patchset->apply) continue; - for (int j = 0; j < patchset->nopatches; j++) { + for (size_t j = 0; j < patchset->nopatches; j++) { patch_t patch = patchset->patches[j]; if (memcmp(patch.from, (void*)patch.offset, patch.count) != 0) { @@ -48,11 +40,14 @@ void enable_traces() { } void prebind_hooks() { - hook_setupapi(); - hook_commio(); - hook_io(); - hook_processes(); - hook_network(); + hook_all(); + install_devices(); + + // TODO: Figure out why we're needing to call this manually (medium priority) + if (wcscmp(exePath, L"ALLNetProc.exe") == 0) { + // OPENSSL_add_all_algorithms_noconf + ((void (*)(void))(0x00459770))(); + } } void init_injection() { diff --git a/src/micetools/dll/drivers/columba.c b/src/micetools/dll/drivers/columba.c index 4041396..f307276 100644 --- a/src/micetools/dll/drivers/columba.c +++ b/src/micetools/dll/drivers/columba.c @@ -1,8 +1,5 @@ -#include - #include "../lib/dmi/dmi.h" -#include "../lib/mice/mice.h" -#include "files.h" +#include "mx.h" // Much easier than pulling in winddk.h typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS; @@ -15,8 +12,9 @@ typedef struct { #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) { +BOOL columba_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) { switch (dwIoControlCode) { case IOCTL_COLUMBA_READ_DMI: log_misc("columba", @@ -36,7 +34,7 @@ BOOL columba_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn if (request->addr.QuadPart == DMI_HEADER_START) { DMI_HEADER dmi = { - .Signature = {'_', 'D', 'M', 'I', '_'}, + .Signature = { '_', 'D', 'M', 'I', '_' }, .Checksum = 0, .StructLength = dmi_size, .StructAddr = DMI_TABLES_START, diff --git a/src/micetools/dll/drivers/jvs.h b/src/micetools/dll/drivers/jvs.h new file mode 100644 index 0000000..4631bc3 --- /dev/null +++ b/src/micetools/dll/drivers/jvs.h @@ -0,0 +1,82 @@ +#define JVS_MARK 0xd0 +#define JVS_SYNC 0xe0 +#define JVS_NODE_MASTER 0x00 +#define JVS_NODE_BROADCAST 0xff + +#define JVS_VERSION_CMD 0x13 // A real board reports 1.1, but we support 1.3 +#define JVS_VERSION_JVS 0x20 +#define JVS_VERSION_COMM 0x10 + +#define JVS_STATUS_OK 0x01 +#define JVS_STATUS_UKCOM 0x02 +#define JVS_STATUS_SUM 0x03 +#define JVS_STATUS_OVERFLOW 0x04 +#define JVS_STATUS_UNKNOWN 0xff // Not a spec-compliant status, but there's none for this! + +#define JVS_REPORT_OK 0x01 +#define JVS_REPORT_PARAM_NODATA 0x02 +#define JVS_REPORT_PARAM_INVALID 0x03 +#define JVS_REPORT_BUSY 0x04 + +#define JVS_FEATURE_PAD 0x00 +#define JVS_FEATURE_EOF 0x00 +#define JVS_FEATURE_PLAYERS 0x01 +#define JVS_FEATURE_COINS 0x02 +#define JVS_FEATURE_ANALOG 0x03 +#define JVS_FEATURE_ROTARY 0x04 +#define JVS_FEATURE_KEYCODE 0x05 +#define JVS_FEATURE_SCREEN_POS 0x06 +#define JVS_FEATURE_MISC_SWITCH 0x07 +#define JVS_FEATURE_CARDS 0x10 +#define JVS_FEATURE_MEDAL_HOPPER 0x11 +#define JVS_FEATURE_GPIO 0x12 +#define JVS_FEATURE_ANALOG_OUT 0x13 +#define JVS_FEATURE_CHAR_OUT 0x14 +#define JVS_FEATURE_BACKUP 0x15 + +#define JVS_CHARTYPE_UNKNOWN 0x00 +#define JVS_CHARTYPE_NUMBER 0x01 +#define JVS_CHARTYPE_ALNUM 0x02 +#define JVS_CHARTYPE_ALNUM_KATAKANA 0x03 +#define JVS_CHARTYPE_SHIFTJIS 0x04 + +#define JVS_COINSLOT_NORMAL 0x00 +#define JVS_COINSLOT_JAM 0x01 +#define JVS_COINSLOT_COUNTER_DISCON 0x02 +#define JVS_COINSLOT_BUSY 0x03 + +// Mandatory JVS commands +#define JVS_CMD_RESET 0xf0 +#define JVS_CMD_RESET_ASSERT 0xd9 +#define JVS_CMD_ASSIGN_ADDR 0xf1 +#define JVS_CMD_CHANGE_COMMS 0xf2 + +#define JVS_CMD_READ_ID 0x10 +#define JVS_CMD_GET_CMD_VERSION 0x11 +#define JVS_CMD_GET_JVS_VERSION 0x12 +#define JVS_CMD_GET_COMM_VERSION 0x13 +#define JVS_CMD_GET_FEATURES 0x14 + +#define JVS_CMD_REQUEST_RETRANSMIT 0x2f + +// Optional JVS commands +#define JVS_CMD_RECEIVE_MAIN_ID 0x15 + +#define JVS_CMD_READ_SW 0x20 +#define JVS_CMD_READ_COIN 0x21 +#define JVS_CMD_READ_ANALOGS 0x22 +#define JVS_CMD_READ_ROTARY 0x23 +#define JVS_CMD_READ_KEYCODE 0x24 +#define JVS_CMD_READ_SCREEN_POS 0x25 +#define JVS_CMD_READ_MISC_SWITCH 0x26 +#define JVS_CMD_REMAINING_PAYOUT 0x2e + +#define JVS_CMD_COIN_DECREASE 0x30 +#define JVS_CMD_PAYOUT_INCREASE 0x31 +#define JVS_CMD_WRITE_GPIO1 0x32 +#define JVS_CMD_WRITE_ANALOG 0x33 +#define JVS_CMD_WRITE_CHARACTER 0x34 +#define JVS_CMD_COIN_INCREASE 0x35 +#define JVS_CMD_PAYOUT_DECREATE 0x36 +#define JVS_CMD_WRITE_GPIO2 0x37 +#define JVS_CMD_WRITE_GPIO3 0x38 diff --git a/src/micetools/dll/drivers/meson.build b/src/micetools/dll/drivers/meson.build new file mode 100644 index 0000000..7ee8333 --- /dev/null +++ b/src/micetools/dll/drivers/meson.build @@ -0,0 +1,9 @@ +drivers_files = files( + 'columba.c', + 'mxhwreset.c', + 'mxjvs.c', + 'mxparallel.c', + 'mxsmbus.c', + 'mxsram.c', + 'mxsuperio.c', +) \ No newline at end of file diff --git a/src/micetools/dll/drivers/mx.h b/src/micetools/dll/drivers/mx.h index 04d4f16..8c54065 100644 --- a/src/micetools/dll/drivers/mx.h +++ b/src/micetools/dll/drivers/mx.h @@ -1,6 +1,6 @@ -#include "../com.h" -#include "../files.h" -#include +#pragma once +#include "../hooks/_hooks.h" +#include "../common.h" FnDeviceIoControl mxhwreset_DeviceIoControl; void setup_mxhwreset(); @@ -20,5 +20,8 @@ void setup_mxsram(); FnDeviceIoControl mxsuperio_DeviceIoControl; void setup_mxsuperio(); +FnDeviceIoControl columba_DeviceIoControl; +void setup_columba(); + DEFINE_GUID(MXSMBUS_GUID, 0x5C49E1FE, 0x3FEC, 0x4B8D, 0xA4, 0xB5, 0x76, 0xBE, 0x70, 0x25, 0xD8, 0x42); DEFINE_GUID(PLATFORM_GUID, 0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3e, 0x30, 0x1F, 0x73); diff --git a/src/micetools/dll/drivers/mxhwreset.c b/src/micetools/dll/drivers/mxhwreset.c index ff1ce13..bdc8e64 100644 --- a/src/micetools/dll/drivers/mxhwreset.c +++ b/src/micetools/dll/drivers/mxhwreset.c @@ -1,10 +1,8 @@ -#include - -#include "../lib/mice/mice.h" #include "mx.h" -BOOL mxhwreset_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +BOOL mxhwreset_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) { switch (dwIoControlCode) { case IOCTL_MXHWRESET_RESET: if (lpBytesReturned) *lpBytesReturned = 0; diff --git a/src/micetools/dll/drivers/mxjvs.c b/src/micetools/dll/drivers/mxjvs.c index ffbcccd..f778095 100644 --- a/src/micetools/dll/drivers/mxjvs.c +++ b/src/micetools/dll/drivers/mxjvs.c @@ -1,25 +1,336 @@ #include -#include "../lib/mice/mice.h" +#include "../common.h" +#include "jvs.h" #include "mx.h" BOOL JVS_SENSE = false; +BOOL coin_solenoid = false; +BOOL test_btn = false; -BOOL mxjvs_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +// #define SCAN_COIN 0x70 +#define SCAN_TEST VK_OEM_4 // [{ +// 2 Players, 16 buttons each +int jvs_buttons[2][16] = { + { + 'C', // *1P3 + 'P', // NC + 'E', // *1P1 + 'D', // *1P2 + 'P', // NC + 'P', // NC + '1', // *1P Service + 'P', // NC + 'P', // -- + 'P', // -- + 'P', // -- + 'W', // *1P8 + 'Q', // *1P7 + 'A', // *1P6 + 'Z', // *1P5 + 'X', // *1P4 + }, + { + VK_OEM_PERIOD, // *2P3 + 'P', // NC + 'O', // *2P1 + 'L', // *2P2 + 'P', // NC + 'P', // NC + '2', // *2P Service + 'P', // NC + 'P', // -- + 'P', // -- + 'P', // -- + 'I', // *2P8 + 'U', // *2P7 + 'J', // *2P6 + 'M', // *2P5 + VK_OEM_COMMA, // *2P4 + }, +}; + +short jvs_unpad(char* paddedData, short length, char* unpaddedData) { + short index = 0; + bool escape = false; + for (short i = 0; i < length; i++) { + if (escape) + unpaddedData[index++] = paddedData[i] + 1; + else if (paddedData[i] == JVS_MARK) + escape = true; + else + unpaddedData[index++] = paddedData[i]; + } + return index; +} + +short jvs_pad(char* unpaddedData, short length, char* paddedData, short paddedMax) { + short index = 0; + for (short i = 0; i < length; i++) { + if (i > paddedMax) return -1; + + if (unpaddedData[i] == JVS_MARK || unpaddedData[i] == JVS_SYNC) { + paddedData[index++] = JVS_MARK; + paddedData[index++] = unpaddedData[i] - 1; + } else { + paddedData[index++] = unpaddedData[i]; + } + } + return index; +} + +const char JVS_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10"; + +void mxjvs_exchange(char* paddedIn, short inCount, char* outData, int maxOut, int* outCount) { + unsigned char* inData = malloc(inCount); + inCount = jvs_unpad(paddedIn, inCount, inData); + unsigned char* response = malloc(maxOut); + + unsigned char status = JVS_STATUS_OK; + + // JVS frame is 4 bytes in total + if (inCount < 4) { + log_error("mxjvs", "inCount impossibly small: %d", inCount); + status = JVS_STATUS_UNKNOWN; + goto jvs_exchange_error; + } + // This isn't a JVS packet + if (inData[0] != JVS_SYNC) { + log_error("mxjvs", "SYNC missing. Saw 0x%02x", inData[0]); + status = JVS_STATUS_UNKNOWN; + goto jvs_exchange_error; + } + + // Validate the checksum before proceeding + unsigned char sum = 0; + for (int i = 1; i < inCount - 1; i++) sum += inData[i]; + if (sum != inData[inCount - 1]) { + log_error("mxjvs", "Checksum failed. Computed 0x%02x, expected 0x%02x", sum, inData[inCount - 1]); + status = JVS_STATUS_SUM; + goto jvs_exchange_error; + } + + unsigned char destination = inData[1]; + unsigned char length = inData[2]; + // length 0 is nonsensical because there's a checksum! + if (length == 0) { + status = JVS_STATUS_SUM; + goto jvs_exchange_error; + } + short jvsIndex = 3; // D0 + + response[0] = JVS_SYNC; + response[1] = JVS_NODE_MASTER; + short respIndex = 4; // D0 +#define jvs_read(x) \ + if (jvsIndex - 2 >= length) { \ + status = JVS_STATUS_OVERFLOW; \ + goto jvs_exchange_error; \ + } else { \ + (x) = inData[jvsIndex++]; \ + } +#define jvs_write(x) response[respIndex++] = (x); + + while (jvsIndex - 2 < length) { + unsigned char cmd; + jvs_read(cmd); + // log_info("jvs", "jvs cmd: %02x", cmd); + switch (cmd) { + case JVS_CMD_RESET: + unsigned char reset_assert; + jvs_read(reset_assert); + if (reset_assert != JVS_CMD_RESET_ASSERT) { + status = JVS_STATUS_UKCOM; + goto jvs_exchange_error; + } + JVS_SENSE = true; + // Special case + *outCount = 0; + return; + case JVS_CMD_CHANGE_COMMS: + // Special case + *outCount = 0; + return; + + case JVS_CMD_ASSIGN_ADDR: + jvs_write(JVS_REPORT_OK); + JVS_SENSE = false; + // we don't bother remembering the address because at the moment we only simulate + // a single board in the JVS chain. + unsigned char _; + jvs_read(_); + break; + + case JVS_CMD_READ_ID: + jvs_write(JVS_REPORT_OK); + for (int i = 0; i < sizeof JVS_ID; i++) jvs_write(JVS_ID[i]); + break; + case JVS_CMD_GET_CMD_VERSION: + jvs_write(JVS_REPORT_OK); + jvs_write(JVS_VERSION_CMD); + break; + case JVS_CMD_GET_JVS_VERSION: + jvs_write(JVS_REPORT_OK); + jvs_write(JVS_VERSION_JVS); + break; + case JVS_CMD_GET_COMM_VERSION: + jvs_write(JVS_REPORT_OK); + jvs_write(JVS_VERSION_COMM); + break; + + case JVS_CMD_GET_FEATURES: + jvs_write(JVS_REPORT_OK); + + jvs_write(JVS_FEATURE_PLAYERS); + jvs_write(2); + jvs_write(13); + jvs_write(JVS_FEATURE_PAD); + jvs_write(JVS_FEATURE_COINS); + jvs_write(2); + jvs_write(JVS_FEATURE_PAD); + jvs_write(JVS_FEATURE_PAD); + jvs_write(JVS_FEATURE_ANALOG); + jvs_write(8); // 8 ADC channels + jvs_write(JVS_FEATURE_PAD); // ?? (was "10" prior) + jvs_write(JVS_FEATURE_PAD); + jvs_write(JVS_FEATURE_GPIO); + jvs_write(6); // 6 ports + jvs_write(JVS_FEATURE_PAD); + jvs_write(JVS_FEATURE_PAD); + + jvs_write(JVS_FEATURE_EOF); + + break; + case JVS_CMD_RECEIVE_MAIN_ID: + unsigned char tempRead = -1; + while (tempRead != 0) jvs_read(tempRead); + // TODO: Do we need to report here? + break; + + case JVS_CMD_READ_SW: + unsigned char players; + unsigned char switch_bytes; + jvs_read(players); + jvs_read(switch_bytes); + if (players > 2 || switch_bytes != 2) { + jvs_write(JVS_REPORT_PARAM_INVALID); + break; + } + + jvs_write(JVS_REPORT_OK); + unsigned char buttons = 0x00; + if (GetAsyncKeyState(SCAN_TEST) < 0) buttons |= 0x80; + jvs_write(buttons); + + for (int i = 0; i < players; i++) { + for (int j = 0; j < switch_bytes; j++) { + buttons = 0x00; + for (int bit = 0; bit < 8; bit++) { + int scancode = jvs_buttons[i][j * 8 + bit]; + + // Buttons on maimai use beam interrupt sensors, so logical high = unpressed. + bool invert = ((j == 0 && (bit == 0 || bit == 2 || bit == 3)) || (j == 1 && bit >= 3)); + + if (invert) + buttons |= (GetAsyncKeyState(scancode) >= 0) << bit; + else + buttons |= (GetAsyncKeyState(scancode) < 0) << bit; + + // JAMMA does **NOT** do any of this lol + // Service is pull-down for some reason + // bool pulse = (j == 0) && (bit == 6); + // // JAMMA uses the falling edge of a pull-up switch + // if (pulse) { + // buttons |= (GetAsyncKeyState(scancode) >= 0) << bit; + // buttons |= (!(GetAsyncKeyState(scancode) & 1)) << bit; + // } else { + // buttons |= (GetAsyncKeyState(scancode) < 0) << bit; + // buttons |= (GetAsyncKeyState(scancode) & 1) << bit; + // } + } + jvs_write(buttons); + } + } + + break; + + case JVS_CMD_READ_ANALOGS: + jvs_write(JVS_REPORT_OK); + // TODO: Actually emulate these (super low priority) + unsigned char analog_count; + jvs_read(analog_count); + for (int i = analog_count; i > 0; i--) { + jvs_write(0xde); + jvs_write(0xad); + } + break; + + case JVS_CMD_WRITE_GPIO1: + jvs_write(JVS_REPORT_OK); + unsigned char gpio_bytes; + jvs_read(gpio_bytes); + for (int i = 0; i < gpio_bytes; i++) { + unsigned char gpio_value; + jvs_read(gpio_value); + + if (i == 0) { + if (!!(gpio_value & 0x80) != coin_solenoid) { + coin_solenoid = !!(gpio_value & 0x80); + log_info("mxjvs", "Coin solenoid: %s", coin_solenoid ? "Locked" : "Unlocked"); + } + } + + // log_warning("mxjvs", "Unhandled GPIO write: *(%d) = %02x", i, gpio_value); + } + break; + + default: + log_error("mxjvs", "Unknown command: 0x%02x", cmd); + + status = JVS_STATUS_UKCOM; + goto jvs_exchange_error; + } + } +#undef jvs_read +#undef jvs_write + + goto jvs_exchange_complete; +jvs_exchange_error: + log_error("mxjvs", "JVS status: 0x%02x", status); + respIndex = 4; // As if we've just written status, but nothing else + +jvs_exchange_complete: + response[2] = respIndex - 2; // respIndex doesn't include SUM yet + response[3] = status; + + // Compute and set the checksum + sum = 0; + for (int i = 1; i < respIndex; i++) sum += response[i]; + response[respIndex++] = sum; + + short paddedLength = jvs_pad(response, respIndex, outData, maxOut); + // We failed hard. It's not worth sending an overflow response + if (paddedLength == -1) + *outCount = 0; + else + *outCount = 0x00000000 | paddedLength; + + free(response); + free(inData); +} + +BOOL mxjvs_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) { switch (dwIoControlCode) { case IOCTL_MXJVS_EXCHANGE: - log_error("mxjvs", - "DeviceIoControl(, , 0x%p, 0x%x, -, " - "0x%x, -, -)", - lpInBuffer, nInBufferSize, nOutBufferSize); + log_misc("mxjvs", + "DeviceIoControl(, , 0x%p, 0x%x, -, " + "0x%x, -, -)", + lpInBuffer, nInBufferSize, nOutBufferSize); - // mxjvsDevice->exchange( - // lpbyte(lpInBuffer), nInBufferSize & 0xFFFF, - // lpbyte(lpOutBuffer), lpBytesReturned - // ); + mxjvs_exchange(lpInBuffer, nInBufferSize & 0xffff, lpOutBuffer, nOutBufferSize, lpBytesReturned); - if (lpBytesReturned) *lpBytesReturned = 0; break; default: log_warning("mxjvs", "unhandled 0x%08x", dwIoControlCode); @@ -35,13 +346,13 @@ 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; + *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"}; + 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; diff --git a/src/micetools/dll/drivers/mxsmbus.c b/src/micetools/dll/drivers/mxsmbus.c index 1a950ea..8e65f07 100644 --- a/src/micetools/dll/drivers/mxsmbus.c +++ b/src/micetools/dll/drivers/mxsmbus.c @@ -1,7 +1,5 @@ -#include - #include "../lib/dmi/dmi.h" -#include "../lib/mice/mice.h" +#include "../hooks/setupapi_.h" #include "mx.h" #include "smbus.h" @@ -18,8 +16,17 @@ #define PCA9535_CONF0 0x06 #define PCA9535_CONF1 0x07 -#define PCA9535 0x20 -#define EEPROM 0x57 +#define SMBUS_PCA9535 0x20 +#define SMBUS_EEPROM 0x57 // Doesn't line up with manual! + +#define SMBUS_DDR2_DIMM_A1 0x000 // what does 0xA0 mean? +#define SMBUS_DDR2_DIMM_B1 0x010 // what does 0xA4 mean? +#define SMBUS_EEPROM_ 0x0AE // = AT24C64AN +#define SMBUS_ICS9LPRS908 0xfff // Unknown +#define SMBUS_W83627UHG 0xfff // Unknown; hwmon. Possibly 0x2e or 0x4e +#define SMBUS_UPI_UP6261BM8 0xfff // Unknown; vref +#define SMBUS_UPI_ISL6322CR 0xfff // Unknown; vrm +// SMBUS is send onto the mezzanine board! #define EEPROM_DUMP L"dev/eeprom.bin" typedef struct eeprom_reg { @@ -39,53 +46,6 @@ eeprom_bank_t EEPROM_DATA; * - Reg 0x0e: Stores */ -typedef uint_fast32_t crc_t; - -static const crc_t crc_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, - 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, - 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, - 0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, - 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, - 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, - 0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, - 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, - 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, - 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, - 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, - 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d}; -#define CRC_ALGO_TABLE_DRIVEN 1 -static inline crc_t crc_init(void) { return 0xffffffff; } -crc_t crc_update(crc_t crc, const void* data, size_t data_len) { - const unsigned char* d = (const unsigned char*)data; - unsigned int tbl_idx; - - while (data_len--) { - tbl_idx = (crc ^ *d) & 0xff; - crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff; - d++; - } - return crc & 0xffffffff; -} -static inline crc_t crc_finalize(crc_t crc) { return crc ^ 0xffffffff; } - void eeprom_dump() { HANDLE dump = _CreateFileW(EEPROM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (dump == INVALID_HANDLE_VALUE) { @@ -107,11 +67,14 @@ void eeprom_restore() { } DWORD eeprom_crc(BYTE reg) { - if (reg == 0x80 || reg == 0x280) { + if (reg == 0x04 || reg == 0x14 || reg == 0x80 || reg == 0x280) { // Some registers are only treated as 16 byte values - return crc_finalize(crc_update(crc_init(), EEPROM_DATA.reg[reg].data + 4, 12)); + crc32_build_table(); + return crc32(12, EEPROM_DATA.reg[reg].data + 4, 0); } - return crc_finalize(crc_update(crc_init(), EEPROM_DATA.reg[reg].data + 4, 28)); + + crc32_build_table(); + return crc32(28, EEPROM_DATA.reg[reg].data + 4, 0); } void eeprom_read(BYTE reg, BYTE index, BYTE* data, BYTE length) { eeprom_restore(); @@ -149,8 +112,9 @@ BYTE eeprom_read_one(BYTE reg, BYTE index) { } void eeprom_write_one(BYTE reg, BYTE index, BYTE data) { eeprom_write(reg, index, &data, 1); } -BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +BOOL mxsmbus_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) { mxsmbus_i2c_packet* i2c_packet = (mxsmbus_i2c_packet*)lpInBuffer; mxsmbus_i2c_packet* i2c_out = (mxsmbus_i2c_packet*)lpOutBuffer; @@ -203,21 +167,21 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn // 48: addr 0x00: amHmGetLPCChipId switch (i2c_packet->addr) { - case PCA9535: + case SMBUS_PCA9535: switch (i2c_packet->prt) { case PCA9535_WRITE: switch (i2c_packet->reg) { case PCA9535_OUT1: log_info("mxsmbus", "pca9535 OUT1: %02x %02x", i2c_packet->data[0], - i2c_packet->data[1]); + i2c_packet->data[1]); break; case PCA9535_INV0: log_info("mxsmbus", "pca9535 INV0: %02x %02x", i2c_packet->data[0], - i2c_packet->data[1]); + i2c_packet->data[1]); break; case PCA9535_INV1: log_info("mxsmbus", "pca9535 INV1: %02x %02x", i2c_packet->data[0], - i2c_packet->data[1]); + i2c_packet->data[1]); break; default: log_error("mxsmbux", @@ -232,12 +196,22 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn case PCA9535_IN0: // DIPSW i2c_packet->data[0] = 0x00; break; - case PCA9535_IN1: // What's this one? - i2c_packet->data[0] = 0x00; + case PCA9535_IN1: // SW1/2 + extras + /* + 0: uk + 1: uk + 2: ¬test + 3: ¬service + 4: uk + 5: uk + 6: uk + 7: uk + */ + i2c_packet->data[0] = 0x0c; break; case PCA9535_INV0: case PCA9535_INV1: - case PCA9535_OUT1: + case PCA9535_OUT1: // LEDs, probably i2c_packet->data[0] = 0x00; break; default: @@ -254,7 +228,7 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn exit(1); } break; - case EEPROM: + case SMBUS_EEPROM: switch (i2c_packet->prt) { case 3: // Wait // 0x18 = wait, 0x00 = done @@ -311,7 +285,7 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn return FALSE; } - if (request_packet->addr != EEPROM) { + if (request_packet->addr != SMBUS_EEPROM) { log_error("mxsmbus", "Unexpected I2C device: 0x%02x", request_packet->addr); exit(1); } @@ -358,6 +332,6 @@ void setup_mxsmbus() { hook_file(mxsmbus); if (!add_fake_device(&MXSMBUS_GUID, L"\\\\.\\mxsmbus")) { - log_error("mxsmbus", "failed to install mxsmbus device"); - } + log_error("mxsmbus", "failed to install mxsmbus device"); + } } diff --git a/src/micetools/dll/drivers/mxsram.c b/src/micetools/dll/drivers/mxsram.c index 411d4a2..0d7566f 100644 --- a/src/micetools/dll/drivers/mxsram.c +++ b/src/micetools/dll/drivers/mxsram.c @@ -1,6 +1,3 @@ -#include - -#include "../lib/mice/mice.h" #include "mx.h" #define SRAM_DUMP L"dev/sram.bin" @@ -27,8 +24,9 @@ void sram_restore() { _CloseHandle(dump); } -BOOL mxsram_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +BOOL mxsram_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) { DWORD SRAM_VERSION = 0x0001; DWORD SRAM_SECTOR_SIZE = 0x100; // Max is 0x800 @@ -74,7 +72,7 @@ BOOL mxsram_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInB return TRUE; } -DWORD mxsram_SetFilePointer(LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { +DWORD mxsram_SetFilePointer(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) { if (dwMoveMethod == FILE_BEGIN) { SRAM_POINTER = lDistanceToMove; } else if (dwMoveMethod == FILE_CURRENT) { @@ -83,7 +81,7 @@ DWORD mxsram_SetFilePointer(LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DW return SRAM_POINTER; } -BOOL mxsram_WriteFile(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, +BOOL mxsram_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { log_misc("mxsram", "sram write 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToWrite); if (SRAM_POINTER + nNumberOfBytesToWrite >= SRAM_SIZE) { @@ -95,7 +93,7 @@ BOOL mxsram_WriteFile(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpN return TRUE; } -BOOL mxsram_ReadFile(LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, +BOOL mxsram_ReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) { log_misc("mxsram", "sram read 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToRead); if (SRAM_POINTER + nNumberOfBytesToRead >= SRAM_SIZE) { diff --git a/src/micetools/dll/drivers/mxsuperio.c b/src/micetools/dll/drivers/mxsuperio.c index 4c0b281..c1df90b 100644 --- a/src/micetools/dll/drivers/mxsuperio.c +++ b/src/micetools/dll/drivers/mxsuperio.c @@ -1,6 +1,3 @@ -#include - -#include "../lib/mice/mice.h" #include "mx.h" #include "smbus.h" #include "w83791d.h" @@ -16,8 +13,9 @@ BYTE w83791d_crit_t3 = 80; // C BYTE w83791d_vbat_monitor_control = 0x00; BOOL w83791d_4f_high = 0; -BOOL mxsuperio_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +BOOL mxsuperio_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) { mxsuperio_lpc_packet* lpc_packet = (mxsuperio_lpc_packet*)lpInBuffer; mxsuperio_lpc_packet* lpc_out = (mxsuperio_lpc_packet*)lpOutBuffer; diff --git a/src/micetools/dll/files.h b/src/micetools/dll/files.h deleted file mode 100644 index 33ecf32..0000000 --- a/src/micetools/dll/files.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include - -static HANDLE(WINAPI* TrueCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile); -static HANDLE(WINAPI* TrueCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, - DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, - HANDLE hTemplateFile); - -static BOOL(WINAPI* TrueDeviceIoControl)(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, - DWORD nOutBufferSize, LPDWORD lpBytesReturned, - LPOVERLAPPED lpOverlapped); - -static DWORD(WINAPI* TrueSetFilePointer)(HANDLE hFile, LONG lDistanceToMove, - PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); -static BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); -static BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, - LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); - -static BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject); - -typedef BOOL(FnDeviceIoControl)(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, - LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, - LPOVERLAPPED lpOverlapped); - -typedef DWORD(FnSetFilePointer)(LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, - DWORD dwMoveMethod); -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) -#define _CloseHandle (TrueCloseHandle ? TrueCloseHandle : CloseHandle) -#define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW) - -typedef struct drive_redirect { - const CHAR* drive; - const CHAR* path; -} drive_redirect_t; - -typedef struct file_hook { - LPCWSTR filename; - - FnDeviceIoControl* DeviceIoControl; - FnSetFilePointer* SetFilePointer; - FnWriteFile* WriteFile; - FnReadFile* ReadFile; - - LPHANDLE virtual_handle; - struct file_hook* next; -} file_hook_t; - -file_hook_t* new_file_hook(LPCWSTR filename); -void hook_file(file_hook_t* hook); -void hook_io(); diff --git a/src/micetools/dll/hooks/_hooks.c b/src/micetools/dll/hooks/_hooks.c new file mode 100644 index 0000000..27eaa4d --- /dev/null +++ b/src/micetools/dll/hooks/_hooks.c @@ -0,0 +1,12 @@ +#include "_hooks.h" + +void hook_all() { + hook_logging(); + hook_gui(); + hook_setupapi(); + hook_commio(); + hook_io(); + hook_processes(); + hook_network(); + hook_time(); +} diff --git a/src/micetools/dll/hooks/_hooks.h b/src/micetools/dll/hooks/_hooks.h new file mode 100644 index 0000000..20f8c8c --- /dev/null +++ b/src/micetools/dll/hooks/_hooks.h @@ -0,0 +1,12 @@ +#pragma once + +#include "com.h" +#include "files.h" +#include "gui.h" +#include "logging.h" +#include "network.h" +#include "processes.h" +#include "setupapi_.h" +#include "time.h" + +void hook_all(); diff --git a/src/micetools/dll/com.c b/src/micetools/dll/hooks/com.c similarity index 97% rename from src/micetools/dll/com.c rename to src/micetools/dll/hooks/com.c index 6109c92..284f118 100644 --- a/src/micetools/dll/com.c +++ b/src/micetools/dll/hooks/com.c @@ -1,12 +1,13 @@ #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); + memset(hook->wName, 0, sizeof hook->wName); swprintf(hook->wName, (sizeof hook->wName) / (sizeof hook->wName[0]), L"COM%d", port); + memset(hook->wDosName, 0, sizeof hook->wDosName); + swprintf(hook->wDosName, (sizeof hook->wDosName) / (sizeof hook->wDosName[0]), L"\\\\.\\COM%d", port); hook->com = port; hook->GetCommState = NULL; diff --git a/src/micetools/dll/com.h b/src/micetools/dll/hooks/com.h similarity index 92% rename from src/micetools/dll/com.h rename to src/micetools/dll/hooks/com.h index 16ba7a0..05be00d 100644 --- a/src/micetools/dll/com.h +++ b/src/micetools/dll/hooks/com.h @@ -1,6 +1,6 @@ -#include -#include -#include +#pragma once + +#include "../common.h" static BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB); static BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB); @@ -24,7 +24,8 @@ typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat); typedef struct com_hook { LPHANDLE virtual_handle; - WCHAR wName[7]; // max is COM255 + WCHAR wName[7]; // max is "COM255" + WCHAR wDosName[11]; // max is "\\\\.\\COM255" BYTE com; FnGetCommState* GetCommState; @@ -44,4 +45,5 @@ typedef struct com_hook { com_hook_t* new_com_hook(BYTE port); void hook_com(com_hook_t* hook); -void hook_com(); + +void hook_commio(); diff --git a/src/micetools/dll/files.c b/src/micetools/dll/hooks/files.c similarity index 71% rename from src/micetools/dll/files.c rename to src/micetools/dll/hooks/files.c index 11af159..6046774 100644 --- a/src/micetools/dll/files.c +++ b/src/micetools/dll/hooks/files.c @@ -1,20 +1,14 @@ #include "files.h" -#include "../lib/mice/mice.h" - HANDLE fake_handle = (HANDLE)0x10000000; file_hook_t* file_hook_list = NULL; file_hook_t* new_file_hook(LPCWSTR filename) { file_hook_t* hook = (file_hook_t*)malloc(sizeof(file_hook_t)); + memset(hook, 0, sizeof(file_hook_t)); hook->filename = filename; - hook->DeviceIoControl = NULL; - hook->SetFilePointer = NULL; - hook->WriteFile = NULL; - hook->ReadFile = NULL; - return hook; } void hook_file(file_hook_t* hook) { @@ -32,8 +26,11 @@ void hook_file(file_hook_t* hook) { }; drive_redirect_t DRIVE_REDIRECT_TABLE[] = { - {.drive = "Y:\\", .path = ".\\dev\\Y\\"}, - {.drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\"}}; + { .drive = "Y:\\", .path = ".\\dev\\Y\\" }, + // Note: Had tp create last_shime.log + { .drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\" }, + // {.drive = "C:\\ProgramData/boost_interprocess/", .path = "\\\\.\\ipc\\"}, +}; char* redirect_path(char* path) { for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) { @@ -66,13 +63,16 @@ HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD d file_hook_t* hook = file_hook_list; while (hook != NULL) { - if (wcscmp(lpFileName, hook->filename) == 0) { + if (wcscmp(lpFileName, hook->filename) == 0 || + (hook->altFilename != NULL && wcscmp(lpFileName, hook->altFilename) == 0)) { if (*hook->virtual_handle == NULL) { // TODO: Assign handles better! *hook->virtual_handle = fake_handle; ((size_t)fake_handle)++; } handle = *hook->virtual_handle; + + log_info(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle); break; } hook = hook->next; @@ -113,8 +113,12 @@ BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lp // TODO: Less jank if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent); - return hook->DeviceIoControl(dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize, - lpBytesReturned, lpOverlapped); + BOOL ret = hook->DeviceIoControl(hook->data, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, + nOutBufferSize, lpBytesReturned, lpOverlapped); + if (ret && lpOverlapped && lpBytesReturned) { + lpOverlapped->InternalHigh = *lpBytesReturned; + } + return ret; } else { log_error(HOOKS_LOGGER, "DeviceIoControl(%ls) unimplemented", hook->filename); return FALSE; @@ -134,7 +138,7 @@ DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDist while (hook != NULL) { if (*hook->virtual_handle == hFile) { if (hook->SetFilePointer) { - return hook->SetFilePointer(lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod); + return hook->SetFilePointer(hook->data, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod); } else { log_error(HOOKS_LOGGER, "SetFilePointer(%ls) unimplemented", hook->filename); return FALSE; @@ -146,13 +150,49 @@ DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDist return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod); } +BOOL WINAPI FakeSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, + DWORD dwMoveMethod) { + file_hook_t* hook = file_hook_list; + while (hook != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->SetFilePointerEx) { + return hook->SetFilePointerEx(hook->data, liDistanceToMove, lpNewFilePointer, dwMoveMethod); + } else { + log_error(HOOKS_LOGGER, "SetFilePointerEx(%ls) unimplemented", hook->filename); + return FALSE; + } + } + hook = hook->next; + } + + return TrueSetFilePointerEx(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod); +} + +DWORD WINAPI FakeGetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) { + file_hook_t* hook = file_hook_list; + while (hook != NULL) { + if (*hook->virtual_handle == hFile) { + if (hook->GetFileSizeEx) { + return hook->GetFileSizeEx(hook->data, lpFileSize); + } else { + log_error(HOOKS_LOGGER, "GetFileSizeEx(%ls) unimplemented", hook->filename); + return FALSE; + } + } + hook = hook->next; + } + + return TrueGetFileSizeEx(hFile, lpFileSize); +} + DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) { file_hook_t* hook = file_hook_list; while (hook != NULL) { if (*hook->virtual_handle == hFile) { if (hook->WriteFile) { - return hook->WriteFile(lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped); + return hook->WriteFile(hook->data, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, + lpOverlapped); } else { log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", hook->filename); return FALSE; @@ -170,7 +210,7 @@ BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRe while (hook != NULL) { if (*hook->virtual_handle == hFile) { if (hook->ReadFile) { - return hook->ReadFile(lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); + return hook->ReadFile(hook->data, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped); } else { log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", hook->filename); return FALSE; @@ -185,7 +225,8 @@ BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRe BOOL WINAPI FakeCloseHandle(HANDLE hObject) { file_hook_t* hook = file_hook_list; while (hook != NULL) { - if (hook->virtual_handle == hObject) { + if (hObject != NULL && *hook->virtual_handle == hObject) { + log_misc("file", "close %08x", hObject); return TRUE; } hook = hook->next; @@ -206,8 +247,10 @@ void hook_io() { hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6); hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6); + hook("Kernel32.dll", "SetFilePointerEx", FakeSetFilePointerEx, (void**)&TrueSetFilePointerEx, 6); hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile, 6); hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile, 6); + hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx, 6); hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32, 5); } diff --git a/src/micetools/dll/hooks/files.h b/src/micetools/dll/hooks/files.h new file mode 100644 index 0000000..5219c91 --- /dev/null +++ b/src/micetools/dll/hooks/files.h @@ -0,0 +1,72 @@ +#pragma once +#include "../common.h" + +static HANDLE(WINAPI* TrueCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); +static HANDLE(WINAPI* TrueCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile); + +static BOOL(WINAPI* TrueDeviceIoControl)(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped); + +static DWORD(WINAPI* TrueSetFilePointer)(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, + DWORD dwMoveMethod); +static BOOL(WINAPI* TrueSetFilePointerEx)(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, + DWORD dwMoveMethod); +// logging needs access to WriteFile, so we can't static it! +BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); +static BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, + LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped); +static BOOL(WINAPI* TrueGetFileSizeEx)(HANDLE hFile, PLARGE_INTEGER lpFileSize); +static BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject); + +typedef BOOL(FnDeviceIoControl)(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, + LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped); + +typedef DWORD(FnSetFilePointer)(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod); +typedef BOOL(FnSetFilePointerEx)(void* file, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer, + DWORD dwMoveMethod); +typedef BOOL(FnWriteFile)(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, + LPOVERLAPPED lpOverlapped); +typedef BOOL(FnReadFile)(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, + LPOVERLAPPED lpOverlapped); + +typedef BOOL(FnGetFileSizeEx)(void* file, PLARGE_INTEGER lpFileSize); + +static int(WINAPIV* True_stat64i32)(const char* path, struct _stat64i32* buffer); + +#define _WriteFile (TrueWriteFile ? TrueWriteFile : WriteFile) +#define _ReadFile (TrueReadFile ? TrueReadFile : ReadFile) +#define _CloseHandle (TrueCloseHandle ? TrueCloseHandle : CloseHandle) +#define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW) + +typedef struct drive_redirect { + const CHAR* drive; + const CHAR* path; +} drive_redirect_t; + +typedef struct file_hook { + LPCWSTR filename; + LPCWSTR altFilename; + + FnDeviceIoControl* DeviceIoControl; + FnSetFilePointer* SetFilePointer; + FnSetFilePointerEx* SetFilePointerEx; + FnWriteFile* WriteFile; + FnReadFile* ReadFile; + FnGetFileSizeEx* GetFileSizeEx; + + void* data; + + LPHANDLE virtual_handle; + struct file_hook* next; +} file_hook_t; + +file_hook_t* new_file_hook(LPCWSTR filename); +void hook_file(file_hook_t* hook); +void hook_io(); diff --git a/src/micetools/dll/hooks/gui.c b/src/micetools/dll/hooks/gui.c new file mode 100644 index 0000000..d8c3227 --- /dev/null +++ b/src/micetools/dll/hooks/gui.c @@ -0,0 +1,111 @@ +#include "gui.h" + +static HWND window; +BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) { + DWORD wndProcId; + GetWindowThreadProcessId(handle, &wndProcId); + + if (GetCurrentProcessId() != wndProcId) return TRUE; + + window = handle; + return FALSE; +} +HWND GetProcessWindow() { + window = NULL; + EnumWindows(EnumWindowsCallback, 0); + return window; +} +BOOL GetD3D9Device(void** pTable, size_t Size) { + if (!pTable) return false; + + IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION); + if (!pD3D) return false; + + IDirect3DDevice9* pDummyDevice = NULL; + D3DPRESENT_PARAMETERS d3dpp = { 0 }; + d3dpp.Windowed = false; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = GetProcessWindow(); + + HRESULT dummyDeviceCreated = + pD3D->lpVtbl->CreateDevice(pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice); + + if (dummyDeviceCreated != S_OK) { + d3dpp.Windowed = !d3dpp.Windowed; + + dummyDeviceCreated = pD3D->lpVtbl->CreateDevice(pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice); + if (dummyDeviceCreated != S_OK) { + pD3D->lpVtbl->Release(pD3D); + return false; + } + } + + memcpy(pTable, *(void***)pDummyDevice, Size); + + pDummyDevice->lpVtbl->Release(pDummyDevice); + pD3D->lpVtbl->Release(pD3D); + return true; +} + +static HRESULT(WINAPI* TrueEndScene)(IDirect3DDevice9*); + +void draw_rect(IDirect3DDevice9* dev, int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b) { + D3DCOLOR rectColor = D3DCOLOR_XRGB(r, g, b); + D3DRECT BarRect = { x, y, x + w, y + h }; + + dev->lpVtbl->Clear(dev, 1, &BarRect, D3DCLEAR_TARGET | D3DCLEAR_TARGET, rectColor, 0, 0); +} + +HRESULT __stdcall hkEndScene(IDirect3DDevice9* pDevice) { + static bool showMenu = false; + + end_scene_hook_t* head = end_scene_hook_list; + while (head != NULL) { + head->hook(pDevice); + head = head->next; + } + return TrueEndScene(pDevice); +} + +void register_gui_hook(FnEndScene* end_scene) { + end_scene_hook_t** head = &end_scene_hook_list; + while (*head != NULL) { + head = &((*head)->next); + } + end_scene_hook_t* hook = malloc(sizeof(end_scene_hook_t)); + hook->hook = end_scene; + hook->next = NULL; + *head = hook; +} + +LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, + DWORD_PTR dwRefData) { + // ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam); + + return DefSubclassProc(hWnd, uMsg, wParam, lParam); +} +HWND WINAPI FakeCreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y, + int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, + LPVOID lpParam) { + HWND hWnd = TrueCreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, + hMenu, hInstance, lpParam); + + void* d3d9Device[119]; + + if (GetD3D9Device(d3d9Device, sizeof(d3d9Device))) { + *((PVOID*)&TrueEndScene) = CreateHook((PVOID)d3d9Device[42], (PVOID)hkEndScene, 7); + } + + if (hWnd && !SetWindowSubclass(hWnd, WndProc, (int)&WndProc, (DWORD_PTR)NULL)) { + log_error("gui", "failed to SetWindowSubclass(%d)", GetLastError()); + } + + return hWnd; +} + +void hook_gui() { + // + hook("User32.dll", "CreateWindowExA", FakeCreateWindowExA, (void**)&TrueCreateWindowExA, 7); +} diff --git a/src/micetools/dll/hooks/gui.h b/src/micetools/dll/hooks/gui.h new file mode 100644 index 0000000..018bc18 --- /dev/null +++ b/src/micetools/dll/hooks/gui.h @@ -0,0 +1,20 @@ +#pragma once +#include "common.h" + + +static HWND(WINAPI* TrueCreateWindowExA)(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, + int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, + HINSTANCE hInstance, LPVOID lpParam); + +void draw_rect(IDirect3DDevice9* dev, int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b); + +typedef VOID(FnEndScene)(IDirect3DDevice9* dev); + +typedef struct end_scene_hook { + FnEndScene* hook; + struct end_scene_hook* next; +} end_scene_hook_t; +end_scene_hook_t* end_scene_hook_list; + +void register_gui_hook(FnEndScene* end_scene); +void hook_gui(); diff --git a/src/micetools/dll/hooks/logging.c b/src/micetools/dll/hooks/logging.c new file mode 100644 index 0000000..318ff89 --- /dev/null +++ b/src/micetools/dll/hooks/logging.c @@ -0,0 +1,99 @@ +#include "../util/_util.h" +#include "logging.h" + +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; +} + +#define WORK_FORMAT_MAX 1024 +char format_buf[WORK_FORMAT_MAX]; // Will do. We guard against overflow in Fake[f]printf + +int WINAPIV Fakeprintf(const char* _Format, ...) { + int flen = strlen(_Format); + if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) { + strcpy_s(format_buf, WORK_FORMAT_MAX, _Format); + format_buf[flen - 1] = 0; + _Format = format_buf; + } + va_list args; + va_start(args, _Format); + + int ret = vlog_game("printf", _Format, args); + + va_end(args); + return vlog_game("printf", _Format, args); +} + +int WINAPIV Fakefprintf(FILE* _File, const char* _Format, ...) { + int flen = strlen(_Format); + if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) { + strcpy_s(format_buf, WORK_FORMAT_MAX, _Format); + format_buf[flen - 1] = 0; + _Format = format_buf; + } + va_list args; + va_start(args, _Format); + + int ret = vlog_game("fprintf", _Format, args); + + va_end(args); + return ret; +} + +int WINAPIV Fakefprintf_s(FILE* _Stream, const char* _Format, ...) { + va_list args; + va_start(args, _Format); + + int ret = vlog_game("fprintf_s", _Format, args); + + va_end(args); + return ret; +} +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); } + +void hook_logging() { + hook("MSVCR90.DLL", "printf", Fakeprintf, (void**)&Trueprintf, 6); + hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf, 6); + hook("MSVCR90.DLL", "fprintf_s", Fakefprintf_s, (void**)&Truefprintf_s, 6); + + hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA, (void**)&TrueRegisterEventSourceA, 6); + hook("Advapi32.dll", "ReportEventA", FakeReportEventA, (void**)&TrueReportEventA, 6); + hook("Advapi32.dll", "DeregisterEventSource", FakeDeregisterEventSource, (void**)&TrueDeregisterEventSource, 6); +} diff --git a/src/micetools/dll/hooks/logging.h b/src/micetools/dll/hooks/logging.h new file mode 100644 index 0000000..1ec4c3e --- /dev/null +++ b/src/micetools/dll/hooks/logging.h @@ -0,0 +1,16 @@ +#pragma once +// #include "../common.h" +#include +#include +#include + +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); + +int(WINAPIV* Trueprintf)(const char* _Format, ...); +static int(WINAPIV* Truefprintf)(FILE* _File, const char* _Format, ...); +static int(WINAPIV* Truefprintf_s)(FILE* _Stream, const char* _Format, ...); + +void hook_logging(); diff --git a/src/micetools/dll/hooks/meson.build b/src/micetools/dll/hooks/meson.build new file mode 100644 index 0000000..5bc949c --- /dev/null +++ b/src/micetools/dll/hooks/meson.build @@ -0,0 +1,11 @@ +hooks_files = files( + '_hooks.c', + 'com.c', + 'files.c', + 'gui.c', + 'logging.c', + 'network.c', + 'processes.c', + 'setupapi.c', + 'time.c', +) \ No newline at end of file diff --git a/src/micetools/dll/network.c b/src/micetools/dll/hooks/network.c similarity index 55% rename from src/micetools/dll/network.c rename to src/micetools/dll/hooks/network.c index 68bc662..0741609 100644 --- a/src/micetools/dll/network.c +++ b/src/micetools/dll/hooks/network.c @@ -1,9 +1,7 @@ #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); + ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_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); @@ -33,29 +31,55 @@ const char* INTERCEPT_DNS[] = { DNS_RECORDA dummy_record; +unsigned char SPOOF_IP[4] = { 10, 0, 0, 4 }; 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); + log_info("dns", "Replacing %s with %hhu.%hhu.%hhu.%hhu", pszName, SPOOF_IP[0], SPOOF_IP[1], SPOOF_IP[2], + SPOOF_IP[3]); // 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; + (*ppQueryResults)->Data.A.IpAddress = + (SPOOF_IP[0]) | (SPOOF_IP[1] << 8) | (SPOOF_IP[2] << 16) | (SPOOF_IP[3] << 24); return ERROR_SUCCESS; } } } + log_warning("dns", "DNS passthrough for %s", pszName); return TrueDnsQuery_A(pszName, wType, Options, pExtra, ppQueryResults, pReserved); }; +INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily, LPWSAPROTOCOL_INFOA lpProtocolInfo, + LPSOCKADDR lpAddress, LPINT lpAddressLength) { + log_misc("dns", "(WSA)DNS lookup for %s", AddressString); + for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) { + if (strcmp(AddressString, INTERCEPT_DNS[i]) == 0) { + log_info("dns", "(WSA)Replacing %s with %hhu.%hhu.%hhu.%hhu", AddressString, SPOOF_IP[0], SPOOF_IP[1], + SPOOF_IP[2], SPOOF_IP[3]); + + lpAddress->sa_family = AF_INET; + // ... :) + lpAddress->sa_data[2] = SPOOF_IP[0]; + lpAddress->sa_data[3] = SPOOF_IP[1]; + lpAddress->sa_data[4] = SPOOF_IP[2]; + lpAddress->sa_data[5] = SPOOF_IP[3]; + + return ERROR_SUCCESS; + } + } + log_warning("dns", "(WSA)DNS passthrough for %s", AddressString); + return TrueWSAStringToAddressA(AddressString, AddressFamily, lpProtocolInfo, lpAddress, lpAddressLength); +} + void hook_network() { hook("Ws2_32.dll", "connect", Fake_connect, (void**)&True_connect, 5); + hook("Ws2_32.dll", "WSAStringToAddressA", FakeWSAStringToAddressA, (void**)&TrueWSAStringToAddressA, 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/hooks/network.h similarity index 60% rename from src/micetools/dll/network.h rename to src/micetools/dll/hooks/network.h index 815a90d..01bcf1e 100644 --- a/src/micetools/dll/network.h +++ b/src/micetools/dll/hooks/network.h @@ -1,8 +1,5 @@ -#include -#include -#include -#include - +#pragma once +#include "../common.h" static int(WINAPI* True_connect)(SOCKET s, const SOCKADDR* name, int namelen); @@ -11,4 +8,7 @@ static DWORD(WINAPI* TrueGetIfTable)(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL static DNS_STATUS(WINAPI* TrueDnsQuery_A)(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra, PDNS_RECORDA* ppQueryResults, PVOID* pReserved); +static INT(WSAAPI* TrueWSAStringToAddressA)(LPSTR AddressString, INT AddressFamily, LPWSAPROTOCOL_INFOA lpProtocolInfo, + LPSOCKADDR lpAddress, LPINT lpAddressLength); + void hook_network(); diff --git a/src/micetools/dll/processes.c b/src/micetools/dll/hooks/processes.c similarity index 63% rename from src/micetools/dll/processes.c rename to src/micetools/dll/hooks/processes.c index fc92901..147433b 100644 --- a/src/micetools/dll/processes.c +++ b/src/micetools/dll/hooks/processes.c @@ -1,7 +1,5 @@ #include "processes.h" -#include "../lib/mice/mice.h" - const wchar_t* HOOK_BINARIES[] = { L"app\\ALLNetProc.exe", L"app\\CameraUploader.exe", @@ -17,11 +15,19 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR 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, false); + HANDLE child; + if (lpCommandLine != NULL) { + CHAR commandLine[MAX_PATH + 1]; + WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL, NULL); + child = start_and_inject(applicationName, commandLine, MICELIB, false); + } else { + child = start_and_inject(applicationName, NULL, MICELIB, false); + } + return child != NULL; } -void hook_processes() { hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6); } +void hook_processes() { + // hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6); +} diff --git a/src/micetools/dll/processes.h b/src/micetools/dll/hooks/processes.h similarity index 89% rename from src/micetools/dll/processes.h rename to src/micetools/dll/hooks/processes.h index 524a791..898dfd2 100644 --- a/src/micetools/dll/processes.h +++ b/src/micetools/dll/hooks/processes.h @@ -1,6 +1,5 @@ -#include -#include -#include +#pragma once +#include "../common.h" static BOOL(WINAPI* TrueCreateProcessW)(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, diff --git a/src/micetools/dll/setupapi.c b/src/micetools/dll/hooks/setupapi.c similarity index 99% rename from src/micetools/dll/setupapi.c rename to src/micetools/dll/hooks/setupapi.c index 716a65d..0e5e4c3 100644 --- a/src/micetools/dll/setupapi.c +++ b/src/micetools/dll/hooks/setupapi.c @@ -1,4 +1,4 @@ -#include "micesetupapi.h" +#include "setupapi_.h" FAKE_DEVICE* fake_devices = NULL; diff --git a/src/micetools/dll/micesetupapi.h b/src/micetools/dll/hooks/setupapi_.h similarity index 93% rename from src/micetools/dll/micesetupapi.h rename to src/micetools/dll/hooks/setupapi_.h index 09abffb..dcf3d40 100644 --- a/src/micetools/dll/micesetupapi.h +++ b/src/micetools/dll/hooks/setupapi_.h @@ -1,8 +1,5 @@ -#include -#include -#include - -#include "../lib/mice/mice.h" +#pragma once +#include "common.h" static HDEVINFO(WINAPI* TrueSetupDiGetClassDevsA)(const GUID* ClassGuid, PCWSTR Enumerator, HWND hwndParent, DWORD Flags); diff --git a/src/micetools/dll/hooks/time.c b/src/micetools/dll/hooks/time.c new file mode 100644 index 0000000..ddc21e6 --- /dev/null +++ b/src/micetools/dll/hooks/time.c @@ -0,0 +1,48 @@ +#include "time.h" + +SYSTEMTIME localTime; +BOOL ltCache = FALSE; +SYSTEMTIME systemTime; +BOOL stCache = FALSE; + +BOOL WINAPI Fake_SetLocalTime(const SYSTEMTIME* lpSystemTime) { + memcpy(&localTime, lpSystemTime, sizeof localTime); + ltCache = TRUE; + + log_info("time", "Not setting local time to: %04d-%02d-%02d %02d:%02d:%02d.%04d", lpSystemTime->wYear, + lpSystemTime->wMonth, lpSystemTime->wDay, lpSystemTime->wHour, lpSystemTime->wMinute, + lpSystemTime->wSecond, lpSystemTime->wMilliseconds); + return TRUE; +} +BOOL WINAPI Fake_SetSystemTime(const SYSTEMTIME* lpSystemTime) { + memcpy(&systemTime, lpSystemTime, sizeof systemTime); + stCache = TRUE; + + log_info("time", "Not setting system time to: %04d-%02d-%02d %02d:%02d:%02d.%04d", lpSystemTime->wYear, + lpSystemTime->wMonth, lpSystemTime->wDay, lpSystemTime->wHour, lpSystemTime->wMinute, + lpSystemTime->wSecond, lpSystemTime->wMilliseconds); + return TRUE; +} + +// TODO: Store deltas instead +BOOL WINAPI Fake_GetLocalTime(SYSTEMTIME* lpSystemTime) { + if (ltCache) { + memcpy(lpSystemTime, &localTime, sizeof localTime); + return TRUE; + } + return TrueGetLocalTime(lpSystemTime); +} +BOOL WINAPI Fake_GetSystemTime(SYSTEMTIME* lpSystemTime) { + if (stCache) { + memcpy(lpSystemTime, &systemTime, sizeof systemTime); + return TRUE; + } + return TrueGetSystemTime(lpSystemTime); +} + +void hook_time() { + hook("Kernel32.dll", "SetLocalTime", Fake_SetLocalTime, (void**)&TrueSetLocalTime, 6); + hook("Kernel32.dll", "SetSystemTime", Fake_SetSystemTime, (void**)&TrueSetSystemTime, 6); + hook("Kernel32.dll", "GetLocalTime", Fake_GetLocalTime, (void**)&TrueGetLocalTime, 6); + hook("Kernel32.dll", "GetSystemTime", Fake_GetSystemTime, (void**)&TrueGetSystemTime, 6); +} diff --git a/src/micetools/dll/hooks/time.h b/src/micetools/dll/hooks/time.h new file mode 100644 index 0000000..23f3414 --- /dev/null +++ b/src/micetools/dll/hooks/time.h @@ -0,0 +1,9 @@ +#pragma once +#include "../common.h" + +static BOOL(WINAPI* TrueSetLocalTime)(const SYSTEMTIME* lpSystemTime); +static BOOL(WINAPI* TrueGetLocalTime)(SYSTEMTIME* lpSystemTime); +static BOOL(WINAPI* TrueSetSystemTime)(const SYSTEMTIME* lpSystemTime); +static BOOL(WINAPI* TrueGetSystemTime)(SYSTEMTIME* lpSystemTime); + +void hook_time(); diff --git a/src/micetools/dll/meson.build b/src/micetools/dll/meson.build index 778b6c7..1af8cfd 100644 --- a/src/micetools/dll/meson.build +++ b/src/micetools/dll/meson.build @@ -1,24 +1,25 @@ +subdir('drivers') +subdir('devices') +subdir('hooks') + shared_library( 'mice', name_prefix: '', vs_module_defs: 'mice.def', sources: [ - 'dllmain.c', - 'files.c', - 'drivers/columba.c', - 'drivers/mxsram.c', - 'drivers/mxsuperio.c', - 'drivers/mxjvs.c', - 'drivers/mxsmbus.c', - 'drivers/mxhwreset.c', - 'setupapi.c', - 'com.c', + 'util/log.c', + 'util/hook.c', + + drivers_files, + devices_files, + hooks_files, + 'comdevice.c', - 'processes.c', - 'network.c', + + 'dllmain.c', ], link_with: [ dmi_lib, mice_lib, - ], + ] ) diff --git a/src/micetools/dll/smbus.h b/src/micetools/dll/smbus.h index 807b203..a87e25d 100644 --- a/src/micetools/dll/smbus.h +++ b/src/micetools/dll/smbus.h @@ -1,4 +1,5 @@ -#include +#pragma once +#include "common.h" #pragma pack(1) typedef struct mxsmbus_request_packet_ { diff --git a/src/micetools/dll/util/_util.h b/src/micetools/dll/util/_util.h new file mode 100644 index 0000000..04dfbc1 --- /dev/null +++ b/src/micetools/dll/util/_util.h @@ -0,0 +1,4 @@ +#pragma once + +#include "log.h" +#include "hook.h" diff --git a/src/micetools/lib/mice/hook.c b/src/micetools/dll/util/hook.c similarity index 93% rename from src/micetools/lib/mice/hook.c rename to src/micetools/dll/util/hook.c index 46722ea..b7812cf 100644 --- a/src/micetools/lib/mice/hook.c +++ b/src/micetools/dll/util/hook.c @@ -1,4 +1,8 @@ #include "hook.h" +#include "log.h" + +#include +#include function_hook_t* hook_list = NULL; @@ -36,8 +40,8 @@ void clear_at(PVOID addr, BYTE clearVal, DWORD length) { VirtualProtect(addr, length, oldProt, &oldProt); } -bool Detour(PVOID src, PVOID dst, const intptr_t len) { - if (len < 5) return false; +BOOL Detour(PVOID src, PVOID dst, const intptr_t len) { + if (len < 5) return FALSE; DWORD oldProt; VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &oldProt); @@ -46,7 +50,7 @@ bool Detour(PVOID src, PVOID dst, const intptr_t len) { *(PINT)((int)src + 1) = (int)dst - (int)src - 5; VirtualProtect(src, len, oldProt, &oldProt); - return true; + return TRUE; } void* CreateHook(PVOID src, PVOID dst, const intptr_t len) { @@ -78,6 +82,7 @@ void setup_hooks() { HMODULE dll = LoadLibraryA(hook->dll); if (dll == NULL) { log_error(HOOKS_LOGGER, "failed to load dll %s. %s skipped", hook->dll, hook->name); + hook = hook->next; continue; } diff --git a/src/micetools/lib/mice/hook.h b/src/micetools/dll/util/hook.h similarity index 81% rename from src/micetools/lib/mice/hook.h rename to src/micetools/dll/util/hook.h index 09b608c..5513001 100644 --- a/src/micetools/lib/mice/hook.h +++ b/src/micetools/dll/util/hook.h @@ -2,8 +2,6 @@ #include -#include "./mice.h" - typedef struct function_hook { LPCSTR dll; LPCSTR name; @@ -13,10 +11,13 @@ typedef struct function_hook { struct function_hook* next; } function_hook_t; +static BOOL Detour(PVOID src, PVOID dst, const intptr_t len); + void patch_at(PVOID addr, const char* patch, DWORD length); void clear_at(PVOID addr, BYTE clearVal, DWORD length); void* CreateHook(PVOID src, PVOID dst, const intptr_t len); +static void append_hook(function_hook_t* hook); void hook(LPCSTR dll, LPCSTR name, void* patch, void** store, UINT length); void setup_hooks(); diff --git a/src/micetools/dll/util/log.c b/src/micetools/dll/util/log.c new file mode 100644 index 0000000..ccec806 --- /dev/null +++ b/src/micetools/dll/util/log.c @@ -0,0 +1,144 @@ +#include "log.h" + +#include +#include +#include +#include + +#include "../hooks/logging.h" + +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; + struct tm timeinfo; + + time(&rawtime); + localtime_s(&timeinfo, &rawtime); + + strftime(_log_prelude, sizeof _log_prelude, "[%Y/%m/%d %H:%M:%S] ", &timeinfo); + return _log_prelude; +} + +HANDLE LOG_FILE = NULL; +VOID trace_hook(char* output); +CRITICAL_SECTION logger_lock; + +int _do_log(const char* caller, const char* level, const char* format, va_list args, bool toStdout, char* colour) { + EnterCriticalSection(&logger_lock); + int len = snprintf(NULL, 0, "%s%s:%s:", log_prelude(), level, caller) + vsnprintf(NULL, 0, format, args); + char* buf = (char*)malloc(len + 2); + if (!buf) { + LeaveCriticalSection(&logger_lock); + return 0; + } + + int wrote_a = snprintf(buf, len, "%s%s:%s:", log_prelude(), level, caller); + int wrote_b = vsnprintf(buf + wrote_a, len - wrote_a + 1, format, args); + buf[len] = '\n'; + buf[len + 1] = '\0'; + + // No +1 here to not get the \n + if (toStdout) { + HANDLE sout = GetStdHandle(STD_OUTPUT_HANDLE); + if (HAS_COLOUR) (TrueWriteFile ? TrueWriteFile : WriteFile)(sout, colour, strlen(colour), NULL, NULL); + if (sout != INVALID_HANDLE_VALUE) (TrueWriteFile ? TrueWriteFile : WriteFile)(sout, buf, len, NULL, NULL); + puts(HAS_COLOUR ? "\033[0m" : ""); + } +#ifdef LOG_TO_FILE + if (LOG_FILE && LOG_FILE != INVALID_HANDLE_VALUE) + (TrueWriteFile ? TrueWriteFile : WriteFile)(LOG_FILE, buf, len + 1, NULL, NULL); +#endif + + free(buf); + + LeaveCriticalSection(&logger_lock); + return wrote_b; +} +int vlog_misc(const char* caller, const char* format, va_list args) { + return _do_log(caller, "M", format, args, LOG_MISC, "\033[90m"); +} +int log_misc(const char* caller, const char* format, ...) { + va_list args; + va_start(args, format); + int ret = vlog_misc(caller, format, args); + va_end(args); + return ret; +} +int vlog_info(const char* caller, const char* format, va_list args) { + return _do_log(caller, "I", format, args, LOG_INFO, "\033[97m"); +} +int log_info(const char* caller, const char* format, ...) { + va_list args; + va_start(args, format); + int ret = vlog_info(caller, format, args); + va_end(args); + return ret; +} +int vlog_warning(const char* caller, const char* format, va_list args) { + return _do_log(caller, "W", format, args, LOG_WARNING, "\033[33m"); +} +int log_warning(const char* caller, const char* format, ...) { + va_list args; + va_start(args, format); + int ret = vlog_warning(caller, format, args); + va_end(args); + return ret; +} +int vlog_error(const char* caller, const char* format, va_list args) { + return _do_log(caller, "E", format, args, LOG_ERROR, "\033[91m"); +} +int log_error(const char* caller, const char* format, ...) { + va_list args; + va_start(args, format); + int ret = vlog_error(caller, format, args); + va_end(args); + return ret; +} +int vlog_game(const char* caller, const char* format, va_list args) { + return _do_log(caller, "G", format, args, LOG_GAME, "\033[96m"); +} +int log_game(const char* caller, const char* format, ...) { + va_list args; + va_start(args, format); + int ret = vlog_game(caller, format, args); + va_end(args); + return ret; +} + +VOID trace_hook(char* output) { + output[strcspn(output, "\n")] = 0; + log_error("trace", output); +} + +void setup_logging() { + // Force stdio even for GUI applications + AttachConsole(ATTACH_PARENT_PROCESS); + if (GetStdHandle(STD_INPUT_HANDLE)) { + freopen("CONIN$", "r", stdin); + setvbuf(stdin, NULL, _IONBF, 0); + } + if (GetStdHandle(STD_OUTPUT_HANDLE)) { + freopen("CONOUT$", "w", stdout); + setvbuf(stdout, NULL, _IONBF, 0); + } + if (GetStdHandle(STD_ERROR_HANDLE)) { + freopen("CONOUT$", "w", stderr); + setvbuf(stderr, NULL, _IONBF, 0); + } + + // 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); + + InitializeCriticalSection(&logger_lock); + + if (LOG_FILE == NULL) + LOG_FILE = CreateFileA("log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); +} diff --git a/src/micetools/lib/mice/log.h b/src/micetools/dll/util/log.h similarity index 58% rename from src/micetools/lib/mice/log.h rename to src/micetools/dll/util/log.h index 4907d2c..d7af4ed 100644 --- a/src/micetools/lib/mice/log.h +++ b/src/micetools/dll/util/log.h @@ -1,17 +1,15 @@ +#pragma once + #include -#include #include -#include -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 FALSE +#define LOG_INFO TRUE +#define LOG_WARNING TRUE +#define LOG_ERROR TRUE +#define LOG_GAME TRUE -// #define LOG_MISC -#define LOG_INFO -#define LOG_WARNING -#define LOG_ERROR +// #define LOG_TO_FILE #define COMM_LOGGER "comm" #define HOOKS_LOGGER "hooks" @@ -23,10 +21,12 @@ int log_misc(const char* caller, const char* format, ...); int log_info(const char* caller, const char* format, ...); int log_warning(const char* caller, const char* format, ...); int log_error(const char* caller, const char* format, ...); +int log_game(const char* caller, const char* format, ...); int vlog_misc(const char* caller, const char* format, va_list args); int vlog_info(const char* caller, const char* format, va_list args); int vlog_warning(const char* caller, const char* format, va_list args); int vlog_error(const char* caller, const char* format, va_list args); +int vlog_game(const char* caller, const char* format, va_list args); void setup_logging(); diff --git a/src/micetools/launcher/locate.c b/src/micetools/launcher/locate.c index 723b274..947aeff 100644 --- a/src/micetools/launcher/locate.c +++ b/src/micetools/launcher/locate.c @@ -12,7 +12,7 @@ bool locate_file(char* path, size_t len, const char* exe) { HANDLE hFind = NULL; char work_path[2048]; - sprintf(work_path, ".\\*.*"); + snprintf(work_path, sizeof work_path, ".\\*.*"); if ((hFind = FindFirstFile(work_path, &fdFile)) == INVALID_HANDLE_VALUE) return false; diff --git a/src/micetools/launcher/locate.h b/src/micetools/launcher/locate.h index 18ef402..fdfd806 100644 --- a/src/micetools/launcher/locate.h +++ b/src/micetools/launcher/locate.h @@ -6,3 +6,4 @@ bool locate_exe(char* path, size_t len, const char* exe); bool locate_game(char* path, size_t len); +bool locate_library(char* path, size_t len); diff --git a/src/micetools/launcher/main.c b/src/micetools/launcher/main.c index 2f3a74c..406d65f 100644 --- a/src/micetools/launcher/main.c +++ b/src/micetools/launcher/main.c @@ -11,11 +11,11 @@ bool gametest = false; char exe_name[MAX_PATH + 1] = ""; void print_help(char* exe) { - log_info(BOOT_LOGGER, "Usage: %s [-h] [-t] [-b executable.exe] [-d]", exe); - log_info(BOOT_LOGGER, " -h: Print this help message and exit"); - log_info(BOOT_LOGGER, " -t: Start the game in test mode"); - log_info(BOOT_LOGGER, " -b: Specify the game binary to use"); - log_info(BOOT_LOGGER, " -d: Wait for a debugger to attach when starting"); + fprintf(stderr, "Usage: %s [-h] [-t] [-b executable.exe] [-d]\n", exe); + fprintf(stderr, " -h: Print this help message and exit\n"); + fprintf(stderr, " -t: Start the game in test mode\n"); + fprintf(stderr, " -b: Specify the game binary to use\n"); + fprintf(stderr, " -d: Wait for a debugger to attach when starting\n"); exit(0); } @@ -25,7 +25,8 @@ void parse_cmdline(int argc, char* argv[]) { print_help(argv[0]); } else if (strcmp(argv[i], "-b") == 0) { if (i + 1 == argc) print_help(argv[0]); - strcpy(exe_name, argv[++i]); + char* val = argv[++i]; + memcpy(exe_name, val, strlen(val) + 1); } else if (strcmp(argv[i], "-d") == 0) { boot_delay = true; } else if (strcmp(argv[i], "-t") == 0) { @@ -35,30 +36,29 @@ void parse_cmdline(int argc, char* argv[]) { } int main(int argc, char* argv[]) { - setup_logging(); - - log_info(BOOT_LOGGER, "Micetools version: %s", VERSION); + fprintf(stderr, "Micetools version: %s\n", VERSION); parse_cmdline(argc, argv); if (exe_name[0] == '\0') { if (!locate_game(exe_name, MAX_PATH + 1)) { - log_error(BOOT_LOGGER, "Failed to locate a game"); + fprintf(stderr, "Fatal: Failed to locate a game\n"); return 0; } } else { DWORD dwAttrib = GetFileAttributes(exe_name); if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) { - log_error(BOOT_LOGGER, "%s: no such file found", exe_name); + fprintf(stderr, "Fatal: %s: no such file found\n", exe_name); + return 0; } } - char* cmdline = gametest ? "gametest" : ""; - log_info(BOOT_LOGGER, "%s %s", exe_name, cmdline); + char* cmdline = gametest ? ". gametest" : ""; + fprintf(stderr, "exec: %s %s\n", exe_name, cmdline); char micepath[MAX_PATH + 1]; if (!locate_library(micepath, MAX_PATH + 1)) { - log_error(BOOT_LOGGER, "Failed to locate micelib"); + fprintf(stderr, "Fatal: Failed to locate micelib\n"); return 0; } @@ -66,9 +66,9 @@ int main(int argc, char* argv[]) { if (!game_proc) return -1; if (FAILED(WaitForSingleObject(game_proc, INFINITE))) { - log_error(BOOT_LOGGER, "WaitForSingleObject failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError()); } else { - log_info(BOOT_LOGGER, "Shutting down"); + fprintf(stderr, "Shutting down\n"); CloseHandle(game_proc); } return 0; diff --git a/src/micetools/launcher/meson.build b/src/micetools/launcher/meson.build index 15f4f22..3ecbc54 100644 --- a/src/micetools/launcher/meson.build +++ b/src/micetools/launcher/meson.build @@ -1,7 +1,7 @@ rc = import('windows').compile_resources('mice.rc', depend_files: mice_ico) executable( 'mice', - win_subsystem: 'console', + win_subsystem: subsystem, sources: [ 'locate.c', 'main.c', diff --git a/src/micetools/lib/dmi/dmi.c b/src/micetools/lib/dmi/dmi.c index 0ff68fe..d233893 100644 --- a/src/micetools/lib/dmi/dmi.c +++ b/src/micetools/lib/dmi/dmi.c @@ -1,11 +1,13 @@ #include "dmi.h" +#include + LPBYTE dmi_table = NULL; WORD dmi_size = 0; size_t _dmi_max = 0; DMI_BIOS deafult_dmi_bios = { - .Head.Type = 0x00, + .Head.Type = 0x00, .Head.Length = 0x12, .Head.Handle = 0x0000, .Vendor = 0x00, @@ -20,7 +22,7 @@ DMI_SYSTEM default_dmi_system = { .Head.Type = 0x01, .Head.Length = 0x08, .Head.Handle = 0x0001, - // TODO: Are these used? + // TODO: Are these used? .Manufacturer = 0x00, .ProductName = 0x00, .Version = 0x00, @@ -38,7 +40,7 @@ static void dmi_init(void) { if (dmi_table) free(dmi_table); _dmi_max = 0xff; dmi_table = (LPBYTE)malloc(_dmi_max); - memset(dmi_table, 0, _dmi_max); + memset(dmi_table, 0, _dmi_max); dmi_size = 0; } @@ -64,7 +66,7 @@ static void dmi_append_with_strings(void* data, size_t size, int num_strings, .. 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); + memcpy((char*)dmi_table + dmi_size, str, len + 1); dmi_size += len + 1; dmi_table[dmi_size - 1] = 0; } diff --git a/src/micetools/lib/json/json.c b/src/micetools/lib/json/json.c index 6162f97..34d6dea 100644 --- a/src/micetools/lib/json/json.c +++ b/src/micetools/lib/json/json.c @@ -28,7 +28,6 @@ */ #include "json.h" -#include "../util/hex.h" #include #include @@ -38,6 +37,8 @@ #include #include +#include "../util/hex.h" + #define JSON_INT_MAX 9223372036854775807LL typedef unsigned int json_uchar; @@ -194,7 +195,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t if (flags & flag_string) { if (!b) { - sprintf(error, "%u:%u: Unexpected EOF in string", line_and_col); + snprintf(error, json_error_max, "%u:%u: Unexpected EOF in string", line_and_col); goto e_failed; } @@ -225,7 +226,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t (uc_b2 = hex_value(*++state.ptr)) == 0xFF || (uc_b3 = hex_value(*++state.ptr)) == 0xFF || (uc_b4 = hex_value(*++state.ptr)) == 0xFF) { - sprintf(error, "%u:%u: Invalid character value `%c`", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, b); goto e_failed; } @@ -241,7 +242,8 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t (uc_b2 = hex_value(*++state.ptr)) == 0xFF || (uc_b3 = hex_value(*++state.ptr)) == 0xFF || (uc_b4 = hex_value(*++state.ptr)) == 0xFF) { - sprintf(error, "%u:%u: Invalid character value `%c`", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, + b); goto e_failed; } @@ -354,7 +356,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t if (flags & flag_block_comment) { if (!b) { - sprintf(error, "%u:%u: Unexpected EOF in block comment", line_and_col); + snprintf(error, json_error_max, "%u:%u: Unexpected EOF in block comment", line_and_col); goto e_failed; } @@ -367,12 +369,12 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t } } else if (b == '/') { if (!(flags & (flag_seek_value | flag_done)) && top->type != json_object) { - sprintf(error, "%u:%u: Comment not allowed here", line_and_col); + snprintf(error, json_error_max, "%u:%u: Comment not allowed here", line_and_col); goto e_failed; } if (++state.ptr == end) { - sprintf(error, "%u:%u: EOF unexpected", line_and_col); + snprintf(error, json_error_max, "%u:%u: EOF unexpected", line_and_col); goto e_failed; } @@ -386,7 +388,8 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t continue; default: - sprintf(error, "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in comment opening sequence", + line_and_col, b); goto e_failed; }; } @@ -400,7 +403,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t continue; default: - sprintf(error, "%u:%u: Trailing garbage: `%c`", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Trailing garbage: `%c`", line_and_col, b); goto e_failed; }; } @@ -414,7 +417,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t if (top && top->type == json_array) flags = (flags & ~(flag_need_comma | flag_seek_value)) | flag_next; else { - sprintf(error, "%u:%u: Unexpected `]`", line_and_col); + snprintf(error, json_error_max, "%u:%u: Unexpected `]`", line_and_col); goto e_failed; } @@ -426,7 +429,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t flags &= ~flag_need_comma; continue; } else { - sprintf(error, "%u:%u: Expected `,` before `%c`", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Expected `,` before `%c`", line_and_col, b); goto e_failed; } @@ -437,7 +440,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t flags &= ~flag_need_colon; continue; } else { - sprintf(error, "%u:%u: Expected `:` before `%c`", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Expected `:` before `%c`", line_and_col, b); goto e_failed; } @@ -535,7 +538,8 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t flags |= flag_num_negative; continue; } else { - sprintf(error, "%u:%u: Unexpected `%c` when seeking value", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Unexpected `%c` when seeking value", + line_and_col, b); goto e_failed; } }; @@ -548,7 +552,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t continue; case '"': if (flags & flag_need_comma) { - sprintf(error, "%u:%u: Expected `,` before `\"`", line_and_col); + snprintf(error, json_error_max, "%u:%u: Expected `,` before `\"`", line_and_col); goto e_failed; } @@ -570,7 +574,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t } /* FALLTHRU */ default: - sprintf(error, "%u:%u: Unexpected `%c` in object", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in object", line_and_col, b); goto e_failed; }; break; @@ -583,7 +587,8 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t if (top->type == json_integer || flags & flag_num_e) { if (!(flags & flag_num_e)) { if (flags & flag_num_zero) { - sprintf(error, "%u:%u: Unexpected `0` before `%c`", line_and_col, b); + snprintf(error, json_error_max, "%u:%u: Unexpected `0` before `%c`", + line_and_col, b); goto e_failed; } @@ -627,7 +632,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t json_int_t integer = top->u.integer; if (!num_digits) { - sprintf(error, "%u:%u: Expected digit before `.`", line_and_col); + snprintf(error, json_error_max, "%u:%u: Expected digit before `.`", line_and_col); goto e_failed; } @@ -642,7 +647,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t if (!(flags & flag_num_e)) { if (top->type == json_double) { if (!num_digits) { - sprintf(error, "%u:%u: Expected digit after `.`", line_and_col); + snprintf(error, json_error_max, "%u:%u: Expected digit after `.`", line_and_col); goto e_failed; } @@ -665,7 +670,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t } } else { if (!num_digits) { - sprintf(error, "%u:%u: Expected digit after `e`", line_and_col); + snprintf(error, json_error_max, "%u:%u: Expected digit after `e`", line_and_col); goto e_failed; } @@ -731,23 +736,23 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t return root; e_unknown_value: - sprintf(error, "%u:%u: Unknown value", line_and_col); + snprintf(error, json_error_max, "%u:%u: Unknown value", line_and_col); goto e_failed; e_alloc_failure: - strcpy(error, "Memory allocation failure"); + snprintf(error, json_error_max, "Memory allocation failure"); goto e_failed; e_overflow: - sprintf(error, "%u:%u: Too long (caught overflow)", line_and_col); + snprintf(error, json_error_max, "%u:%u: Too long (caught overflow)", line_and_col); goto e_failed; e_failed: if (error_buf) { if (*error) - strcpy(error_buf, error); + memcpy(error_buf, error, json_error_max); else - strcpy(error_buf, "Unknown error"); + snprintf(error_buf, json_error_max, "Unknown error"); } if (state.first_pass) alloc = root; diff --git a/src/micetools/lib/libpcp/pcpa.h b/src/micetools/lib/libpcp/pcpa.h index 6aceab4..19d14fb 100644 --- a/src/micetools/lib/libpcp/pcpa.h +++ b/src/micetools/lib/libpcp/pcpa.h @@ -51,6 +51,9 @@ typedef struct pcpa { // char* field_0x254; pcp_parse_data_t recv_data; pcp_send_data_t send_data; + + // Our additions + pcpa_callback* before_cb; } pcpa_t; void pcpaClose(pcpa_t* stream); diff --git a/src/micetools/lib/mice/crc.c b/src/micetools/lib/mice/crc.c new file mode 100644 index 0000000..3a401a6 --- /dev/null +++ b/src/micetools/lib/mice/crc.c @@ -0,0 +1,29 @@ +unsigned int CRC_TABLE[256]; +unsigned int CTC_TABLE_BUILT = 0; + +#define CRC32_POLYNOMIAL 0xedb88320 + +void crc32_build_table() { + if (CTC_TABLE_BUILT) return; + CTC_TABLE_BUILT = 1; + + for (int i = 0; i < 256; i++) { + unsigned int value = (~i & 1) - 1 & CRC32_POLYNOMIAL; + value = (((int)i >> 1 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = (((int)i >> 2 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = (((int)i >> 3 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = (((int)i >> 4 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = (((int)i >> 5 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + value = (((int)i >> 6 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + CRC_TABLE[i] = (((int)i >> 7 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1; + } +} + +unsigned int crc32(int length, unsigned char *data, unsigned int initial) { + unsigned int value = ~initial; + while (length--) { + value = value >> 8 ^ CRC_TABLE[(*data ^ value) & 0xff]; + data++; + } + return ~value; +} diff --git a/src/micetools/lib/mice/crc.h b/src/micetools/lib/mice/crc.h new file mode 100644 index 0000000..462771f --- /dev/null +++ b/src/micetools/lib/mice/crc.h @@ -0,0 +1,2 @@ +void crc32_build_table(); +unsigned int crc32(int length, unsigned char *data, unsigned int initial); diff --git a/src/micetools/lib/mice/exe.c b/src/micetools/lib/mice/exe.c index c479d84..8ff23f1 100644 --- a/src/micetools/lib/mice/exe.c +++ b/src/micetools/lib/mice/exe.c @@ -1,18 +1,17 @@ #include "exe.h" -#include "log.h" bool inject_debug_wait(HANDLE process) { BOOL present; - log_info(BOOT_LOGGER, "Waiting for debugger to attach."); + fprintf(stderr, "Waiting for debugger to attach.\n"); do { Sleep(1000); if (FAILED(CheckRemoteDebuggerPresent(process, &present))) { - log_error(BOOT_LOGGER, "CheckRemoteDebuggerPresent failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: CheckRemoteDebuggerPresent failed: %03x\n", GetLastError()); return false; } } while (!present); - log_info(BOOT_LOGGER, "Debugger attached, resuming"); + fprintf(stderr, "Debugger attached, resuming\n"); return true; } bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) { @@ -20,33 +19,33 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) { LPVOID arg_addr = VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); if (arg_addr == NULL) { - log_error(BOOT_LOGGER, "VirtualAllocEx failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: VirtualAllocEx failed: %03x\n", GetLastError()); return false; } if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) { - log_error(BOOT_LOGGER, "WriteProcessMemory failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: WriteProcessMemory failed: %03x\n", GetLastError()); return false; } HANDLE remote_thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL); if (remote_thread == NULL) { - log_error(BOOT_LOGGER, "CreateRemoteThread failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: CreateRemoteThread failed: %03x\n", GetLastError()); return false; } if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) { - log_error(BOOT_LOGGER, "WaitForSingleObject failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError()); return false; } DWORD result; if (FAILED(GetExitCodeThread(remote_thread, &result))) { - log_error(BOOT_LOGGER, "GetExitCodeThread failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: GetExitCodeThread failed: %03x\n", GetLastError()); return false; } if (result == 0) { - log_error(BOOT_LOGGER, "GetExitCodeThread failed: result == 0"); + fprintf(stderr, "Fatal: GetExitCodeThread failed: result == 0\n"); return false; } @@ -55,13 +54,13 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) { bool inject_dll(HANDLE process, LPCSTR inject) { HMODULE kernel32 = GetModuleHandleA("kernel32.dll"); if (kernel32 == NULL) { - log_error(BOOT_LOGGER, "GetModuleHandleA failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: GetModuleHandleA failed: %03x\n", GetLastError()); return false; } LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA"); if (addr_LoadLibraryA == NULL) { - log_error(BOOT_LOGGER, "GetProcAddress failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: GetProcAddress failed: %03x\n", GetLastError()); return false; } @@ -69,7 +68,6 @@ bool inject_dll(HANDLE process, LPCSTR inject) { } HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) { - log_misc(BOOT_LOGGER, "Using %s for hooks", inject); STARTUPINFOA startupInfo; PROCESS_INFORMATION processInformation; @@ -83,14 +81,14 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) { // Validate that we're not about to try something insane DWORD found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL); if (found == 0) { - log_error(BOOT_LOGGER, "Cannot inject %s: not found: %03x", inject, GetLastError()); + fprintf(stderr, "Fatal: Cannot inject %s: not found: %03x\n", inject, GetLastError()); goto abort; } // Start the binary if (FAILED(CreateProcessA(path, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInformation))) { - log_error(BOOT_LOGGER, "CreateProcessA failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError()); goto abort; } @@ -101,7 +99,7 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) { // Injection completed, let the program continue execution if (FAILED(ResumeThread(processInformation.hThread))) { - log_error(BOOT_LOGGER, "ResumeThread failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: ResumeThread failed: %03x\n", GetLastError()); goto abort; } @@ -110,14 +108,14 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) { abort: if (processInformation.hProcess) { if (FAILED(CloseHandle(processInformation.hThread))) - log_error(BOOT_LOGGER, "CloseHandle(hProcess) failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: CloseHandle(hProcess) failed: %03x\n", GetLastError()); if (FAILED(TerminateProcess(processInformation.hProcess, 1))) - log_error(BOOT_LOGGER, "TerminateProcess failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: TerminateProcess failed: %03x\n", GetLastError()); } if (processInformation.hThread) { if (FAILED(CloseHandle(processInformation.hThread))) - log_error(BOOT_LOGGER, "CloseHandle(hThread) failed: %03x", GetLastError()); + fprintf(stderr, "Fatal: CloseHandle(hThread) failed: %03x\n", GetLastError()); } return NULL; diff --git a/src/micetools/lib/mice/exe.h b/src/micetools/lib/mice/exe.h index 0f578b4..d17664b 100644 --- a/src/micetools/lib/mice/exe.h +++ b/src/micetools/lib/mice/exe.h @@ -1,5 +1,6 @@ #include #include +#include HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay); diff --git a/src/micetools/lib/mice/log.c b/src/micetools/lib/mice/log.c deleted file mode 100644 index 63843c3..0000000 --- a/src/micetools/lib/mice/log.c +++ /dev/null @@ -1,212 +0,0 @@ -#include "log.h" - -BOOL HAS_COLOUR = FALSE; - -char _log_prelude[32]; -char* log_prelude() { - time_t rawtime; - struct tm* timeinfo; - - time(&rawtime); - timeinfo = localtime(&rawtime); - - strftime(_log_prelude, 32, "[%Y/%m/%d %H:%M:%S] ", timeinfo); - return _log_prelude; -} - -HANDLE LOG_FILE = NULL; -VOID trace_hook(char* output); -CRITICAL_SECTION logger_lock; - -int _do_log(const char* caller, const char* level, const char* format, va_list args, bool toStdout) { - EnterCriticalSection(&logger_lock); - - int len = snprintf(NULL, 0, "%s%s:%s:", log_prelude(), level, caller) + vsnprintf(NULL, 0, format, args); - char* buf = (char*)malloc(len + 2); - if (!buf) { - LeaveCriticalSection(&logger_lock); - return 0; - } - - int wrote_a = snprintf(buf, len, "%s%s:%s:", log_prelude(), level, caller); - int wrote_b = vsnprintf(buf + wrote_a, len - wrote_a + 1, format, args); - buf[len] = '\n'; - buf[len + 1] = '\0'; - - // No +1 here to not get the \n - if (toStdout) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len, NULL, NULL); -#ifdef LOG_TO_FILE - if (LOG_FILE && LOG_FILE != INVALID_HANDLE_VALUE) WriteFile(LOG_FILE, buf, len + 1, NULL, NULL); -#endif - - free(buf); - - LeaveCriticalSection(&logger_lock); - return wrote_b; -} -int vlog_misc(const char* caller, const char* format, va_list args) { -#ifdef LOG_MISC - if (HAS_COLOUR) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\033[90m", 5, NULL, NULL); - int ret = _do_log(caller, "M", format, args, true); - puts(HAS_COLOUR ? "\033[0m" : ""); - return ret; -#else - return _do_log(caller, "M", format, args, false); -#endif -} -int log_misc(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_misc(caller, format, args); - va_end(args); - return ret; -} -int vlog_info(const char* caller, const char* format, va_list args) { -#ifdef LOG_INFO - if (HAS_COLOUR) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\033[97m", 5, NULL, NULL); - int ret = _do_log(caller, "I", format, args, true); - puts(HAS_COLOUR ? "\033[0m" : ""); - return ret; -#else - return _do_log(caller, "I", format, args, false); -#endif -} -int log_info(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_info(caller, format, args); - va_end(args); - return ret; -} -int vlog_warning(const char* caller, const char* format, va_list args) { -#ifdef LOG_WARNING - if (HAS_COLOUR) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\033[33m", 5, NULL, NULL); - int ret = _do_log(caller, "W", format, args, true); - puts(HAS_COLOUR ? "\033[0m" : ""); - return ret; -#else - return _do_log(caller, "W", format, args, false); -#endif -} -int log_warning(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_warning(caller, format, args); - va_end(args); - return ret; -} -int vlog_error(const char* caller, const char* format, va_list args) { -#ifdef LOG_ERROR - if (HAS_COLOUR) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\033[91m", 5, NULL, NULL); - int ret = _do_log(caller, "E", format, args, true); - puts(HAS_COLOUR ? "\033[0m" : ""); - return ret; -#else - return _do_log(caller, "E", format, args, false); -#endif -} -int log_error(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_error(caller, format, args); - va_end(args); - return ret; -} - -// char format_buf[1024]; // Will do. We guard against overflow in -// Fake[f]printf int WINAPIV Fakeprintf(const char* _Format, ...) { int -// flen = strlen(_Format); if (flen == strcspn(_Format, "\n") + 1 && flen -// < (sizeof format_buf)) { strcpy_s(format_buf, flen, _Format); -// format_buf[flen - 1] = 0; _Format = format_buf; -// } -// va_list args; -// va_start(args, _Format); -// int ret = vlog_info("printf", _Format, args); -// va_end(args); -// return ret; -// }; -// int WINAPIV Fakefprintf(FILE* _File, const char* _Format, ...) { -// int flen = strlen(_Format); -// if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) -// { strcpy_s(format_buf, flen, _Format); format_buf[flen -// - 1] = 0; _Format = format_buf; -// } -// va_list args; -// va_start(args, _Format); -// int ret = vlog_error("fprintf", _Format, args); -// va_end(args); -// return ret; -// }; - -// int WINAPIV Fakefprintf_s(FILE* _Stream, const char* _Format, ...) { -// va_list args; -// va_start(args, _Format); -// int ret = vlog_error("fprintf_s", _Format, args); -// va_end(args); -// 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); } - -VOID trace_hook(char* output) { - output[strcspn(output, "\n")] = 0; - log_error("trace", output); -} - -void setup_logging() { - // 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); - - InitializeCriticalSection(&logger_lock); - - 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/meson.build b/src/micetools/lib/mice/meson.build index 3e2e8b6..9aedba1 100644 --- a/src/micetools/lib/mice/meson.build +++ b/src/micetools/lib/mice/meson.build @@ -1,10 +1,10 @@ mice_lib = static_library( 'mice', sources: [ - 'hook.c', - 'log.c', 'exe.c', 'patch.c', + 'crc.c', + 'ringbuf.c', ], link_with: [ json_lib, diff --git a/src/micetools/lib/mice/mice.h b/src/micetools/lib/mice/mice.h index 93ced2d..e387ada 100644 --- a/src/micetools/lib/mice/mice.h +++ b/src/micetools/lib/mice/mice.h @@ -1,5 +1,8 @@ -#include "hook.h" +#include +#include + #include "ioctl.h" -#include "log.h" #include "exe.h" #include "patch.h" +#include "crc.h" +#include "ringbuf.h" diff --git a/src/micetools/lib/mice/patch.c b/src/micetools/lib/mice/patch.c index baf5318..35c7584 100644 --- a/src/micetools/lib/mice/patch.c +++ b/src/micetools/lib/mice/patch.c @@ -1,5 +1,8 @@ #include "patch.h" +#include +#include + 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++) { @@ -47,9 +50,10 @@ void free_patches(patches_t* patches) { } json_value* load_json_from_file(char* path, char* error) { - FILE* fp = fopen(path, "r"); + FILE* fp; + fopen_s(&fp, path, "r"); if (fp == NULL) { - if (error != NULL) sprintf(error, "Failed to open patch file"); + if (error != NULL) snprintf(error, json_error_max, "Failed to open patch file"); return NULL; } @@ -59,18 +63,18 @@ json_value* load_json_from_file(char* path, char* error) { char* json_buf = (char*)malloc(sz); if (json_buf == NULL) { - if (error != NULL) sprintf(error, "Failed to allocate file buffer"); + if (error != NULL) snprintf(error, json_error_max, "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"); + if (error != NULL) snprintf(error, json_error_max, "Failed to read file"); fclose(fp); return NULL; }; fclose(fp); - json_settings settings = {0}; + json_settings settings = { 0 }; return json_parse_ex(&settings, json_buf, sz, error); } @@ -112,11 +116,11 @@ bool parse_patches(patches_t* patches, json_value** set_json, int set_count, cha 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); + fprintf(stderr, "W: patcher: Failed to load '%s': %s\n", 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); + fprintf(stderr, "W: patcher: Failed to load '%s': not an array\n", patches_file_path); continue; } } else { @@ -214,7 +218,7 @@ bool load_patches(patches_t* patches, char* path, char* error) { loaded_patches = 1; patches_json = &parsed; } else { - sprintf(error, "Patch file format error"); + snprintf(error, json_error_max, "Patch file format error"); json_value_free(parsed); return false; } diff --git a/src/micetools/lib/mice/ringbuf.c b/src/micetools/lib/mice/ringbuf.c new file mode 100644 index 0000000..3bd21fb --- /dev/null +++ b/src/micetools/lib/mice/ringbuf.c @@ -0,0 +1,58 @@ +#include "ringbuf.h" + +#include + +void ringbuf_purge(ring_buffer_t* ring) { + ring->read = 0; + ring->write = 0; +} + +short ringbuf_available(ring_buffer_t* ring) { + short populated = ring->write - ring->read; + if (populated < 0) populated += RING_BUFFER_SIZE; + return populated; +} + +bool ringbuf_write(ring_buffer_t* ring, unsigned const char* data, short bytes) { + short unpopulated = ring->read - ring->write; + if (unpopulated < 0) unpopulated += RING_BUFFER_SIZE; + bool overflow = unpopulated < bytes; + + while (bytes > 0) { + short chunk; + if (bytes + ring->write > RING_BUFFER_SIZE) + chunk = RING_BUFFER_SIZE - ring->write; + else + chunk = bytes; + + memcpy(ring->buffer + ring->write, data, chunk); + data += chunk; + bytes -= chunk; + ring->write = (ring->write + chunk) % RING_BUFFER_SIZE; + } + + return overflow; +} + +short ringbuf_read(ring_buffer_t* ring, unsigned char* data, short bytes) { + short populated = ring->write - ring->read; + if (populated < 0) populated += RING_BUFFER_SIZE; + // Underflow + if (populated < bytes) bytes = populated; + + short left = bytes; + while (left > 0) { + short chunk; + if (left + ring->read > RING_BUFFER_SIZE) + chunk = RING_BUFFER_SIZE - ring->read; + else + chunk = left; + + memcpy(data, ring->buffer + ring->read, chunk); + data += chunk; + left -= chunk; + ring->read = (ring->read + chunk) % RING_BUFFER_SIZE; + } + + return bytes; +} diff --git a/src/micetools/lib/mice/ringbuf.h b/src/micetools/lib/mice/ringbuf.h new file mode 100644 index 0000000..3131be3 --- /dev/null +++ b/src/micetools/lib/mice/ringbuf.h @@ -0,0 +1,16 @@ +#pragma once +#include + +// We use shorts for indexes so the max allowed here is 0x7fff +#define RING_BUFFER_SIZE 2048 + +typedef struct ring_buffer { + unsigned char buffer[RING_BUFFER_SIZE]; + short read; + short write; +} ring_buffer_t; + +bool ringbuf_write(ring_buffer_t* ring, unsigned const char* data, short bytes); +short ringbuf_read(ring_buffer_t* ring, unsigned char* data, short bytes); +short ringbuf_available(ring_buffer_t* ring); +void ringbuf_purge(ring_buffer_t* ring); diff --git a/src/micetools/lib/util/hex.c b/src/micetools/lib/util/hex.c index 5c6eb85..2ae6b58 100644 --- a/src/micetools/lib/util/hex.c +++ b/src/micetools/lib/util/hex.c @@ -1,3 +1,5 @@ +#include + unsigned char hex_value(char c) { if (isdigit((unsigned char)c)) return c - '0'; diff --git a/src/micetools/meson.build b/src/micetools/meson.build index 896fb30..4dff25f 100644 --- a/src/micetools/meson.build +++ b/src/micetools/meson.build @@ -4,3 +4,5 @@ subdir('micepatch') subdir('micekeychip') subdir('launcher') subdir('dll') + +subdir('micetest') diff --git a/src/micetools/micekeychip/callbacks/appboot.c b/src/micetools/micekeychip/callbacks/appboot.c index ce14f8c..03f3622 100644 --- a/src/micetools/micekeychip/callbacks/appboot.c +++ b/src/micetools/micekeychip/callbacks/appboot.c @@ -1,9 +1,8 @@ #include "../config.h" +#include "../lib/libpcp/libpcp.h" #include "callbacks.h" -void mxkPcpAbGameId(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, AB_GAMEID, Config.appboot_gameid); -} +void mxkPcpAbGameId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, AB_GAMEID, Config.appboot_gameid); } void mxkPcpAbSystemFlag(pcpa_t* stream, void* data) { char sf[3]; snprintf(sf, 3, "%02X", Config.appboot_systemflag); @@ -11,17 +10,17 @@ void mxkPcpAbSystemFlag(pcpa_t* stream, void* data) { } void mxkPcpAbModelType(pcpa_t* stream, void* data) { char mt[16]; - snprintf(mt, 16, "%d", Config.appboot_modeltype); + snprintf(mt, 16, "%02X", Config.appboot_modeltype); pcpaSetSendPacket(stream, AB_MODELTYPE, mt); } void mxkPcpAbFormatType(pcpa_t* stream, void* data) { char ft[16]; - snprintf(ft, 16, "%d", Config.appboot_formattype); + snprintf(ft, 16, "%02X", Config.appboot_formattype); pcpaSetSendPacket(stream, AB_FORMATTYPE, ft); } void mxkPcpAbRegion(pcpa_t* stream, void* data) { char rg[16]; - snprintf(rg, 16, "%d", Config.appboot_region); + snprintf(rg, 16, "%02X", Config.appboot_region); pcpaSetSendPacket(stream, AB_REGION, rg); } void mxkPcpAbPlatformId(pcpa_t* stream, void* data) { @@ -32,7 +31,7 @@ void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) { } void mxkPcpAbDvd(pcpa_t* stream, void* data) { char dvd[16]; - snprintf(dvd, 16, "%d", Config.appboot_dvdflag); + snprintf(dvd, 16, "%02X", Config.appboot_dvdflag); pcpaSetSendPacket(stream, AB_DVD, dvd); } @@ -41,7 +40,8 @@ byte SEED_BUF[SEED_BUF_MAX]; int SEED_BUF_LEN = 0; void mxkPcpAbSeed(pcpa_t* stream, void* data) { if (SEED_BUF_LEN == 0) { - FILE* fCert = fopen(Config.appboot_seed, "r"); + FILE* fCert; + fopen_s(&fCert, Config.appboot_seed, "r"); if (fCert == NULL) SEED_BUF_LEN = -1; else { @@ -72,6 +72,6 @@ void mxkPcpAbSeed(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, AB_SEED, "0"); pcpaAddSendPacket(stream, "port", "40107"); char sSize[16]; // todo: nicer lol - itoa(SEED_BUF_LEN, sSize, 10); + _itoa(SEED_BUF_LEN, sSize, 10); pcpaAddSendPacket(stream, "size", sSize); } diff --git a/src/micetools/micekeychip/callbacks/billing.c b/src/micetools/micekeychip/callbacks/billing.c index 47317f9..3939f8e 100644 --- a/src/micetools/micekeychip/callbacks/billing.c +++ b/src/micetools/micekeychip/callbacks/billing.c @@ -1,12 +1,9 @@ #include "../config.h" +#include "../lib/libpcp/libpcp.h" #include "callbacks.h" -void mxkPcpPbKeyId(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, BIL_KEYID, Config.billing_keyid); -} -void mxkPcpPbMainId(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, BIL_MAINID, Config.billing_mainid); -} +void mxkPcpPbKeyId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_KEYID, Config.billing_keyid); } +void mxkPcpPbMainId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_MAINID, Config.billing_mainid); } void mxkPcpPbPlayCount(pcpa_t* stream, void* data) { char pc[9]; snprintf(pc, sizeof pc, "%08X", Config.billing_playcount); @@ -36,7 +33,8 @@ byte PUBKEY_BUF[PUBKEY_BUF_MAX]; int PUBKEY_LEN = 0; void mxkPcpPbSignaturePubKey(pcpa_t* stream, void* data) { if (PUBKEY_LEN == 0) { - FILE* fPubkey = fopen(Config.billing_pubkey, "r"); + FILE* fPubkey; + fopen_s(&fPubkey, Config.billing_pubkey, "r"); if (fPubkey == NULL) PUBKEY_LEN = -1; else { @@ -76,7 +74,8 @@ byte CA_CERTIFICATION[CA_CERT_BUF_MAX]; int CA_CERT_LEN = 0; void mxkPcpPbCaCertification(pcpa_t* stream, void* data) { if (CA_CERT_LEN == 0) { - FILE* fCert = fopen(Config.billing_cacert, "r"); + FILE* fCert; + fopen_s(&fCert, Config.billing_cacert, "r"); if (fCert == NULL) CA_CERT_LEN = -1; else { @@ -107,6 +106,6 @@ void mxkPcpPbCaCertification(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_CACERT, "0"); pcpaAddSendPacket(stream, "port", "40107"); char sSize[16]; // todo: nicer lol - itoa(CA_CERT_LEN, sSize, 10); + _itoa(CA_CERT_LEN, sSize, 10); pcpaAddSendPacket(stream, "size", sSize); } diff --git a/src/micetools/micekeychip/callbacks/crypto.c b/src/micetools/micekeychip/callbacks/crypto.c index d3bdceb..530fa8a 100644 --- a/src/micetools/micekeychip/callbacks/crypto.c +++ b/src/micetools/micekeychip/callbacks/crypto.c @@ -1,12 +1,12 @@ #include "callbacks.h" -void mxkPcpDsCompute(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, "code", "54"); -} -void mxkPcpSsdProof(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, "code", "54"); -} +void mxkPcpDsCompute(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, "code", "54"); } +void mxkPcpSsdProof(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, "code", "54"); } void mxkPcpSsdHostProof(pcpa_t* stream, void* data) {} -void mkxPcpEncrypt(pcpa_t* stream, void* data) {} -void mxkPcpDecrypt(pcpa_t* stream, void* data) {} -void mxkPcpSetIv(pcpa_t* stream, void* data) {} +void mkxPcpEncrypt(pcpa_t* stream, void* data) { + pcpaSetSendPacket(stream, KC_ENCRYPT, "B6787E941C3956EAC70095D6A91E635C"); +} +void mxkPcpDecrypt(pcpa_t* stream, void* data) { + pcpaSetSendPacket(stream, KC_DECRYPT, "68271898FB92ABFB49321FAF72F04FF1"); +} +void mxkPcpSetIv(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, KC_SETIV, "1"); } diff --git a/src/micetools/micekeychip/main.c b/src/micetools/micekeychip/main.c index b0a3c4c..b2ffb25 100644 --- a/src/micetools/micekeychip/main.c +++ b/src/micetools/micekeychip/main.c @@ -9,7 +9,8 @@ config_t Config = { ._keep_linter_happy = true}; void make_default_config() { - FILE *config_file = fopen(CONFIG_PATH, "w"); + FILE *config_file; + fopen_s(&config_file, CONFIG_PATH, "w"); if (config_file == NULL) { puts("Failed to create config file!"); return; @@ -21,10 +22,9 @@ void make_default_config() { fprintf(config_file, "; (string) default = %s\n", default); \ fprintf(config_file, "%s = %s\n", #n, default); -#define CFG_bool(s, n, default, comment) \ - if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \ - fprintf(config_file, "; (bool) default = %s\n", \ - default ? "true" : "false"); \ +#define CFG_bool(s, n, default, comment) \ + if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \ + fprintf(config_file, "; (bool) default = %s\n", default ? "true" : "false"); \ fprintf(config_file, "%s = %s\n", #n, default ? "true" : "false"); #define CFG_int(s, n, default, comment) \ @@ -32,10 +32,9 @@ void make_default_config() { fprintf(config_file, "; (int) default = %d\n", default); \ fprintf(config_file, "%s = %d\n", #n, default); -#define CFG_hex(s, n, precision, default, comment) \ - if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \ - fprintf(config_file, "; (hex) default = %.*X\n", precision, \ - 0x##default); \ +#define CFG_hex(s, n, precision, default, comment) \ + if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \ + fprintf(config_file, "; (hex) default = %.*X\n", precision, 0x##default); \ fprintf(config_file, "%s = %.*X\n", #n, precision, 0x##default); #define SECTION(s, comment) \ @@ -53,31 +52,26 @@ void make_default_config() { fclose(config_file); } -int handler(void *user, const char *section, const char *name, - const char *value) { +int handler(void *user, const char *section, const char *name, const char *value) { config_t *cfg = (config_t *)user; char *end; if (false) ; -#define CFG_str(s, n, default, comment) \ - else if (stricmp(section, #s) == 0 && stricmp(name, #n) == 0) \ - cfg->s##_##n = strdup(value); -#define CFG_bool(s, n, default, comment) \ - else if (stricmp(section, #s) == 0 && stricmp(name, #n) == 0) \ - cfg->s##_##n = strcmp(value, "true") == 0; -#define CFG_int(s, n, default, comment) \ - else if (stricmp(section, #s) == 0 && stricmp(name, #n) == 0) { \ - cfg->s##_##n = strtol(value, &end, 10); \ - if (end == value || *end != '\0' || errno == ERANGE) \ - cfg->s##_##n = default; \ +#define CFG_str(s, n, default, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) cfg->s##_##n = _strdup(value); +#define CFG_bool(s, n, default, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) cfg->s##_##n = strcmp(value, "true") == 0; +#define CFG_int(s, n, default, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \ + cfg->s##_##n = strtol(value, &end, 10); \ + if (end == value || *end != '\0' || errno == ERANGE) cfg->s##_##n = default; \ } -#define CFG_hex(s, n, precision, default, comment) \ - else if (stricmp(section, #s) == 0 && stricmp(name, #n) == 0) { \ - cfg->s##_##n = strtol(value, &end, 16); \ - if (end == value || *end != '\0' || errno == ERANGE) \ - cfg->s##_##n = 0x##default; \ +#define CFG_hex(s, n, precision, default, comment) \ + else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \ + cfg->s##_##n = strtol(value, &end, 16); \ + if (end == value || *end != '\0' || errno == ERANGE) cfg->s##_##n = 0x##default; \ } #include "config.def" @@ -86,15 +80,12 @@ int handler(void *user, const char *section, const char *name, } void load_config() { - if (ini_parse(CONFIG_PATH, handler, &Config) < 0) - printf("Can't load '%s', using defaults\n", CONFIG_PATH); + if (ini_parse(CONFIG_PATH, handler, &Config) < 0) printf("Can't load '%s', using defaults\n", CONFIG_PATH); } int main() { DWORD dwAttrib = GetFileAttributes(CONFIG_PATH); - if (dwAttrib == INVALID_FILE_ATTRIBUTES || - (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) - make_default_config(); + if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) make_default_config(); load_config(); diff --git a/src/micetools/micekeychip/meson.build b/src/micetools/micekeychip/meson.build index 96122f4..a94510d 100644 --- a/src/micetools/micekeychip/meson.build +++ b/src/micetools/micekeychip/meson.build @@ -13,7 +13,7 @@ endif rc = import('windows').compile_resources('micekeychip.rc', depend_files: micekeychip_ico) executable( 'micekeychip', - win_subsystem: 'console', + win_subsystem: subsystem, sources: [ 'main.c', 'mxk.c', diff --git a/src/micetools/micekeychip/mxk.c b/src/micetools/micekeychip/mxk.c index 8736200..568c8fe 100644 --- a/src/micetools/micekeychip/mxk.c +++ b/src/micetools/micekeychip/mxk.c @@ -7,16 +7,13 @@ pcpa_cb_table_t CALLBACK_FUNCTION_BUFFER[40]; byte BINARY_DATA[4096]; size_t BINARY_DATA_LEN; -void mxkBinaryCallback(pcpa_t* stream, void* data) { - pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); -} +void mxkBinaryCallback(pcpa_t* stream, void* data) { pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); } int mxkInit() { // Enable colour HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwMode = 0; - if (GetConsoleMode(hConsole, &dwMode)) - SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + if (GetConsoleMode(hConsole, &dwMode)) SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); WSADATA wsaData; int err = WSAStartup(2, &wsaData); @@ -24,9 +21,19 @@ int mxkInit() { return err; } +void log_callback(struct pcpa* stream, void* data) { + FILE* log_file = fopen("pcp.log", "a"); + if (log_file != NULL) { + fprintf(log_file, "%s\n", (char*)data); + fclose(log_file); + } +} + e_pcpa_t mxkPcpStreamInit() { e_pcpa_t err; + PCP.before_cb = log_callback; + err = pcpaInitStream(&PCP); if (err != e_pcpa_ok) { printf("pcpaInitStream Error. Code:%d\n", err); @@ -34,8 +41,7 @@ e_pcpa_t mxkPcpStreamInit() { } err = pcpaSetCallbackFuncBuffer(&PCP, CALLBACK_FUNCTION_BUFFER, - (sizeof CALLBACK_FUNCTION_BUFFER) / - (sizeof CALLBACK_FUNCTION_BUFFER[0])); + (sizeof CALLBACK_FUNCTION_BUFFER) / (sizeof CALLBACK_FUNCTION_BUFFER[0])); if (err != e_pcpa_ok) { printf("pcpaSetCallBackFuncBuffer Error. Code:%d\n", err); return err; @@ -58,8 +64,7 @@ e_pcpa_t mxkPcpStreamInit() { pcpaSetCallbackFunc(&PCP, AB_FORMATTYPE, mxkPcpAbFormatType, NULL); pcpaSetCallbackFunc(&PCP, AB_REGION, mxkPcpAbRegion, NULL); pcpaSetCallbackFunc(&PCP, AB_PLATFORMID, mxkPcpAbPlatformId, NULL); - pcpaSetCallbackFunc(&PCP, AB_NETWORKADDRESS, mxkPcpAbNetworkAddress, - NULL); + pcpaSetCallbackFunc(&PCP, AB_NETWORKADDRESS, mxkPcpAbNetworkAddress, NULL); pcpaSetCallbackFunc(&PCP, AB_DVD, mxkPcpAbDvd, NULL); pcpaSetCallbackFunc(&PCP, AB_SEED, mxkPcpAbSeed, NULL); // Billing @@ -101,21 +106,20 @@ e_pcpa_t mxkPcpStreamInit() { } int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_1; - err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port, binary_port, - 300000); + err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port & 0xffff, binary_port & 0xffff, 300000); if (err != e_pcpa_ok && err != e_pcpa_to) { printf("pcpaOpenServerWithBinary Error. Code %d\n", err); return e_pcpa_not_open; } if (open_mode == OPEN_MODE_GLOBAL) - printf("Listening on 0.0.0.0:%d (:%d)\n", text_port, binary_port); + printf("Listening on 0.0.0.0:%d (:%d)\n", text_port & 0xffff, binary_port & 0xffff); else - printf("Listening on 127.0.0.1:%d (:%d)\n", text_port, binary_port); + printf("Listening on 127.0.0.1:%d (:%d)\n", text_port & 0xffff, binary_port & 0xffff); return e_pcpa_ok; } #define TICK_MS 16 -#define PRINT_DEBUG +// #define PRINT_DEBUG #ifdef PRINT_DEBUG // Larger TICK_MS for testing #undef TICK_MS diff --git a/src/micetools/micepatch/main.c b/src/micetools/micepatch/main.c index bc49d13..d86f602 100644 --- a/src/micetools/micepatch/main.c +++ b/src/micetools/micepatch/main.c @@ -19,7 +19,8 @@ void print_patches(patches_t* patches, char* filename) { } void apply_patches(patches_t* patches, char* filename) { - FILE* fp = fopen(filename, "r+b"); + FILE* fp; + fopen_s(&fp, filename, "r+b"); if (fp == NULL) { fprintf(stderr, "Failed to open %s for modification\n", filename); return; @@ -98,7 +99,7 @@ int main(int argc, char** argv) { char error[json_error_max]; patches_t all_patches; if (!load_patches(&all_patches, argv[1], error)) { - fprintf(stderr, "%s", error); + fprintf(stderr, "%s\n", error); return -1; } diff --git a/src/micetools/micepatch/meson.build b/src/micetools/micepatch/meson.build index aa9bf7a..09dc2cb 100644 --- a/src/micetools/micepatch/meson.build +++ b/src/micetools/micepatch/meson.build @@ -1,7 +1,7 @@ rc = import('windows').compile_resources('micepatch.rc', depend_files: micepatch_ico) micepatch = executable( 'micepatch', - win_subsystem: 'console', + win_subsystem: subsystem, sources: [ 'main.c', rc, diff --git a/src/micetools/micetest/main.c b/src/micetools/micetest/main.c new file mode 100644 index 0000000..3394a91 --- /dev/null +++ b/src/micetools/micetest/main.c @@ -0,0 +1,6 @@ +#include "stdio.h" + +int main() { + puts("Hello world"); + return 0; +} diff --git a/src/micetools/micetest/meson.build b/src/micetools/micetest/meson.build new file mode 100644 index 0000000..41058e3 --- /dev/null +++ b/src/micetools/micetest/meson.build @@ -0,0 +1,7 @@ +executable( + 'micetest', + win_subsystem: subsystem, + sources: [ + 'main.c', + ], +)