Initial commit

This commit is contained in:
Bottersnike
2022-06-13 04:22:52 +01:00
commit 320617e2e5
83 changed files with 5822 additions and 0 deletions

4
src/meson.build Normal file
View 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
View 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
View 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();

View 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;
}

View 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
View 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;
}

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

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

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

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

View File

View 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");
}
}

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

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

View 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,
],
)

View File

@@ -0,0 +1 @@
LIBRARY mice

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

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

View 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;
}

View File

@@ -0,0 +1,4 @@
#include <Windows.h>
#include <stdbool.h>
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject);

View 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;
}

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

View 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;
}

View File

@@ -0,0 +1,12 @@
executable(
'mice',
win_subsystem: 'console',
sources: [
'locate.c',
'exe.c',
'main.c',
],
link_with: [
mice_lib,
],
)

View 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;
}

View 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)

View File

@@ -0,0 +1,6 @@
amlib = static_library(
'am',
sources: [
'amtimer.c',
],
)

110
src/micetools/lib/dmi/dmi.c Normal file
View 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);
}

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

View File

@@ -0,0 +1,6 @@
dmi_lib = static_library(
'dmi',
sources: [
'dmi.c'
],
)

View 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.

View File

@@ -0,0 +1 @@
https://github.com/json-parser/json-parser

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

View 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

View File

@@ -0,0 +1,7 @@
json_lib = static_library(
'micejson',
sources: [
'json.c',
],
link_with: [util_lib]
)

View 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

View 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");
}

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

View 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)

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

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

View File

@@ -0,0 +1,7 @@
mice_lib = static_library(
'mice',
sources: [
'hook.c',
'log.c',
],
)

View File

@@ -0,0 +1,3 @@
#include "hook.h"
#include "ioctl.h"
#include "log.h"

View 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;
}

View File

@@ -0,0 +1,2 @@
unsigned char hex_value(char c);
int hex_to_bin(char *hex, unsigned char *bin, int hex_len);

View File

@@ -0,0 +1,6 @@
util_lib = static_library(
'miceutil',
sources: [
'hex.c',
],
)

View File

@@ -0,0 +1,6 @@
subdir('lib')
subdir('micepatch')
subdir('micekeychip')
subdir('launcher')
subdir('dll')

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

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

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

View 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) {}

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

View 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");
}

View 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, "");
}

View 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

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

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

View 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,
)

View 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;
}

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

View 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;
}

View 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
View File

BIN
src/system/billing.pub Normal file

Binary file not shown.

BIN
src/system/ca.crt Normal file

Binary file not shown.

40
src/tools/keys.py Normal file
View 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")