Initial commit
This commit is contained in:
4
src/meson.build
Normal file
4
src/meson.build
Normal file
@@ -0,0 +1,4 @@
|
||||
inih = subproject('inih_dep')
|
||||
|
||||
libs_dir = meson.current_source_dir()
|
||||
subdir('micetools')
|
||||
141
src/micetools/dll/com.c
Normal file
141
src/micetools/dll/com.c
Normal file
@@ -0,0 +1,141 @@
|
||||
#include "com.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);
|
||||
|
||||
swprintf(hook->wName, (sizeof hook->wName) / (sizeof hook->wName[0]), L"COM%d", port);
|
||||
hook->com = port;
|
||||
|
||||
hook->GetCommState = NULL;
|
||||
hook->SetCommState = NULL;
|
||||
hook->GetCommTimeouts = NULL;
|
||||
hook->SetCommTimeouts = NULL;
|
||||
hook->SetupComm = NULL;
|
||||
hook->PurgeComm = NULL;
|
||||
hook->GetCommModemStatus = NULL;
|
||||
hook->WaitCommEvent = NULL;
|
||||
hook->ClearCommError = NULL;
|
||||
|
||||
return hook;
|
||||
};
|
||||
void hook_com(com_hook_t* hook) {
|
||||
hook->next = NULL;
|
||||
hook->virtual_handle = NULL;
|
||||
if (com_hook_list == NULL) {
|
||||
com_hook_list = hook;
|
||||
return;
|
||||
}
|
||||
|
||||
com_hook_t* hl = com_hook_list;
|
||||
while (hl->next != NULL) hl = hl->next;
|
||||
hl->next = hook;
|
||||
};
|
||||
|
||||
BOOL WINAPI FakeGetCommState(HANDLE hFile, LPDCB lpDCB) {
|
||||
log_misc("comm", "GetCommState(0x%p, 0x%p)", hFile, lpDCB);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->GetCommState != NULL) {
|
||||
return hook->GetCommState(hook->data, lpDCB);
|
||||
}
|
||||
}
|
||||
return TrueGetCommState(hFile, lpDCB);
|
||||
}
|
||||
BOOL WINAPI FakeSetCommState(HANDLE hFile, LPDCB lpDCB) {
|
||||
log_misc("comm", "SetCommState(0x%p, 0x%p)", hFile, lpDCB);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->SetCommState != NULL) {
|
||||
return hook->SetCommState(hook->data, lpDCB);
|
||||
}
|
||||
}
|
||||
return TrueSetCommState(hFile, lpDCB);
|
||||
}
|
||||
BOOL WINAPI FakeGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
|
||||
log_misc("comm", "GetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->GetCommTimeouts != NULL) {
|
||||
return hook->GetCommTimeouts(hook->data, lpCommTimeouts);
|
||||
}
|
||||
}
|
||||
return TrueGetCommTimeouts(hFile, lpCommTimeouts);
|
||||
}
|
||||
BOOL WINAPI FakeSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
|
||||
log_misc("comm", "SetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->SetCommTimeouts != NULL) {
|
||||
return hook->SetCommTimeouts(hook->data, lpCommTimeouts);
|
||||
}
|
||||
}
|
||||
return TrueSetCommTimeouts(hFile, lpCommTimeouts);
|
||||
}
|
||||
BOOL WINAPI FakeSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) {
|
||||
log_misc("comm", "SetupCom(0x%p, 0x%08x, 0x%08x)", hFile, dwInQueue, dwOutQueue);
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->SetupComm != NULL) {
|
||||
return hook->SetupComm(hook->data, dwInQueue, dwOutQueue);
|
||||
}
|
||||
}
|
||||
return TrueSetupComm(hFile, dwInQueue, dwOutQueue);
|
||||
}
|
||||
BOOL WINAPI FakePurgeComm(HANDLE hFile, DWORD dwFlags) {
|
||||
log_misc("comm", "PurgeComm(0x%p, 0x%08x)", hFile, dwFlags);
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->PurgeComm != NULL) {
|
||||
return hook->PurgeComm(hook->data, dwFlags);
|
||||
}
|
||||
}
|
||||
return TruePurgeComm(hFile, dwFlags);
|
||||
}
|
||||
BOOL WINAPI FakeGetCommModemStatus(HANDLE hFile, LPDWORD lpModelStat) {
|
||||
log_misc("comm", "GetCommModemStatus(0x%p, 0x%p)", hFile, lpModelStat);
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->GetCommModemStatus != NULL) {
|
||||
return hook->GetCommModemStatus(hook->data, lpModelStat);
|
||||
}
|
||||
}
|
||||
return TrueGetCommModemStatus(hFile, lpModelStat);
|
||||
}
|
||||
BOOL WINAPI FakeWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
|
||||
log_misc("comm", "WaitCommEvent");
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->WaitCommEvent != NULL) {
|
||||
return hook->WaitCommEvent(hook->data, lpEvtMask, lpOverlapped);
|
||||
}
|
||||
}
|
||||
return TrueWaitCommEvent(hFile, lpEvtMask, lpOverlapped);
|
||||
}
|
||||
BOOL WINAPI FakeClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) {
|
||||
log_misc("comm", "ClearCommError");
|
||||
|
||||
com_hook_t* hook = com_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile && hook->ClearCommError != NULL) {
|
||||
return hook->ClearCommError(hook->data, lpErrors, lpStat);
|
||||
}
|
||||
}
|
||||
return TrueClearCommError(hFile, lpErrors, lpStat);
|
||||
}
|
||||
|
||||
void hook_commio() {
|
||||
hook("Kernel32.dll", "GetCommState", FakeGetCommState, (void**)&TrueGetCommState, 6);
|
||||
hook("Kernel32.dll", "SetCommState", FakeSetCommState, (void**)&TrueSetCommState, 6);
|
||||
hook("Kernel32.dll", "GetCommTimeouts", FakeGetCommTimeouts, (void**)&TrueGetCommTimeouts, 6);
|
||||
hook("Kernel32.dll", "SetCommTimeouts", FakeSetCommTimeouts, (void**)&TrueSetCommTimeouts, 6);
|
||||
hook("Kernel32.dll", "SetupComm", FakeSetupComm, (void**)&TrueSetupComm, 6);
|
||||
hook("Kernel32.dll", "PurgeComm", FakePurgeComm, (void**)&TruePurgeComm, 6);
|
||||
hook("Kernel32.dll", "GetCommModemStatus", FakeGetCommModemStatus, (void**)&TrueGetCommModemStatus, 6);
|
||||
hook("Kernel32.dll", "WaitCommEvent", FakeWaitCommEvent, (void**)&TrueWaitCommEvent, 6);
|
||||
hook("Kernel32.dll", "ClearCommError", FakeClearCommError, (void**)&TrueClearCommError, 6);
|
||||
}
|
||||
47
src/micetools/dll/com.h
Normal file
47
src/micetools/dll/com.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#include <Windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB);
|
||||
static BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB);
|
||||
static BOOL(WINAPI* TrueGetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
static BOOL(WINAPI* TrueSetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
static BOOL(WINAPI* TrueSetupComm)(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue);
|
||||
static BOOL(WINAPI* TruePurgeComm)(HANDLE hFile, DWORD dwFlags);
|
||||
static BOOL(WINAPI* TrueGetCommModemStatus)(HANDLE hFile, LPDWORD lpModelStat);
|
||||
static BOOL(WINAPI* TrueWaitCommEvent)(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
|
||||
static BOOL(WINAPI* TrueClearCommError)(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat);
|
||||
|
||||
typedef BOOL(FnGetCommState)(void* com, LPDCB lpDCB);
|
||||
typedef BOOL(FnSetCommState)(void* com, LPDCB lpDCB);
|
||||
typedef BOOL(FnGetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
typedef BOOL(FnSetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
|
||||
typedef BOOL(FnSetupComm)(void* com, DWORD dwInQueue, DWORD dwOutQueue);
|
||||
typedef BOOL(FnPurgeComm)(void* com, DWORD dwFlags);
|
||||
typedef BOOL(FnGetCommModemStatus)(void* com, LPDWORD lpModelStat);
|
||||
typedef BOOL(FnWaitCommEvent)(void* com, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
|
||||
typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat);
|
||||
|
||||
typedef struct com_hook {
|
||||
HANDLE virtual_handle;
|
||||
WCHAR wName[7]; // max is COM255
|
||||
BYTE com;
|
||||
|
||||
FnGetCommState* GetCommState;
|
||||
FnSetCommState* SetCommState;
|
||||
FnGetCommTimeouts* GetCommTimeouts;
|
||||
FnSetCommTimeouts* SetCommTimeouts;
|
||||
FnSetupComm* SetupComm;
|
||||
FnPurgeComm* PurgeComm;
|
||||
FnGetCommModemStatus* GetCommModemStatus;
|
||||
FnWaitCommEvent* WaitCommEvent;
|
||||
FnClearCommError* ClearCommError;
|
||||
|
||||
void* data;
|
||||
|
||||
struct com_hook* next;
|
||||
} com_hook_t;
|
||||
|
||||
com_hook_t* new_com_hook(BYTE port);
|
||||
void hook_com(com_hook_t* hook);
|
||||
void hook_com();
|
||||
44
src/micetools/dll/comdevice.c
Normal file
44
src/micetools/dll/comdevice.c
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "comdevice.h"
|
||||
|
||||
BOOL DevGetCommState(void* data, LPDCB lpDCB) { return TRUE; }
|
||||
BOOL DevSetCommState(void* data, LPDCB lpDCB) { return TRUE; }
|
||||
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;
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevGetCommModemStatus(void* data, LPDWORD lpModelStat) {
|
||||
// TODO: JVS SENSE
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevWaitCommEvent(void* data, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
|
||||
WaitForSingleObject(((com_device_t*)data)->event, INFINITE);
|
||||
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
|
||||
return TRUE;
|
||||
}
|
||||
BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) { return TRUE; }
|
||||
|
||||
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);
|
||||
com->data = hook;
|
||||
|
||||
com->GetCommState = DevGetCommState;
|
||||
com->SetCommState = DevSetCommState;
|
||||
com->GetCommTimeouts = DevGetCommTimeouts;
|
||||
com->SetCommTimeouts = DevSetCommTimeouts;
|
||||
com->SetupComm = DevSetupComm;
|
||||
com->PurgeComm = DevPurgeComm;
|
||||
com->GetCommModemStatus = DevGetCommModemStatus;
|
||||
com->WaitCommEvent = DevWaitCommEvent;
|
||||
com->ClearCommError = DevClearCommError;
|
||||
|
||||
hook->filled = 0;
|
||||
hook->event = CreateEventW(NULL, TRUE, FALSE, hook->com->wName);
|
||||
hook->com = com;
|
||||
|
||||
return hook;
|
||||
}
|
||||
11
src/micetools/dll/comdevice.h
Normal file
11
src/micetools/dll/comdevice.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "com.h"
|
||||
#include "files.h"
|
||||
|
||||
typedef struct com_device {
|
||||
com_hook_t* com;
|
||||
file_hook_t* file;
|
||||
|
||||
BYTE queue[2048];
|
||||
DWORD filled;
|
||||
HANDLE event;
|
||||
} com_device_t;
|
||||
147
src/micetools/dll/dllmain.c
Normal file
147
src/micetools/dll/dllmain.c
Normal file
@@ -0,0 +1,147 @@
|
||||
#include <Windows.h>
|
||||
#include <shlwapi.h>
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "drivers/mx.h"
|
||||
#include "files.h"
|
||||
#include "com.h"
|
||||
#include "micesetupapi.h"
|
||||
|
||||
WCHAR exePath[MAX_PATH + 1];
|
||||
|
||||
void enable_traces() {
|
||||
if (wcscmp(exePath, L"Game.exe") == 0) {
|
||||
*(DWORD*)(0x008717a0) = 1;
|
||||
*(DWORD*)(0x00871728) = 1;
|
||||
*(DWORD*)(0x00871cd8) = 1;
|
||||
*(DWORD*)(0x00872660) = 1;
|
||||
*(DWORD*)(0x0087297c) = 1; // LOG_EN_EEPROM
|
||||
*(DWORD*)(0x00872980) = 1;
|
||||
*(DWORD*)(0x00872988) = 1;
|
||||
*(DWORD*)(0x00873540) = 1;
|
||||
*(DWORD*)(0x00873538) = 1;
|
||||
*(DWORD*)(0x0087f890) = 1;
|
||||
*(DWORD*)(0x00882ce4) = 1;
|
||||
*(DWORD*)(0x00882cec) = 1;
|
||||
*(DWORD*)(0x00883018) = 1;
|
||||
*(DWORD*)(0x00886ff8) = 1;
|
||||
*(DWORD*)(0x0088b1b8) = 1;
|
||||
*(DWORD*)(0x0088b1c0) = 1;
|
||||
} else if (wcscmp(exePath, L"ALLNetProc_Win.exe") == 0) {
|
||||
*(DWORD*)(0x004f48b0) = 1; // LOG_EN_DONGLE
|
||||
*(DWORD*)(0x004f989c) = 1; // LOG_EN_PCP
|
||||
*(DWORD*)(0x004f7d04) = 1; // LOG_EN_EEPROM
|
||||
*(DWORD*)(0x004f7d08) = 1; // LOG_EN_BACKUP
|
||||
*(DWORD*)(0x004f8118) = 1; // LOG_EN_RTC
|
||||
*(DWORD*)(0x004f96dc) = 1; // LOG_EN_GFETCHER
|
||||
*(DWORD*)(0x004f8338) = 1; // LOG_EN_NETWORK
|
||||
*(DWORD*)(0x004f88c0) = 1; // LOG_EN_MASTER
|
||||
*(DWORD*)(0x004f88b0) = 1; // LOG_EN_HM
|
||||
*(DWORD*)(0x004f8330) = 1; // LOG_EN_SRAM
|
||||
*(DWORD*)(0x004f9728) = 1; // LOG_EN_PLATFORM
|
||||
|
||||
//*(DWORD*)(0x004f9e7c) = 5; // LOG_EN_ASSERTS (handled by the bellow
|
||||
// instead)
|
||||
*(DWORD*)(0x004e884c) = 10; // ALPB_LOG_LEVEL (0=None, 1=Error,
|
||||
// 2=Warning, 3=Most, 4=Debug)
|
||||
} else if (wcscmp(exePath, L"ORIG_mxsegaboot.exe") == 0 || wcscmp(exePath, L"mxsegaboot.exe") == 0) {
|
||||
// start of am
|
||||
*(DWORD*)(0x0054fcd8) = 1; // LOG_EN_JVS_DRIVER
|
||||
*(DWORD*)(0x00538810) = 1; // LOG_EN_DIPSW
|
||||
*(DWORD*)(0x0054afc8) = 1; // LOG_EN_ATA
|
||||
*(DWORD*)(0x00544b78) = 1; // LOG_EN_DONGLE
|
||||
*(DWORD*)(0x00536c98) = 1; // LOG_EN_EEPROM
|
||||
*(DWORD*)(0x00537834) = 1; // LOG_EN_GCATCHER
|
||||
*(DWORD*)(0x00537d4c) = 1; // LOG_EN_GDELIVER
|
||||
*(DWORD*)(0x0053828c) = 1; // LOG_EN_GFETCHER
|
||||
*(DWORD*)(0x00547fd0) = 1; // LOG_EN_HWRESET
|
||||
*(DWORD*)(0x00547fd8) = 1; // LOG_EN_PLATFORM
|
||||
*(DWORD*)(0x00548268) = 1; // LOG_EN_HM
|
||||
*(DWORD*)(0x00536f30) = 1; // LOG_EN_BACKUP
|
||||
*(DWORD*)(0x00547fcc) = 1; // LOG_EN_CMOS
|
||||
*(DWORD*)(0x005382d8) = 1; // LOG_EN_INSTALL
|
||||
*(DWORD*)(0x00538818) = 1; // LOG_EN_JVS
|
||||
*(DWORD*)(0x00544b68) = 1; // LOG_EN_JVSP
|
||||
*(DWORD*)(0x0054b3d8) = 1; // LOG_EN_MASTER
|
||||
*(DWORD*)(0x00548280) = 1; // LOG_EN_NETWORK
|
||||
*(DWORD*)(0x00548050) = 1; // LOG_EN_RTC
|
||||
*(DWORD*)(0x00536c94) = 1; // LOG_EN_SRAM
|
||||
*(DWORD*)(0x005487f8) = 1; // LOG_EN_STORAGE
|
||||
*(DWORD*)(0x00536c90) = 1; // LOG_EN_SYS
|
||||
// end of am
|
||||
*(DWORD*)(0x00536c70) = 1; // LOG_EN_PCPT
|
||||
} else if (wcscmp(exePath, L"maimai_dump_.exe") == 0) {
|
||||
*(DWORD*)(0x00c8ab7c) = 1; // LOG_EN_SRAM
|
||||
*(DWORD*)(0x00f406f0) = 1; // LOG_EN_CABINET_DL
|
||||
*(DWORD*)(0x00c88680) = 1; // LOG_EN_INSTALL
|
||||
*(DWORD*)(0x00c8ab78) = 1; // LOG_EN_EEPROM
|
||||
*(DWORD*)(0x00c88608) = 1; // LOG_EN_PLATFORM
|
||||
*(DWORD*)(0x00c88dd0) = 1; // LOG_EN_STORAGE
|
||||
*(DWORD*)(0x00ca25ec) = 1; // LOG_EN_PCP
|
||||
*(DWORD*)(0x00c96ed0) = 1; // LOG_EN_HM
|
||||
*(DWORD*)(0x00f406ec) = 1; // LOG_EN_HTTP
|
||||
*(DWORD*)(0x00c89ca8) = 1; // LOG_EN_DIPSW
|
||||
*(DWORD*)(0x00c96ed8) = 1; // LOG_EN_DONGLE
|
||||
*(DWORD*)(0x00c9a83c) = 1; // LOG_EN_JVSP
|
||||
*(DWORD*)(0x00c89730) = 1; // LOG_EN_NETWORK
|
||||
*(DWORD*)(0x00c9a440) = 1; // LOG_EN_JVST_THREAD
|
||||
*(DWORD*)(0x00c8ab80) = 1; // LOG_EN_JVS
|
||||
*(DWORD*)(0x00c89fc8) = 1; // LOG_EN_MASTER
|
||||
*(DWORD*)(0x00c88bb8) = 1; // LOG_EN_RTC
|
||||
*(DWORD*)(0x00c9e420) = 1; // LOG_EN_JVST_DRIVER
|
||||
*(DWORD*)(0x00c89320) = 1; // LOG_EN_BACKUP
|
||||
*(DWORD*)(0x00c88bb4) = 1; // LOG_EN_HWRESET
|
||||
*(DWORD*)(0x00c830e8) = 1; // LOG_EN
|
||||
} else if (wcscmp(exePath, L"mxnetwork.exe") == 0) {
|
||||
*(DWORD*)(0x004438e0) = 1; // LOG_EN_PCP
|
||||
*(DWORD*)(0x004433f8) = 1; // LOG_EN_UTL
|
||||
} else {
|
||||
log_warning("traces", "No known traces for %ls", exePath);
|
||||
}
|
||||
}
|
||||
|
||||
void prebind_hooks() {
|
||||
hook_setupapi();
|
||||
hook_commio();
|
||||
hook_io();
|
||||
}
|
||||
|
||||
void init_injection() {
|
||||
// We're in a new context now, so need to reconfigure
|
||||
setup_logging();
|
||||
log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exePath);
|
||||
|
||||
dmi_build_default();
|
||||
|
||||
enable_traces();
|
||||
|
||||
setup_columba();
|
||||
setup_mxsram();
|
||||
setup_mxsuperio();
|
||||
setup_mxjvs();
|
||||
setup_mxhwreset();
|
||||
setup_mxsmbus();
|
||||
|
||||
if (!add_fake_device(&PLATFORM_GUID, L"\\\\.\\platform")) {
|
||||
log_error("platform", "failed to install platform device");
|
||||
}
|
||||
|
||||
// Must be the last thing called!
|
||||
// register_devices();
|
||||
prebind_hooks();
|
||||
setup_hooks();
|
||||
}
|
||||
|
||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
|
||||
|
||||
GetModuleFileNameW(NULL, exePath, MAX_PATH);
|
||||
wcscpy_s(exePath, MAX_PATH + 1, PathFindFileNameW(exePath));
|
||||
|
||||
init_injection();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
51
src/micetools/dll/drivers/columba.c
Normal file
51
src/micetools/dll/drivers/columba.c
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../lib/dmi/dmi.h"
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "files.h"
|
||||
|
||||
BOOL columba_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
|
||||
DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_COLUMBA_READ_DMI:
|
||||
log_misc("columba",
|
||||
"DeviceIoControl(<columba>, <read dmi>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
memset(lpOutBuffer, 0, nOutBufferSize);
|
||||
|
||||
if (((LPWORD)lpInBuffer)[0] == 0x0000) {
|
||||
DMI_HEADER dmi = {
|
||||
.Signature = {'_', 'D', 'M', 'I', '_'},
|
||||
.Checksum = 0,
|
||||
.StructLength = dmi_size,
|
||||
.StructAddr = 0xdeeabeef,
|
||||
.NumberOfStructs = 0x20,
|
||||
.BCDRevision = 0,
|
||||
.Reserved = 0,
|
||||
};
|
||||
dmi.Checksum = dmi_calc_checksum((char*)&dmi, 15);
|
||||
|
||||
memcpy(lpOutBuffer, &dmi, sizeof(DMI_HEADER));
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(DMI_HEADER);
|
||||
} else {
|
||||
memcpy(lpOutBuffer, dmi_table, dmi_size);
|
||||
if (lpBytesReturned) *lpBytesReturned = dmi_size;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
log_warning("columba", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void setup_columba() {
|
||||
file_hook_t* columba = new_file_hook(L"\\\\.\\columba");
|
||||
columba->DeviceIoControl = &columba_DeviceIoControl;
|
||||
|
||||
hook_file(columba);
|
||||
}
|
||||
23
src/micetools/dll/drivers/mx.h
Normal file
23
src/micetools/dll/drivers/mx.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#include "../files.h"
|
||||
#include <initguid.h>
|
||||
|
||||
FnDeviceIoControl mxhwreset_DeviceIoControl;
|
||||
void setup_mxhwreset();
|
||||
|
||||
FnDeviceIoControl mxjvs_DeviceIoControl;
|
||||
void setup_mxjvs();
|
||||
|
||||
FnDeviceIoControl mxsmbus_DeviceIoControl;
|
||||
void setup_mxsmbus();
|
||||
|
||||
FnDeviceIoControl mxsram_DeviceIoControl;
|
||||
FnSetFilePointer mxsram_SetFilePointer;
|
||||
FnWriteFile mxsram_WriteFile;
|
||||
FnReadFile mxsram_ReadFile;
|
||||
void setup_mxsram();
|
||||
|
||||
FnDeviceIoControl mxsuperio_DeviceIoControl;
|
||||
void setup_mxsuperio();
|
||||
|
||||
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);
|
||||
24
src/micetools/dll/drivers/mxhwreset.c
Normal file
24
src/micetools/dll/drivers/mxhwreset.c
Normal file
@@ -0,0 +1,24 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#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) {
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXHWRESET_RESET:
|
||||
if (lpBytesReturned) *lpBytesReturned = 0;
|
||||
break;
|
||||
default:
|
||||
log_warning("mxhwreset", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxhwreset() {
|
||||
file_hook_t* mxhwreset = new_file_hook(L"\\\\.\\mxhwreset");
|
||||
mxhwreset->DeviceIoControl = &mxhwreset_DeviceIoControl;
|
||||
|
||||
hook_file(mxhwreset);
|
||||
}
|
||||
37
src/micetools/dll/drivers/mxjvs.c
Normal file
37
src/micetools/dll/drivers/mxjvs.c
Normal file
@@ -0,0 +1,37 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "mx.h"
|
||||
|
||||
BOOL mxjvs_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer,
|
||||
DWORD nInBufferSize, LPVOID lpOutBuffer,
|
||||
DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXJVS_EXCHANGE:
|
||||
log_misc("mxjvs",
|
||||
"DeviceIoControl(<mxjvs>, <exchange>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
// mxjvsDevice->exchange(
|
||||
// lpbyte(lpInBuffer), nInBufferSize & 0xFFFF,
|
||||
// lpbyte(lpOutBuffer), lpBytesReturned
|
||||
// );
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = 0;
|
||||
break;
|
||||
default:
|
||||
log_warning("mxjvs", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxjvs() {
|
||||
file_hook_t* mxjvs = new_file_hook(L"\\\\.\\mxjvs");
|
||||
mxjvs->DeviceIoControl = &mxjvs_DeviceIoControl;
|
||||
|
||||
hook_file(mxjvs);
|
||||
}
|
||||
0
src/micetools/dll/drivers/mxparallel.c
Normal file
0
src/micetools/dll/drivers/mxparallel.c
Normal file
363
src/micetools/dll/drivers/mxsmbus.c
Normal file
363
src/micetools/dll/drivers/mxsmbus.c
Normal file
@@ -0,0 +1,363 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../lib/dmi/dmi.h"
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "mx.h"
|
||||
#include "smbus.h"
|
||||
|
||||
// PCA9535 (DIPSW)
|
||||
#define PCA9535_WRITE 0x04
|
||||
#define PCA9535_READ 0x05
|
||||
|
||||
#define PCA9535_IN0 0x00
|
||||
#define PCA9535_IN1 0x01
|
||||
#define PCA9535_OUT0 0x02
|
||||
#define PCA9535_OUT1 0x03
|
||||
#define PCA9535_INV0 0x04
|
||||
#define PCA9535_INV1 0x05
|
||||
#define PCA9535_CONF0 0x06
|
||||
#define PCA9535_CONF1 0x07
|
||||
|
||||
#define PCA9535 0x20
|
||||
#define EEPROM 0x57
|
||||
|
||||
#define EEPROM_DUMP L"dev/eeprom.bin"
|
||||
typedef struct eeprom_reg {
|
||||
BYTE data[32];
|
||||
} eeprom_reg_t;
|
||||
typedef struct eeprom_bank {
|
||||
eeprom_reg_t reg[0x100];
|
||||
} eeprom_bank_t;
|
||||
|
||||
// 256 registers, 32 bytes each
|
||||
eeprom_bank_t EEPROM_DATA;
|
||||
/*
|
||||
* Known registers:
|
||||
* - Reg 0x00: Stores ??? in [00]
|
||||
* - Reg 0x08: Stores LPC address in [00, 01]
|
||||
* - Reg 0x16: Stores ??? in [00, 01]
|
||||
* - 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) {
|
||||
log_error("eeprom", "CreateFileA(EEPROM_DUMP) failed");
|
||||
return;
|
||||
}
|
||||
_WriteFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, NULL, NULL);
|
||||
FlushFileBuffers(dump);
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
void eeprom_restore() {
|
||||
HANDLE dump =
|
||||
_CreateFileW(EEPROM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) return;
|
||||
DWORD read;
|
||||
if (!_ReadFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, &read, NULL))
|
||||
log_error("eeprom", "failed to restore (%d)", GetLastError());
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
DWORD eeprom_crc(BYTE reg) {
|
||||
if (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));
|
||||
}
|
||||
return crc_finalize(crc_update(crc_init(), EEPROM_DATA.reg[reg].data + 4, 28));
|
||||
}
|
||||
void eeprom_read(BYTE reg, BYTE index, BYTE* data, BYTE length) {
|
||||
eeprom_restore();
|
||||
for (BYTE i = index; i < index + length; i++) {
|
||||
if (i > 0x1f) break;
|
||||
|
||||
BYTE byte = EEPROM_DATA.reg[reg].data[i];
|
||||
|
||||
// If register has a CRC
|
||||
// if (reg == 0x00 || reg == 0x01 || reg == 0x02 || reg == 0x10 || reg
|
||||
// == 0x11 || reg == 0x12 || reg == 0x200) {
|
||||
if (true) {
|
||||
// Intercept the read and inject a CRC instead
|
||||
if (i == 0x00 || i == 0x01 || i == 0x02 || i == 0x03) {
|
||||
DWORD crc = eeprom_crc(reg);
|
||||
byte = crc >> 8 * i & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
data[i - index] = byte;
|
||||
}
|
||||
}
|
||||
void eeprom_write(BYTE reg, BYTE index, BYTE* data, BYTE length) {
|
||||
for (BYTE i = index; i < index + length; i++) {
|
||||
if (i > 0x1f) break;
|
||||
EEPROM_DATA.reg[reg].data[i] = data[i - index];
|
||||
}
|
||||
eeprom_dump();
|
||||
}
|
||||
|
||||
BYTE eeprom_read_one(BYTE reg, BYTE index) {
|
||||
BYTE data;
|
||||
eeprom_read(reg, index, &data, 1);
|
||||
return data;
|
||||
}
|
||||
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) {
|
||||
mxsmbus_i2c_packet* i2c_packet = (mxsmbus_i2c_packet*)lpInBuffer;
|
||||
mxsmbus_i2c_packet* i2c_out = (mxsmbus_i2c_packet*)lpOutBuffer;
|
||||
|
||||
mxsmbus_request_packet* request_packet = (mxsmbus_request_packet*)lpInBuffer;
|
||||
mxsmbus_request_packet* request_out = (mxsmbus_request_packet*)lpOutBuffer;
|
||||
|
||||
BYTE dlen;
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSMBUS_GET_VERSION:
|
||||
log_misc("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <get version>, 0x%p, 0x%x, "
|
||||
"-, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = 0x01020001;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSMBUS_REQUEST: // dip r/w
|
||||
log_misc("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <request>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
// Game trace:
|
||||
// 05 for 20
|
||||
// ^[x3]
|
||||
// 04 for 20
|
||||
// ^[x3]
|
||||
// 05 for 20
|
||||
// 03 for 57
|
||||
// ^[after every eeprom read/write]
|
||||
|
||||
// Address 0x20 = PCA9535 = DIP switches
|
||||
// Address 0x30 = Keychip? "N2"
|
||||
// Address 0x55 = Keychip?
|
||||
// Address 0x57 = EEPROM
|
||||
|
||||
// dyn = 0x57
|
||||
// 03: addr dyn: amEepromWait
|
||||
// 04: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
|
||||
// 05: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
|
||||
//
|
||||
// dyn2 = 0x20
|
||||
// 04: addr dyn2: amDipswWriteByteInternal
|
||||
// 05: addr dyn2: amDipswReadByteInternal[Ex]
|
||||
|
||||
// 0B: addr 0x20: amHmGetLPCChipId
|
||||
// 0B: addr 0x21: amHmGetLPCChipId
|
||||
// 48: addr 0x00: amHmGetLPCChipId
|
||||
|
||||
switch (i2c_packet->addr) {
|
||||
case PCA9535:
|
||||
switch (i2c_packet->prt) {
|
||||
case PCA9535_WRITE:
|
||||
switch (i2c_packet->reg) {
|
||||
case PCA9535_OUT1:
|
||||
log_error("mxsmbus", "pca9535 OUT1: %02x %02x", i2c_packet->data[0],
|
||||
i2c_packet->data[1]);
|
||||
break;
|
||||
case PCA9535_INV0:
|
||||
log_error("mxsmbus", "pca9535 INV0: %02x %02x", i2c_packet->data[0],
|
||||
i2c_packet->data[1]);
|
||||
break;
|
||||
case PCA9535_INV1:
|
||||
log_error("mxsmbus", "pca9535 INV1: %02x %02x", i2c_packet->data[0],
|
||||
i2c_packet->data[1]);
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbux",
|
||||
"(write) Undefined pca9535 "
|
||||
"register: 0x%02x",
|
||||
i2c_packet->reg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case PCA9535_READ:
|
||||
switch (i2c_packet->reg) {
|
||||
case PCA9535_IN0: // DIPSW
|
||||
i2c_packet->data[0] = 0x00;
|
||||
break;
|
||||
case PCA9535_IN1: // What's this one?
|
||||
i2c_packet->data[0] = 0x00;
|
||||
break;
|
||||
case PCA9535_INV0:
|
||||
case PCA9535_INV1:
|
||||
case PCA9535_OUT1:
|
||||
i2c_packet->data[0] = 0x00;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbux",
|
||||
"(read) Undefined pca9535 "
|
||||
"register: 0x%02x",
|
||||
i2c_packet->reg);
|
||||
exit(1);
|
||||
}
|
||||
i2c_packet->status = 0x00;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbux", "Unknown pca9535 command: 0x%02x", i2c_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
case EEPROM:
|
||||
switch (i2c_packet->prt) {
|
||||
case 3: // Wait
|
||||
// 0x18 = wait, 0x00 = done
|
||||
i2c_packet->status = 0;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbux", "Unknown eeprom command: 0x%02x", i2c_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("mxsmbus", "Unknown smbus device: 0x%02x", i2c_packet->addr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
i2c_out->status = MXSBUS_OKAY;
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_i2c_packet);
|
||||
break;
|
||||
case IOCTL_MXSMBUS_I2C: // i2c r/w
|
||||
log_misc("mxsmbus",
|
||||
"DeviceIoControl(<mxsmbus>, <i2c>, 0x%p, 0x%x, -, 0x%x, "
|
||||
"-, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
log_misc("mxsmbus", "SMBus I2C request for %02x: 0x%02x (%02x bytes @ %02x)", request_packet->addr,
|
||||
request_packet->prt, request_packet->dlen, request_packet->reg);
|
||||
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[0],
|
||||
// dwordInBuffer[1], dwordInBuffer[2], dwordInBuffer[3]);
|
||||
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[4],
|
||||
// dwordInBuffer[5], dwordInBuffer[6], dwordInBuffer[7]);
|
||||
// log_warning("eeprom", "%08x %08x", dwordInBuffer[8],
|
||||
// dwordInBuffer[9]);
|
||||
|
||||
// for (int i = 0; i < nInBufferSize; i++) {
|
||||
// printf("%02x ", ((LPBYTE)lpInBuffer)[i]);
|
||||
// }
|
||||
// puts("");
|
||||
|
||||
// prt = byteInBuffer[1];
|
||||
// addr = wordInBuffer[1];
|
||||
// reg = wordInBuffer[2] & 0xFF;
|
||||
dlen = request_packet->dlen;
|
||||
if (dlen > 0x20) dlen = 0x20;
|
||||
|
||||
/*
|
||||
* Known addresses:
|
||||
* - 0x57: EEPROM
|
||||
**/
|
||||
|
||||
request_packet->status = MXSBUS_OKAY;
|
||||
|
||||
if (request_packet->status != 0) {
|
||||
log_error("mxsmbus", "invalid i2c packet");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (request_packet->addr != EEPROM) {
|
||||
log_error("mxsmbus", "Unexpected I2C device: 0x%02x", request_packet->addr);
|
||||
exit(1);
|
||||
}
|
||||
// 04 = Write byte
|
||||
// 05 = Read byte
|
||||
//
|
||||
// 08 = Write block
|
||||
// 09 = Read block
|
||||
|
||||
if (request_packet->prt == 0x08) {
|
||||
// Write
|
||||
log_misc("mxsmbus", "eeprom write %02x (0x%04x)", dlen, request_packet->reg);
|
||||
// for (int i = 0; i < dlen; i++) printf("%02x ",
|
||||
// request_packet->data[i]); puts("");
|
||||
|
||||
eeprom_write(request_packet->reg >> 5, request_packet->reg & 0x1f, request_packet->data,
|
||||
request_packet->dlen);
|
||||
request_out->status = 0;
|
||||
} else if (i2c_packet->prt == 0x09) {
|
||||
// Read
|
||||
log_misc("mxsmbus", "eeprom read %02x (0x%04x)", dlen, request_packet->reg);
|
||||
eeprom_read(request_packet->reg >> 5, request_packet->reg & 0x1f, request_out->data, dlen);
|
||||
// for (int i = 0; i < dlen; i++) printf("%02x ",
|
||||
// request_out->data[i]); puts("");
|
||||
request_out->status = 0;
|
||||
} else {
|
||||
log_warning("mxsmbus", "UNHANDLED MXSMBUS I2C %02x", request_packet->prt);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_request_packet);
|
||||
break;
|
||||
default:
|
||||
log_warning("mxsmbus", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsmbus() {
|
||||
file_hook_t* mxsmbus = new_file_hook(L"\\\\.\\mxsmbus");
|
||||
mxsmbus->DeviceIoControl = &mxsmbus_DeviceIoControl;
|
||||
|
||||
hook_file(mxsmbus);
|
||||
|
||||
if (!add_fake_device(&MXSMBUS_GUID, L"\\\\.\\mxsmbus")) {
|
||||
log_error("mxsmbus", "failed to install mxsmbus device");
|
||||
}
|
||||
}
|
||||
126
src/micetools/dll/drivers/mxsram.c
Normal file
126
src/micetools/dll/drivers/mxsram.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "mx.h"
|
||||
|
||||
#define SRAM_DUMP L"dev/sram.bin"
|
||||
#define SRAM_SIZE 1024 * 2084
|
||||
LPBYTE SRAM;
|
||||
DWORD SRAM_POINTER = 0;
|
||||
|
||||
void sram_dump() {
|
||||
HANDLE dump = _CreateFileW(SRAM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) {
|
||||
log_error("sram", "CreateFileA(SRAM_DUMP) failed");
|
||||
return;
|
||||
}
|
||||
_WriteFile(dump, SRAM, SRAM_SIZE, NULL, NULL);
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
void sram_restore() {
|
||||
HANDLE dump =
|
||||
_CreateFileW(SRAM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (dump == INVALID_HANDLE_VALUE) return;
|
||||
DWORD read;
|
||||
if (!_ReadFile(dump, SRAM, SRAM_SIZE, &read, NULL)) log_error("sram", "failed to restore (%d)", GetLastError());
|
||||
_CloseHandle(dump);
|
||||
}
|
||||
|
||||
BOOL mxsram_DeviceIoControl(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
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSRAM_PING: // Get version
|
||||
log_misc("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <ping>, 0x%p, 0x%x, -, 0x%x, "
|
||||
"-, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = SRAM_VERSION;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
|
||||
log_misc("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <get drive geom>, 0x%p, "
|
||||
"0x%x, -, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
DISK_GEOMETRY out = *(PDISK_GEOMETRY)lpOutBuffer;
|
||||
memset(&out, 0, sizeof(out));
|
||||
out.Cylinders.QuadPart = 1;
|
||||
out.MediaType = FixedMedia;
|
||||
out.TracksPerCylinder = 224;
|
||||
out.SectorsPerTrack = 32;
|
||||
out.BytesPerSector = 1;
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(DISK_GEOMETRY);
|
||||
break;
|
||||
case IOCTL_MXSRAM_GET_SECTOR_SIZE:
|
||||
log_misc("mxsram",
|
||||
"DeviceIoControl(<mxsram>, <get sector size>, 0x%p, "
|
||||
"0x%x, -, 0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = SRAM_SECTOR_SIZE;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
default:
|
||||
log_warning("mxsram", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
DWORD mxsram_SetFilePointer(LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
|
||||
if (dwMoveMethod == FILE_BEGIN) {
|
||||
SRAM_POINTER = lDistanceToMove;
|
||||
} else if (dwMoveMethod == FILE_CURRENT) {
|
||||
SRAM_POINTER += lDistanceToMove;
|
||||
}
|
||||
return SRAM_POINTER;
|
||||
}
|
||||
|
||||
BOOL mxsram_WriteFile(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) {
|
||||
nNumberOfBytesToWrite = SRAM_SIZE - SRAM_POINTER;
|
||||
}
|
||||
memcpy(SRAM + SRAM_POINTER, lpBuffer, nNumberOfBytesToWrite);
|
||||
sram_dump();
|
||||
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL mxsram_ReadFile(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) {
|
||||
nNumberOfBytesToRead = SRAM_SIZE - SRAM_POINTER;
|
||||
}
|
||||
sram_restore();
|
||||
memcpy((LPVOID)lpBuffer, SRAM + SRAM_POINTER, nNumberOfBytesToRead);
|
||||
*lpNumberOfBytesRead = nNumberOfBytesToRead;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsram() {
|
||||
// Allocate 2MB of SRAM
|
||||
SRAM = (LPBYTE)malloc(SRAM_SIZE);
|
||||
if (!SRAM) {
|
||||
log_error(BOOT_LOGGER, "unable to allocate 2MiB for SRAM");
|
||||
exit(1);
|
||||
}
|
||||
memset(SRAM, 0, SRAM_SIZE);
|
||||
sram_restore();
|
||||
|
||||
file_hook_t* mxsram = new_file_hook(L"\\\\.\\mxsram");
|
||||
mxsram->SetFilePointer = &mxsram_SetFilePointer;
|
||||
mxsram->ReadFile = &mxsram_ReadFile;
|
||||
mxsram->WriteFile = &mxsram_WriteFile;
|
||||
|
||||
hook_file(mxsram);
|
||||
}
|
||||
289
src/micetools/dll/drivers/mxsuperio.c
Normal file
289
src/micetools/dll/drivers/mxsuperio.c
Normal file
@@ -0,0 +1,289 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "mx.h"
|
||||
#include "smbus.h"
|
||||
#include "w83791d.h"
|
||||
|
||||
BYTE w83791d_bank = 0x00;
|
||||
BYTE w83791d_config = W83791D_CONFIG_START;
|
||||
BYTE w83791d_noncrit_t1 = 75; // C
|
||||
BYTE w83791d_crit_t1 = 80; // C
|
||||
BYTE w83791d_noncrit_t2 = 75; // C
|
||||
BYTE w83791d_crit_t2 = 80; // C
|
||||
BYTE w83791d_noncrit_t3 = 75; // C
|
||||
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) {
|
||||
mxsuperio_lpc_packet* lpc_packet = (mxsuperio_lpc_packet*)lpInBuffer;
|
||||
mxsuperio_lpc_packet* lpc_out = (mxsuperio_lpc_packet*)lpOutBuffer;
|
||||
|
||||
switch (dwIoControlCode) {
|
||||
case IOCTL_MXSUPERIO_PING:
|
||||
log_misc("mxsuperio",
|
||||
"DeviceIoControl(<mxsuperio>, <ping>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
((LPDWORD)lpOutBuffer)[0] = 0x01000001;
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSUPERIO_READ:
|
||||
log_warning("mxsuperio",
|
||||
"DeviceIoControl(<mxsuperio>, <read>, 0x%p, 0x%x, -, "
|
||||
"0x%x, -, -)",
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
/*
|
||||
BYTE chipId = 0|1
|
||||
BYTE ?? = 0x0b
|
||||
BYTE ?? = 0x20|0x21
|
||||
BYTE ret = 0
|
||||
*/
|
||||
|
||||
switch (((LPBYTE)lpInBuffer)[2]) {
|
||||
case 0x20:
|
||||
((LPBYTE)lpInBuffer)[3] = 0xa0;
|
||||
break;
|
||||
case 0x21:
|
||||
((LPBYTE)lpInBuffer)[3] = 0x20;
|
||||
break;
|
||||
default:
|
||||
((LPBYTE)lpInBuffer)[3] = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = 4;
|
||||
break;
|
||||
case IOCTL_MXSUPERIO_HWMONITOR_LPC_READ: {
|
||||
BYTE index = lpc_packet->index;
|
||||
BYTE reg = lpc_packet->reg;
|
||||
|
||||
switch (w83791d_bank) {
|
||||
case 0x00: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_WCHIPID:
|
||||
lpc_out->data = 0x71;
|
||||
break;
|
||||
case W83791D_REG_CHIPMAN:
|
||||
if (w83791d_4f_high)
|
||||
lpc_out->data = 0x5c; // High byte
|
||||
else
|
||||
lpc_out->data = 0xa3; // Low byte
|
||||
break;
|
||||
case W83791D_REG_I2C_ADDR:
|
||||
lpc_out->data = 0x11;
|
||||
break;
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
case W83791D_REG_CONFIG:
|
||||
lpc_out->data = w83791d_config;
|
||||
break;
|
||||
|
||||
case W83791D_REG_BEEP_CTRL_0:
|
||||
lpc_out->data = 0xff; // All the beeps! (see main.h)
|
||||
break;
|
||||
|
||||
case W83791D_REG_TEMP1_0:
|
||||
lpc_out->data = 0x00; // TODO: Figure out the temp val lol
|
||||
break;
|
||||
case W83791D_RAM_VCOREA:
|
||||
case W83791D_RAM_VNIR0:
|
||||
case W83791D_RAM_12VIN:
|
||||
lpc_out->data = 0x00; // TODO: Figure out the batt val
|
||||
break;
|
||||
|
||||
case W83791D_RAM_FAN1:
|
||||
case W83791D_RAM_FAN2:
|
||||
case W83791D_RAM_FAN3:
|
||||
lpc_out->data = 0x00; // Fan no spinny!
|
||||
break;
|
||||
|
||||
case W83791D_VID_FAN_DIV:
|
||||
// Boths fans divide by 2 (01), VDD 5 latched
|
||||
// good.
|
||||
lpc_out->data = 0b01011111; // Let's not /0!
|
||||
break;
|
||||
|
||||
case W83791D_VBAT_MONITOR_CONTROL:
|
||||
lpc_out->data = w83791d_vbat_monitor_control;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b0 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x01: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
case W83791D_NONCRIT_TEMP_1:
|
||||
lpc_out->data = w83791d_noncrit_t1;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_1:
|
||||
lpc_out->data = w83791d_crit_t1;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_2:
|
||||
lpc_out->data = w83791d_noncrit_t2;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_2:
|
||||
lpc_out->data = w83791d_crit_t2;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_3:
|
||||
lpc_out->data = w83791d_noncrit_t3;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_3:
|
||||
lpc_out->data = w83791d_crit_t3;
|
||||
break;
|
||||
|
||||
case W83791D_VIN0:
|
||||
lpc_out->data = W83791D_ENTITY_CPU;
|
||||
break;
|
||||
case W83791D_VIN1:
|
||||
lpc_out->data = W83791D_ENTITY_SYSTEM;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x05: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
lpc_out->data = w83791d_bank;
|
||||
break;
|
||||
|
||||
// Used in amHmReadVoltageInternal
|
||||
// What are these??
|
||||
case 0x51:
|
||||
case 0x40:
|
||||
lpc_out->data = 0xff;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
|
||||
return FALSE;
|
||||
// exit(1);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// reg 0x48 = LPC Chip ID
|
||||
// index = 0,1
|
||||
// data > 0x0f, data < 0x70
|
||||
|
||||
// lpc_out->data = eeprom_read_one(reg, index);
|
||||
log_misc("mxsuperio", "amHmLpcReadByte Index=0x%02x Reg=0x%02x Data=0x%02x", index, reg, lpc_out->data);
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsuperio_lpc_packet);
|
||||
} break;
|
||||
case IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE: {
|
||||
BYTE index = lpc_packet->index;
|
||||
BYTE reg = lpc_packet->reg;
|
||||
log_misc("mxsuperio", "amHmLpcWriteByte Index=0x%02x Reg=0x%02x Data=0x%02b", index, reg, lpc_packet->data);
|
||||
|
||||
switch (w83791d_bank) {
|
||||
case 0x00: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BEEP_CTRL_0:
|
||||
// Ignore for now
|
||||
break;
|
||||
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
case W83791D_REG_CONFIG:
|
||||
w83791d_config = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_VBAT_MONITOR_CONTROL:
|
||||
w83791d_vbat_monitor_control = lpc_packet->data;
|
||||
break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b0 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 0x01: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
|
||||
case W83791D_NONCRIT_TEMP_1:
|
||||
w83791d_noncrit_t1 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_1:
|
||||
w83791d_crit_t1 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_2:
|
||||
w83791d_noncrit_t2 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_2:
|
||||
w83791d_crit_t2 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_NONCRIT_TEMP_3:
|
||||
w83791d_noncrit_t3 = lpc_packet->data;
|
||||
break;
|
||||
case W83791D_CRIT_TEMP_3:
|
||||
w83791d_crit_t3 = lpc_packet->data;
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
|
||||
exit(1);
|
||||
}
|
||||
} break;
|
||||
case 0x05: {
|
||||
switch (reg) {
|
||||
case W83791D_REG_BANK:
|
||||
w83791d_4f_high = !!(lpc_packet->data & 0x80);
|
||||
w83791d_bank = lpc_packet->data & 7;
|
||||
break;
|
||||
|
||||
// Used in amHmReadVoltageInternal
|
||||
// What is this??
|
||||
case 0x40:
|
||||
break;
|
||||
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
|
||||
return FALSE;
|
||||
// exit(1);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (lpBytesReturned) *lpBytesReturned = 0;
|
||||
} break;
|
||||
default:
|
||||
log_warning("mxsuperio", "unhandled 0x%08x", dwIoControlCode);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void setup_mxsuperio() {
|
||||
file_hook_t* mxsuperio = new_file_hook(L"\\\\.\\mxsuperio");
|
||||
mxsuperio->DeviceIoControl = &mxsuperio_DeviceIoControl;
|
||||
|
||||
hook_file(mxsuperio);
|
||||
}
|
||||
205
src/micetools/dll/files.c
Normal file
205
src/micetools/dll/files.c
Normal file
@@ -0,0 +1,205 @@
|
||||
#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));
|
||||
|
||||
hook->filename = filename;
|
||||
|
||||
hook->DeviceIoControl = NULL;
|
||||
hook->SetFilePointer = NULL;
|
||||
hook->WriteFile = NULL;
|
||||
hook->ReadFile = NULL;
|
||||
|
||||
return hook;
|
||||
}
|
||||
void hook_file(file_hook_t* hook) {
|
||||
hook->next = NULL;
|
||||
hook->virtual_handle = NULL;
|
||||
if (file_hook_list == NULL) {
|
||||
file_hook_list = hook;
|
||||
return;
|
||||
}
|
||||
|
||||
file_hook_t* hl = file_hook_list;
|
||||
while (hl->next != NULL) hl = hl->next;
|
||||
hl->next = hook;
|
||||
};
|
||||
|
||||
drive_redirect_t DRIVE_REDIRECT_TABLE[] = {{"Y:\\", ".\\dev\\Y\\"},
|
||||
{"C:\\Documents and Settings\\AppUser\\temp\\", ".\\dev\\temp\\"}};
|
||||
|
||||
char* redirect_path(char* path) {
|
||||
for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) {
|
||||
drive_redirect_t row = DRIVE_REDIRECT_TABLE[i];
|
||||
if (strstr(path, row.drive)) {
|
||||
log_misc(HOOKS_LOGGER, "Redirecting '%s' to '%s'", path, row.path);
|
||||
|
||||
size_t new_len = strlen(path) - strlen(row.drive) + strlen(row.path);
|
||||
// TODO: Make this not leak memory!
|
||||
char* new_str = (char*)malloc(new_len + 1);
|
||||
strcpy_s(new_str, new_len + 1, row.path);
|
||||
|
||||
char* dst = new_str + strlen(row.path);
|
||||
size_t len = strlen(path) - strlen(row.drive);
|
||||
char* src = path + strlen(row.drive);
|
||||
|
||||
for (; len > 0; len--) (dst++)[0] = (src++)[0];
|
||||
dst[0] = 0;
|
||||
log_misc(HOOKS_LOGGER, "New filename: '%s'", new_str);
|
||||
return new_str;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
||||
// for (int i = 0; i < (sizeof HOOKED_HANDLES) / (sizeof HANDLE_HOOK);
|
||||
// i++) { HANDLE_HOOK hook = HOOKED_HANDLES[i]; if (lpFileName &&
|
||||
// wcscmp(lpFileName, hook.wName) == 0) {
|
||||
// log_warning(HOOKS_LOGGER, "CreateFileW intercepting driver file %ls",
|
||||
// hook.wName); return hook.handle;
|
||||
// }
|
||||
// }
|
||||
|
||||
// HANDLE result = TrueCreateFileW(lpFileName, dwDesiredAccess,
|
||||
// dwShareMode, lpSecurityAttributes, dwCreationDisposition,
|
||||
// dwFlagsAndAttributes, hTemplateFile); log_misc(HOOKS_LOGGER,
|
||||
// "CreateFileW(%ls) -> 0x%p", lpFileName, result);
|
||||
|
||||
HANDLE handle = NULL;
|
||||
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (wcscmp(lpFileName, hook->filename) == 0) {
|
||||
if (hook->virtual_handle == NULL) {
|
||||
// TODO: Assign handles better!
|
||||
hook->virtual_handle = fake_handle;
|
||||
((size_t)fake_handle)++;
|
||||
}
|
||||
handle = hook->virtual_handle;
|
||||
break;
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
if (handle == NULL) {
|
||||
handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition,
|
||||
dwFlagsAndAttributes, hTemplateFile);
|
||||
}
|
||||
|
||||
log_misc(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
|
||||
return handle;
|
||||
}
|
||||
HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
|
||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
|
||||
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
|
||||
lpFileName = redirect_path((char*)lpFileName);
|
||||
|
||||
WCHAR wideFileName[MAX_PATH + 1];
|
||||
MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, (LPWSTR)&wideFileName, MAX_PATH + 1);
|
||||
|
||||
HANDLE result = FakeCreateFileW((LPCWSTR)&wideFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
|
||||
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
|
||||
log_misc(HOOKS_LOGGER, "^-> CreateFileA(%s) -> 0x%p", lpFileName, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
|
||||
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
log_misc(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice, dwIoControlCode,
|
||||
lpInBuffer, nInBufferSize, nOutBufferSize);
|
||||
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hDevice) {
|
||||
if (hook->DeviceIoControl) {
|
||||
// TODO: Less jank
|
||||
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
|
||||
|
||||
return hook->DeviceIoControl(dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize,
|
||||
lpBytesReturned, lpOverlapped);
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize,
|
||||
lpBytesReturned, lpOverlapped);
|
||||
}
|
||||
|
||||
DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile) {
|
||||
if (hook->SetFilePointer) {
|
||||
return hook->SetFilePointer(lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
|
||||
LPOVERLAPPED lpOverlapped) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hFile) {
|
||||
if (hook->WriteFile) {
|
||||
return hook->ReadFile(lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
|
||||
}
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
|
||||
return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
|
||||
file_hook_t* hook = file_hook_list;
|
||||
while (hook != NULL) {
|
||||
if (hook->virtual_handle == hObject) {
|
||||
return TRUE;
|
||||
}
|
||||
hook = hook->next;
|
||||
}
|
||||
return TrueCloseHandle(hObject);
|
||||
}
|
||||
|
||||
void hook_io() {
|
||||
hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl, 5);
|
||||
|
||||
hook("Kernel32.dll", "CreateFileA", FakeCreateFileA, (void**)&TrueCreateFileA, 6);
|
||||
hook("Kernel32.dll", "CreateFileW", FakeCreateFileW, (void**)&TrueCreateFileW, 6);
|
||||
|
||||
hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6);
|
||||
hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6);
|
||||
hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile, 6);
|
||||
hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile, 6);
|
||||
|
||||
// hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, &True_stat64i32, 5);
|
||||
}
|
||||
63
src/micetools/dll/files.h
Normal file
63
src/micetools/dll/files.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#include <Windows.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* 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);
|
||||
|
||||
#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;
|
||||
|
||||
HANDLE 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();
|
||||
22
src/micetools/dll/meson.build
Normal file
22
src/micetools/dll/meson.build
Normal file
@@ -0,0 +1,22 @@
|
||||
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',
|
||||
'comdevice.c',
|
||||
],
|
||||
link_with: [
|
||||
dmi_lib,
|
||||
mice_lib,
|
||||
],
|
||||
)
|
||||
1
src/micetools/dll/mice.def
Normal file
1
src/micetools/dll/mice.def
Normal file
@@ -0,0 +1 @@
|
||||
LIBRARY mice
|
||||
29
src/micetools/dll/micesetupapi.h
Normal file
29
src/micetools/dll/micesetupapi.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <Windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
|
||||
static HDEVINFO(WINAPI* TrueSetupDiGetClassDevsA)(const GUID* ClassGuid, PCWSTR Enumerator, HWND hwndParent,
|
||||
DWORD Flags);
|
||||
static BOOL(WINAPI* TrueSetupDiEnumDeviceInterfaces)(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData,
|
||||
const GUID* InterfaceClassGuid, DWORD MemberIndex,
|
||||
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
|
||||
static BOOL(WINAPI* TrueSetupDiGetDeviceInterfaceDetailA)(HDEVINFO DeviceInfoSet,
|
||||
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
|
||||
DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize,
|
||||
PSP_DEVINFO_DATA DeviceInfoData);
|
||||
static BOOL(WINAPI* TrueSetupDiDestroyDeviceInfoList)(HDEVINFO DevicesInfoSet);
|
||||
|
||||
typedef struct FAKE_DEVICE_ {
|
||||
HDEVINFO handle;
|
||||
const GUID* guid;
|
||||
const WCHAR* path;
|
||||
struct FAKE_DEVICE_* next;
|
||||
} FAKE_DEVICE;
|
||||
extern FAKE_DEVICE* fake_devices;
|
||||
|
||||
BOOL add_fake_device(const GUID* guid, const WCHAR* path);
|
||||
|
||||
void hook_setupapi();
|
||||
119
src/micetools/dll/setupapi.c
Normal file
119
src/micetools/dll/setupapi.c
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "micesetupapi.h"
|
||||
|
||||
FAKE_DEVICE* fake_devices = NULL;
|
||||
|
||||
BOOL add_fake_device(const GUID* guid, const WCHAR* path) {
|
||||
FAKE_DEVICE* new_device = (FAKE_DEVICE*)malloc(sizeof *new_device);
|
||||
if (!new_device) return FALSE;
|
||||
new_device->guid = guid;
|
||||
new_device->path = path;
|
||||
new_device->handle = NULL;
|
||||
new_device->next = NULL;
|
||||
FAKE_DEVICE** tail = &fake_devices;
|
||||
while (*tail) tail = &((*tail)->next);
|
||||
*tail = new_device;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HDEVINFO WINAPI FakeSetupDiGetClassDevsA(const GUID* ClassGuid, PCWSTR Enumerator, HWND hwndParent, DWORD Flags) {
|
||||
log_misc("setupapi", "SetupDiGetClassDevsA(%p, %s, %d, %d)", ClassGuid, Enumerator, hwndParent, Flags);
|
||||
HDEVINFO res = TrueSetupDiGetClassDevsA(ClassGuid, Enumerator, hwndParent, Flags);
|
||||
|
||||
if (res != INVALID_HANDLE_VALUE && ClassGuid != NULL) {
|
||||
FAKE_DEVICE* device = fake_devices;
|
||||
while (device != NULL) {
|
||||
if (memcmp(device->guid, ClassGuid, sizeof(*ClassGuid)) == 0) {
|
||||
log_misc("setupapi", "injecting %ls into class devs list", device->path);
|
||||
device->handle = res;
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
} else {
|
||||
log_warning("setupapi", "upstream SetupDiGetClassDevsA failed: %d", GetLastError());
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetupDiEnumDeviceInterfaces(HDEVINFO DeviceInfoSet, PSP_DEVINFO_DATA DeviceInfoData,
|
||||
const GUID* InterfaceClassGuid, DWORD MemberIndex,
|
||||
PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData) {
|
||||
log_misc("setupapi", "SetupDiEnumDeviceInterfaces");
|
||||
FAKE_DEVICE* device = fake_devices;
|
||||
if (DeviceInterfaceData) {
|
||||
while (device != NULL) {
|
||||
if (device->handle == DeviceInfoSet) {
|
||||
log_info("setupapi", "hooking fake device: %ls", device->path);
|
||||
memcpy(&DeviceInterfaceData->InterfaceClassGuid, device->guid, sizeof *device->guid);
|
||||
DeviceInterfaceData->Flags = SPINT_ACTIVE;
|
||||
DeviceInterfaceData->Reserved = (ULONG_PTR)device->path;
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
return TRUE;
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback
|
||||
log_misc("setupapi", "device info fallthrough");
|
||||
return TrueSetupDiEnumDeviceInterfaces(DeviceInfoSet, DeviceInfoData, InterfaceClassGuid, MemberIndex,
|
||||
DeviceInterfaceData);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetupDiGetDeviceInterfaceDetailA(HDEVINFO DeviceInfoSet, PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,
|
||||
DWORD DeviceInterfaceDetailDataSize, PDWORD RequiredSize,
|
||||
PSP_DEVINFO_DATA DeviceInfoData) {
|
||||
log_misc("setupapi", "SetupDiGetDeviceInterfaceDetailA");
|
||||
FAKE_DEVICE* device = fake_devices;
|
||||
while (device != NULL) {
|
||||
if (device->handle == DeviceInfoSet && (ULONG_PTR)device->path == DeviceInterfaceData->Reserved) {
|
||||
log_info("setupapi", "Yoinked SetupDiGetDeviceInterfaceDetailA");
|
||||
|
||||
const WCHAR* res = (WCHAR*)DeviceInterfaceData->Reserved;
|
||||
int new_len = (wcslen(res) + 1) * (sizeof *res);
|
||||
char* new_res = (char*)malloc(new_len);
|
||||
size_t convertedChars = 0;
|
||||
wcstombs_s(&convertedChars, new_res, new_len, res, _TRUNCATE);
|
||||
|
||||
size_t len = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA_W, DevicePath) + convertedChars;
|
||||
if (RequiredSize) *RequiredSize = len;
|
||||
if (!DeviceInterfaceDetailData && DeviceInterfaceDetailDataSize < len) {
|
||||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return FALSE;
|
||||
}
|
||||
if (!DeviceInterfaceDetailData || sizeof *DeviceInterfaceDetailData != DeviceInterfaceDetailData->cbSize) {
|
||||
SetLastError(ERROR_INVALID_PARAMETER);
|
||||
return FALSE;
|
||||
}
|
||||
memcpy(DeviceInterfaceDetailData->DevicePath, new_res, len);
|
||||
free(new_res);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
return TRUE;
|
||||
}
|
||||
device = device->next;
|
||||
}
|
||||
|
||||
log_misc("setupapi", "TrueSetupDiGetDeviceInterfaceDetailA fallthrough");
|
||||
return TrueSetupDiGetDeviceInterfaceDetailA(DeviceInfoSet, DeviceInterfaceData, DeviceInterfaceDetailData,
|
||||
DeviceInterfaceDetailDataSize, RequiredSize, DeviceInfoData);
|
||||
}
|
||||
|
||||
BOOL WINAPI FakeSetupDiDestroyDeviceInfoList(HDEVINFO DevicesInfoSet) {
|
||||
FAKE_DEVICE* device = fake_devices;
|
||||
while (device != NULL) {
|
||||
if (device->handle == DevicesInfoSet) device->handle = NULL;
|
||||
device = device->next;
|
||||
}
|
||||
return TrueSetupDiDestroyDeviceInfoList(DevicesInfoSet);
|
||||
}
|
||||
|
||||
void hook_setupapi() {
|
||||
hook("Setupapi.DLL", "SetupDiGetClassDevsA", FakeSetupDiGetClassDevsA, (void**)&TrueSetupDiGetClassDevsA, 6);
|
||||
hook("Setupapi.DLL", "SetupDiEnumDeviceInterfaces", FakeSetupDiEnumDeviceInterfaces,
|
||||
(void**)&TrueSetupDiEnumDeviceInterfaces, 7);
|
||||
hook("Setupapi.DLL", "SetupDiGetDeviceInterfaceDetailA", FakeSetupDiGetDeviceInterfaceDetailA,
|
||||
(void**)&TrueSetupDiGetDeviceInterfaceDetailA, 6);
|
||||
hook("Setupapi.DLL", "SetupDiDestroyDeviceInfoList", FakeSetupDiDestroyDeviceInfoList,
|
||||
(void**)&TrueSetupDiDestroyDeviceInfoList, 7);
|
||||
}
|
||||
29
src/micetools/dll/smbus.h
Normal file
29
src/micetools/dll/smbus.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <Windows.h>
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsmbus_request_packet_ {
|
||||
BYTE status;
|
||||
BYTE prt;
|
||||
WORD addr;
|
||||
WORD reg;
|
||||
BYTE dlen;
|
||||
BYTE data[32];
|
||||
} mxsmbus_request_packet;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsmbus_i2c_packet_ {
|
||||
BYTE status;
|
||||
BYTE prt;
|
||||
BYTE addr;
|
||||
BYTE reg;
|
||||
BYTE dlen;
|
||||
BYTE data[32];
|
||||
} mxsmbus_i2c_packet;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct mxsuperio_lpc_packet_ {
|
||||
BYTE index;
|
||||
BYTE reg;
|
||||
BYTE data;
|
||||
} mxsuperio_lpc_packet;
|
||||
enum mxsbus_status { MXSBUS_OKAY = 0 };
|
||||
143
src/micetools/dll/w83791d.h
Normal file
143
src/micetools/dll/w83791d.h
Normal file
@@ -0,0 +1,143 @@
|
||||
// W83791D (H/W monitor)
|
||||
// https://elixir.bootlin.com/linux/latest/source/drivers/hwmon/w83791d.c
|
||||
// https://datasheetspdf.com/pdf-file/641504/Winbond/W83791D/1
|
||||
// Bank 0
|
||||
#define W83791D_REG_BANK 0x4E
|
||||
#define W83791D_REG_TEMP2_CONFIG 0xC2
|
||||
#define W83791D_REG_TEMP3_CONFIG 0xCA
|
||||
#define W83791D_REG_TEMP1_0 0x27
|
||||
#define W83791D_REG_TEMP1_1 0x39
|
||||
#define W83791D_REG_TEMP1_2 0x3A
|
||||
#define W83791D_REG_BEEP_CONFIG 0x4D
|
||||
#define W83791D_REG_BEEP_CTRL_0 0x56
|
||||
#define W83791D_REG_BEEP_CTRL_1 0x57
|
||||
#define W83791D_REG_BEEP_CTRL_2 0xA3
|
||||
#define W83791D_REG_GPIO 0x15
|
||||
#define W83791D_REG_CONFIG 0x40
|
||||
#define W83791D_REG_VID_FANDIV 0x47
|
||||
#define W83791D_REG_DID_VID4 0x49
|
||||
#define W83791D_REG_WCHIPID 0x58
|
||||
#define W83791D_REG_CHIPMAN 0x4F //
|
||||
#define W83791D_REG_PIN 0x4B
|
||||
#define W83791D_REG_I2C_SUBADDR 0x4A
|
||||
#define W83791D_REG_ALARM1 0xA9
|
||||
#define W83791D_REG_ALARM2 0xAA
|
||||
#define W83791D_REG_ALARM3 0xAB
|
||||
#define W83791D_REG_VBAT 0x5D
|
||||
#define W83791D_REG_I2C_ADDR 0x48 // Used
|
||||
|
||||
#define W83791D_RAM_VCOREA 0x20
|
||||
#define W83791D_RAM_VNIR0 0x21
|
||||
#define W83791D_RAM_3V3 0x22
|
||||
#define W83791D_RAM_VDD5 0x23
|
||||
#define W83791D_RAM_12VIN 0x24
|
||||
#define W83791D_RAM_N12VIN 0x25
|
||||
#define W83791D_RAM_N5VIN 0x26
|
||||
#define W83791D_RAM_TEMP 0x27
|
||||
#define W83791D_RAM_FAN1 0x28
|
||||
#define W83791D_RAM_FAN2 0x29
|
||||
#define W83791D_RAM_FAN3 0x2a
|
||||
#define W83791D_RAM_VCOREA_HIGH 0x2b
|
||||
#define W83791D_RAM_VCOREA_LOW 0x2c
|
||||
#define W83791D_RAM_VINR0_HIGH 0x2d
|
||||
#define W83791D_RAM_VINR0_LOW 0x2e
|
||||
#define W83791D_RAM_3V3_HIGH 0x2f
|
||||
#define W83791D_RAM_3V3_LOW 0x30
|
||||
#define W83791D_RAM_VDD5_HIGH 0x31
|
||||
#define W83791D_RAM_VDD5_LOW 0x32
|
||||
#define W83791D_RAM_12VIN_HIGH 0x33
|
||||
#define W83791D_RAM_12VIN_LOW 0x34
|
||||
#define W83791D_RAM_N12VIN_HIGH 0x35
|
||||
#define W83791D_RAM_N12VIN_LOW 0x36
|
||||
#define W83791D_RAM_N5VIN_HIGH 0x37
|
||||
#define W83791D_RAM_N5VIN_LOW 0x38
|
||||
#define W83791D_RAM_VTIN1_HIGH 0x39
|
||||
#define W83791D_RAM_VTIN1_HYST 0x3a
|
||||
#define W83791D_RAM_FAN1_LIMIT 0x3b
|
||||
#define W83791D_RAM_FAN2_LIMIT 0x3c
|
||||
#define W83791D_RAM_FAN3_LIMIT 0x3d
|
||||
|
||||
#define W83791D_VID_FAN_DIV 0x47
|
||||
#define W83791D_VBAT_MONITOR_CONTROL 0x5d
|
||||
|
||||
// Beep flags
|
||||
#define W83791D_BEEP0_EN_FAN2 0x80
|
||||
#define W83791D_BEEP0_EN_FAN1 0x40
|
||||
#define W83791D_BEEP0_EN_T2 0x20
|
||||
#define W83791D_BEEP0_EN_T1 0x10
|
||||
#define W83791D_BEEP0_EN_V5 0x08
|
||||
#define W83791D_BEEP0_EN_V33 0x04
|
||||
#define W83791D_BEEP0_EN_T3 0x02
|
||||
#define W83791D_BEEP0_EN_V25A 0x01
|
||||
|
||||
#define W83791D_BEEP1_EN_G 0x80
|
||||
#define W83791D_BEEP1_EN_VR1 0x40
|
||||
#define W83791D_BEEP1_EN_VR0 0x20
|
||||
#define W83791D_BEEP1_EN_CASO 0x10
|
||||
#define W83791D_BEEP1_EN_FAN3 0x08
|
||||
#define W83791D_BEEP1_EN_NV5 0x04
|
||||
#define W83791D_BEEP1_EN_NV12 0x02
|
||||
#define W83791D_BEEP1_EN_V13 0x01
|
||||
|
||||
#define W83791D_BEEP2_EN_USER 0x80
|
||||
#define W83791D_BEEP2_EN_FAN5 0x40
|
||||
#define W83791D_BEEP2_EN_FAN4 0x20
|
||||
#define W83791D_BEEP2_EN_TART3 0x10
|
||||
#define W83791D_BEEP2_EN_TART2 0x08
|
||||
#define W83791D_BEEP2_EN_TART1 0x04
|
||||
#define W83791D_BEEP2_EN_VBAT 0x02
|
||||
#define W83791D_BEEP2_EN_VSB 0x01
|
||||
|
||||
// Config flags
|
||||
#define W83791D_CONFIG_INIT 0x80
|
||||
#define W83791D_CONFIG_IRQ_OUT 0x40
|
||||
#define W83791D_CONFIG_IRQ_POL 0x40
|
||||
#define W83791D_CONFIG_RESERVED 0x10
|
||||
#define W83791D_CONFIG_INT_CLEAR 0x08
|
||||
#define W83791D_CONFIG_IRQ_EN 0x04
|
||||
#define W83791D_CONFIG_SMI_EN 0x02
|
||||
#define W83791D_CONFIG_START 0x01
|
||||
|
||||
// VBAT monitor control
|
||||
#define W83791D_VBMC_FANDIV3 0x80
|
||||
#define W83791D_VBMC_FANDIV2 0x40
|
||||
#define W83791D_VBMC_FANDIV1 0x20
|
||||
#define W83791D_VBMC_EN_ALM_RSP 0x10
|
||||
#define W83791D_VBMC_BJTS3 0x08
|
||||
#define W83791D_VBMC_BJTS2 0x04
|
||||
#define W83791D_VBMC_BJTS1 0x02
|
||||
#define W83791D_VBMC_EN_VBAT_MINT 0x01
|
||||
|
||||
// Bank 1
|
||||
#define W83791D_NONCRIT_TEMP_1 0x40
|
||||
#define W83791D_CRIT_TEMP_1 0x41
|
||||
#define W83791D_NONCRIT_TEMP_2 0x42
|
||||
#define W83791D_CRIT_TEMP_2 0x43
|
||||
#define W83791D_NONCRIT_TEMP_3 0x44
|
||||
#define W83791D_CRIT_TEMP_3 0x45
|
||||
#define W83791D_SENSOR_SBMUS_ADDRESS 0x4F
|
||||
|
||||
#define W83791D_VIN0 0x50 // VCORE
|
||||
#define W83791D_VIN1 0x51 // VINR0
|
||||
#define W83791D_VIN2 0x52 // +3.3 VIN
|
||||
#define W83791D_VIN3 0x53 // +5 VIN
|
||||
#define W83791D_VIN4 0x54 // +12 VIN
|
||||
#define W83791D_VIN5 0x55 // -12 VIN
|
||||
#define W83791D_VIN6 0x56 // -5 VIN
|
||||
#define W83791D_VSB 0x57
|
||||
#define W83791D_VBAT 0x58
|
||||
#define W83791D_VINR1 0x59
|
||||
#define W83791D_FAN1 0x5a
|
||||
#define W83791D_FAN2 0x5b
|
||||
#define W83791D_FAN3 0x5c
|
||||
#define W83791D_TEMP1 0x5d
|
||||
#define W83791D_TEMP2 0x5e
|
||||
#define W83791D_TEMP3 0x5f
|
||||
#define W83791D_CHASIS 0x50
|
||||
|
||||
#define W83791D_ENTITY_CPU 0x03
|
||||
#define W83791D_ENTITY_SYSTEM 0x07
|
||||
#define W83791D_ENTITY_MEMORY_MOD 0x08
|
||||
#define W83791D_ENTITY_CHASIS 0x17
|
||||
#define W83791D_ENTITY_FAN 0x1d
|
||||
#define W83791D_ENTITY_MEMORY_DEV 0x20
|
||||
123
src/micetools/launcher/exe.c
Normal file
123
src/micetools/launcher/exe.c
Normal file
@@ -0,0 +1,123 @@
|
||||
#include "exe.h"
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
|
||||
bool inject_debug_wait(HANDLE process) {
|
||||
BOOL present;
|
||||
|
||||
log_info(BOOT_LOGGER, "Waiting for debugger to attach.");
|
||||
do {
|
||||
Sleep(1000);
|
||||
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
|
||||
log_error(BOOT_LOGGER, "CheckRemoteDebuggerPresent failed: %03x", GetLastError());
|
||||
return false;
|
||||
}
|
||||
} while (!present);
|
||||
log_info(BOOT_LOGGER, "Debugger attached, resuming");
|
||||
return true;
|
||||
}
|
||||
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) {
|
||||
int nchars = strlen(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());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
|
||||
log_error(BOOT_LOGGER, "WriteProcessMemory failed: %03x", 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());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
|
||||
log_error(BOOT_LOGGER, "WaitForSingleObject failed: %03x", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD result;
|
||||
if (FAILED(GetExitCodeThread(remote_thread, &result))) {
|
||||
log_error(BOOT_LOGGER, "GetExitCodeThread failed: %03x", GetLastError());
|
||||
return false;
|
||||
}
|
||||
if (result == 0) {
|
||||
log_error(BOOT_LOGGER, "GetExitCodeThread failed: result == 0");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool inject_dll(HANDLE process, LPCSTR inject) {
|
||||
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
|
||||
if (kernel32 == NULL) {
|
||||
log_error(BOOT_LOGGER, "GetModuleHandleA failed: %03x", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
|
||||
if (addr_LoadLibraryA == NULL) {
|
||||
log_error(BOOT_LOGGER, "GetProcAddress failed: %03x", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return remote_call(process, addr_LoadLibraryA, inject);
|
||||
}
|
||||
|
||||
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject) {
|
||||
log_misc(BOOT_LOGGER, "Using %s for hooks", inject);
|
||||
STARTUPINFOA startupInfo;
|
||||
PROCESS_INFORMATION processInformation;
|
||||
|
||||
memset(&startupInfo, 0, sizeof(startupInfo));
|
||||
startupInfo.cb = sizeof(startupInfo);
|
||||
|
||||
// char real_inject_path[MAX_PATH + 1];
|
||||
// snprintf(real_inject_path, MAX_PATH + 1, ".\\%s", inject);
|
||||
// GetFullPathNameA(real_inject_path, MAX_PATH + 1, &real_inject_path, NULL);
|
||||
|
||||
// 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());
|
||||
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());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
// if (!inject_debug_wait(processInformation.hProcess)) goto abort;
|
||||
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
|
||||
|
||||
// Injection completed, let the program continue execution
|
||||
if (FAILED(ResumeThread(processInformation.hThread))) {
|
||||
log_error(BOOT_LOGGER, "ResumeThread failed: %03x", GetLastError());
|
||||
goto abort;
|
||||
}
|
||||
|
||||
return processInformation.hProcess;
|
||||
|
||||
abort:
|
||||
if (processInformation.hProcess) {
|
||||
if (FAILED(CloseHandle(processInformation.hThread)))
|
||||
log_error(BOOT_LOGGER, "CloseHandle(hProcess) failed: %03x", GetLastError());
|
||||
|
||||
if (FAILED(TerminateProcess(processInformation.hProcess, 1)))
|
||||
log_error(BOOT_LOGGER, "TerminateProcess failed: %03x", GetLastError());
|
||||
}
|
||||
if (processInformation.hThread) {
|
||||
if (FAILED(CloseHandle(processInformation.hThread)))
|
||||
log_error(BOOT_LOGGER, "CloseHandle(hThread) failed: %03x", GetLastError());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
4
src/micetools/launcher/exe.h
Normal file
4
src/micetools/launcher/exe.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#include <Windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject);
|
||||
65
src/micetools/launcher/locate.c
Normal file
65
src/micetools/launcher/locate.c
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "locate.h"
|
||||
|
||||
const char* KNOWN_GAMES[] = {
|
||||
// Preferentially use a decrypted dump if present
|
||||
"maimai_dump_.exe",
|
||||
"maimai.exe",
|
||||
};
|
||||
|
||||
#ifndef MICELIB
|
||||
#ifdef MICE_WIN32
|
||||
#define MICELIB "mice86.dll"
|
||||
#else // MICE_WIN32
|
||||
#define MICELIB "mice64.dll"
|
||||
#endif // MICE_WIN32
|
||||
#endif // MICELIB
|
||||
|
||||
bool locate_file(char* path, size_t len, const char* exe) {
|
||||
WIN32_FIND_DATA fdFile;
|
||||
HANDLE hFind = NULL;
|
||||
|
||||
char work_path[2048];
|
||||
sprintf(work_path, ".\\*.*");
|
||||
|
||||
if ((hFind = FindFirstFile(work_path, &fdFile)) == INVALID_HANDLE_VALUE) return false;
|
||||
|
||||
do {
|
||||
if (!strcmp(fdFile.cFileName, ".") || !strcmp(fdFile.cFileName, "..")) continue;
|
||||
|
||||
if (fdFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) continue;
|
||||
|
||||
if (!strcmp(fdFile.cFileName, exe)) {
|
||||
snprintf(path, len, ".\\%s", fdFile.cFileName);
|
||||
FindClose(hFind);
|
||||
return true;
|
||||
}
|
||||
} while (FindNextFile(hFind, &fdFile));
|
||||
|
||||
FindClose(hFind);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool locate_game(char* path, size_t len) {
|
||||
// This is slightly wasteful, but is needed to ensure priority!
|
||||
for (size_t i = 0; i < ((sizeof KNOWN_GAMES) / (sizeof KNOWN_GAMES[0])); i++) {
|
||||
if (locate_file(path, len, KNOWN_GAMES[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool locate_library(char* path, size_t len) {
|
||||
if (locate_file(path, len, MICELIB)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Don't call DllMain! We don't want to hook ourself!
|
||||
HANDLE mice = LoadLibraryExA(MICELIB, NULL, DONT_RESOLVE_DLL_REFERENCES);
|
||||
if (mice != NULL) {
|
||||
GetModuleFileNameA(mice, path, len);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
8
src/micetools/launcher/locate.h
Normal file
8
src/micetools/launcher/locate.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#include <Windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
bool locate_exe(char* path, size_t len, const char* exe);
|
||||
bool locate_game(char* path, size_t len);
|
||||
41
src/micetools/launcher/main.c
Normal file
41
src/micetools/launcher/main.c
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../lib/mice/mice.h"
|
||||
#include "exe.h"
|
||||
#include "locate.h"
|
||||
|
||||
const char* VERSION = "0.0-pre";
|
||||
|
||||
int main(int argc, CHAR** argv) {
|
||||
setup_logging();
|
||||
|
||||
log_info(BOOT_LOGGER, "Micetools version: %s", VERSION);
|
||||
|
||||
char path[MAX_PATH + 1];
|
||||
if (!locate_game(path, MAX_PATH + 1)) {
|
||||
log_error(BOOT_LOGGER, "Failed to locate a game");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* cmdline = "";
|
||||
|
||||
log_info(BOOT_LOGGER, "%s %s", path, cmdline);
|
||||
|
||||
char micepath[MAX_PATH + 1];
|
||||
if (!locate_library(micepath, MAX_PATH + 1)) {
|
||||
log_error(BOOT_LOGGER, "Failed to locate micelib");
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE game_proc = start_and_inject(path, cmdline, micepath);
|
||||
if (!game_proc) return -1;
|
||||
|
||||
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {
|
||||
log_error(BOOT_LOGGER, "WaitForSingleObject failed: %03x", GetLastError());
|
||||
} else {
|
||||
log_info(BOOT_LOGGER, "Shutting down");
|
||||
CloseHandle(game_proc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
12
src/micetools/launcher/meson.build
Normal file
12
src/micetools/launcher/meson.build
Normal file
@@ -0,0 +1,12 @@
|
||||
executable(
|
||||
'mice',
|
||||
win_subsystem: 'console',
|
||||
sources: [
|
||||
'locate.c',
|
||||
'exe.c',
|
||||
'main.c',
|
||||
],
|
||||
link_with: [
|
||||
mice_lib,
|
||||
],
|
||||
)
|
||||
19
src/micetools/lib/am/amtimer.c
Normal file
19
src/micetools/lib/am/amtimer.c
Normal file
@@ -0,0 +1,19 @@
|
||||
#include <amtimer.h>
|
||||
|
||||
int frequency_loaded = 0;
|
||||
LARGE_INTEGER frequency;
|
||||
|
||||
amtime_t* amiTimerGet(amtime_t* time) {
|
||||
LARGE_INTEGER counter;
|
||||
|
||||
if (time == NULL) return NULL;
|
||||
|
||||
if (frequency_loaded == 0) {
|
||||
QueryPerformanceFrequency(&frequency);
|
||||
frequency_loaded = 1;
|
||||
}
|
||||
QueryPerformanceCounter(&counter);
|
||||
time->microseconds = (counter.QuadPart * 1000000) / frequency.QuadPart;
|
||||
time->seconds = counter.QuadPart / frequency.QuadPart;
|
||||
return time;
|
||||
}
|
||||
15
src/micetools/lib/am/amtimer.h
Normal file
15
src/micetools/lib/am/amtimer.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
typedef struct amtime {
|
||||
unsigned int seconds;
|
||||
unsigned int microseconds;
|
||||
} amtime_t;
|
||||
|
||||
amtime_t* amiTimerGet(amtime_t* time);
|
||||
|
||||
#define _amTimeMs(time) (((time).microseconds / 1000 + (time).seconds * 1000))
|
||||
#define _amTimeDelta(now, start) \
|
||||
(((now).microseconds - (start).microseconds) / 1000 + \
|
||||
((now).seconds - (start).seconds) * 1000)
|
||||
6
src/micetools/lib/am/meson.build
Normal file
6
src/micetools/lib/am/meson.build
Normal file
@@ -0,0 +1,6 @@
|
||||
amlib = static_library(
|
||||
'am',
|
||||
sources: [
|
||||
'amtimer.c',
|
||||
],
|
||||
)
|
||||
110
src/micetools/lib/dmi/dmi.c
Normal file
110
src/micetools/lib/dmi/dmi.c
Normal file
@@ -0,0 +1,110 @@
|
||||
#include "dmi.h"
|
||||
|
||||
LPBYTE dmi_table = NULL;
|
||||
WORD dmi_size = 0;
|
||||
size_t _dmi_max = 0;
|
||||
|
||||
DMI_BIOS deafult_dmi_bios = {
|
||||
.Type = 0x00,
|
||||
.Length = 0x12,
|
||||
.Handle = 0x0000,
|
||||
.Vendor = 0x00,
|
||||
.Version = 0x00,
|
||||
.StartSegment = 0x0000,
|
||||
.ReleaseDate = 0x00,
|
||||
.ROMSize = 0x00,
|
||||
.Chars = 0x04,
|
||||
};
|
||||
|
||||
DMI_SYSTEM default_dmi_system = {
|
||||
.Type = 0x01,
|
||||
.Length = 0x08,
|
||||
.Handle = 0x0000,
|
||||
.Manufacturer = 0x00,
|
||||
.ProductName = 0x00,
|
||||
.Version = 0x00,
|
||||
.Serial = 0x00,
|
||||
};
|
||||
|
||||
DMI_STRING deafult_dmi_string = {
|
||||
.Type = 0x0b,
|
||||
.Length = 0x05,
|
||||
.Handle = 0x0000,
|
||||
.NoStrings = 0x00,
|
||||
};
|
||||
|
||||
static void dmi_init(void) {
|
||||
if (dmi_table) free(dmi_table);
|
||||
dmi_table = (LPBYTE)malloc(0xff);
|
||||
dmi_size = 0;
|
||||
_dmi_max = 1024;
|
||||
}
|
||||
|
||||
static void dmi_append(void* data, size_t size) {
|
||||
if (!dmi_table) return;
|
||||
while (dmi_size + (size + 1) >= _dmi_max) {
|
||||
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
|
||||
if (!new_table) return;
|
||||
dmi_table = new_table;
|
||||
}
|
||||
memcpy(dmi_table + dmi_size, &data, size);
|
||||
dmi_size += size;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
dmi_table[dmi_size++] = 0;
|
||||
}
|
||||
|
||||
static void dmi_append_with_strings(void* data, size_t size, int num_strings, ...) {
|
||||
va_list args;
|
||||
va_start(args, num_strings);
|
||||
|
||||
dmi_append(data, size);
|
||||
dmi_size -= 2;
|
||||
for (int i = 0; i < num_strings; i++) {
|
||||
char* str = va_arg(args, char*);
|
||||
int len = strlen(str);
|
||||
// #pragma warning(disable : 4996)
|
||||
strcpy((char*)dmi_table + dmi_size, str);
|
||||
dmi_size += len + 1;
|
||||
dmi_table[dmi_size - 1] = 0;
|
||||
}
|
||||
dmi_table[dmi_size++] = 0;
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void dmi_build_default() {
|
||||
dmi_init();
|
||||
dmi_append(&deafult_dmi_bios, sizeof deafult_dmi_bios);
|
||||
// Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2)
|
||||
// Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3)
|
||||
|
||||
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 1, "Supermicro");
|
||||
|
||||
deafult_dmi_string.NoStrings = 3;
|
||||
|
||||
dmi_append_with_strings(&deafult_dmi_string, sizeof deafult_dmi_string,
|
||||
// OEM strings:
|
||||
// 0: ??
|
||||
// 1: ??
|
||||
// 2: Platform ID (AAL, AAM)
|
||||
// AAL = Nvidia drivers
|
||||
// AAM = AMD drivers
|
||||
// *** = No dedicated drivers
|
||||
// 3: ??
|
||||
// 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech)
|
||||
// If present -> makes board = 4
|
||||
// AAL = 4
|
||||
// AAM = 4
|
||||
// Supermicro = 4
|
||||
// Advantech = 4
|
||||
5, ".", ".", "AAM", ".", "AAL"
|
||||
);
|
||||
}
|
||||
|
||||
BYTE dmi_calc_checksum(const char* buf, int len) {
|
||||
int sum = 0;
|
||||
int a;
|
||||
for (a = 0; a < len; a++)
|
||||
sum += buf[a];
|
||||
return (BYTE)(sum == 0);
|
||||
}
|
||||
58
src/micetools/lib/dmi/dmi.h
Normal file
58
src/micetools/lib/dmi/dmi.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#include <Windows.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern LPBYTE dmi_table;
|
||||
extern WORD dmi_size;
|
||||
|
||||
// #define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct DMI_HEADER_ {
|
||||
CHAR Signature[5];
|
||||
BYTE Checksum;
|
||||
WORD StructLength;
|
||||
DWORD StructAddr;
|
||||
WORD NumberOfStructs;
|
||||
BYTE BCDRevision;
|
||||
BYTE Reserved;
|
||||
} DMI_HEADER;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct DMI_BIOS_ {
|
||||
BYTE Type;
|
||||
BYTE Length;
|
||||
WORD Handle;
|
||||
BYTE Vendor;
|
||||
BYTE Version;
|
||||
WORD StartSegment;
|
||||
BYTE ReleaseDate;
|
||||
BYTE ROMSize;
|
||||
uint64_t Chars;
|
||||
} DMI_BIOS;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct DMI_SYSTEM_ {
|
||||
BYTE Type;
|
||||
BYTE Length;
|
||||
WORD Handle;
|
||||
BYTE Manufacturer;
|
||||
BYTE ProductName;
|
||||
BYTE Version;
|
||||
BYTE Serial;
|
||||
} DMI_SYSTEM;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct DMI_STRING_ {
|
||||
BYTE Type;
|
||||
BYTE Length;
|
||||
WORD Handle;
|
||||
BYTE NoStrings;
|
||||
} DMI_STRING;
|
||||
|
||||
static void dmi_init(void);
|
||||
static void dmi_append(void* data, size_t size);
|
||||
static void dmi_append_with_strings(void* data, size_t size, int num_strings,
|
||||
...);
|
||||
|
||||
void dmi_build_default(void);
|
||||
BYTE dmi_calc_checksum(const char* buf, int len);
|
||||
6
src/micetools/lib/dmi/meson.build
Normal file
6
src/micetools/lib/dmi/meson.build
Normal file
@@ -0,0 +1,6 @@
|
||||
dmi_lib = static_library(
|
||||
'dmi',
|
||||
sources: [
|
||||
'dmi.c'
|
||||
],
|
||||
)
|
||||
25
src/micetools/lib/json/LICESNSE
Normal file
25
src/micetools/lib/json/LICESNSE
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Copyright (C) 2012-2021 the json-parser authors All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
1
src/micetools/lib/json/README.txt
Normal file
1
src/micetools/lib/json/README.txt
Normal file
@@ -0,0 +1 @@
|
||||
https://github.com/json-parser/json-parser
|
||||
813
src/micetools/lib/json/json.c
Normal file
813
src/micetools/lib/json/json.c
Normal file
@@ -0,0 +1,813 @@
|
||||
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
||||
*
|
||||
* Copyright (C) 2012-2021 the json-parser authors All rights reserved.
|
||||
* https://github.com/json-parser/json-parser
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "json.h"
|
||||
#include "../util/hex.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define JSON_INT_MAX 9223372036854775807LL
|
||||
|
||||
typedef unsigned int json_uchar;
|
||||
|
||||
const struct _json_value json_value_none;
|
||||
|
||||
static int would_overflow(json_int_t value, json_char b) { return ((JSON_INT_MAX - (b - '0')) / 10) < value; }
|
||||
|
||||
typedef struct {
|
||||
size_t used_memory;
|
||||
|
||||
json_settings settings;
|
||||
int first_pass;
|
||||
|
||||
const json_char *ptr;
|
||||
unsigned int cur_line, cur_col;
|
||||
} json_state;
|
||||
|
||||
static void *default_alloc(size_t size, int zero) { return zero ? calloc(1, size) : malloc(size); }
|
||||
|
||||
static void *json_alloc(json_state *state, size_t size, int zero) {
|
||||
if ((ULONG_MAX - 8 - state->used_memory) < size) return 0;
|
||||
|
||||
if (state->settings.max_memory && (state->used_memory += size) > state->settings.max_memory) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return default_alloc(size, zero);
|
||||
}
|
||||
|
||||
static int new_value(json_state *state, json_value **top, json_value **root, json_value **alloc, json_type type) {
|
||||
json_value *value;
|
||||
size_t values_size;
|
||||
|
||||
if (!state->first_pass) {
|
||||
value = *top = *alloc;
|
||||
*alloc = (*alloc)->_reserved.next_alloc;
|
||||
|
||||
if (!*root) *root = value;
|
||||
|
||||
switch (value->type) {
|
||||
case json_array:
|
||||
if (value->u.array.length == 0) break;
|
||||
if (!(value->u.array.values =
|
||||
(json_value **)json_alloc(state, value->u.array.length * sizeof(json_value *), 0))) {
|
||||
return 0;
|
||||
}
|
||||
value->u.array.length = 0;
|
||||
break;
|
||||
case json_object:
|
||||
if (value->u.object.length == 0) break;
|
||||
|
||||
values_size = sizeof(*value->u.object.values) * value->u.object.length;
|
||||
|
||||
if (!(value->u.object.values = (json_object_entry *)json_alloc(
|
||||
state, values_size + ((uintptr_t)value->u.object.values), 0))) {
|
||||
return 0;
|
||||
}
|
||||
value->_reserved.object_mem = (void *)(((char *)value->u.object.values) + values_size);
|
||||
value->u.object.length = 0;
|
||||
break;
|
||||
case json_string:
|
||||
if (!(value->u.string.ptr =
|
||||
(json_char *)json_alloc(state, (value->u.string.length + 1) * sizeof(json_char), 0))) {
|
||||
return 0;
|
||||
}
|
||||
value->u.string.length = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(value = (json_value *)json_alloc(state, sizeof(json_value) + state->settings.value_extra, 1))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!*root) *root = value;
|
||||
|
||||
value->type = type;
|
||||
value->parent = *top;
|
||||
|
||||
#ifdef JSON_TRACK_SOURCE
|
||||
value->line = state->cur_line;
|
||||
value->col = state->cur_col;
|
||||
#endif
|
||||
|
||||
if (*alloc) (*alloc)->_reserved.next_alloc = value;
|
||||
|
||||
*alloc = *top = value;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define whitespace \
|
||||
case '\n': \
|
||||
++state.cur_line; \
|
||||
state.cur_col = 0; /* FALLTHRU */ \
|
||||
case ' ': /* FALLTHRU */ \
|
||||
case '\t': /* FALLTHRU */ \
|
||||
case '\r'
|
||||
|
||||
#define string_add(b) \
|
||||
do { \
|
||||
if (!state.first_pass) string[string_length] = b; \
|
||||
++string_length; \
|
||||
} while (0);
|
||||
|
||||
#define line_and_col state.cur_line, state.cur_col
|
||||
|
||||
static const long flag_next = 1 << 0, flag_reproc = 1 << 1, flag_need_comma = 1 << 2, flag_seek_value = 1 << 3,
|
||||
flag_escaped = 1 << 4, flag_string = 1 << 5, flag_need_colon = 1 << 6, flag_done = 1 << 7,
|
||||
flag_num_negative = 1 << 8, flag_num_zero = 1 << 9, flag_num_e = 1 << 10,
|
||||
flag_num_e_got_sign = 1 << 11, flag_num_e_negative = 1 << 12, flag_line_comment = 1 << 13,
|
||||
flag_block_comment = 1 << 14, flag_num_got_decimal = 1 << 15;
|
||||
|
||||
json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t length, char *error_buf) {
|
||||
char error[json_error_max];
|
||||
const json_char *end;
|
||||
json_value *top, *root, *alloc = 0;
|
||||
json_state state = {0};
|
||||
long flags = 0;
|
||||
int num_digits = 0;
|
||||
double num_e = 0, num_fraction = 0;
|
||||
|
||||
/* Skip UTF-8 BOM
|
||||
*/
|
||||
if (length >= 3 && ((unsigned char)json[0]) == 0xEF && ((unsigned char)json[1]) == 0xBB &&
|
||||
((unsigned char)json[2]) == 0xBF) {
|
||||
json += 3;
|
||||
length -= 3;
|
||||
}
|
||||
|
||||
error[0] = '\0';
|
||||
end = (json + length);
|
||||
|
||||
memcpy(&state.settings, settings, sizeof(json_settings));
|
||||
|
||||
for (state.first_pass = 1; state.first_pass >= 0; --state.first_pass) {
|
||||
json_uchar uchar;
|
||||
unsigned char uc_b1, uc_b2, uc_b3, uc_b4;
|
||||
json_char *string = 0;
|
||||
unsigned int string_length = 0;
|
||||
|
||||
top = root = 0;
|
||||
flags = flag_seek_value;
|
||||
|
||||
state.cur_line = 1;
|
||||
|
||||
for (state.ptr = json;; ++state.ptr) {
|
||||
json_char b = (state.ptr == end ? 0 : *state.ptr);
|
||||
|
||||
if (flags & flag_string) {
|
||||
if (!b) {
|
||||
sprintf(error, "%u:%u: Unexpected EOF in string", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
if (string_length > UINT_MAX - 8) goto e_overflow;
|
||||
|
||||
if (flags & flag_escaped) {
|
||||
flags &= ~flag_escaped;
|
||||
|
||||
switch (b) {
|
||||
case 'b':
|
||||
string_add('\b');
|
||||
break;
|
||||
case 'f':
|
||||
string_add('\f');
|
||||
break;
|
||||
case 'n':
|
||||
string_add('\n');
|
||||
break;
|
||||
case 'r':
|
||||
string_add('\r');
|
||||
break;
|
||||
case 't':
|
||||
string_add('\t');
|
||||
break;
|
||||
case 'u':
|
||||
|
||||
if (end - state.ptr <= 4 || (uc_b1 = hex_value(*++state.ptr)) == 0xFF ||
|
||||
(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);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
uc_b1 = (uc_b1 << 4) | uc_b2;
|
||||
uc_b2 = (uc_b3 << 4) | uc_b4;
|
||||
uchar = (uc_b1 << 8) | uc_b2;
|
||||
|
||||
if ((uchar & 0xF800) == 0xD800) {
|
||||
json_uchar uchar2;
|
||||
|
||||
if (end - state.ptr <= 6 || (*++state.ptr) != '\\' || (*++state.ptr) != 'u' ||
|
||||
(uc_b1 = hex_value(*++state.ptr)) == 0xFF ||
|
||||
(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);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
uc_b1 = (uc_b1 << 4) | uc_b2;
|
||||
uc_b2 = (uc_b3 << 4) | uc_b4;
|
||||
uchar2 = (uc_b1 << 8) | uc_b2;
|
||||
|
||||
uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF);
|
||||
}
|
||||
|
||||
if (sizeof(json_char) >= sizeof(json_uchar) || (uchar <= 0x7F)) {
|
||||
string_add((json_char)uchar);
|
||||
break;
|
||||
}
|
||||
|
||||
if (uchar <= 0x7FF) {
|
||||
if (state.first_pass)
|
||||
string_length += 2;
|
||||
else {
|
||||
string[string_length++] = 0xC0 | (uchar >> 6);
|
||||
string[string_length++] = 0x80 | (uchar & 0x3F);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (uchar <= 0xFFFF) {
|
||||
if (state.first_pass)
|
||||
string_length += 3;
|
||||
else {
|
||||
string[string_length++] = 0xE0 | (uchar >> 12);
|
||||
string[string_length++] = 0x80 | ((uchar >> 6) & 0x3F);
|
||||
string[string_length++] = 0x80 | (uchar & 0x3F);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (state.first_pass)
|
||||
string_length += 4;
|
||||
else {
|
||||
string[string_length++] = 0xF0 | (uchar >> 18);
|
||||
string[string_length++] = 0x80 | ((uchar >> 12) & 0x3F);
|
||||
string[string_length++] = 0x80 | ((uchar >> 6) & 0x3F);
|
||||
string[string_length++] = 0x80 | (uchar & 0x3F);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
string_add(b);
|
||||
};
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == '\\') {
|
||||
flags |= flag_escaped;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == '"') {
|
||||
if (!state.first_pass) string[string_length] = 0;
|
||||
|
||||
flags &= ~flag_string;
|
||||
string = 0;
|
||||
|
||||
switch (top->type) {
|
||||
case json_string:
|
||||
top->u.string.length = string_length;
|
||||
flags |= flag_next;
|
||||
|
||||
break;
|
||||
|
||||
case json_object:
|
||||
if (state.first_pass) {
|
||||
json_char **chars = (json_char **)&top->u.object.values;
|
||||
chars[0] += string_length + 1;
|
||||
} else {
|
||||
top->u.object.values[top->u.object.length].name =
|
||||
(json_char *)top->_reserved.object_mem;
|
||||
|
||||
top->u.object.values[top->u.object.length].name_length = string_length;
|
||||
|
||||
(*(json_char **)&top->_reserved.object_mem) += string_length + 1;
|
||||
}
|
||||
|
||||
flags |= flag_seek_value | flag_need_colon;
|
||||
continue;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
} else {
|
||||
string_add(b);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (state.settings.settings & json_enable_comments) {
|
||||
if (flags & (flag_line_comment | flag_block_comment)) {
|
||||
if (flags & flag_line_comment) {
|
||||
if (b == '\r' || b == '\n' || !b) {
|
||||
flags &= ~flag_line_comment;
|
||||
--state.ptr; /* so null can be reproc'd */
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags & flag_block_comment) {
|
||||
if (!b) {
|
||||
sprintf(error, "%u:%u: Unexpected EOF in block comment", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
if (b == '*' && state.ptr < (end - 1) && state.ptr[1] == '/') {
|
||||
flags &= ~flag_block_comment;
|
||||
++state.ptr; /* skip closing sequence */
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
} 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);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
if (++state.ptr == end) {
|
||||
sprintf(error, "%u:%u: EOF unexpected", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
switch (b = *state.ptr) {
|
||||
case '/':
|
||||
flags |= flag_line_comment;
|
||||
continue;
|
||||
|
||||
case '*':
|
||||
flags |= flag_block_comment;
|
||||
continue;
|
||||
|
||||
default:
|
||||
sprintf(error, "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b);
|
||||
goto e_failed;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & flag_done) {
|
||||
if (!b) break;
|
||||
|
||||
switch (b) {
|
||||
whitespace:
|
||||
continue;
|
||||
|
||||
default:
|
||||
sprintf(error, "%u:%u: Trailing garbage: `%c`", line_and_col, b);
|
||||
goto e_failed;
|
||||
};
|
||||
}
|
||||
|
||||
if (flags & flag_seek_value) {
|
||||
switch (b) {
|
||||
whitespace:
|
||||
continue;
|
||||
|
||||
case ']':
|
||||
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);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (flags & flag_need_comma) {
|
||||
if (b == ',') {
|
||||
flags &= ~flag_need_comma;
|
||||
continue;
|
||||
} else {
|
||||
sprintf(error, "%u:%u: Expected `,` before `%c`", line_and_col, b);
|
||||
|
||||
goto e_failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & flag_need_colon) {
|
||||
if (b == ':') {
|
||||
flags &= ~flag_need_colon;
|
||||
continue;
|
||||
} else {
|
||||
sprintf(error, "%u:%u: Expected `:` before `%c`", line_and_col, b);
|
||||
|
||||
goto e_failed;
|
||||
}
|
||||
}
|
||||
|
||||
flags &= ~flag_seek_value;
|
||||
|
||||
switch (b) {
|
||||
case '{':
|
||||
if (!new_value(&state, &top, &root, &alloc, json_object)) goto e_alloc_failure;
|
||||
|
||||
continue;
|
||||
|
||||
case '[':
|
||||
if (!new_value(&state, &top, &root, &alloc, json_array)) goto e_alloc_failure;
|
||||
|
||||
flags |= flag_seek_value;
|
||||
continue;
|
||||
|
||||
case '"':
|
||||
if (!new_value(&state, &top, &root, &alloc, json_string)) goto e_alloc_failure;
|
||||
|
||||
flags |= flag_string;
|
||||
|
||||
string = top->u.string.ptr;
|
||||
string_length = 0;
|
||||
|
||||
continue;
|
||||
|
||||
case 't':
|
||||
if ((end - state.ptr) <= 3 || *(++state.ptr) != 'r' || *(++state.ptr) != 'u' ||
|
||||
*(++state.ptr) != 'e') {
|
||||
goto e_unknown_value;
|
||||
}
|
||||
|
||||
if (!new_value(&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure;
|
||||
|
||||
top->u.boolean = 1;
|
||||
|
||||
flags |= flag_next;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if ((end - state.ptr) <= 4 || *(++state.ptr) != 'a' || *(++state.ptr) != 'l' ||
|
||||
*(++state.ptr) != 's' || *(++state.ptr) != 'e') {
|
||||
goto e_unknown_value;
|
||||
}
|
||||
|
||||
if (!new_value(&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure;
|
||||
|
||||
flags |= flag_next;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
if ((end - state.ptr) <= 3 || *(++state.ptr) != 'u' || *(++state.ptr) != 'l' ||
|
||||
*(++state.ptr) != 'l') {
|
||||
goto e_unknown_value;
|
||||
}
|
||||
|
||||
if (!new_value(&state, &top, &root, &alloc, json_null)) goto e_alloc_failure;
|
||||
|
||||
flags |= flag_next;
|
||||
break;
|
||||
default:
|
||||
if (isdigit((unsigned char)b) || b == '-') {
|
||||
if (!new_value(&state, &top, &root, &alloc, json_integer)) goto e_alloc_failure;
|
||||
|
||||
if (!state.first_pass) {
|
||||
while (isdigit((unsigned char)b) || b == '+' || b == '-' || b == 'e' ||
|
||||
b == 'E' || b == '.') {
|
||||
if ((++state.ptr) == end) {
|
||||
b = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
b = *state.ptr;
|
||||
}
|
||||
|
||||
flags |= flag_next | flag_reproc;
|
||||
break;
|
||||
}
|
||||
|
||||
flags &= ~(flag_num_negative | flag_num_e | flag_num_e_got_sign |
|
||||
flag_num_e_negative | flag_num_zero);
|
||||
|
||||
num_digits = 0;
|
||||
num_fraction = 0;
|
||||
num_e = 0;
|
||||
|
||||
if (b != '-') {
|
||||
flags |= flag_reproc;
|
||||
break;
|
||||
}
|
||||
|
||||
flags |= flag_num_negative;
|
||||
continue;
|
||||
} else {
|
||||
sprintf(error, "%u:%u: Unexpected `%c` when seeking value", line_and_col, b);
|
||||
goto e_failed;
|
||||
}
|
||||
};
|
||||
};
|
||||
} else {
|
||||
switch (top->type) {
|
||||
case json_object:
|
||||
switch (b) {
|
||||
whitespace:
|
||||
continue;
|
||||
case '"':
|
||||
if (flags & flag_need_comma) {
|
||||
sprintf(error, "%u:%u: Expected `,` before `\"`", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
flags |= flag_string;
|
||||
|
||||
string = (json_char *)top->_reserved.object_mem;
|
||||
string_length = 0;
|
||||
|
||||
break;
|
||||
|
||||
case '}':
|
||||
flags = (flags & ~flag_need_comma) | flag_next;
|
||||
break;
|
||||
|
||||
case ',':
|
||||
if (flags & flag_need_comma) {
|
||||
flags &= ~flag_need_comma;
|
||||
break;
|
||||
} /* FALLTHRU */
|
||||
|
||||
default:
|
||||
sprintf(error, "%u:%u: Unexpected `%c` in object", line_and_col, b);
|
||||
goto e_failed;
|
||||
};
|
||||
break;
|
||||
|
||||
case json_integer:
|
||||
case json_double:
|
||||
if (isdigit((unsigned char)b)) {
|
||||
++num_digits;
|
||||
|
||||
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);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
if (num_digits == 1 && b == '0') flags |= flag_num_zero;
|
||||
} else {
|
||||
flags |= flag_num_e_got_sign;
|
||||
num_e = (num_e * 10) + (b - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (would_overflow(top->u.integer, b)) {
|
||||
json_int_t integer = top->u.integer;
|
||||
--num_digits;
|
||||
--state.ptr;
|
||||
top->type = json_double;
|
||||
top->u.dbl = (double)integer;
|
||||
continue;
|
||||
}
|
||||
|
||||
top->u.integer = (top->u.integer * 10) + (b - '0');
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flags & flag_num_got_decimal)
|
||||
num_fraction = (num_fraction * 10) + (b - '0');
|
||||
else
|
||||
top->u.dbl = (top->u.dbl * 10) + (b - '0');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (b == '+' || b == '-') {
|
||||
if ((flags & flag_num_e) && !(flags & flag_num_e_got_sign)) {
|
||||
flags |= flag_num_e_got_sign;
|
||||
|
||||
if (b == '-') flags |= flag_num_e_negative;
|
||||
|
||||
continue;
|
||||
}
|
||||
} else if (b == '.' && top->type == json_integer) {
|
||||
json_int_t integer = top->u.integer;
|
||||
|
||||
if (!num_digits) {
|
||||
sprintf(error, "%u:%u: Expected digit before `.`", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
top->type = json_double;
|
||||
top->u.dbl = (double)integer;
|
||||
|
||||
flags |= flag_num_got_decimal;
|
||||
num_digits = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(flags & flag_num_e)) {
|
||||
if (top->type == json_double) {
|
||||
if (!num_digits) {
|
||||
sprintf(error, "%u:%u: Expected digit after `.`", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
top->u.dbl += num_fraction / pow(10.0, num_digits);
|
||||
}
|
||||
|
||||
if (b == 'e' || b == 'E') {
|
||||
flags |= flag_num_e;
|
||||
|
||||
if (top->type == json_integer) {
|
||||
json_int_t integer = top->u.integer;
|
||||
top->type = json_double;
|
||||
top->u.dbl = (double)integer;
|
||||
}
|
||||
|
||||
num_digits = 0;
|
||||
flags &= ~flag_num_zero;
|
||||
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (!num_digits) {
|
||||
sprintf(error, "%u:%u: Expected digit after `e`", line_and_col);
|
||||
goto e_failed;
|
||||
}
|
||||
|
||||
top->u.dbl *= pow(10.0, (flags & flag_num_e_negative ? -num_e : num_e));
|
||||
}
|
||||
|
||||
if (flags & flag_num_negative) {
|
||||
if (top->type == json_integer)
|
||||
top->u.integer = -top->u.integer;
|
||||
else
|
||||
top->u.dbl = -top->u.dbl;
|
||||
}
|
||||
|
||||
flags |= flag_next | flag_reproc;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
if (flags & flag_reproc) {
|
||||
flags &= ~flag_reproc;
|
||||
--state.ptr;
|
||||
}
|
||||
|
||||
if (flags & flag_next) {
|
||||
flags = (flags & ~flag_next) | flag_need_comma;
|
||||
|
||||
if (!top->parent) {
|
||||
/* root value done */
|
||||
|
||||
flags |= flag_done;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (top->parent->type == json_array) flags |= flag_seek_value;
|
||||
|
||||
if (!state.first_pass) {
|
||||
json_value *parent = top->parent;
|
||||
|
||||
switch (parent->type) {
|
||||
case json_object:
|
||||
parent->u.object.values[parent->u.object.length].value = top;
|
||||
break;
|
||||
case json_array:
|
||||
parent->u.array.values[parent->u.array.length] = top;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
}
|
||||
|
||||
if ((++top->parent->u.array.length) > UINT_MAX - 8) goto e_overflow;
|
||||
top = top->parent;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
alloc = root;
|
||||
}
|
||||
|
||||
return root;
|
||||
|
||||
e_unknown_value:
|
||||
sprintf(error, "%u:%u: Unknown value", line_and_col);
|
||||
goto e_failed;
|
||||
|
||||
e_alloc_failure:
|
||||
strcpy(error, "Memory allocation failure");
|
||||
goto e_failed;
|
||||
|
||||
e_overflow:
|
||||
sprintf(error, "%u:%u: Too long (caught overflow)", line_and_col);
|
||||
goto e_failed;
|
||||
|
||||
e_failed:
|
||||
if (error_buf) {
|
||||
if (*error)
|
||||
strcpy(error_buf, error);
|
||||
else
|
||||
strcpy(error_buf, "Unknown error");
|
||||
}
|
||||
|
||||
if (state.first_pass) alloc = root;
|
||||
|
||||
while (alloc) {
|
||||
top = alloc->_reserved.next_alloc;
|
||||
free(alloc);
|
||||
alloc = top;
|
||||
}
|
||||
|
||||
if (!state.first_pass) json_value_free(root);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
json_value *json_parse(const json_char *json, size_t length) {
|
||||
json_settings settings = {0};
|
||||
return json_parse_ex(&settings, json, length, 0);
|
||||
}
|
||||
|
||||
void json_value_free(json_value *value) {
|
||||
json_value *cur_value;
|
||||
|
||||
if (!value) return;
|
||||
|
||||
value->parent = 0;
|
||||
|
||||
while (value) {
|
||||
switch (value->type) {
|
||||
case json_array:
|
||||
|
||||
if (!value->u.array.length) {
|
||||
free(value->u.array.values);
|
||||
break;
|
||||
}
|
||||
|
||||
value = value->u.array.values[--value->u.array.length];
|
||||
continue;
|
||||
|
||||
case json_object:
|
||||
|
||||
if (!value->u.object.length) {
|
||||
free(value->u.object.values);
|
||||
break;
|
||||
}
|
||||
|
||||
value = value->u.object.values[--value->u.object.length].value;
|
||||
continue;
|
||||
|
||||
case json_string:
|
||||
|
||||
free(value->u.string.ptr);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
cur_value = value;
|
||||
value = value->parent;
|
||||
free(cur_value);
|
||||
}
|
||||
}
|
||||
114
src/micetools/lib/json/json.h
Normal file
114
src/micetools/lib/json/json.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/* vim: set et ts=3 sw=3 sts=3 ft=c:
|
||||
*
|
||||
* Copyright (C) 2012-2021 the json-parser authors All rights reserved.
|
||||
* https://github.com/json-parser/json-parser
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _JSON_H
|
||||
#define _JSON_H
|
||||
|
||||
#ifndef json_char
|
||||
#define json_char char
|
||||
#endif
|
||||
|
||||
#ifndef json_int_t
|
||||
#define json_int_t __int64
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
unsigned long max_memory; /* should be size_t, but would modify the API */
|
||||
int settings;
|
||||
size_t value_extra; /* how much extra space to allocate for values? */
|
||||
} json_settings;
|
||||
|
||||
#define json_enable_comments 0x01
|
||||
|
||||
typedef enum {
|
||||
json_none,
|
||||
json_object,
|
||||
json_array,
|
||||
json_integer,
|
||||
json_double,
|
||||
json_string,
|
||||
json_boolean,
|
||||
json_null
|
||||
} json_type;
|
||||
|
||||
extern const struct _json_value json_value_none;
|
||||
|
||||
typedef struct _json_object_entry {
|
||||
json_char *name;
|
||||
unsigned int name_length;
|
||||
struct _json_value *value;
|
||||
} json_object_entry;
|
||||
|
||||
typedef struct _json_value {
|
||||
struct _json_value *parent;
|
||||
|
||||
json_type type;
|
||||
|
||||
union {
|
||||
int boolean;
|
||||
json_int_t integer;
|
||||
double dbl;
|
||||
|
||||
struct {
|
||||
unsigned int length;
|
||||
json_char *ptr; /* null terminated */
|
||||
} string;
|
||||
|
||||
struct {
|
||||
unsigned int length;
|
||||
json_object_entry *values;
|
||||
} object;
|
||||
|
||||
struct {
|
||||
unsigned int length;
|
||||
struct _json_value **values;
|
||||
} array;
|
||||
} u;
|
||||
|
||||
union {
|
||||
struct _json_value *next_alloc;
|
||||
void *object_mem;
|
||||
} _reserved;
|
||||
|
||||
#ifdef JSON_TRACK_SOURCE
|
||||
unsigned int line, col;
|
||||
#endif
|
||||
|
||||
} json_value;
|
||||
|
||||
json_value *json_parse(const json_char *json, size_t length);
|
||||
|
||||
#define json_error_max 128
|
||||
json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t length, char *error);
|
||||
|
||||
void json_value_free(json_value *);
|
||||
|
||||
#endif
|
||||
7
src/micetools/lib/json/meson.build
Normal file
7
src/micetools/lib/json/meson.build
Normal file
@@ -0,0 +1,7 @@
|
||||
json_lib = static_library(
|
||||
'micejson',
|
||||
sources: [
|
||||
'json.c',
|
||||
],
|
||||
link_with: [util_lib]
|
||||
)
|
||||
16
src/micetools/lib/meson.build
Normal file
16
src/micetools/lib/meson.build
Normal file
@@ -0,0 +1,16 @@
|
||||
subdir('util') # This is the only lib that should ever be link_with'd by another lib
|
||||
subdir('am')
|
||||
subdir('mice')
|
||||
subdir('dmi')
|
||||
subdir('json')
|
||||
|
||||
fs = import('fs')
|
||||
# Handle the fact we aren't distributing the libpcp source
|
||||
if fs.is_dir('libpcp')
|
||||
subdir('libpcp')
|
||||
libpcp_is_static = true
|
||||
else
|
||||
libpcp = meson.get_compiler('c').find_library('libpcp', dirs: libs_dir, required: false)
|
||||
assert(libpcp.found(), 'Unable to locate libpcp.lib. Make sure to place it in the src/ folder prior to building.')
|
||||
libpcp_is_static = false
|
||||
endif
|
||||
95
src/micetools/lib/mice/hook.c
Normal file
95
src/micetools/lib/mice/hook.c
Normal file
@@ -0,0 +1,95 @@
|
||||
#include "hook.h"
|
||||
|
||||
function_hook_t* hook_list = NULL;
|
||||
|
||||
void append_hook(function_hook_t* hook) {
|
||||
hook->next = NULL;
|
||||
if (hook_list == NULL) {
|
||||
hook_list = hook;
|
||||
return;
|
||||
}
|
||||
|
||||
function_hook_t* hl = hook_list;
|
||||
while (hl->next != NULL) hl = hl->next;
|
||||
hl->next = hook;
|
||||
}
|
||||
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store, UINT length) {
|
||||
function_hook_t* hook = (function_hook_t*)malloc(sizeof(struct function_hook));
|
||||
hook->dll = dll;
|
||||
hook->name = name;
|
||||
hook->patch = patch;
|
||||
hook->store = store;
|
||||
hook->length = length;
|
||||
append_hook(hook);
|
||||
}
|
||||
|
||||
void patch_at(PVOID addr, const char* patch, DWORD length) {
|
||||
DWORD oldProt;
|
||||
VirtualProtect(addr, length, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
memcpy(addr, patch, length);
|
||||
VirtualProtect(addr, length, oldProt, &oldProt);
|
||||
}
|
||||
void clear_at(PVOID addr, BYTE clearVal, DWORD length) {
|
||||
DWORD oldProt;
|
||||
VirtualProtect(addr, length, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
memset(addr, clearVal, length);
|
||||
VirtualProtect(addr, length, oldProt, &oldProt);
|
||||
}
|
||||
|
||||
bool Detour(PVOID src, PVOID dst, const intptr_t len) {
|
||||
if (len < 5) return false;
|
||||
|
||||
DWORD oldProt;
|
||||
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &oldProt);
|
||||
|
||||
*(PCHAR)src = '\xE9';
|
||||
*(PINT)((int)src + 1) = (int)dst - (int)src - 5;
|
||||
|
||||
VirtualProtect(src, len, oldProt, &oldProt);
|
||||
return true;
|
||||
}
|
||||
|
||||
void* CreateHook(PVOID src, PVOID dst, const intptr_t len) {
|
||||
if (len < 5) return NULL;
|
||||
|
||||
PVOID gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
|
||||
if (!gateway) return NULL;
|
||||
memcpy(gateway, src, len);
|
||||
|
||||
*(PCHAR)((int)gateway + len) = '\xE9';
|
||||
*(PINT)((int)gateway + len + 1) = (int)src - (int)gateway - 5;
|
||||
|
||||
Detour(src, dst, len);
|
||||
|
||||
return gateway;
|
||||
}
|
||||
|
||||
void setup_hooks() {
|
||||
log_info(HOOKS_LOGGER, "attaching");
|
||||
|
||||
if (hook_list == NULL) {
|
||||
log_warning(HOOKS_LOGGER, "No hooks to register!");
|
||||
return;
|
||||
}
|
||||
function_hook_t* hook = hook_list;
|
||||
do {
|
||||
if (hook->dll == NULL) continue;
|
||||
|
||||
HMODULE dll = LoadLibraryA(hook->dll);
|
||||
if (dll == NULL) {
|
||||
log_error(HOOKS_LOGGER, "failed to load dll %s. %s skipped", hook->dll, hook->name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((*(hook->store) = GetProcAddress(dll, hook->name)) == NULL) {
|
||||
log_warning(HOOKS_LOGGER, "failed to get original %s", hook->name);
|
||||
} else {
|
||||
*((void**)hook->store) = CreateHook(*hook->store, hook->patch, hook->length);
|
||||
log_misc(HOOKS_LOGGER, "hooked %s", hook->name);
|
||||
}
|
||||
|
||||
hook = hook->next;
|
||||
} while (hook != NULL);
|
||||
|
||||
log_info(HOOKS_LOGGER, "attach complete");
|
||||
}
|
||||
22
src/micetools/lib/mice/hook.h
Normal file
22
src/micetools/lib/mice/hook.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include "./mice.h"
|
||||
|
||||
typedef struct function_hook {
|
||||
LPCSTR dll;
|
||||
LPCSTR name;
|
||||
PVOID patch;
|
||||
PVOID* store;
|
||||
UINT length;
|
||||
struct function_hook* next;
|
||||
} function_hook_t;
|
||||
|
||||
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);
|
||||
|
||||
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store, UINT length);
|
||||
|
||||
void setup_hooks();
|
||||
56
src/micetools/lib/mice/ioctl.h
Normal file
56
src/micetools/lib/mice/ioctl.h
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <winioctl.h>
|
||||
|
||||
#define FILE_DEVICE_SEGA 0x9c40
|
||||
|
||||
// amSramInit
|
||||
#define IOCTL_MXSRAM_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amSramInit
|
||||
#define IOCTL_MXSRAM_GET_SECTOR_SIZE CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXSRAM_GET_VERSION CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
// EEPROM uses MXSMBUS_GUID device class
|
||||
// DIPSW uses MXSMBUS_GUID device class
|
||||
// Platform uses PLATFORM_GUID device class
|
||||
|
||||
// amDipswRequestReadByteInternal
|
||||
// amDipswReadByteInternal
|
||||
// amDipswWriteByteInternal
|
||||
// /\ all either use SUPERIO or SMBUS. Which is unknown atm. All use 0x801
|
||||
//
|
||||
// amDipswGetDriverVersion
|
||||
// /\ uses either SUPERIO or SMBUS. Which is unknown atm. Uses 0x802
|
||||
|
||||
// Same as IOCTL_MXSRAM_PING
|
||||
// amHmProbeSuperIoDevice
|
||||
#define IOCTL_MXSUPERIO_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amHmGetLPCChipId
|
||||
#define IOCTL_MXSUPERIO_READ CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_MXSUPERIO_UNKNOWN CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
// amHmLpcReadByte
|
||||
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_READ CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
// amHmLpcWriteByte
|
||||
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
|
||||
#define IOCTL_MXJVS_EXCHANGE CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
// Same as IOCTL_MXSUPERIO_READ
|
||||
// amHmI2CReadByte,amHmI2CWriteByte,amEepromWait
|
||||
#define IOCTL_MXSMBUS_REQUEST CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
// amEepromGetDriverVerision
|
||||
#define IOCTL_MXSMBUS_GET_VERSION CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
// amEepromI2CReadBlock,amEepromI2CWriteBlock,amHmGetLPCChipId
|
||||
#define IOCTL_MXSMBUS_I2C CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#define IOCTL_MXSMBUS_IDK CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
#define IOCTL_COLUMBA_READ_DMI CTL_CODE(FILE_DEVICE_SEGA, 0x841, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
|
||||
#define IOCTL_MXHWRESET_RESET CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
|
||||
#define IOCTL_MXPARALLEL_WRITE_DATA CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_DATA CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_STATUS CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_STATUS CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_CTRL_PORT CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_CTRL_PORT CTL_CODE(FILE_DEVICE_SEGA, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_WRITE_FLAGS CTL_CODE(FILE_DEVICE_SEGA, 0x806, METHOD_BUFFERED, FILE_WRITE_ACCESS)
|
||||
#define IOCTL_MXPARALLEL_READ_FLAGS CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
|
||||
168
src/micetools/lib/mice/log.c
Normal file
168
src/micetools/lib/mice/log.c
Normal file
@@ -0,0 +1,168 @@
|
||||
#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;
|
||||
// };
|
||||
|
||||
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);
|
||||
}
|
||||
26
src/micetools/lib/mice/log.h
Normal file
26
src/micetools/lib/mice/log.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <Windows.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#define LOG_MISC
|
||||
#define LOG_INFO
|
||||
#define LOG_WARNING
|
||||
#define LOG_ERROR
|
||||
|
||||
#define HOOKS_LOGGER "hooks"
|
||||
#define BOOT_LOGGER "boot"
|
||||
|
||||
extern CRITICAL_SECTION logger_lock;
|
||||
|
||||
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 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);
|
||||
|
||||
void setup_logging();
|
||||
7
src/micetools/lib/mice/meson.build
Normal file
7
src/micetools/lib/mice/meson.build
Normal file
@@ -0,0 +1,7 @@
|
||||
mice_lib = static_library(
|
||||
'mice',
|
||||
sources: [
|
||||
'hook.c',
|
||||
'log.c',
|
||||
],
|
||||
)
|
||||
3
src/micetools/lib/mice/mice.h
Normal file
3
src/micetools/lib/mice/mice.h
Normal file
@@ -0,0 +1,3 @@
|
||||
#include "hook.h"
|
||||
#include "ioctl.h"
|
||||
#include "log.h"
|
||||
57
src/micetools/lib/util/hex.c
Normal file
57
src/micetools/lib/util/hex.c
Normal file
@@ -0,0 +1,57 @@
|
||||
unsigned char hex_value(char c) {
|
||||
if (isdigit((unsigned char)c)) return c - '0';
|
||||
|
||||
switch (c) {
|
||||
case 'a':
|
||||
case 'A':
|
||||
return 0x0A;
|
||||
case 'b':
|
||||
case 'B':
|
||||
return 0x0B;
|
||||
case 'c':
|
||||
case 'C':
|
||||
return 0x0C;
|
||||
case 'd':
|
||||
case 'D':
|
||||
return 0x0D;
|
||||
case 'e':
|
||||
case 'E':
|
||||
return 0x0E;
|
||||
case 'f':
|
||||
case 'F':
|
||||
return 0x0F;
|
||||
default:
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
int hex_to_bin(char *hex, unsigned char *bin, int hex_len) {
|
||||
if (hex_len == 0) return 1;
|
||||
|
||||
int work_len = 0;
|
||||
for (int hex_ptr = 0; hex_ptr < hex_len; hex_ptr += 2, work_len++) {
|
||||
char msn = hex[hex_ptr];
|
||||
|
||||
if ('0' <= msn && msn <= '9')
|
||||
msn = msn - '0';
|
||||
else if ('A' <= msn && msn <= 'F')
|
||||
msn = msn - 'A' + 10;
|
||||
else if ('a' <= msn && msn <= 'f')
|
||||
msn = msn - 'a' + 10;
|
||||
else
|
||||
return 0;
|
||||
|
||||
char lsn = hex_ptr + 1 == hex_len ? '0' : hex[hex_ptr + 1];
|
||||
|
||||
if ('0' <= lsn && lsn <= '9')
|
||||
lsn = lsn - '0';
|
||||
else if ('A' <= lsn && lsn <= 'F')
|
||||
lsn = lsn - 'A' + 10;
|
||||
else if ('a' <= lsn && lsn <= 'f')
|
||||
lsn = lsn - 'a' + 10;
|
||||
else
|
||||
return 0;
|
||||
|
||||
bin[work_len] = msn << 4 | lsn;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
2
src/micetools/lib/util/hex.h
Normal file
2
src/micetools/lib/util/hex.h
Normal file
@@ -0,0 +1,2 @@
|
||||
unsigned char hex_value(char c);
|
||||
int hex_to_bin(char *hex, unsigned char *bin, int hex_len);
|
||||
6
src/micetools/lib/util/meson.build
Normal file
6
src/micetools/lib/util/meson.build
Normal file
@@ -0,0 +1,6 @@
|
||||
util_lib = static_library(
|
||||
'miceutil',
|
||||
sources: [
|
||||
'hex.c',
|
||||
],
|
||||
)
|
||||
6
src/micetools/meson.build
Normal file
6
src/micetools/meson.build
Normal file
@@ -0,0 +1,6 @@
|
||||
subdir('lib')
|
||||
|
||||
subdir('micepatch')
|
||||
subdir('micekeychip')
|
||||
subdir('launcher')
|
||||
subdir('dll')
|
||||
77
src/micetools/micekeychip/callbacks/appboot.c
Normal file
77
src/micetools/micekeychip/callbacks/appboot.c
Normal file
@@ -0,0 +1,77 @@
|
||||
#include "../config.h"
|
||||
#include "callbacks.h"
|
||||
|
||||
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);
|
||||
pcpaSetSendPacket(stream, AB_SYSTEMFLAG, sf);
|
||||
}
|
||||
void mxkPcpAbModelType(pcpa_t* stream, void* data) {
|
||||
char mt[16];
|
||||
snprintf(mt, 16, "%d", 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);
|
||||
pcpaSetSendPacket(stream, AB_FORMATTYPE, ft);
|
||||
}
|
||||
void mxkPcpAbRegion(pcpa_t* stream, void* data) {
|
||||
char rg[16];
|
||||
snprintf(rg, 16, "%d", Config.appboot_region);
|
||||
pcpaSetSendPacket(stream, AB_REGION, rg);
|
||||
}
|
||||
void mxkPcpAbPlatformId(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, AB_PLATFORMID, Config.appboot_platformid);
|
||||
}
|
||||
void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, AB_NETWORKADDRESS, Config.appboot_network);
|
||||
}
|
||||
void mxkPcpAbDvd(pcpa_t* stream, void* data) {
|
||||
char dvd[16];
|
||||
snprintf(dvd, 16, "%d", Config.appboot_dvdflag);
|
||||
pcpaSetSendPacket(stream, AB_DVD, dvd);
|
||||
}
|
||||
|
||||
#define SEED_BUF_MAX 1024
|
||||
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");
|
||||
if (fCert == NULL)
|
||||
SEED_BUF_LEN = -1;
|
||||
else {
|
||||
fseek(fCert, 0, SEEK_END);
|
||||
SEED_BUF_LEN = ftell(fCert);
|
||||
if (SEED_BUF_LEN > SEED_BUF_MAX) SEED_BUF_LEN = SEED_BUF_MAX;
|
||||
rewind(fCert);
|
||||
|
||||
fread(SEED_BUF, SEED_BUF_LEN, 1, fCert);
|
||||
fclose(fCert);
|
||||
}
|
||||
}
|
||||
|
||||
if (SEED_BUF_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, AB_SEED, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = SEED_BUF_LEN;
|
||||
memcpy(BINARY_DATA, SEED_BUF, SEED_BUF_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, AB_SEED, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16]; // todo: nicer lol
|
||||
itoa(SEED_BUF_LEN, sSize, 10);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
112
src/micetools/micekeychip/callbacks/billing.c
Normal file
112
src/micetools/micekeychip/callbacks/billing.c
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "../config.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 mxkPcpPbPlayCount(pcpa_t* stream, void* data) {
|
||||
char pc[9];
|
||||
snprintf(pc, sizeof pc, "%08X", Config.billing_playcount);
|
||||
pcpaSetSendPacket(stream, BIL_PLAYCOUNT, pc);
|
||||
}
|
||||
void mxkPcpPbPlayLimit(pcpa_t* stream, void* data) {
|
||||
char pl[9];
|
||||
snprintf(pl, sizeof pl, "%08X", Config.billing_playlimit);
|
||||
|
||||
char* playlimit = pcpaGetCommand(stream, BIL_PLAYLIMIT);
|
||||
pcpaSetSendPacket(stream, BIL_PLAYLIMIT, pl);
|
||||
|
||||
if (!strcmp(playlimit, "?")) return;
|
||||
|
||||
// TODO: This
|
||||
pcpaSetSendPacket(stream, "code", "-1");
|
||||
}
|
||||
void mxkPcpPbNearfull(pcpa_t* stream, void* data) {
|
||||
char nf[9];
|
||||
snprintf(nf, sizeof nf, "%08X", Config.billing_nearfull);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_NEARFUL, nf);
|
||||
}
|
||||
|
||||
#define PUBKEY_BUF_MAX 1024
|
||||
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");
|
||||
if (fPubkey == NULL)
|
||||
PUBKEY_LEN = -1;
|
||||
else {
|
||||
fseek(fPubkey, 0, SEEK_END);
|
||||
PUBKEY_LEN = ftell(fPubkey);
|
||||
if (PUBKEY_LEN > PUBKEY_BUF_MAX) PUBKEY_LEN = PUBKEY_BUF_MAX;
|
||||
rewind(fPubkey);
|
||||
|
||||
fread(PUBKEY_BUF, PUBKEY_LEN, 1, fPubkey);
|
||||
fclose(fPubkey);
|
||||
}
|
||||
}
|
||||
|
||||
if (PUBKEY_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, BIL_SIGNATURE, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = PUBKEY_LEN;
|
||||
memcpy(BINARY_DATA, PUBKEY_BUF, PUBKEY_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_SIGNATURE, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16];
|
||||
snprintf(sSize, 16, "%d", PUBKEY_LEN);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
|
||||
#define CA_CERT_BUF_MAX 1024
|
||||
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");
|
||||
if (fCert == NULL)
|
||||
CA_CERT_LEN = -1;
|
||||
else {
|
||||
fseek(fCert, 0, SEEK_END);
|
||||
CA_CERT_LEN = ftell(fCert);
|
||||
if (CA_CERT_LEN > CA_CERT_BUF_MAX) CA_CERT_LEN = CA_CERT_BUF_MAX;
|
||||
rewind(fCert);
|
||||
|
||||
fread(CA_CERTIFICATION, CA_CERT_LEN, 1, fCert);
|
||||
fclose(fCert);
|
||||
}
|
||||
}
|
||||
|
||||
if (CA_CERT_LEN == -1) {
|
||||
// TODO: Fix this maybe?
|
||||
pcpaSetBinaryMode(stream, binary_mode_none);
|
||||
pcpaSetSendPacket(stream, BIL_CACERT, "-1");
|
||||
return;
|
||||
}
|
||||
|
||||
pcpaSetBinaryMode(stream, binary_mode_send);
|
||||
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
|
||||
|
||||
BINARY_DATA_LEN = CA_CERT_LEN;
|
||||
memcpy(BINARY_DATA, CA_CERTIFICATION, CA_CERT_LEN);
|
||||
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
|
||||
|
||||
pcpaSetSendPacket(stream, BIL_CACERT, "0");
|
||||
pcpaAddSendPacket(stream, "port", "40107");
|
||||
char sSize[16]; // todo: nicer lol
|
||||
itoa(CA_CERT_LEN, sSize, 10);
|
||||
pcpaAddSendPacket(stream, "size", sSize);
|
||||
}
|
||||
94
src/micetools/micekeychip/callbacks/callbacks.h
Normal file
94
src/micetools/micekeychip/callbacks/callbacks.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "../lib/libpcp/libpcp.h"
|
||||
|
||||
pcpa_callback mxkBinaryCallback;
|
||||
extern byte BINARY_DATA[4096];
|
||||
extern size_t BINARY_DATA_LEN;
|
||||
|
||||
#define KEYCHIP "keychip."
|
||||
#define APPBOOT KEYCHIP##"appboot."
|
||||
#define BILLING KEYCHIP##"billing."
|
||||
#define TRACEDATA KEYCHIP##"tracedata."
|
||||
|
||||
// Misc
|
||||
#define KC_VERSION KEYCHIP##"version"
|
||||
#define KC_STATUS KEYCHIP##"status"
|
||||
pcpa_callback mxkPcpVersion;
|
||||
pcpa_callback mxkPcpStatus;
|
||||
|
||||
// Crypto
|
||||
#define DS_COMPUTE KEYCHIP##"ds.compute"
|
||||
#define SSD_PROOF KEYCHIP##"ssd.proof"
|
||||
#define SSD_HOSTPROOF KEYCHIP##"ssd.hostproof"
|
||||
#define KC_ENCRYPT KEYCHIP##"encrypt"
|
||||
#define KC_DECRYPT KEYCHIP##"decrypt"
|
||||
#define KC_SETIV KEYCHIP##"setiv"
|
||||
pcpa_callback mxkPcpDsCompute;
|
||||
pcpa_callback mxkPcpSsdProof;
|
||||
pcpa_callback mxkPcpSsdHostProof;
|
||||
pcpa_callback mkxPcpEncrypt;
|
||||
pcpa_callback mxkPcpDecrypt;
|
||||
pcpa_callback mxkPcpSetIv;
|
||||
|
||||
// Appboot
|
||||
#define AB_GAMEID APPBOOT##"gameid"
|
||||
#define AB_SYSTEMFLAG APPBOOT##"systemflag"
|
||||
#define AB_MODELTYPE APPBOOT##"modeltype"
|
||||
#define AB_FORMATTYPE APPBOOT##"formattype"
|
||||
#define AB_REGION APPBOOT##"region"
|
||||
#define AB_PLATFORMID APPBOOT##"platformid"
|
||||
#define AB_NETWORKADDRESS APPBOOT##"networkaddr"
|
||||
#define AB_DVD APPBOOT##"dvdflag"
|
||||
#define AB_SEED APPBOOT##"seed"
|
||||
pcpa_callback mxkPcpAbGameId;
|
||||
pcpa_callback mxkPcpAbSystemFlag;
|
||||
pcpa_callback mxkPcpAbModelType;
|
||||
pcpa_callback mxkPcpAbFormatType;
|
||||
pcpa_callback mxkPcpAbRegion;
|
||||
pcpa_callback mxkPcpAbPlatformId;
|
||||
pcpa_callback mxkPcpAbNetworkAddress;
|
||||
pcpa_callback mxkPcpAbDvd;
|
||||
pcpa_callback mxkPcpAbSeed;
|
||||
|
||||
// Billing
|
||||
#define BIL_KEYID BILLING##"keyid"
|
||||
#define BIL_MAINID BILLING##"mainid"
|
||||
#define BIL_PLAYCOUNT BILLING##"playcount"
|
||||
#define BIL_PLAYLIMIT BILLING##"playlimit"
|
||||
#define BIL_NEARFUL BILLING##"nearful"
|
||||
#define BIL_SIGNATURE BILLING##"signaturepubkey"
|
||||
#define BIL_CACERT BILLING##"cacertification"
|
||||
pcpa_callback mxkPcpPbKeyId;
|
||||
pcpa_callback mxkPcpPbMainId;
|
||||
pcpa_callback mxkPcpPbPlayCount;
|
||||
pcpa_callback mxkPcpPbPlayLimit;
|
||||
pcpa_callback mxkPcpPbNearfull;
|
||||
pcpa_callback mxkPcpPbSignaturePubKey;
|
||||
pcpa_callback mxkPcpPbCaCertification;
|
||||
|
||||
// Tracedata
|
||||
#define TRA_RESTORE TRACEDATA##"restore"
|
||||
#define TRA_PUT TRACEDATA##"put"
|
||||
#define TRA_GET TRACEDATA##"get"
|
||||
#define TRA_LOGICALERASE TRACEDATA##"logicalerase"
|
||||
#define TRA_SECTOREERASE TRACEDATA##"sectorerase"
|
||||
pcpa_callback mxkPcpTdRestore;
|
||||
pcpa_callback mxkPcpTdPut;
|
||||
pcpa_callback mxkPcpTdGet;
|
||||
pcpa_callback mxkPcpTdLogicalErase;
|
||||
pcpa_callback mxkPcpTdSectorErase;
|
||||
|
||||
// Storage
|
||||
#define KC_EEPROM KEYCHIP##"eeprom"
|
||||
#define KC_NVRAM KEYCHIP##"nvram"
|
||||
#define KC_NVRAM0 KC_NVRAM##"0"
|
||||
#define KC_NVRAM1 KC_NVRAM##"1"
|
||||
#define KC_NVRAM2 KC_NVRAM##"2"
|
||||
#define KC_NVRAM3 KC_NVRAM##"3"
|
||||
#define KC_NVRAM4 KC_NVRAM##"4"
|
||||
#define KC_NVRAM5 KC_NVRAM##"5"
|
||||
#define KC_NVRAM6 KC_NVRAM##"6"
|
||||
#define KC_NVRAM7 KC_NVRAM##"7"
|
||||
#define KC_NVRAM8 KC_NVRAM##"8"
|
||||
#define KC_NVRAM9 KC_NVRAM##"9"
|
||||
pcpa_callback mxkPcpEeprom;
|
||||
pcpa_callback mxkPcpNvram;
|
||||
12
src/micetools/micekeychip/callbacks/crypto.c
Normal file
12
src/micetools/micekeychip/callbacks/crypto.c
Normal file
@@ -0,0 +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 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) {}
|
||||
20
src/micetools/micekeychip/callbacks/misc.c
Normal file
20
src/micetools/micekeychip/callbacks/misc.c
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "../config.h"
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpVersion(pcpa_t* stream, void* data) {
|
||||
char* sCache = pcpaGetCommand(stream, "cache");
|
||||
char* sDevice = pcpaGetCommand(stream, "device");
|
||||
|
||||
bool cache = sCache != NULL && strcmp(sCache, "0") == 0;
|
||||
|
||||
char version[5];
|
||||
if (sDevice && strcmp(sDevice, "n2") == 0)
|
||||
snprintf(version, 5, "%04X", Config.keychip_dongle_version);
|
||||
else
|
||||
snprintf(version, 5, "%04X", Config.keychip_pic_version);
|
||||
pcpaSetSendPacket(stream, KC_VERSION, version);
|
||||
}
|
||||
|
||||
void mxkPcpStatus(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, KC_STATUS, Config.keychip_status);
|
||||
}
|
||||
10
src/micetools/micekeychip/callbacks/storage.c
Normal file
10
src/micetools/micekeychip/callbacks/storage.c
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpEeprom(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, KC_EEPROM, "0");
|
||||
}
|
||||
|
||||
void mxkPcpNvram(pcpa_t* stream, void* data) {
|
||||
char* keyword = pcpaGetKeyword(stream, 0);
|
||||
pcpaSetSendPacket(stream, keyword, "0");
|
||||
}
|
||||
35
src/micetools/micekeychip/callbacks/tracedata.c
Normal file
35
src/micetools/micekeychip/callbacks/tracedata.c
Normal file
@@ -0,0 +1,35 @@
|
||||
#include "callbacks.h"
|
||||
|
||||
void mxkPcpTdRestore(pcpa_t* stream, void* data) {
|
||||
char* sUpdate = pcpaGetCommand(stream, "update");
|
||||
char* sRestart = pcpaGetCommand(stream, "restart");
|
||||
bool update = sUpdate != NULL && strcmp(sUpdate, "1") == 0;
|
||||
bool restart = sRestart != NULL && strcmp(sRestart, "1") == 0;
|
||||
|
||||
if (restart) {
|
||||
pcpaSetSendPacket(stream, TRA_RESTORE, "1");
|
||||
} else {
|
||||
pcpaSetSendPacket(stream, TRA_RESTORE, "2");
|
||||
}
|
||||
}
|
||||
void mxkPcpTdPut(pcpa_t* stream, void* data) {
|
||||
char* sPut = pcpaGetCommand(stream, TRA_PUT);
|
||||
|
||||
if (strcmp(sPut, "?")) {
|
||||
pcpaSetSendPacket(stream, TRA_PUT, "0");
|
||||
return;
|
||||
}
|
||||
|
||||
// Process packet maybe?
|
||||
pcpaSetSendPacket(stream, TRA_PUT, "0");
|
||||
}
|
||||
void mxkPcpTdGet(pcpa_t* stream, void* data) {
|
||||
// TODO: lol
|
||||
pcpaSetSendPacket(stream, TRA_GET, "");
|
||||
}
|
||||
void mxkPcpTdLogicalErase(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, TRA_LOGICALERASE, "");
|
||||
}
|
||||
void mxkPcpTdSectorErase(pcpa_t* stream, void* data) {
|
||||
pcpaSetSendPacket(stream, TRA_SECTOREERASE, "");
|
||||
}
|
||||
50
src/micetools/micekeychip/config.def
Normal file
50
src/micetools/micekeychip/config.def
Normal file
@@ -0,0 +1,50 @@
|
||||
#ifndef SECTION
|
||||
#define SECTION(n, comment)
|
||||
#endif
|
||||
#ifndef HEADER
|
||||
#define HEADER(comment)
|
||||
#endif
|
||||
|
||||
HEADER("The main config file for micekeychip")
|
||||
|
||||
SECTION(pcp, "")
|
||||
CFG_int(pcp, control_port, 40106, "The port to bind for control")
|
||||
CFG_int(pcp, binary_port, 40107, "The port to bind for binary transfer")
|
||||
CFG_bool(pcp, bind_global, false, "Should we bind to 0.0.0.0 instead of 127.0.0.1")
|
||||
|
||||
SECTION(keychip, "")
|
||||
CFG_hex(keychip, pic_version, 4, 0104, "The version to report for the pic")
|
||||
CFG_hex(keychip, dongle_version, 4, 0104, "The version to report for the dongle")
|
||||
CFG_str(keychip, status, "available", "Status to report")
|
||||
|
||||
SECTION(appboot, "")
|
||||
CFG_str(appboot, gameid, "SDEY", "4-letter game ID this keychip is for")
|
||||
CFG_hex(appboot, systemflag, 2, 6C, "System flags")
|
||||
CFG_int(appboot, modeltype, 2, "System model this keychip is for")
|
||||
CFG_int(appboot, formattype, 1, "Not totally sure about this")
|
||||
CFG_int(appboot, region, 1, "Region bitmask\n; 8 4 2 1\n; CN EX US JP")
|
||||
CFG_str(appboot, platformid, "AAS", "The platform this keychip is for. AAM=AMD, AAS=Nvidia")
|
||||
CFG_str(appboot, network, "192.168.103.0", "The subnet this keychip allows for networking. Must be 192.168.103.0 for network checks to pass")
|
||||
CFG_int(appboot, dvdflag, 1, "")
|
||||
CFG_str(appboot, seed, "C:\\system\\device\\seed.bin", "Path to constant appboot.seed (indev)")
|
||||
|
||||
SECTION(crypto, "")
|
||||
CFG_bool(crypto, ds_enable, false, "Process keychip.ds.compute?")
|
||||
CFG_bool(crypto, ssd_enable, false, "Process keychip.ssd.proof?")
|
||||
CFG_str(crypto, table, "C:\\system\\device\\SDEY_Table.dat", "Path to the *_Table.dat file")
|
||||
|
||||
SECTION(billing, "")
|
||||
CFG_str(billing, keyid, "A69E-01A8888", "This keychip's ID")
|
||||
CFG_str(billing, mainid, "", "The board ID")
|
||||
CFG_int(billing, playcount, 0, "Initial playcount value")
|
||||
CFG_hex(billing, playlimit, 8, 00001400, "Max playcount before lockout")
|
||||
CFG_hex(billing, nearfull, 8, 00066048, "Number of plays before reporting to billing")
|
||||
CFG_str(billing, pubkey, "C:\\system\\device\\billing.pub", "Path to the billing pubkey (billing.pub)")
|
||||
CFG_str(billing, cacert, "C:\\system\\device\\ca.crt", "Path to the root certificate authority (ca.crt)")
|
||||
|
||||
#undef CFG_str
|
||||
#undef CFG_int
|
||||
#undef CFG_bool
|
||||
#undef CFG_hex
|
||||
#undef SECTION
|
||||
#undef HEADER
|
||||
14
src/micetools/micekeychip/config.h
Normal file
14
src/micetools/micekeychip/config.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#define CONFIG_PATH "config.ini"
|
||||
|
||||
typedef struct config {
|
||||
#define CFG_str(s, n, default, comment) char* s##_##n;
|
||||
#define CFG_bool(s, n, default, comment) bool s##_##n;
|
||||
#define CFG_int(s, n, default, comment) int s##_##n;
|
||||
#define CFG_hex(s, n, precision, default, comment) int s##_##n;
|
||||
#include "config.def"
|
||||
bool _keep_linter_happy;
|
||||
} config_t;
|
||||
|
||||
extern config_t Config;
|
||||
111
src/micetools/micekeychip/main.c
Normal file
111
src/micetools/micekeychip/main.c
Normal file
@@ -0,0 +1,111 @@
|
||||
#include "mxk.h"
|
||||
|
||||
config_t Config = {
|
||||
#define CFG_str(s, n, default, comment) .s##_##n = default,
|
||||
#define CFG_bool(s, n, default, comment) .s##_##n = default,
|
||||
#define CFG_int(s, n, default, comment) .s##_##n = default,
|
||||
#define CFG_hex(s, n, precision, default, comment) .s##_##n = 0x##default,
|
||||
#include "config.def"
|
||||
._keep_linter_happy = true};
|
||||
|
||||
void make_default_config() {
|
||||
FILE *config_file = fopen(CONFIG_PATH, "w");
|
||||
if (config_file == NULL) {
|
||||
puts("Failed to create config file!");
|
||||
return;
|
||||
};
|
||||
int first_section = true;
|
||||
|
||||
#define CFG_str(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \
|
||||
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"); \
|
||||
fprintf(config_file, "%s = %s\n", #n, default ? "true" : "false");
|
||||
|
||||
#define CFG_int(s, n, default, comment) \
|
||||
if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \
|
||||
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); \
|
||||
fprintf(config_file, "%s = %.*X\n", #n, precision, 0x##default);
|
||||
|
||||
#define SECTION(s, comment) \
|
||||
if (!first_section) fprintf(config_file, "\n"); \
|
||||
first_section = false; \
|
||||
if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \
|
||||
fprintf(config_file, "[%s]\n", #s);
|
||||
|
||||
#define HEADER(comment) \
|
||||
fprintf(config_file, "; %s\n", comment); \
|
||||
first_section = false;
|
||||
|
||||
#include "config.def"
|
||||
|
||||
fclose(config_file);
|
||||
}
|
||||
|
||||
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_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"
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void load_config() {
|
||||
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();
|
||||
|
||||
load_config();
|
||||
|
||||
int err = mxkInit();
|
||||
if (err != 0) {
|
||||
PCP_LOG("Error mxkInit. Code %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
err = mxkPcpServer();
|
||||
if (err != e_pcpp_ok) PCP_LOG("Server tick: %d\n", err);
|
||||
}
|
||||
}
|
||||
28
src/micetools/micekeychip/meson.build
Normal file
28
src/micetools/micekeychip/meson.build
Normal file
@@ -0,0 +1,28 @@
|
||||
dependencies = []
|
||||
link_with = [inih.get_variable('lib_inih')]
|
||||
|
||||
# Depending on how we're getting access to libpcp, we need some extra work here
|
||||
if libpcp_is_static
|
||||
link_with += libpcp
|
||||
else
|
||||
link_with += amlib
|
||||
dependencies += libpcp
|
||||
dependencies += meson.get_compiler('c').find_library('ws2_32')
|
||||
endif
|
||||
|
||||
executable(
|
||||
'micekeychip',
|
||||
win_subsystem: 'console',
|
||||
sources: [
|
||||
'main.c',
|
||||
'mxk.c',
|
||||
'callbacks/appboot.c',
|
||||
'callbacks/billing.c',
|
||||
'callbacks/crypto.c',
|
||||
'callbacks/misc.c',
|
||||
'callbacks/tracedata.c',
|
||||
'callbacks/storage.c',
|
||||
],
|
||||
link_with: link_with,
|
||||
dependencies: dependencies,
|
||||
)
|
||||
154
src/micetools/micekeychip/mxk.c
Normal file
154
src/micetools/micekeychip/mxk.c
Normal file
@@ -0,0 +1,154 @@
|
||||
#include "mxk.h"
|
||||
|
||||
byte SERVER_STATE = 0;
|
||||
pcpa_t PCP;
|
||||
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);
|
||||
}
|
||||
|
||||
int mxkInit() {
|
||||
// Enable colour
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD dwMode = 0;
|
||||
if (GetConsoleMode(hConsole, &dwMode))
|
||||
SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
|
||||
WSADATA wsaData;
|
||||
int err = WSAStartup(2, &wsaData);
|
||||
SERVER_STATE = 1;
|
||||
return err;
|
||||
}
|
||||
|
||||
e_pcpa_t mxkPcpStreamInit() {
|
||||
e_pcpa_t err;
|
||||
|
||||
err = pcpaInitStream(&PCP);
|
||||
if (err != e_pcpa_ok) {
|
||||
printf("pcpaInitStream Error. Code:%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = pcpaSetCallbackFuncBuffer(&PCP, CALLBACK_FUNCTION_BUFFER,
|
||||
(sizeof CALLBACK_FUNCTION_BUFFER) /
|
||||
(sizeof CALLBACK_FUNCTION_BUFFER[0]));
|
||||
if (err != e_pcpa_ok) {
|
||||
printf("pcpaSetCallBackFuncBuffer Error. Code:%d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
// Misc
|
||||
pcpaSetCallbackFunc(&PCP, KC_VERSION, mxkPcpVersion, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_STATUS, mxkPcpStatus, NULL);
|
||||
// Crypto
|
||||
pcpaSetCallbackFunc(&PCP, DS_COMPUTE, mxkPcpDsCompute, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, SSD_PROOF, mxkPcpSsdProof, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, SSD_HOSTPROOF, mxkPcpSsdHostProof, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_ENCRYPT, mkxPcpEncrypt, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_DECRYPT, mxkPcpDecrypt, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_SETIV, mxkPcpSetIv, NULL);
|
||||
// Appboot
|
||||
pcpaSetCallbackFunc(&PCP, AB_GAMEID, mxkPcpAbGameId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_SYSTEMFLAG, mxkPcpAbSystemFlag, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_MODELTYPE, mxkPcpAbModelType, NULL);
|
||||
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_DVD, mxkPcpAbDvd, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, AB_SEED, mxkPcpAbSeed, NULL);
|
||||
// Billing
|
||||
pcpaSetCallbackFunc(&PCP, BIL_KEYID, mxkPcpPbKeyId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_MAINID, mxkPcpPbMainId, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_PLAYCOUNT, mxkPcpPbPlayCount, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_PLAYLIMIT, mxkPcpPbPlayLimit, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_NEARFUL, mxkPcpPbNearfull, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_SIGNATURE, mxkPcpPbSignaturePubKey, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, BIL_CACERT, mxkPcpPbCaCertification, NULL);
|
||||
// Tracedata
|
||||
pcpaSetCallbackFunc(&PCP, TRA_RESTORE, mxkPcpTdRestore, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_PUT, mxkPcpTdPut, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_GET, mxkPcpTdGet, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_LOGICALERASE, mxkPcpTdLogicalErase, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, TRA_SECTOREERASE, mxkPcpTdSectorErase, NULL);
|
||||
// Storage
|
||||
pcpaSetCallbackFunc(&PCP, KC_EEPROM, mxkPcpEeprom, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM0, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM1, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM2, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM3, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM4, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM5, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM6, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM7, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM8, mxkPcpNvram, NULL);
|
||||
pcpaSetCallbackFunc(&PCP, KC_NVRAM9, mxkPcpNvram, NULL);
|
||||
|
||||
long text_port = Config.pcp_control_port;
|
||||
if (text_port > 0xffff) {
|
||||
puts("PCP control port invalid");
|
||||
exit(-1);
|
||||
}
|
||||
long binary_port = Config.pcp_binary_port;
|
||||
if (binary_port > 0xffff) {
|
||||
puts("PCP binary port invalid");
|
||||
exit(-1);
|
||||
}
|
||||
int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_1;
|
||||
|
||||
err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port, binary_port,
|
||||
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);
|
||||
else
|
||||
printf("Listening on 127.0.0.1:%d (:%d)\n", text_port, binary_port);
|
||||
return e_pcpa_ok;
|
||||
}
|
||||
|
||||
#define TICK_MS 16
|
||||
#define PRINT_DEBUG
|
||||
#ifdef PRINT_DEBUG
|
||||
// Larger TICK_MS for testing
|
||||
#undef TICK_MS
|
||||
#define TICK_MS 100
|
||||
#endif
|
||||
|
||||
e_pcpa_t mxkPcpServer() {
|
||||
int err;
|
||||
if (SERVER_STATE == 1) {
|
||||
err = mxkPcpStreamInit();
|
||||
if (err == 0) {
|
||||
SERVER_STATE = 2;
|
||||
return err;
|
||||
}
|
||||
} else {
|
||||
if (SERVER_STATE != 2) {
|
||||
return (SERVER_STATE == 0) ? e_pcpa_cannot_open : e_pcpa_not_open;
|
||||
}
|
||||
err = pcpaServer(&PCP, TICK_MS);
|
||||
if (err == e_pcpa_to || err == e_pcpa_closed) err = e_pcpa_ok;
|
||||
|
||||
if (err) {
|
||||
printf("Error pcpaServer. Code %d\n", err);
|
||||
pcpaClose(&PCP);
|
||||
SERVER_STATE = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PRINT_DEBUG
|
||||
puts("\033[H\033[J\033[H");
|
||||
pcpaPrint(&PCP);
|
||||
puts("\033[J");
|
||||
#endif
|
||||
|
||||
return err;
|
||||
}
|
||||
11
src/micetools/micekeychip/mxk.h
Normal file
11
src/micetools/micekeychip/mxk.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../../../subprojects/inih_dep/ini.h"
|
||||
#include "../lib/libpcp/libpcp.h"
|
||||
#include "callbacks/callbacks.h"
|
||||
#include "config.h"
|
||||
|
||||
void mxkBinaryCallback(pcpa_t* stream, void* data);
|
||||
int mxkInit();
|
||||
e_pcpa_t mxkPcpStreamInit();
|
||||
e_pcpa_t mxkPcpServer();
|
||||
303
src/micetools/micepatch/main.c
Normal file
303
src/micetools/micepatch/main.c
Normal file
@@ -0,0 +1,303 @@
|
||||
#include "../lib/json/json.h"
|
||||
#include "../lib/util/hex.h"
|
||||
#include "stdbool.h"
|
||||
#include "stdio.h"
|
||||
#include "string.h"
|
||||
|
||||
typedef struct {
|
||||
size_t offset;
|
||||
size_t count;
|
||||
unsigned char* from;
|
||||
unsigned char* to;
|
||||
} patch_t;
|
||||
|
||||
typedef struct {
|
||||
char* name;
|
||||
char* description;
|
||||
bool apply;
|
||||
size_t nopatches;
|
||||
patch_t patches[];
|
||||
} patchset_t;
|
||||
|
||||
typedef struct {
|
||||
size_t nopatchsets;
|
||||
patchset_t** patchsets;
|
||||
} patches_t;
|
||||
|
||||
bool fetch(json_value* object, char* name, json_value** value) {
|
||||
if (object->type != json_object) return false;
|
||||
for (size_t j = 0; j < object->u.object.length; j++) {
|
||||
json_object_entry* entry = &(object->u.object.values[j]);
|
||||
if (strncmp(name, entry->name, entry->name_length) == 0) {
|
||||
*value = entry->value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool fetch_string(json_value* object, char* name, char** value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_string) return false;
|
||||
*value = fetched->u.string.ptr;
|
||||
return true;
|
||||
}
|
||||
bool fetch_int(json_value* object, char* name, size_t* value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_integer) return false;
|
||||
*value = fetched->u.integer;
|
||||
return true;
|
||||
}
|
||||
bool fetch_bool(json_value* object, char* name, bool* value) {
|
||||
json_value* fetched;
|
||||
if (!fetch(object, name, &fetched)) return false;
|
||||
if (fetched->type != json_boolean) return false;
|
||||
*value = fetched->u.boolean;
|
||||
return true;
|
||||
}
|
||||
void free_patches(patches_t* patches) {
|
||||
if (patches->nopatchsets == 0) return;
|
||||
for (int i = patches->nopatchsets - 1; i >= 0; i--) {
|
||||
if (patches->patchsets[i] != NULL) {
|
||||
for (int j = 0; j < patches->patchsets[i]->nopatches; j++) {
|
||||
if (patches->patchsets[i]->patches[j].from != NULL) free(patches->patchsets[i]->patches[j].from);
|
||||
if (patches->patchsets[i]->patches[j].to != NULL) free(patches->patchsets[i]->patches[j].to);
|
||||
}
|
||||
free(patches->patchsets[i]);
|
||||
}
|
||||
}
|
||||
patches->nopatchsets = 0;
|
||||
}
|
||||
|
||||
bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error) {
|
||||
patches->nopatchsets = set_count;
|
||||
patches->patchsets = (patchset_t**)malloc(set_count * sizeof(patchset_t*));
|
||||
for (int i = 0; i < set_count; i++) patches->patchsets[i] = NULL;
|
||||
|
||||
error[0] = '\0';
|
||||
for (int i = 0; i < set_count; i++) {
|
||||
char *name, *description;
|
||||
if (!fetch_string(set_json[i], "name", &name)) {
|
||||
snprintf(error, json_error_max, "'name' missing for patch %d", i);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(set_json[i], "description", &description)) {
|
||||
snprintf(error, json_error_max, "'description' missing for patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
bool apply;
|
||||
if (!fetch_bool(set_json[i], "apply", &apply)) {
|
||||
snprintf(error, json_error_max, "'apply' missing for patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
json_value* set_patches;
|
||||
if (!fetch(set_json[i], "patches", &set_patches) || set_patches->type != json_array) {
|
||||
snprintf(error, json_error_max, "'patches' missing for patch %d (%s)", i, name);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
int count = set_patches->u.array.length;
|
||||
patchset_t* patchset = (patchset_t*)malloc(sizeof(patchset_t) + (sizeof(patch_t) * count));
|
||||
patches->patchsets[i] = patchset;
|
||||
patchset->name = name;
|
||||
patchset->apply = apply;
|
||||
patchset->description = description;
|
||||
patchset->nopatches = count;
|
||||
|
||||
for (int j = 0; j < count; j++) {
|
||||
json_value* this_patch = set_patches->u.array.values[j];
|
||||
size_t at;
|
||||
char *from, *to;
|
||||
if (!fetch_int(this_patch, "at", &at)) {
|
||||
snprintf(error, json_error_max, "'at' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(this_patch, "from", &from)) {
|
||||
snprintf(error, json_error_max, "'from' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
if (!fetch_string(this_patch, "to", &to)) {
|
||||
snprintf(error, json_error_max, "'to' missing for patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
patchset->patches[j].offset = at;
|
||||
size_t size = strlen(from);
|
||||
if (size != strlen(to)) {
|
||||
snprintf(error, json_error_max, "'from' and 'to' lengths differ in patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
if (size % 2 != 0) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d]", name, j);
|
||||
goto failed;
|
||||
}
|
||||
char* bin_from = patchset->patches[j].from = (char*)malloc(size / 2);
|
||||
char* bin_to = patchset->patches[j].to = (char*)malloc(size / 2);
|
||||
if (!hex_to_bin(from, bin_from, size)) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].from", name, j);
|
||||
goto failed;
|
||||
};
|
||||
if (!hex_to_bin(to, bin_to, size)) {
|
||||
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].to", name, j);
|
||||
goto failed;
|
||||
};
|
||||
|
||||
patchset->patches[j].count = size / 2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
failed:
|
||||
free_patches(patches);
|
||||
return false;
|
||||
}
|
||||
|
||||
void print_patches(patches_t* patches) {
|
||||
for (int i = 0; i < patches->nopatchsets; i++) {
|
||||
patchset_t* patchset = patches->patchsets[i];
|
||||
|
||||
printf("Patch: %s (%s)\n", patchset->name, patchset->apply ? "applied" : "unapplied");
|
||||
printf("- %s\n", patchset->description);
|
||||
for (int i = 0; i < patchset->nopatches; i++) {
|
||||
printf(":: %d bytes at %08x\n", patchset->patches[i].count, patchset->patches[i].offset);
|
||||
}
|
||||
puts("======================");
|
||||
}
|
||||
}
|
||||
|
||||
void apply_patches(patches_t* patches, char* filename) {
|
||||
FILE* fp = fopen(filename, "r+b");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Failed to open %s for modification\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
size_t sz = ftell(fp);
|
||||
|
||||
for (int i = 0; i < patches->nopatchsets; i++) {
|
||||
patchset_t* patchset = patches->patchsets[i];
|
||||
for (int j = 0; j < patchset->nopatches; j++) {
|
||||
patch_t patch = patchset->patches[j];
|
||||
if (patch.offset + patch.count > sz) {
|
||||
fprintf(stderr, "E: Patch %s[%d] outside file bounds\n", patchset->name, j);
|
||||
goto done;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
bool matches_from = true;
|
||||
bool matches_to = true;
|
||||
for (int i = 0; i < patch.count; i++) {
|
||||
unsigned char seen;
|
||||
if (!fread(&seen, 1, 1, fp)) {
|
||||
matches_from = false;
|
||||
matches_to = false;
|
||||
break;
|
||||
}
|
||||
if (seen != patch.from[i]) matches_from = false;
|
||||
if (seen != patch.to[i]) matches_to = false;
|
||||
if (!(matches_from || matches_to)) break;
|
||||
}
|
||||
|
||||
printf("%s[%d]: ", patchset->name, j);
|
||||
if (patchset->apply) {
|
||||
if (matches_to) {
|
||||
puts("Already applied");
|
||||
continue;
|
||||
}
|
||||
if (!matches_from) {
|
||||
puts("From value missmatch! Ignoring");
|
||||
continue;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
fwrite(patch.to, 1, patch.count, fp);
|
||||
puts("Patch applied");
|
||||
} else {
|
||||
if (matches_from) {
|
||||
puts("Not applied");
|
||||
continue;
|
||||
}
|
||||
if (!matches_to) {
|
||||
puts("We didn't perform this patch. Leaving patched");
|
||||
continue;
|
||||
}
|
||||
fseek(fp, patch.offset, SEEK_SET);
|
||||
fwrite(patch.from, 1, patch.count, fp);
|
||||
puts("Patch removed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "Usage: %s <patch file> <exe>\n", argc > 0 ? argv[0] : "micepatch.exe");
|
||||
return -1;
|
||||
}
|
||||
|
||||
FILE* fp = fopen(argv[1], "r");
|
||||
if (fp == NULL) {
|
||||
fprintf(stderr, "Failed to open '%s' (%d)\n", argv[1], errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fseek(fp, 0L, SEEK_END);
|
||||
size_t sz = ftell(fp);
|
||||
rewind(fp);
|
||||
|
||||
char* json_buf = (char*)malloc(sz);
|
||||
if (json_buf == NULL) {
|
||||
fprintf(stderr, "Failed to allocate %d bytes\n", sz, errno);
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
if (!(sz = fread(json_buf, 1, sz, fp))) {
|
||||
fprintf(stderr, "Failed to read from '%s' (%d)\n", argv[1], errno);
|
||||
fclose(fp);
|
||||
return -1;
|
||||
};
|
||||
fclose(fp);
|
||||
|
||||
json_settings settings = {0};
|
||||
char error[json_error_max];
|
||||
json_value* parsed = json_parse_ex(&settings, json_buf, sz, error);
|
||||
|
||||
if (parsed == NULL) {
|
||||
fprintf(stderr, "Parse error: %s\n", error);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int loaded_patches = 0;
|
||||
json_value** patches_json;
|
||||
if (parsed->type == json_array) {
|
||||
loaded_patches = parsed->u.array.length;
|
||||
patches_json = parsed->u.array.values;
|
||||
} else if (parsed->type == json_object) {
|
||||
loaded_patches = 1;
|
||||
patches_json = &parsed;
|
||||
} else {
|
||||
fprintf(stderr, "Patch file format error\n");
|
||||
json_value_free(parsed);
|
||||
return;
|
||||
}
|
||||
|
||||
patches_t all_patches;
|
||||
if (!parse_patches(&all_patches, patches_json, loaded_patches, error)) {
|
||||
fprintf(stderr, "Patch file format error: %s\n", error);
|
||||
return;
|
||||
}
|
||||
|
||||
puts("");
|
||||
puts("Loaded patches:");
|
||||
puts("---------------");
|
||||
print_patches(&all_patches);
|
||||
|
||||
apply_patches(&all_patches, argv[2]);
|
||||
|
||||
free_patches(&all_patches);
|
||||
return 0;
|
||||
}
|
||||
15
src/micetools/micepatch/meson.build
Normal file
15
src/micetools/micepatch/meson.build
Normal file
@@ -0,0 +1,15 @@
|
||||
executable(
|
||||
'micepatch',
|
||||
win_subsystem: 'console',
|
||||
sources: [
|
||||
'main.c',
|
||||
],
|
||||
link_with: [
|
||||
mice_lib,
|
||||
json_lib,
|
||||
],
|
||||
link_args: [
|
||||
'/MANIFEST:EMBED',
|
||||
'/MANIFESTUAC:level="asInvoker" uiAccess="false"',
|
||||
]
|
||||
)
|
||||
0
src/micetools/traces.c
Normal file
0
src/micetools/traces.c
Normal file
BIN
src/system/billing.pub
Normal file
BIN
src/system/billing.pub
Normal file
Binary file not shown.
BIN
src/system/ca.crt
Normal file
BIN
src/system/ca.crt
Normal file
Binary file not shown.
40
src/tools/keys.py
Normal file
40
src/tools/keys.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import json
|
||||
|
||||
patches = []
|
||||
patchset = {
|
||||
"name": "Rebind keys",
|
||||
"description": "Automatically generated",
|
||||
"apply": True,
|
||||
"patches": patches
|
||||
}
|
||||
|
||||
original = ['W', 'E', 'D', 'C', 'X', 'Z', 'A', 'Q']
|
||||
|
||||
base = 1517787
|
||||
for i in range(8):
|
||||
key = input(f"Key for {i+1}: ")
|
||||
if len(key) != 1:
|
||||
print("That's not one key!")
|
||||
quit()
|
||||
|
||||
key = f"{ord(key.upper()):02x}"
|
||||
orig = f"{ord(original[i].upper()):02x}"
|
||||
|
||||
if i == 0:
|
||||
patches.append({
|
||||
"at": base,
|
||||
"from": f"c70424{orig}000000",
|
||||
"to": f"c70424{key}000000",
|
||||
})
|
||||
else:
|
||||
instr = f"c74424{4 * i:02x}"
|
||||
patches.append({
|
||||
"at": base + 7 + 8 * (i - 1),
|
||||
"from": instr + orig + "000000",
|
||||
"to": instr + key + "000000",
|
||||
})
|
||||
|
||||
with open("keybinds.json", "w") as f:
|
||||
json.dump([patchset], f)
|
||||
|
||||
print("Wrote patches to keybinds.json")
|
||||
Reference in New Issue
Block a user