Too much for one commit message

This commit is contained in:
Bottersnike 2022-07-02 16:07:54 +01:00
parent cc705ed0d4
commit 4464d9188f
76 changed files with 1976 additions and 656 deletions

View File

@ -3,13 +3,18 @@ BUILD_DIR_32 := $(BUILD_DIR)/build32
BUILD_DIR_64 := $(BUILD_DIR)/build64
DIST_DIR := dist
BUILD_DRIVE = M:
BUILD_DRIVE := M:
MICE_32 = "$(BUILD_DIR_32)/src\mice.exe"
MICE_64 = "$(BUILD_DIR_64)/src\mice.exe"
MICE_32 := "$(BUILD_DIR_32)/src\mice.exe"
MICE_64 := "$(BUILD_DIR_64)/src\mice.exe"
VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat"
VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat"
# For windows XP:
# VCVARS_32 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat" -vcvars_ver=14.16
# VCVARS_64 := "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat" -vcvars_ver=14.16
VCVARS_32 = C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars32.bat
VCVARS_64 = C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat
.ONESHELL:
@ -19,7 +24,7 @@ all: mice86 dist
mice86:
-@subst $(BUILD_DRIVE) .
@cd /D $(BUILD_DRIVE) \
& "$(VCVARS_32)" \
& $(VCVARS_32) \
& meson setup --cross cross-32.ini $(BUILD_DRIVE)\$(BUILD_DIR_32) \
& meson compile -C $(BUILD_DRIVE)\$(BUILD_DIR_32)
@subst $(BUILD_DRIVE) /D
@ -27,7 +32,7 @@ mice86:
mice64:
-@subst $(BUILD_DRIVE) .
@cd $(BUILD_DRIVE) \
& "$(VCVARS_64)" \
& $(VCVARS_64) \
& meson setup --cross cross-64.ini $(BUILD_DRIVE)\$(BUILD_DIR_64) \
& meson compile -C $(BUILD_DRIVE)\$(BUILD_DIR_64)
@subst $(BUILD_DRIVE) /D
@ -47,6 +52,8 @@ dist:
@copy /Y "$(BUILD_DIR_32)/src/micetools/lib/libpcp\libpcp.lib" "$(DIST_DIR)/libpcp.lib"
@copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice86.exe"
# @copy /Y "$(BUILD_DIR_32)/src/micetools/launcher\mice.pdb" "$(DIST_DIR)/mice86.pdb"
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.pdb" "$(DIST_DIR)/mice86.pdb"
@copy /Y "$(BUILD_DIR_32)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice86.dll"
# @copy /Y "$(BUILD_DIR_64)/src/micetools/launcher\mice.exe" "$(DIST_DIR)/mice64.exe"
# @copy /Y "$(BUILD_DIR_64)/src/micetools/dll\mice.dll" "$(DIST_DIR)/mice64.dll"

View File

@ -1,15 +1,30 @@
project('micetools', 'c')
project('micetools', 'c', default_options: [
'buildtype=minsize',
# ! Tobble /\ and \/ when building for XP (minsize=normal, static=XP)
# 'b_vscrt=static_from_buildtype',
'warning_level=2',
])
winxp = false
subsystem = 'console,5.01'
if (host_machine.cpu_family() == 'x86')
add_project_arguments('-DMICE_WIN32', language: 'c')
endif
add_project_arguments(
'-DWIN32_LEAN_AND_MEAN', # Strip out headers we don't really need
'-D_WIN32_WINNT=_WIN32_WINNT_WINXP', # hahahahaha I hate it
# '/O1', # Optimise size
'/DWIN32_LEAN_AND_MEAN', # Strip out headers we don't really need
'/D_WIN32_WINNT=_WIN32_WINNT_WINXP', # hahahahaha I hate it
language: 'c',
)
if winxp
add_project_arguments(
'/D_USING_V140_SDK71_',
'/DSFML_STATIC',
'/DYNAMICBASE:NO',
language: 'c',
)
endif
subdir('assets')
subdir('src')

View File

@ -6,7 +6,8 @@ BOOL DevGetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE
BOOL DevSetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
BOOL DevSetupComm(void* data, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
BOOL DevPurgeComm(void* data, DWORD dwFlags) {
if (dwFlags & PURGE_RXCLEAR) ((com_device_t*)data)->filled = 0;
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&((com_device_t*)data)->out);
return TRUE;
}
BOOL DevGetCommModemStatus(void* data, LPDWORD lpModelStat) {
@ -18,13 +19,76 @@ BOOL DevWaitCommEvent(void* data, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped)
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
return TRUE;
}
BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) { return TRUE; }
BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) {
if (lpErrors != NULL) *lpErrors = 0;
if (lpStat != NULL) {
lpStat->fCtsHold = FALSE;
lpStat->fDsrHold = FALSE;
lpStat->fRlsdHold = FALSE;
lpStat->fXoffHold = FALSE;
lpStat->fXoffSent = FALSE;
lpStat->fEof = FALSE;
lpStat->fTxim = FALSE;
lpStat->fReserved = 0;
lpStat->cbInQue = ringbuf_available(&((com_device_t*)data)->out);
lpStat->cbOutQue = ringbuf_available(&((com_device_t*)data)->in);
}
return TRUE;
}
BOOL DevWriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped) {
if (nNumberOfBytesToWrite > 0xffff) return FALSE;
// Ignore overflow
ringbuf_write(&((com_device_t*)file)->in, lpBuffer, nNumberOfBytesToWrite & 0xffff);
if (lpNumberOfBytesWritten) *lpNumberOfBytesWritten = nNumberOfBytesToWrite;
return TRUE;
}
BOOL DevReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped) {
if (nNumberOfBytesToRead > 0xffff) return FALSE;
// Make sure we have at least one byte to return
// while (!ringbuf_available(&((com_device_t*)file)->out)) {
// WaitForSingleObject(((com_device_t*)file)->event, INFINITE);
// }
short read = ringbuf_read(&((com_device_t*)file)->out, lpBuffer, nNumberOfBytesToRead & 0xffff);
if (lpNumberOfBytesRead) *lpNumberOfBytesRead = read;
if (read != 0) {
// log_info("drf", "%d", read);
// for (int i = 0; i < read; i++) {
// printf("%02x ", ((unsigned char*)lpBuffer)[i]);
// }
// puts("");
}
return TRUE;
}
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes) {
return ringbuf_read(&com->in, buffer, bytes);
}
bool comdev_write(com_device_t* com, unsigned char* buffer, short bytes) {
bool ret = ringbuf_write(&com->out, buffer, bytes);
SetEvent(com->event);
return ret;
}
short comdev_available(com_device_t* com) { return ringbuf_available(&com->in); }
void com_device_thread(com_device_t* com, FnComDeviceThread* thread) {
com->thread = CreateThread(NULL, 0, thread, com, 0, NULL);
}
com_device_t* new_com_device(BYTE port) {
com_device_t* hook = (com_device_t*)malloc(sizeof *hook);
com_hook_t* com = new_com_hook(port);
file_hook_t* file = new_file_hook(com->wName);
file->altFilename = com->wDosName;
com->data = hook;
file->data = hook;
hook->com = com;
hook->file = file;
com->GetCommState = DevGetCommState;
com->SetCommState = DevSetCommState;
@ -36,9 +100,17 @@ com_device_t* new_com_device(BYTE port) {
com->WaitCommEvent = DevWaitCommEvent;
com->ClearCommError = DevClearCommError;
hook->filled = 0;
file->ReadFile = DevReadFile;
file->WriteFile = DevWriteFile;
ringbuf_purge(&hook->in);
ringbuf_purge(&hook->out);
hook->event = CreateEventW(NULL, TRUE, FALSE, hook->com->wName);
hook->com = com;
hook_file(file);
hook_com(com);
free(com->virtual_handle);
com->virtual_handle = file->virtual_handle;
return hook;
}

View File

@ -1,11 +1,23 @@
#include "com.h"
#include "files.h"
#pragma once
#include "hooks/com.h"
#include "common.h"
#include "hooks/files.h"
typedef struct com_device {
com_hook_t* com;
file_hook_t* file;
BYTE queue[2048];
DWORD filled;
ring_buffer_t in;
ring_buffer_t out;
HANDLE event;
HANDLE thread;
} com_device_t;
typedef DWORD(WINAPI FnComDeviceThread)(com_device_t* com);
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes);
bool comdev_write(com_device_t* com, unsigned char* buffer, short bytes);
short comdev_available(com_device_t* com);
void com_device_thread(com_device_t* com, FnComDeviceThread* thread);
com_device_t* new_com_device(BYTE port);

View File

@ -0,0 +1,24 @@
#pragma once
#include <Windows.h>
#include <Winsock2.h>
#include <initguid.h>
#include <windns.h>
#pragma comment(lib, "Shlwapi.lib")
#include <shlwapi.h>
#pragma comment(lib, "d3d9.lib")
#include <d3d9.h>
#pragma comment(lib, "comctl32.lib")
#include <Iphlpapi.h>
#include <commctrl.h>
#include <memory.h>
#include <setupapi.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../lib/mice/mice.h"
#include "./util/_util.h"

View File

@ -0,0 +1,6 @@
#include "_devices.h"
void install_devices() {
install_led_bd();
install_touch_bd();
}

View File

@ -0,0 +1,8 @@
#pragma once
#include "../comdevice.h"
#include "../common.h"
void install_led_bd();
void install_touch_bd();
void install_devices();

View File

@ -0,0 +1,225 @@
#include "../hooks/gui.h"
#include "_devices.h"
/*
[0] = e0
[1] = dest?
[2] = dst?
[3] = length
[4] = op code
[...] length-1 bytes
[.] = sum
[0] = e0
[2] = dst?
[1] = dest?
[3] = length
[4] = status
[5] = op
[6] = report
[...]
[.] = sum
OP codes:
3c: FUN_005735c0 (1)
10: FUN_00580c00 (1)
7c: FUN_00580c00 (2)
3c: FUN_00580c00 (1)
39: FUN_00580c00 (4)
3b: FUN_00580c00 (1)
31: FUN_00581350 (5)
32: FUN_005813b0 (8)
33: FUN_00581430 (8) -> something at [16]??
39: FUN_005814b0 (4)
3f: FUN_00581220 (7)
7b: FUN_005812a0 (3)
7c: FUN_00581310 (2)
01: was this just an error?
10:
31: Set button. [button] [r] [g] [b]
0-7 = buttons
8 = woofer
9 = center
32: Set multiple. [00] [idx hi] [idx lo] [r] [g] [b]
33: Fade multiple?. [09] [?] [?] [r] [g] [b]
39: Set body light. [intensity] [-] [-]
3b:
3c: Commit?
3f:
7c:
7b:
initial setup: 7c 0-7, 32, 3c, 39, 3f, 3b
*/
unsigned char COLOURS[10][3];
double positions[10][2] = {
{ 0.337963, 0.470833 }, { 0.469444, 0.619792 }, { 0.469444, 0.828125 }, { 0.337037, 0.977083 },
{ 0.152778, 0.976042 }, { 0.020370, 0.828125 }, { 0.020370, 0.618750 }, { 0.151852, 0.472917 },
{ 0.5, 0.75 }, { 0.5, 0.5 },
};
typedef struct rs232c_recv_head {
BYTE sync;
BYTE src;
BYTE dst;
BYTE length;
BYTE op;
} rs232c_recv_head_t;
static DWORD WINAPI led_bd_thread(com_device_t* dev) {
log_warning("led_bd", "%ls woke up", dev->com->wName);
while (1) {
rs232c_recv_head_t head;
if (comdev_available(dev) < sizeof head) {
// Sleep(100);
continue;
}
comdev_read(dev, (char*)&head, sizeof head);
unsigned char* extra = malloc(head.length);
comdev_read(dev, extra, head.length);
// log_info("led_bd", "Bound %02x->%02x", head.src, head.dst);
switch (head.op) {
case 0x01:
log_warning("led_bd", "01");
comdev_write(dev, "\xe0\x01\x11\x03\x01\x01\x01\x18", 8);
// syn dst src len sts op. rep chk
break;
case 0x10:
log_warning("led_bd", "10");
comdev_write(dev, "\xe0\x01\x11\x03\x01\x10\x01\x27", 8);
// syn dst src len sts op. rep chk
break;
case 0x31:
COLOURS[extra[0]][0] = extra[1];
COLOURS[extra[0]][1] = extra[2];
COLOURS[extra[0]][2] = extra[3];
log_warning("led_bd", "31: %02x = (%02x %02x %02x)", extra[0], extra[1], extra[2], extra[3]);
comdev_write(dev, "\xe0\x01\x11\x03\x01\x31\x01\x48", 8);
// syn dst src len sts op. rep chk
break;
case 0x32:
log_warning("led_bd", "32: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
extra[4], extra[5], extra[6], extra[7]);
for (unsigned char i = extra[2] - 1; i < extra[1]; i++) {
COLOURS[i][0] = extra[3];
COLOURS[i][1] = extra[4];
COLOURS[i][2] = extra[5];
}
comdev_write(dev, "\xe0\x01\x11\x03\x01\x32\x01\x49", 8);
// syn dst src len sts op. rep chk
break;
case 0x33:
log_warning("led_bd", "33: %02x %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
extra[4], extra[5], extra[6], extra[7]);
comdev_write(dev, "\xe0\x01\x11\x03\x01\x33\x01\x4a", 8);
// syn dst src len sts op. rep chk
COLOURS[extra[0]][0] = extra[extra[5]];
COLOURS[extra[0]][1] = extra[extra[6]];
COLOURS[extra[0]][2] = extra[extra[7]];
break;
case 0x39:
log_warning("led_bd", "39: %02x %02x %02x", extra[0], extra[1], extra[2]);
comdev_write(dev, "\xe0\x01\x11\x03\x01\x39\x01\x50", 8);
// syn dst src len sts op. rep chk
COLOURS[9][0] = extra[0];
COLOURS[9][1] = extra[0];
COLOURS[9][2] = extra[0];
break;
case 0x3b:
log_warning("led_bd", "3b");
comdev_write(dev, "\xe0\x01\x11\x03\x01\x3b\x01\x52", 8);
// syn dst src len sts op. rep chk
break;
case 0x3c:
log_warning("led_bd", "3c (I am %ls)", dev->com->wName);
comdev_write(dev, "\xe0\x01\x11\x03\x01\x3c\x01\x53", 8);
// syn dst src len sts op. rep chk
break;
case 0x3f:
log_warning("led_bd", "3f: %02x %02x %02x %02x %02x %02x", extra[0], extra[1], extra[2], extra[3],
extra[4], extra[5], extra[6]);
comdev_write(dev, "\xe0\x01\x11\x03\x01\x3f\x01\x56", 8);
// syn dst src len sts op. rep chk
break;
case 0x7c:
// extra[0] goes from 0 to 7
// Could this be some sort of calibration for the buttons?
log_warning("led_bd", "7c: %02x", extra[0]);
comdev_write(dev, "\xe0\x01\x11\x04\x01\x7c\x01\x00\x94", 9);
// \/ causes 7b to be used
// comdev_write(dev, "\xe0\x01\x11\x04\x01\x7c\x01\x10\xa4", 9);
// syn dst src len sts op. rep --- chk
break;
case 0x7b:
log_warning("led_bd", "7b: %02x %02x %02x", extra[0], extra[1], extra[2]);
comdev_write(dev, "\xe0\x01\x11\x03\x01\x7b\x01\x92", 8);
// syn dst src len sts op. rep chk
break;
default:
log_error("led_bd", "Unknown op %02x (%d)", head.op, head.length - 1);
break;
}
free(extra);
}
}
static DWORD WINAPI led_null_thread(com_device_t* dev) {
while (1) Sleep(10000000);
}
void led_overlay(IDirect3DDevice9* dev) {
ShowCursor(true);
D3DDEVICE_CREATION_PARAMETERS cparams;
RECT rect;
dev->lpVtbl->GetCreationParameters(dev, &cparams);
GetClientRect(cparams.hFocusWindow, &rect);
if (GetAsyncKeyState(VK_LBUTTON) & 1) {
POINT cursor;
GetCursorPos(&cursor);
// log_info("led_overlay", "x: %d, y: %d", cursor.x, cursor.y);
log_info("led_overlay", "x%: %f, y%: %f", (float)cursor.x / (float)rect.right,
(float)(cursor.y - 26) / (float)rect.bottom);
}
for (unsigned char i = 0; i < 10; i++) {
int x = rect.right * positions[i][0];
int y = rect.bottom * positions[i][1];
draw_rect(dev, x - 25, y - 25, 50, 50, COLOURS[i][0], COLOURS[i][1], COLOURS[i][2]);
}
}
void install_led_bd() {
register_gui_hook(&led_overlay);
com_device_t* com5 = new_com_device(5);
com_device_thread(com5, led_null_thread);
com_device_t* leds_1p = new_com_device(6);
com_device_thread(leds_1p, led_bd_thread);
com_device_t* com7 = new_com_device(7);
com_device_thread(com7, led_null_thread);
com_device_t* leds_2p = new_com_device(8);
com_device_thread(leds_2p, led_bd_thread);
}

View File

@ -0,0 +1,5 @@
devices_files = files(
'_devices.c',
'led_bd.c',
'touch_bd.c',
)

View File

@ -0,0 +1,84 @@
#include "_devices.h"
static BYTE read_one(com_device_t* dev) {
while (!comdev_available(dev)) Sleep(50);
BYTE data;
comdev_read(dev, (char*)&data, 1);
return data;
}
const BYTE TOUCH_ID_LUT[] = "ABCD\0EFGH\0IJKL\0MNOPQRSTU\0VWXY\0";
static BYTE get_touch_id(BYTE id) {
for (BYTE i = 0; i < sizeof(TOUCH_ID_LUT); i++) {
if (TOUCH_ID_LUT[i] == id) return i;
}
return 0xff;
}
BOOL touch_is_enabled = false;
BYTE thresh = 0x00; // Lazy caching of single value
DWORD WINAPI touch_bd_thread(com_device_t* dev) {
while (1) {
if (touch_is_enabled && !comdev_available(dev)) {
// Active mode!
comdev_write(dev, "(@@@@@@@@@@@@)", 14);
Sleep(100);
continue;
}
while (read_one(dev) != '{') continue;
while (comdev_available(dev) < 5) {
log_info("touch", "<. .>");
Sleep(50);
}
BYTE command[5];
comdev_read(dev, command, 5);
BYTE response[6];
memcpy(response, "( )", 6);
if (memcmp(command, "HALT}", 5) == 0) {
if (touch_is_enabled)
log_info("touch", "Touchscreen left active mode");
else
log_misc("touch", "Touchscreen not in active mode");
touch_is_enabled = false;
} else if (memcmp(command, "STAT}", 5) == 0) {
if (!touch_is_enabled)
log_info("touch", "Touchscreen entered active mode");
else
log_misc("touch", "Touchscreen already in active mode");
touch_is_enabled = true;
} else if (command[2] == 'k' && command[4] == '}') {
BYTE sensor = get_touch_id(command[1]);
log_misc("touch", "k-command recieved: %d >=%d", sensor, command[3]);
// Sensor == '@': failed
// ( <L/R> <sensor> <> <> )
response[1] = command[0];
response[2] = command[1];
thresh = command[3];
comdev_write(dev, response, 6);
} else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') {
BYTE sensor = get_touch_id(command[1]);
// { <L/R> <sensor> t h }
log_misc("touch", "th-command recieved: %d", sensor);
// Sensor == '@': failed
// ( <L/R> <sensor> <> <threshold> )
response[1] = command[0]; // 'L' or 'R'
response[2] = command[1]; // Sensor
response[4] = thresh;
comdev_write(dev, response, 6);
} else {
log_error("touch", "Unhandled: {%.*s", 5, command);
}
}
}
void install_touch_bd() {
com_device_t* touch = new_com_device(3);
com_device_thread(touch, touch_bd_thread);
}

View File

@ -1,15 +1,7 @@
#include <Windows.h>
#include <Winsock2.h>
#include <shlwapi.h>
#pragma comment(lib, "Shlwapi.lib")
#include <stdio.h>
#include "../lib/mice/mice.h"
#include "common.h"
#include "devices/_devices.h"
#include "drivers/mx.h"
#include "micesetupapi.h"
#include "network.h"
#include "processes.h"
#include "hooks/_hooks.h"
WCHAR exePath[MAX_PATH + 1];
@ -22,7 +14,7 @@ void enable_traces() {
char exePathC[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL);
for (int i = 0; i < patches.nopatchsets; i++) {
for (size_t i = 0; i < patches.nopatchsets; i++) {
patchset_t* patchset = patches.patchsets[i];
// Require the binary explicitly named
@ -31,7 +23,7 @@ void enable_traces() {
}
if (!patchset->apply) continue;
for (int j = 0; j < patchset->nopatches; j++) {
for (size_t j = 0; j < patchset->nopatches; j++) {
patch_t patch = patchset->patches[j];
if (memcmp(patch.from, (void*)patch.offset, patch.count) != 0) {
@ -48,11 +40,14 @@ void enable_traces() {
}
void prebind_hooks() {
hook_setupapi();
hook_commio();
hook_io();
hook_processes();
hook_network();
hook_all();
install_devices();
// TODO: Figure out why we're needing to call this manually (medium priority)
if (wcscmp(exePath, L"ALLNetProc.exe") == 0) {
// OPENSSL_add_all_algorithms_noconf
((void (*)(void))(0x00459770))();
}
}
void init_injection() {

View File

@ -1,8 +1,5 @@
#include <Windows.h>
#include "../lib/dmi/dmi.h"
#include "../lib/mice/mice.h"
#include "files.h"
#include "mx.h"
// Much easier than pulling in winddk.h
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
@ -15,8 +12,9 @@ typedef struct {
#define DMI_HEADER_START 0x000f0000
#define DMI_TABLES_START 0x000f1000
BOOL columba_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
BOOL columba_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) {
switch (dwIoControlCode) {
case IOCTL_COLUMBA_READ_DMI:
log_misc("columba",
@ -36,7 +34,7 @@ BOOL columba_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn
if (request->addr.QuadPart == DMI_HEADER_START) {
DMI_HEADER dmi = {
.Signature = {'_', 'D', 'M', 'I', '_'},
.Signature = { '_', 'D', 'M', 'I', '_' },
.Checksum = 0,
.StructLength = dmi_size,
.StructAddr = DMI_TABLES_START,

View File

@ -0,0 +1,82 @@
#define JVS_MARK 0xd0
#define JVS_SYNC 0xe0
#define JVS_NODE_MASTER 0x00
#define JVS_NODE_BROADCAST 0xff
#define JVS_VERSION_CMD 0x13 // A real board reports 1.1, but we support 1.3
#define JVS_VERSION_JVS 0x20
#define JVS_VERSION_COMM 0x10
#define JVS_STATUS_OK 0x01
#define JVS_STATUS_UKCOM 0x02
#define JVS_STATUS_SUM 0x03
#define JVS_STATUS_OVERFLOW 0x04
#define JVS_STATUS_UNKNOWN 0xff // Not a spec-compliant status, but there's none for this!
#define JVS_REPORT_OK 0x01
#define JVS_REPORT_PARAM_NODATA 0x02
#define JVS_REPORT_PARAM_INVALID 0x03
#define JVS_REPORT_BUSY 0x04
#define JVS_FEATURE_PAD 0x00
#define JVS_FEATURE_EOF 0x00
#define JVS_FEATURE_PLAYERS 0x01
#define JVS_FEATURE_COINS 0x02
#define JVS_FEATURE_ANALOG 0x03
#define JVS_FEATURE_ROTARY 0x04
#define JVS_FEATURE_KEYCODE 0x05
#define JVS_FEATURE_SCREEN_POS 0x06
#define JVS_FEATURE_MISC_SWITCH 0x07
#define JVS_FEATURE_CARDS 0x10
#define JVS_FEATURE_MEDAL_HOPPER 0x11
#define JVS_FEATURE_GPIO 0x12
#define JVS_FEATURE_ANALOG_OUT 0x13
#define JVS_FEATURE_CHAR_OUT 0x14
#define JVS_FEATURE_BACKUP 0x15
#define JVS_CHARTYPE_UNKNOWN 0x00
#define JVS_CHARTYPE_NUMBER 0x01
#define JVS_CHARTYPE_ALNUM 0x02
#define JVS_CHARTYPE_ALNUM_KATAKANA 0x03
#define JVS_CHARTYPE_SHIFTJIS 0x04
#define JVS_COINSLOT_NORMAL 0x00
#define JVS_COINSLOT_JAM 0x01
#define JVS_COINSLOT_COUNTER_DISCON 0x02
#define JVS_COINSLOT_BUSY 0x03
// Mandatory JVS commands
#define JVS_CMD_RESET 0xf0
#define JVS_CMD_RESET_ASSERT 0xd9
#define JVS_CMD_ASSIGN_ADDR 0xf1
#define JVS_CMD_CHANGE_COMMS 0xf2
#define JVS_CMD_READ_ID 0x10
#define JVS_CMD_GET_CMD_VERSION 0x11
#define JVS_CMD_GET_JVS_VERSION 0x12
#define JVS_CMD_GET_COMM_VERSION 0x13
#define JVS_CMD_GET_FEATURES 0x14
#define JVS_CMD_REQUEST_RETRANSMIT 0x2f
// Optional JVS commands
#define JVS_CMD_RECEIVE_MAIN_ID 0x15
#define JVS_CMD_READ_SW 0x20
#define JVS_CMD_READ_COIN 0x21
#define JVS_CMD_READ_ANALOGS 0x22
#define JVS_CMD_READ_ROTARY 0x23
#define JVS_CMD_READ_KEYCODE 0x24
#define JVS_CMD_READ_SCREEN_POS 0x25
#define JVS_CMD_READ_MISC_SWITCH 0x26
#define JVS_CMD_REMAINING_PAYOUT 0x2e
#define JVS_CMD_COIN_DECREASE 0x30
#define JVS_CMD_PAYOUT_INCREASE 0x31
#define JVS_CMD_WRITE_GPIO1 0x32
#define JVS_CMD_WRITE_ANALOG 0x33
#define JVS_CMD_WRITE_CHARACTER 0x34
#define JVS_CMD_COIN_INCREASE 0x35
#define JVS_CMD_PAYOUT_DECREATE 0x36
#define JVS_CMD_WRITE_GPIO2 0x37
#define JVS_CMD_WRITE_GPIO3 0x38

View File

@ -0,0 +1,9 @@
drivers_files = files(
'columba.c',
'mxhwreset.c',
'mxjvs.c',
'mxparallel.c',
'mxsmbus.c',
'mxsram.c',
'mxsuperio.c',
)

View File

@ -1,6 +1,6 @@
#include "../com.h"
#include "../files.h"
#include <initguid.h>
#pragma once
#include "../hooks/_hooks.h"
#include "../common.h"
FnDeviceIoControl mxhwreset_DeviceIoControl;
void setup_mxhwreset();
@ -20,5 +20,8 @@ void setup_mxsram();
FnDeviceIoControl mxsuperio_DeviceIoControl;
void setup_mxsuperio();
FnDeviceIoControl columba_DeviceIoControl;
void setup_columba();
DEFINE_GUID(MXSMBUS_GUID, 0x5C49E1FE, 0x3FEC, 0x4B8D, 0xA4, 0xB5, 0x76, 0xBE, 0x70, 0x25, 0xD8, 0x42);
DEFINE_GUID(PLATFORM_GUID, 0x86E0D1E0, 0x8089, 0x11D0, 0x9C, 0xE4, 0x08, 0x00, 0x3e, 0x30, 0x1F, 0x73);

View File

@ -1,10 +1,8 @@
#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) {
BOOL mxhwreset_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) {
switch (dwIoControlCode) {
case IOCTL_MXHWRESET_RESET:
if (lpBytesReturned) *lpBytesReturned = 0;

View File

@ -1,25 +1,336 @@
#include <Windows.h>
#include "../lib/mice/mice.h"
#include "../common.h"
#include "jvs.h"
#include "mx.h"
BOOL JVS_SENSE = false;
BOOL coin_solenoid = false;
BOOL test_btn = false;
BOOL mxjvs_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
// #define SCAN_COIN 0x70
#define SCAN_TEST VK_OEM_4 // [{
// 2 Players, 16 buttons each
int jvs_buttons[2][16] = {
{
'C', // *1P3
'P', // NC
'E', // *1P1
'D', // *1P2
'P', // NC
'P', // NC
'1', // *1P Service
'P', // NC
'P', // --
'P', // --
'P', // --
'W', // *1P8
'Q', // *1P7
'A', // *1P6
'Z', // *1P5
'X', // *1P4
},
{
VK_OEM_PERIOD, // *2P3
'P', // NC
'O', // *2P1
'L', // *2P2
'P', // NC
'P', // NC
'2', // *2P Service
'P', // NC
'P', // --
'P', // --
'P', // --
'I', // *2P8
'U', // *2P7
'J', // *2P6
'M', // *2P5
VK_OEM_COMMA, // *2P4
},
};
short jvs_unpad(char* paddedData, short length, char* unpaddedData) {
short index = 0;
bool escape = false;
for (short i = 0; i < length; i++) {
if (escape)
unpaddedData[index++] = paddedData[i] + 1;
else if (paddedData[i] == JVS_MARK)
escape = true;
else
unpaddedData[index++] = paddedData[i];
}
return index;
}
short jvs_pad(char* unpaddedData, short length, char* paddedData, short paddedMax) {
short index = 0;
for (short i = 0; i < length; i++) {
if (i > paddedMax) return -1;
if (unpaddedData[i] == JVS_MARK || unpaddedData[i] == JVS_SYNC) {
paddedData[index++] = JVS_MARK;
paddedData[index++] = unpaddedData[i] - 1;
} else {
paddedData[index++] = unpaddedData[i];
}
}
return index;
}
const char JVS_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
void mxjvs_exchange(char* paddedIn, short inCount, char* outData, int maxOut, int* outCount) {
unsigned char* inData = malloc(inCount);
inCount = jvs_unpad(paddedIn, inCount, inData);
unsigned char* response = malloc(maxOut);
unsigned char status = JVS_STATUS_OK;
// JVS frame is 4 bytes in total
if (inCount < 4) {
log_error("mxjvs", "inCount impossibly small: %d", inCount);
status = JVS_STATUS_UNKNOWN;
goto jvs_exchange_error;
}
// This isn't a JVS packet
if (inData[0] != JVS_SYNC) {
log_error("mxjvs", "SYNC missing. Saw 0x%02x", inData[0]);
status = JVS_STATUS_UNKNOWN;
goto jvs_exchange_error;
}
// Validate the checksum before proceeding
unsigned char sum = 0;
for (int i = 1; i < inCount - 1; i++) sum += inData[i];
if (sum != inData[inCount - 1]) {
log_error("mxjvs", "Checksum failed. Computed 0x%02x, expected 0x%02x", sum, inData[inCount - 1]);
status = JVS_STATUS_SUM;
goto jvs_exchange_error;
}
unsigned char destination = inData[1];
unsigned char length = inData[2];
// length 0 is nonsensical because there's a checksum!
if (length == 0) {
status = JVS_STATUS_SUM;
goto jvs_exchange_error;
}
short jvsIndex = 3; // D0
response[0] = JVS_SYNC;
response[1] = JVS_NODE_MASTER;
short respIndex = 4; // D0
#define jvs_read(x) \
if (jvsIndex - 2 >= length) { \
status = JVS_STATUS_OVERFLOW; \
goto jvs_exchange_error; \
} else { \
(x) = inData[jvsIndex++]; \
}
#define jvs_write(x) response[respIndex++] = (x);
while (jvsIndex - 2 < length) {
unsigned char cmd;
jvs_read(cmd);
// log_info("jvs", "jvs cmd: %02x", cmd);
switch (cmd) {
case JVS_CMD_RESET:
unsigned char reset_assert;
jvs_read(reset_assert);
if (reset_assert != JVS_CMD_RESET_ASSERT) {
status = JVS_STATUS_UKCOM;
goto jvs_exchange_error;
}
JVS_SENSE = true;
// Special case
*outCount = 0;
return;
case JVS_CMD_CHANGE_COMMS:
// Special case
*outCount = 0;
return;
case JVS_CMD_ASSIGN_ADDR:
jvs_write(JVS_REPORT_OK);
JVS_SENSE = false;
// we don't bother remembering the address because at the moment we only simulate
// a single board in the JVS chain.
unsigned char _;
jvs_read(_);
break;
case JVS_CMD_READ_ID:
jvs_write(JVS_REPORT_OK);
for (int i = 0; i < sizeof JVS_ID; i++) jvs_write(JVS_ID[i]);
break;
case JVS_CMD_GET_CMD_VERSION:
jvs_write(JVS_REPORT_OK);
jvs_write(JVS_VERSION_CMD);
break;
case JVS_CMD_GET_JVS_VERSION:
jvs_write(JVS_REPORT_OK);
jvs_write(JVS_VERSION_JVS);
break;
case JVS_CMD_GET_COMM_VERSION:
jvs_write(JVS_REPORT_OK);
jvs_write(JVS_VERSION_COMM);
break;
case JVS_CMD_GET_FEATURES:
jvs_write(JVS_REPORT_OK);
jvs_write(JVS_FEATURE_PLAYERS);
jvs_write(2);
jvs_write(13);
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_COINS);
jvs_write(2);
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_ANALOG);
jvs_write(8); // 8 ADC channels
jvs_write(JVS_FEATURE_PAD); // ?? (was "10" prior)
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_GPIO);
jvs_write(6); // 6 ports
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_EOF);
break;
case JVS_CMD_RECEIVE_MAIN_ID:
unsigned char tempRead = -1;
while (tempRead != 0) jvs_read(tempRead);
// TODO: Do we need to report here?
break;
case JVS_CMD_READ_SW:
unsigned char players;
unsigned char switch_bytes;
jvs_read(players);
jvs_read(switch_bytes);
if (players > 2 || switch_bytes != 2) {
jvs_write(JVS_REPORT_PARAM_INVALID);
break;
}
jvs_write(JVS_REPORT_OK);
unsigned char buttons = 0x00;
if (GetAsyncKeyState(SCAN_TEST) < 0) buttons |= 0x80;
jvs_write(buttons);
for (int i = 0; i < players; i++) {
for (int j = 0; j < switch_bytes; j++) {
buttons = 0x00;
for (int bit = 0; bit < 8; bit++) {
int scancode = jvs_buttons[i][j * 8 + bit];
// Buttons on maimai use beam interrupt sensors, so logical high = unpressed.
bool invert = ((j == 0 && (bit == 0 || bit == 2 || bit == 3)) || (j == 1 && bit >= 3));
if (invert)
buttons |= (GetAsyncKeyState(scancode) >= 0) << bit;
else
buttons |= (GetAsyncKeyState(scancode) < 0) << bit;
// JAMMA does **NOT** do any of this lol
// Service is pull-down for some reason
// bool pulse = (j == 0) && (bit == 6);
// // JAMMA uses the falling edge of a pull-up switch
// if (pulse) {
// buttons |= (GetAsyncKeyState(scancode) >= 0) << bit;
// buttons |= (!(GetAsyncKeyState(scancode) & 1)) << bit;
// } else {
// buttons |= (GetAsyncKeyState(scancode) < 0) << bit;
// buttons |= (GetAsyncKeyState(scancode) & 1) << bit;
// }
}
jvs_write(buttons);
}
}
break;
case JVS_CMD_READ_ANALOGS:
jvs_write(JVS_REPORT_OK);
// TODO: Actually emulate these (super low priority)
unsigned char analog_count;
jvs_read(analog_count);
for (int i = analog_count; i > 0; i--) {
jvs_write(0xde);
jvs_write(0xad);
}
break;
case JVS_CMD_WRITE_GPIO1:
jvs_write(JVS_REPORT_OK);
unsigned char gpio_bytes;
jvs_read(gpio_bytes);
for (int i = 0; i < gpio_bytes; i++) {
unsigned char gpio_value;
jvs_read(gpio_value);
if (i == 0) {
if (!!(gpio_value & 0x80) != coin_solenoid) {
coin_solenoid = !!(gpio_value & 0x80);
log_info("mxjvs", "Coin solenoid: %s", coin_solenoid ? "Locked" : "Unlocked");
}
}
// log_warning("mxjvs", "Unhandled GPIO write: *(%d) = %02x", i, gpio_value);
}
break;
default:
log_error("mxjvs", "Unknown command: 0x%02x", cmd);
status = JVS_STATUS_UKCOM;
goto jvs_exchange_error;
}
}
#undef jvs_read
#undef jvs_write
goto jvs_exchange_complete;
jvs_exchange_error:
log_error("mxjvs", "JVS status: 0x%02x", status);
respIndex = 4; // As if we've just written status, but nothing else
jvs_exchange_complete:
response[2] = respIndex - 2; // respIndex doesn't include SUM yet
response[3] = status;
// Compute and set the checksum
sum = 0;
for (int i = 1; i < respIndex; i++) sum += response[i];
response[respIndex++] = sum;
short paddedLength = jvs_pad(response, respIndex, outData, maxOut);
// We failed hard. It's not worth sending an overflow response
if (paddedLength == -1)
*outCount = 0;
else
*outCount = 0x00000000 | paddedLength;
free(response);
free(inData);
}
BOOL mxjvs_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) {
switch (dwIoControlCode) {
case IOCTL_MXJVS_EXCHANGE:
log_error("mxjvs",
"DeviceIoControl(<mxjvs>, <exchange>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
log_misc("mxjvs",
"DeviceIoControl(<mxjvs>, <exchange>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
// mxjvsDevice->exchange(
// lpbyte(lpInBuffer), nInBufferSize & 0xFFFF,
// lpbyte(lpOutBuffer), lpBytesReturned
// );
mxjvs_exchange(lpInBuffer, nInBufferSize & 0xffff, lpOutBuffer, nOutBufferSize, lpBytesReturned);
if (lpBytesReturned) *lpBytesReturned = 0;
break;
default:
log_warning("mxjvs", "unhandled 0x%08x", dwIoControlCode);
@ -35,13 +346,13 @@ BOOL mxjvs_GetCommState(void* com, LPDCB lpDCB) { return TRUE; }
BOOL mxjvs_SetCommTimeouts(void* com, LPCOMMTIMEOUTS lpDCB) { return TRUE; }
BOOL mxjvs_GetCommModemStatus(void* com, LPDWORD lpModelStat) {
*lpModelStat = JVS_SENSE ? MS_DSR_ON : 0;
*lpModelStat = !JVS_SENSE ? MS_DSR_ON : 0;
return TRUE;
}
BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) {
char PARITY[] = {'N', 'O', 'E', 'M', 'S'};
char* STOP[] = {"1", "1.5", "2"};
char PARITY[] = { 'N', 'O', 'E', 'M', 'S' };
char* STOP[] = { "1", "1.5", "2" };
log_info("mxjvs", "Switching to %d baud (%d%c%s)", lpDCB->BaudRate, lpDCB->ByteSize, PARITY[lpDCB->Parity],
STOP[lpDCB->StopBits]);
return TRUE;

View File

@ -1,7 +1,5 @@
#include <Windows.h>
#include "../lib/dmi/dmi.h"
#include "../lib/mice/mice.h"
#include "../hooks/setupapi_.h"
#include "mx.h"
#include "smbus.h"
@ -18,8 +16,17 @@
#define PCA9535_CONF0 0x06
#define PCA9535_CONF1 0x07
#define PCA9535 0x20
#define EEPROM 0x57
#define SMBUS_PCA9535 0x20
#define SMBUS_EEPROM 0x57 // Doesn't line up with manual!
#define SMBUS_DDR2_DIMM_A1 0x000 // what does 0xA0 mean?
#define SMBUS_DDR2_DIMM_B1 0x010 // what does 0xA4 mean?
#define SMBUS_EEPROM_ 0x0AE // = AT24C64AN
#define SMBUS_ICS9LPRS908 0xfff // Unknown
#define SMBUS_W83627UHG 0xfff // Unknown; hwmon. Possibly 0x2e or 0x4e
#define SMBUS_UPI_UP6261BM8 0xfff // Unknown; vref
#define SMBUS_UPI_ISL6322CR 0xfff // Unknown; vrm
// SMBUS is send onto the mezzanine board!
#define EEPROM_DUMP L"dev/eeprom.bin"
typedef struct eeprom_reg {
@ -39,53 +46,6 @@ eeprom_bank_t EEPROM_DATA;
* - Reg 0x0e: Stores
*/
typedef uint_fast32_t crc_t;
static const crc_t crc_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832,
0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a,
0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4,
0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074,
0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525,
0x206f85b3, 0xb966d409, 0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76,
0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, 0x36034af6,
0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7,
0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330,
0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
#define CRC_ALGO_TABLE_DRIVEN 1
static inline crc_t crc_init(void) { return 0xffffffff; }
crc_t crc_update(crc_t crc, const void* data, size_t data_len) {
const unsigned char* d = (const unsigned char*)data;
unsigned int tbl_idx;
while (data_len--) {
tbl_idx = (crc ^ *d) & 0xff;
crc = (crc_table[tbl_idx] ^ (crc >> 8)) & 0xffffffff;
d++;
}
return crc & 0xffffffff;
}
static inline crc_t crc_finalize(crc_t crc) { return crc ^ 0xffffffff; }
void eeprom_dump() {
HANDLE dump = _CreateFileW(EEPROM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (dump == INVALID_HANDLE_VALUE) {
@ -107,11 +67,14 @@ void eeprom_restore() {
}
DWORD eeprom_crc(BYTE reg) {
if (reg == 0x80 || reg == 0x280) {
if (reg == 0x04 || reg == 0x14 || reg == 0x80 || reg == 0x280) {
// Some registers are only treated as 16 byte values
return crc_finalize(crc_update(crc_init(), EEPROM_DATA.reg[reg].data + 4, 12));
crc32_build_table();
return crc32(12, EEPROM_DATA.reg[reg].data + 4, 0);
}
return crc_finalize(crc_update(crc_init(), EEPROM_DATA.reg[reg].data + 4, 28));
crc32_build_table();
return crc32(28, EEPROM_DATA.reg[reg].data + 4, 0);
}
void eeprom_read(BYTE reg, BYTE index, BYTE* data, BYTE length) {
eeprom_restore();
@ -149,8 +112,9 @@ BYTE eeprom_read_one(BYTE reg, BYTE index) {
}
void eeprom_write_one(BYTE reg, BYTE index, BYTE data) { eeprom_write(reg, index, &data, 1); }
BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
BOOL mxsmbus_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) {
mxsmbus_i2c_packet* i2c_packet = (mxsmbus_i2c_packet*)lpInBuffer;
mxsmbus_i2c_packet* i2c_out = (mxsmbus_i2c_packet*)lpOutBuffer;
@ -203,21 +167,21 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn
// 48: addr 0x00: amHmGetLPCChipId
switch (i2c_packet->addr) {
case PCA9535:
case SMBUS_PCA9535:
switch (i2c_packet->prt) {
case PCA9535_WRITE:
switch (i2c_packet->reg) {
case PCA9535_OUT1:
log_info("mxsmbus", "pca9535 OUT1: %02x %02x", i2c_packet->data[0],
i2c_packet->data[1]);
i2c_packet->data[1]);
break;
case PCA9535_INV0:
log_info("mxsmbus", "pca9535 INV0: %02x %02x", i2c_packet->data[0],
i2c_packet->data[1]);
i2c_packet->data[1]);
break;
case PCA9535_INV1:
log_info("mxsmbus", "pca9535 INV1: %02x %02x", i2c_packet->data[0],
i2c_packet->data[1]);
i2c_packet->data[1]);
break;
default:
log_error("mxsmbux",
@ -232,12 +196,22 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn
case PCA9535_IN0: // DIPSW
i2c_packet->data[0] = 0x00;
break;
case PCA9535_IN1: // What's this one?
i2c_packet->data[0] = 0x00;
case PCA9535_IN1: // SW1/2 + extras
/*
0: uk
1: uk
2: ¬test
3: ¬service
4: uk
5: uk
6: uk
7: uk
*/
i2c_packet->data[0] = 0x0c;
break;
case PCA9535_INV0:
case PCA9535_INV1:
case PCA9535_OUT1:
case PCA9535_OUT1: // LEDs, probably
i2c_packet->data[0] = 0x00;
break;
default:
@ -254,7 +228,7 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn
exit(1);
}
break;
case EEPROM:
case SMBUS_EEPROM:
switch (i2c_packet->prt) {
case 3: // Wait
// 0x18 = wait, 0x00 = done
@ -311,7 +285,7 @@ BOOL mxsmbus_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nIn
return FALSE;
}
if (request_packet->addr != EEPROM) {
if (request_packet->addr != SMBUS_EEPROM) {
log_error("mxsmbus", "Unexpected I2C device: 0x%02x", request_packet->addr);
exit(1);
}
@ -358,6 +332,6 @@ void setup_mxsmbus() {
hook_file(mxsmbus);
if (!add_fake_device(&MXSMBUS_GUID, L"\\\\.\\mxsmbus")) {
log_error("mxsmbus", "failed to install mxsmbus device");
}
log_error("mxsmbus", "failed to install mxsmbus device");
}
}

View File

@ -1,6 +1,3 @@
#include <Windows.h>
#include "../lib/mice/mice.h"
#include "mx.h"
#define SRAM_DUMP L"dev/sram.bin"
@ -27,8 +24,9 @@ void sram_restore() {
_CloseHandle(dump);
}
BOOL mxsram_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
BOOL mxsram_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) {
DWORD SRAM_VERSION = 0x0001;
DWORD SRAM_SECTOR_SIZE = 0x100; // Max is 0x800
@ -74,7 +72,7 @@ BOOL mxsram_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInB
return TRUE;
}
DWORD mxsram_SetFilePointer(LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
DWORD mxsram_SetFilePointer(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
if (dwMoveMethod == FILE_BEGIN) {
SRAM_POINTER = lDistanceToMove;
} else if (dwMoveMethod == FILE_CURRENT) {
@ -83,7 +81,7 @@ DWORD mxsram_SetFilePointer(LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DW
return SRAM_POINTER;
}
BOOL mxsram_WriteFile(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
BOOL mxsram_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped) {
log_misc("mxsram", "sram write 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToWrite);
if (SRAM_POINTER + nNumberOfBytesToWrite >= SRAM_SIZE) {
@ -95,7 +93,7 @@ BOOL mxsram_WriteFile(LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpN
return TRUE;
}
BOOL mxsram_ReadFile(LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
BOOL mxsram_ReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped) {
log_misc("mxsram", "sram read 0x%08x (0x%04x bytes)", SRAM_POINTER, nNumberOfBytesToRead);
if (SRAM_POINTER + nNumberOfBytesToRead >= SRAM_SIZE) {

View File

@ -1,6 +1,3 @@
#include <Windows.h>
#include "../lib/mice/mice.h"
#include "mx.h"
#include "smbus.h"
#include "w83791d.h"
@ -16,8 +13,9 @@ BYTE w83791d_crit_t3 = 80; // C
BYTE w83791d_vbat_monitor_control = 0x00;
BOOL w83791d_4f_high = 0;
BOOL mxsuperio_DeviceIoControl(DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer,
DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
BOOL mxsuperio_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) {
mxsuperio_lpc_packet* lpc_packet = (mxsuperio_lpc_packet*)lpInBuffer;
mxsuperio_lpc_packet* lpc_out = (mxsuperio_lpc_packet*)lpOutBuffer;

View File

@ -1,64 +0,0 @@
#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);
static int(WINAPIV *True_stat64i32)(const char* path, struct _stat64i32* buffer);
#define _WriteFile (TrueWriteFile ? TrueWriteFile : WriteFile)
#define _ReadFile (TrueReadFile ? TrueReadFile : ReadFile)
#define _CloseHandle (TrueCloseHandle ? TrueCloseHandle : CloseHandle)
#define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW)
typedef struct drive_redirect {
const CHAR* drive;
const CHAR* path;
} drive_redirect_t;
typedef struct file_hook {
LPCWSTR filename;
FnDeviceIoControl* DeviceIoControl;
FnSetFilePointer* SetFilePointer;
FnWriteFile* WriteFile;
FnReadFile* ReadFile;
LPHANDLE virtual_handle;
struct file_hook* next;
} file_hook_t;
file_hook_t* new_file_hook(LPCWSTR filename);
void hook_file(file_hook_t* hook);
void hook_io();

View File

@ -0,0 +1,12 @@
#include "_hooks.h"
void hook_all() {
hook_logging();
hook_gui();
hook_setupapi();
hook_commio();
hook_io();
hook_processes();
hook_network();
hook_time();
}

View File

@ -0,0 +1,12 @@
#pragma once
#include "com.h"
#include "files.h"
#include "gui.h"
#include "logging.h"
#include "network.h"
#include "processes.h"
#include "setupapi_.h"
#include "time.h"
void hook_all();

View File

@ -1,12 +1,13 @@
#include "com.h"
#include "../lib/mice/mice.h"
com_hook_t* com_hook_list = NULL;
com_hook_t* new_com_hook(BYTE port) {
com_hook_t* hook = (com_hook_t*)malloc(sizeof *hook);
memset(hook->wName, 0, sizeof hook->wName);
swprintf(hook->wName, (sizeof hook->wName) / (sizeof hook->wName[0]), L"COM%d", port);
memset(hook->wDosName, 0, sizeof hook->wDosName);
swprintf(hook->wDosName, (sizeof hook->wDosName) / (sizeof hook->wDosName[0]), L"\\\\.\\COM%d", port);
hook->com = port;
hook->GetCommState = NULL;

View File

@ -1,6 +1,6 @@
#include <Windows.h>
#include <stdbool.h>
#include <stdio.h>
#pragma once
#include "../common.h"
static BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB);
static BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB);
@ -24,7 +24,8 @@ typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat);
typedef struct com_hook {
LPHANDLE virtual_handle;
WCHAR wName[7]; // max is COM255
WCHAR wName[7]; // max is "COM255"
WCHAR wDosName[11]; // max is "\\\\.\\COM255"
BYTE com;
FnGetCommState* GetCommState;
@ -44,4 +45,5 @@ typedef struct com_hook {
com_hook_t* new_com_hook(BYTE port);
void hook_com(com_hook_t* hook);
void hook_com();
void hook_commio();

View File

@ -1,20 +1,14 @@
#include "files.h"
#include "../lib/mice/mice.h"
HANDLE fake_handle = (HANDLE)0x10000000;
file_hook_t* file_hook_list = NULL;
file_hook_t* new_file_hook(LPCWSTR filename) {
file_hook_t* hook = (file_hook_t*)malloc(sizeof(file_hook_t));
memset(hook, 0, sizeof(file_hook_t));
hook->filename = filename;
hook->DeviceIoControl = NULL;
hook->SetFilePointer = NULL;
hook->WriteFile = NULL;
hook->ReadFile = NULL;
return hook;
}
void hook_file(file_hook_t* hook) {
@ -32,8 +26,11 @@ void hook_file(file_hook_t* hook) {
};
drive_redirect_t DRIVE_REDIRECT_TABLE[] = {
{.drive = "Y:\\", .path = ".\\dev\\Y\\"},
{.drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\"}};
{ .drive = "Y:\\", .path = ".\\dev\\Y\\" },
// Note: Had tp create last_shime.log
{ .drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\" },
// {.drive = "C:\\ProgramData/boost_interprocess/", .path = "\\\\.\\ipc\\"},
};
char* redirect_path(char* path) {
for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) {
@ -66,13 +63,16 @@ HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD d
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (wcscmp(lpFileName, hook->filename) == 0) {
if (wcscmp(lpFileName, hook->filename) == 0 ||
(hook->altFilename != NULL && wcscmp(lpFileName, hook->altFilename) == 0)) {
if (*hook->virtual_handle == NULL) {
// TODO: Assign handles better!
*hook->virtual_handle = fake_handle;
((size_t)fake_handle)++;
}
handle = *hook->virtual_handle;
log_info(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
break;
}
hook = hook->next;
@ -113,8 +113,12 @@ BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lp
// TODO: Less jank
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
return hook->DeviceIoControl(dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize,
lpBytesReturned, lpOverlapped);
BOOL ret = hook->DeviceIoControl(hook->data, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
nOutBufferSize, lpBytesReturned, lpOverlapped);
if (ret && lpOverlapped && lpBytesReturned) {
lpOverlapped->InternalHigh = *lpBytesReturned;
}
return ret;
} else {
log_error(HOOKS_LOGGER, "DeviceIoControl(%ls) unimplemented", hook->filename);
return FALSE;
@ -134,7 +138,7 @@ DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDist
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->SetFilePointer) {
return hook->SetFilePointer(lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
return hook->SetFilePointer(hook->data, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
} else {
log_error(HOOKS_LOGGER, "SetFilePointer(%ls) unimplemented", hook->filename);
return FALSE;
@ -146,13 +150,49 @@ DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDist
return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
}
BOOL WINAPI FakeSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
DWORD dwMoveMethod) {
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->SetFilePointerEx) {
return hook->SetFilePointerEx(hook->data, liDistanceToMove, lpNewFilePointer, dwMoveMethod);
} else {
log_error(HOOKS_LOGGER, "SetFilePointerEx(%ls) unimplemented", hook->filename);
return FALSE;
}
}
hook = hook->next;
}
return TrueSetFilePointerEx(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod);
}
DWORD WINAPI FakeGetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) {
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->GetFileSizeEx) {
return hook->GetFileSizeEx(hook->data, lpFileSize);
} else {
log_error(HOOKS_LOGGER, "GetFileSizeEx(%ls) unimplemented", hook->filename);
return FALSE;
}
}
hook = hook->next;
}
return TrueGetFileSizeEx(hFile, lpFileSize);
}
DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped) {
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->WriteFile) {
return hook->WriteFile(lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
return hook->WriteFile(hook->data, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten,
lpOverlapped);
} else {
log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", hook->filename);
return FALSE;
@ -170,7 +210,7 @@ BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRe
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->ReadFile) {
return hook->ReadFile(lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
return hook->ReadFile(hook->data, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
} else {
log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", hook->filename);
return FALSE;
@ -185,7 +225,8 @@ BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRe
BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (hook->virtual_handle == hObject) {
if (hObject != NULL && *hook->virtual_handle == hObject) {
log_misc("file", "close %08x", hObject);
return TRUE;
}
hook = hook->next;
@ -206,8 +247,10 @@ void hook_io() {
hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6);
hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6);
hook("Kernel32.dll", "SetFilePointerEx", FakeSetFilePointerEx, (void**)&TrueSetFilePointerEx, 6);
hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile, 6);
hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile, 6);
hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx, 6);
hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32, 5);
}

View File

@ -0,0 +1,72 @@
#pragma once
#include "../common.h"
static HANDLE(WINAPI* TrueCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
static HANDLE(WINAPI* TrueCreateFileW)(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
static BOOL(WINAPI* TrueDeviceIoControl)(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
static DWORD(WINAPI* TrueSetFilePointer)(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod);
static BOOL(WINAPI* TrueSetFilePointerEx)(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
DWORD dwMoveMethod);
// logging needs access to WriteFile, so we can't static it!
BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
static BOOL(WINAPI* TrueReadFile)(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped);
static BOOL(WINAPI* TrueGetFileSizeEx)(HANDLE hFile, PLARGE_INTEGER lpFileSize);
static BOOL(WINAPI* TrueCloseHandle)(HANDLE hObject);
typedef BOOL(FnDeviceIoControl)(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped);
typedef DWORD(FnSetFilePointer)(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
typedef BOOL(FnSetFilePointerEx)(void* file, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
DWORD dwMoveMethod);
typedef BOOL(FnWriteFile)(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);
typedef BOOL(FnReadFile)(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped);
typedef BOOL(FnGetFileSizeEx)(void* file, PLARGE_INTEGER lpFileSize);
static int(WINAPIV* True_stat64i32)(const char* path, struct _stat64i32* buffer);
#define _WriteFile (TrueWriteFile ? TrueWriteFile : WriteFile)
#define _ReadFile (TrueReadFile ? TrueReadFile : ReadFile)
#define _CloseHandle (TrueCloseHandle ? TrueCloseHandle : CloseHandle)
#define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW)
typedef struct drive_redirect {
const CHAR* drive;
const CHAR* path;
} drive_redirect_t;
typedef struct file_hook {
LPCWSTR filename;
LPCWSTR altFilename;
FnDeviceIoControl* DeviceIoControl;
FnSetFilePointer* SetFilePointer;
FnSetFilePointerEx* SetFilePointerEx;
FnWriteFile* WriteFile;
FnReadFile* ReadFile;
FnGetFileSizeEx* GetFileSizeEx;
void* data;
LPHANDLE virtual_handle;
struct file_hook* next;
} file_hook_t;
file_hook_t* new_file_hook(LPCWSTR filename);
void hook_file(file_hook_t* hook);
void hook_io();

View File

@ -0,0 +1,111 @@
#include "gui.h"
static HWND window;
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) {
DWORD wndProcId;
GetWindowThreadProcessId(handle, &wndProcId);
if (GetCurrentProcessId() != wndProcId) return TRUE;
window = handle;
return FALSE;
}
HWND GetProcessWindow() {
window = NULL;
EnumWindows(EnumWindowsCallback, 0);
return window;
}
BOOL GetD3D9Device(void** pTable, size_t Size) {
if (!pTable) return false;
IDirect3D9* pD3D = Direct3DCreate9(D3D_SDK_VERSION);
if (!pD3D) return false;
IDirect3DDevice9* pDummyDevice = NULL;
D3DPRESENT_PARAMETERS d3dpp = { 0 };
d3dpp.Windowed = false;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = GetProcessWindow();
HRESULT dummyDeviceCreated =
pD3D->lpVtbl->CreateDevice(pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
if (dummyDeviceCreated != S_OK) {
d3dpp.Windowed = !d3dpp.Windowed;
dummyDeviceCreated = pD3D->lpVtbl->CreateDevice(pD3D, D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, d3dpp.hDeviceWindow,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDummyDevice);
if (dummyDeviceCreated != S_OK) {
pD3D->lpVtbl->Release(pD3D);
return false;
}
}
memcpy(pTable, *(void***)pDummyDevice, Size);
pDummyDevice->lpVtbl->Release(pDummyDevice);
pD3D->lpVtbl->Release(pD3D);
return true;
}
static HRESULT(WINAPI* TrueEndScene)(IDirect3DDevice9*);
void draw_rect(IDirect3DDevice9* dev, int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b) {
D3DCOLOR rectColor = D3DCOLOR_XRGB(r, g, b);
D3DRECT BarRect = { x, y, x + w, y + h };
dev->lpVtbl->Clear(dev, 1, &BarRect, D3DCLEAR_TARGET | D3DCLEAR_TARGET, rectColor, 0, 0);
}
HRESULT __stdcall hkEndScene(IDirect3DDevice9* pDevice) {
static bool showMenu = false;
end_scene_hook_t* head = end_scene_hook_list;
while (head != NULL) {
head->hook(pDevice);
head = head->next;
}
return TrueEndScene(pDevice);
}
void register_gui_hook(FnEndScene* end_scene) {
end_scene_hook_t** head = &end_scene_hook_list;
while (*head != NULL) {
head = &((*head)->next);
}
end_scene_hook_t* hook = malloc(sizeof(end_scene_hook_t));
hook->hook = end_scene;
hook->next = NULL;
*head = hook;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass,
DWORD_PTR dwRefData) {
// ImGui_ImplWin32_WndProcHandler(hWnd, uMsg, wParam, lParam);
return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
HWND WINAPI FakeCreateWindowExA(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X, int Y,
int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance,
LPVOID lpParam) {
HWND hWnd = TrueCreateWindowExA(dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent,
hMenu, hInstance, lpParam);
void* d3d9Device[119];
if (GetD3D9Device(d3d9Device, sizeof(d3d9Device))) {
*((PVOID*)&TrueEndScene) = CreateHook((PVOID)d3d9Device[42], (PVOID)hkEndScene, 7);
}
if (hWnd && !SetWindowSubclass(hWnd, WndProc, (int)&WndProc, (DWORD_PTR)NULL)) {
log_error("gui", "failed to SetWindowSubclass(%d)", GetLastError());
}
return hWnd;
}
void hook_gui() {
//
hook("User32.dll", "CreateWindowExA", FakeCreateWindowExA, (void**)&TrueCreateWindowExA, 7);
}

View File

@ -0,0 +1,20 @@
#pragma once
#include "common.h"
static HWND(WINAPI* TrueCreateWindowExA)(DWORD dwExStyle, LPCSTR lpClassName, LPCSTR lpWindowName, DWORD dwStyle, int X,
int Y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu,
HINSTANCE hInstance, LPVOID lpParam);
void draw_rect(IDirect3DDevice9* dev, int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b);
typedef VOID(FnEndScene)(IDirect3DDevice9* dev);
typedef struct end_scene_hook {
FnEndScene* hook;
struct end_scene_hook* next;
} end_scene_hook_t;
end_scene_hook_t* end_scene_hook_list;
void register_gui_hook(FnEndScene* end_scene);
void hook_gui();

View File

@ -0,0 +1,99 @@
#include "../util/_util.h"
#include "logging.h"
char* trim_string(char* string) {
size_t len = strlen(string) - 1;
DWORD oldProt;
while (len > 0 && (string[len] == '\n' || string[len] == '\r')) {
// TODO: Reassess this. Suspect it may be causing issues.
// Make sure we can write! This is a terrible hack, but it does work.
VirtualProtect(string + len, 1, PAGE_EXECUTE_READWRITE, &oldProt);
string[len--] = '\0';
VirtualProtect(string + len + 1, 1, oldProt, &oldProt);
}
return string;
}
#define WORK_FORMAT_MAX 1024
char format_buf[WORK_FORMAT_MAX]; // Will do. We guard against overflow in Fake[f]printf
int WINAPIV Fakeprintf(const char* _Format, ...) {
int flen = strlen(_Format);
if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) {
strcpy_s(format_buf, WORK_FORMAT_MAX, _Format);
format_buf[flen - 1] = 0;
_Format = format_buf;
}
va_list args;
va_start(args, _Format);
int ret = vlog_game("printf", _Format, args);
va_end(args);
return vlog_game("printf", _Format, args);
}
int WINAPIV Fakefprintf(FILE* _File, const char* _Format, ...) {
int flen = strlen(_Format);
if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf)) {
strcpy_s(format_buf, WORK_FORMAT_MAX, _Format);
format_buf[flen - 1] = 0;
_Format = format_buf;
}
va_list args;
va_start(args, _Format);
int ret = vlog_game("fprintf", _Format, args);
va_end(args);
return ret;
}
int WINAPIV Fakefprintf_s(FILE* _Stream, const char* _Format, ...) {
va_list args;
va_start(args, _Format);
int ret = vlog_game("fprintf_s", _Format, args);
va_end(args);
return ret;
}
HANDLE WINAPI FakeRegisterEventSourceA(LPCSTR lpUNCServerName, LPCSTR lpSourceName) { return (HANDLE)0xDEADBEEF; }
BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid,
WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData) {
switch (wType) {
case EVENTLOG_SUCCESS:
case EVENTLOG_AUDIT_SUCCESS:
for (int i = 0; i < wNumStrings; i++) log_misc("evtlog", trim_string((char*)lpStrings[i]));
break;
case EVENTLOG_AUDIT_FAILURE:
case EVENTLOG_ERROR_TYPE:
for (int i = 0; i < wNumStrings; i++) log_error("evtlog", trim_string((char*)lpStrings[i]));
break;
case EVENTLOG_WARNING_TYPE:
for (int i = 0; i < wNumStrings; i++) log_warning("evtlog", trim_string((char*)lpStrings[i]));
break;
case EVENTLOG_INFORMATION_TYPE:
default:
for (int i = 0; i < wNumStrings; i++) log_info("evtlog", trim_string((char*)lpStrings[i]));
break;
}
return TRUE;
};
BOOL WINAPI FakeDeregisterEventSource(HANDLE hEventLog) { return TRUE; }
// static VOID(WINAPI* TrueOutputDebugStringA)(LPCSTR lpOutputString);
// VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) { log_info("debug", "%s", lpOutputString); }
void hook_logging() {
hook("MSVCR90.DLL", "printf", Fakeprintf, (void**)&Trueprintf, 6);
hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf, 6);
hook("MSVCR90.DLL", "fprintf_s", Fakefprintf_s, (void**)&Truefprintf_s, 6);
hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA, (void**)&TrueRegisterEventSourceA, 6);
hook("Advapi32.dll", "ReportEventA", FakeReportEventA, (void**)&TrueReportEventA, 6);
hook("Advapi32.dll", "DeregisterEventSource", FakeDeregisterEventSource, (void**)&TrueDeregisterEventSource, 6);
}

View File

@ -0,0 +1,16 @@
#pragma once
// #include "../common.h"
#include <Windows.h>
#include <string.h>
#include <stdlib.h>
static HANDLE(WINAPI* TrueRegisterEventSourceA)(LPCSTR lpUNCServerName, LPCSTR lpSourceName);
static BOOL(WINAPI* TrueReportEventA)(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid,
WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData);
static BOOL(WINAPI* TrueDeregisterEventSource)(HANDLE hEventLog);
int(WINAPIV* Trueprintf)(const char* _Format, ...);
static int(WINAPIV* Truefprintf)(FILE* _File, const char* _Format, ...);
static int(WINAPIV* Truefprintf_s)(FILE* _Stream, const char* _Format, ...);
void hook_logging();

View File

@ -0,0 +1,11 @@
hooks_files = files(
'_hooks.c',
'com.c',
'files.c',
'gui.c',
'logging.c',
'network.c',
'processes.c',
'setupapi.c',
'time.c',
)

View File

@ -1,9 +1,7 @@
#include "network.h"
#include "../lib/mice/mice.h"
int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr);
ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr);
USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port);
log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff,
addr & 0xff, port);
@ -33,29 +31,55 @@ const char* INTERCEPT_DNS[] = {
DNS_RECORDA dummy_record;
unsigned char SPOOF_IP[4] = { 10, 0, 0, 4 };
DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra, PDNS_RECORDA* ppQueryResults,
PVOID* pReserved) {
log_misc("dns", "DNS lookup for %s", pszName);
if (ppQueryResults) {
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(pszName, INTERCEPT_DNS[i]) == 0) {
log_info("dns", "Replacing %s with 10.0.0.4", pszName);
log_info("dns", "Replacing %s with %hhu.%hhu.%hhu.%hhu", pszName, SPOOF_IP[0], SPOOF_IP[1], SPOOF_IP[2],
SPOOF_IP[3]);
// We only support replacing at most one address, but that's all we'll ever need to!
(*ppQueryResults) = &dummy_record;
(*ppQueryResults)->pNext = NULL;
(*ppQueryResults)->wType = DNS_TYPE_A;
(*ppQueryResults)->Data.A.IpAddress = 0x0400000a;
(*ppQueryResults)->Data.A.IpAddress =
(SPOOF_IP[0]) | (SPOOF_IP[1] << 8) | (SPOOF_IP[2] << 16) | (SPOOF_IP[3] << 24);
return ERROR_SUCCESS;
}
}
}
log_warning("dns", "DNS passthrough for %s", pszName);
return TrueDnsQuery_A(pszName, wType, Options, pExtra, ppQueryResults, pReserved);
};
INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily, LPWSAPROTOCOL_INFOA lpProtocolInfo,
LPSOCKADDR lpAddress, LPINT lpAddressLength) {
log_misc("dns", "(WSA)DNS lookup for %s", AddressString);
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(AddressString, INTERCEPT_DNS[i]) == 0) {
log_info("dns", "(WSA)Replacing %s with %hhu.%hhu.%hhu.%hhu", AddressString, SPOOF_IP[0], SPOOF_IP[1],
SPOOF_IP[2], SPOOF_IP[3]);
lpAddress->sa_family = AF_INET;
// ... :)
lpAddress->sa_data[2] = SPOOF_IP[0];
lpAddress->sa_data[3] = SPOOF_IP[1];
lpAddress->sa_data[4] = SPOOF_IP[2];
lpAddress->sa_data[5] = SPOOF_IP[3];
return ERROR_SUCCESS;
}
}
log_warning("dns", "(WSA)DNS passthrough for %s", AddressString);
return TrueWSAStringToAddressA(AddressString, AddressFamily, lpProtocolInfo, lpAddress, lpAddressLength);
}
void hook_network() {
hook("Ws2_32.dll", "connect", Fake_connect, (void**)&True_connect, 5);
hook("Ws2_32.dll", "WSAStringToAddressA", FakeWSAStringToAddressA, (void**)&TrueWSAStringToAddressA, 5);
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable, 5);
hook("Dnsapi.dll", "DnsQuery_A", FakeDnsQuery_A, (void**)&TrueDnsQuery_A, 5);
}

View File

@ -1,8 +1,5 @@
#include <Winsock2.h>
#include <Windows.h>
#include <iphlpapi.h>
#include <windns.h>
#pragma once
#include "../common.h"
static int(WINAPI* True_connect)(SOCKET s, const SOCKADDR* name, int namelen);
@ -11,4 +8,7 @@ static DWORD(WINAPI* TrueGetIfTable)(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL
static DNS_STATUS(WINAPI* TrueDnsQuery_A)(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra,
PDNS_RECORDA* ppQueryResults, PVOID* pReserved);
static INT(WSAAPI* TrueWSAStringToAddressA)(LPSTR AddressString, INT AddressFamily, LPWSAPROTOCOL_INFOA lpProtocolInfo,
LPSOCKADDR lpAddress, LPINT lpAddressLength);
void hook_network();

View File

@ -1,7 +1,5 @@
#include "processes.h"
#include "../lib/mice/mice.h"
const wchar_t* HOOK_BINARIES[] = {
L"app\\ALLNetProc.exe",
L"app\\CameraUploader.exe",
@ -17,11 +15,19 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
CHAR applicationName[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName, NULL, NULL);
CHAR commandLine[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL, NULL);
HANDLE child = start_and_inject(applicationName, commandLine, MICELIB, false);
HANDLE child;
if (lpCommandLine != NULL) {
CHAR commandLine[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL, NULL);
child = start_and_inject(applicationName, commandLine, MICELIB, false);
} else {
child = start_and_inject(applicationName, NULL, MICELIB, false);
}
return child != NULL;
}
void hook_processes() { hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6); }
void hook_processes() {
// hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6);
}

View File

@ -1,6 +1,5 @@
#include <Windows.h>
#include <stdbool.h>
#include <stdio.h>
#pragma once
#include "../common.h"
static BOOL(WINAPI* TrueCreateProcessW)(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,

View File

@ -1,4 +1,4 @@
#include "micesetupapi.h"
#include "setupapi_.h"
FAKE_DEVICE* fake_devices = NULL;

View File

@ -1,8 +1,5 @@
#include <Windows.h>
#include <setupapi.h>
#include <stddef.h>
#include "../lib/mice/mice.h"
#pragma once
#include "common.h"
static HDEVINFO(WINAPI* TrueSetupDiGetClassDevsA)(const GUID* ClassGuid, PCWSTR Enumerator, HWND hwndParent,
DWORD Flags);

View File

@ -0,0 +1,48 @@
#include "time.h"
SYSTEMTIME localTime;
BOOL ltCache = FALSE;
SYSTEMTIME systemTime;
BOOL stCache = FALSE;
BOOL WINAPI Fake_SetLocalTime(const SYSTEMTIME* lpSystemTime) {
memcpy(&localTime, lpSystemTime, sizeof localTime);
ltCache = TRUE;
log_info("time", "Not setting local time to: %04d-%02d-%02d %02d:%02d:%02d.%04d", lpSystemTime->wYear,
lpSystemTime->wMonth, lpSystemTime->wDay, lpSystemTime->wHour, lpSystemTime->wMinute,
lpSystemTime->wSecond, lpSystemTime->wMilliseconds);
return TRUE;
}
BOOL WINAPI Fake_SetSystemTime(const SYSTEMTIME* lpSystemTime) {
memcpy(&systemTime, lpSystemTime, sizeof systemTime);
stCache = TRUE;
log_info("time", "Not setting system time to: %04d-%02d-%02d %02d:%02d:%02d.%04d", lpSystemTime->wYear,
lpSystemTime->wMonth, lpSystemTime->wDay, lpSystemTime->wHour, lpSystemTime->wMinute,
lpSystemTime->wSecond, lpSystemTime->wMilliseconds);
return TRUE;
}
// TODO: Store deltas instead
BOOL WINAPI Fake_GetLocalTime(SYSTEMTIME* lpSystemTime) {
if (ltCache) {
memcpy(lpSystemTime, &localTime, sizeof localTime);
return TRUE;
}
return TrueGetLocalTime(lpSystemTime);
}
BOOL WINAPI Fake_GetSystemTime(SYSTEMTIME* lpSystemTime) {
if (stCache) {
memcpy(lpSystemTime, &systemTime, sizeof systemTime);
return TRUE;
}
return TrueGetSystemTime(lpSystemTime);
}
void hook_time() {
hook("Kernel32.dll", "SetLocalTime", Fake_SetLocalTime, (void**)&TrueSetLocalTime, 6);
hook("Kernel32.dll", "SetSystemTime", Fake_SetSystemTime, (void**)&TrueSetSystemTime, 6);
hook("Kernel32.dll", "GetLocalTime", Fake_GetLocalTime, (void**)&TrueGetLocalTime, 6);
hook("Kernel32.dll", "GetSystemTime", Fake_GetSystemTime, (void**)&TrueGetSystemTime, 6);
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "../common.h"
static BOOL(WINAPI* TrueSetLocalTime)(const SYSTEMTIME* lpSystemTime);
static BOOL(WINAPI* TrueGetLocalTime)(SYSTEMTIME* lpSystemTime);
static BOOL(WINAPI* TrueSetSystemTime)(const SYSTEMTIME* lpSystemTime);
static BOOL(WINAPI* TrueGetSystemTime)(SYSTEMTIME* lpSystemTime);
void hook_time();

View File

@ -1,24 +1,25 @@
subdir('drivers')
subdir('devices')
subdir('hooks')
shared_library(
'mice',
name_prefix: '',
vs_module_defs: 'mice.def',
sources: [
'dllmain.c',
'files.c',
'drivers/columba.c',
'drivers/mxsram.c',
'drivers/mxsuperio.c',
'drivers/mxjvs.c',
'drivers/mxsmbus.c',
'drivers/mxhwreset.c',
'setupapi.c',
'com.c',
'util/log.c',
'util/hook.c',
drivers_files,
devices_files,
hooks_files,
'comdevice.c',
'processes.c',
'network.c',
'dllmain.c',
],
link_with: [
dmi_lib,
mice_lib,
],
]
)

View File

@ -1,4 +1,5 @@
#include <Windows.h>
#pragma once
#include "common.h"
#pragma pack(1)
typedef struct mxsmbus_request_packet_ {

View File

@ -0,0 +1,4 @@
#pragma once
#include "log.h"
#include "hook.h"

View File

@ -1,4 +1,8 @@
#include "hook.h"
#include "log.h"
#include <memory.h>
#include <stdlib.h>
function_hook_t* hook_list = NULL;
@ -36,8 +40,8 @@ void clear_at(PVOID addr, BYTE clearVal, DWORD length) {
VirtualProtect(addr, length, oldProt, &oldProt);
}
bool Detour(PVOID src, PVOID dst, const intptr_t len) {
if (len < 5) return false;
BOOL Detour(PVOID src, PVOID dst, const intptr_t len) {
if (len < 5) return FALSE;
DWORD oldProt;
VirtualProtect(src, len, PAGE_EXECUTE_READWRITE, &oldProt);
@ -46,7 +50,7 @@ bool Detour(PVOID src, PVOID dst, const intptr_t len) {
*(PINT)((int)src + 1) = (int)dst - (int)src - 5;
VirtualProtect(src, len, oldProt, &oldProt);
return true;
return TRUE;
}
void* CreateHook(PVOID src, PVOID dst, const intptr_t len) {
@ -78,6 +82,7 @@ void setup_hooks() {
HMODULE dll = LoadLibraryA(hook->dll);
if (dll == NULL) {
log_error(HOOKS_LOGGER, "failed to load dll %s. %s skipped", hook->dll, hook->name);
hook = hook->next;
continue;
}

View File

@ -2,8 +2,6 @@
#include <Windows.h>
#include "./mice.h"
typedef struct function_hook {
LPCSTR dll;
LPCSTR name;
@ -13,10 +11,13 @@ typedef struct function_hook {
struct function_hook* next;
} function_hook_t;
static BOOL Detour(PVOID src, PVOID dst, const intptr_t len);
void patch_at(PVOID addr, const char* patch, DWORD length);
void clear_at(PVOID addr, BYTE clearVal, DWORD length);
void* CreateHook(PVOID src, PVOID dst, const intptr_t len);
static void append_hook(function_hook_t* hook);
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store, UINT length);
void setup_hooks();

View File

@ -0,0 +1,144 @@
#include "log.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "../hooks/logging.h"
extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped);
BOOL HAS_COLOUR = FALSE;
char _log_prelude[64];
char* log_prelude() {
time_t rawtime;
struct tm timeinfo;
time(&rawtime);
localtime_s(&timeinfo, &rawtime);
strftime(_log_prelude, sizeof _log_prelude, "[%Y/%m/%d %H:%M:%S] ", &timeinfo);
return _log_prelude;
}
HANDLE LOG_FILE = NULL;
VOID trace_hook(char* output);
CRITICAL_SECTION logger_lock;
int _do_log(const char* caller, const char* level, const char* format, va_list args, bool toStdout, char* colour) {
EnterCriticalSection(&logger_lock);
int len = snprintf(NULL, 0, "%s%s:%s:", log_prelude(), level, caller) + vsnprintf(NULL, 0, format, args);
char* buf = (char*)malloc(len + 2);
if (!buf) {
LeaveCriticalSection(&logger_lock);
return 0;
}
int wrote_a = snprintf(buf, len, "%s%s:%s:", log_prelude(), level, caller);
int wrote_b = vsnprintf(buf + wrote_a, len - wrote_a + 1, format, args);
buf[len] = '\n';
buf[len + 1] = '\0';
// No +1 here to not get the \n
if (toStdout) {
HANDLE sout = GetStdHandle(STD_OUTPUT_HANDLE);
if (HAS_COLOUR) (TrueWriteFile ? TrueWriteFile : WriteFile)(sout, colour, strlen(colour), NULL, NULL);
if (sout != INVALID_HANDLE_VALUE) (TrueWriteFile ? TrueWriteFile : WriteFile)(sout, buf, len, NULL, NULL);
puts(HAS_COLOUR ? "\033[0m" : "");
}
#ifdef LOG_TO_FILE
if (LOG_FILE && LOG_FILE != INVALID_HANDLE_VALUE)
(TrueWriteFile ? TrueWriteFile : WriteFile)(LOG_FILE, buf, len + 1, NULL, NULL);
#endif
free(buf);
LeaveCriticalSection(&logger_lock);
return wrote_b;
}
int vlog_misc(const char* caller, const char* format, va_list args) {
return _do_log(caller, "M", format, args, LOG_MISC, "\033[90m");
}
int log_misc(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_misc(caller, format, args);
va_end(args);
return ret;
}
int vlog_info(const char* caller, const char* format, va_list args) {
return _do_log(caller, "I", format, args, LOG_INFO, "\033[97m");
}
int log_info(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_info(caller, format, args);
va_end(args);
return ret;
}
int vlog_warning(const char* caller, const char* format, va_list args) {
return _do_log(caller, "W", format, args, LOG_WARNING, "\033[33m");
}
int log_warning(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_warning(caller, format, args);
va_end(args);
return ret;
}
int vlog_error(const char* caller, const char* format, va_list args) {
return _do_log(caller, "E", format, args, LOG_ERROR, "\033[91m");
}
int log_error(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_error(caller, format, args);
va_end(args);
return ret;
}
int vlog_game(const char* caller, const char* format, va_list args) {
return _do_log(caller, "G", format, args, LOG_GAME, "\033[96m");
}
int log_game(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_game(caller, format, args);
va_end(args);
return ret;
}
VOID trace_hook(char* output) {
output[strcspn(output, "\n")] = 0;
log_error("trace", output);
}
void setup_logging() {
// Force stdio even for GUI applications
AttachConsole(ATTACH_PARENT_PROCESS);
if (GetStdHandle(STD_INPUT_HANDLE)) {
freopen("CONIN$", "r", stdin);
setvbuf(stdin, NULL, _IONBF, 0);
}
if (GetStdHandle(STD_OUTPUT_HANDLE)) {
freopen("CONOUT$", "w", stdout);
setvbuf(stdout, NULL, _IONBF, 0);
}
if (GetStdHandle(STD_ERROR_HANDLE)) {
freopen("CONOUT$", "w", stderr);
setvbuf(stderr, NULL, _IONBF, 0);
}
// Enable colour in CMD
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
if (GetConsoleMode(hConsole, &dwMode))
HAS_COLOUR = SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
InitializeCriticalSection(&logger_lock);
if (LOG_FILE == NULL)
LOG_FILE = CreateFileA("log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
}

View File

@ -1,17 +1,15 @@
#pragma once
#include <Windows.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>
static HANDLE(WINAPI* TrueRegisterEventSourceA)(LPCSTR lpUNCServerName, LPCSTR lpSourceName);
static BOOL(WINAPI* TrueReportEventA)(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid,
WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData);
static BOOL(WINAPI* TrueDeregisterEventSource)(HANDLE hEventLog);
#define LOG_MISC FALSE
#define LOG_INFO TRUE
#define LOG_WARNING TRUE
#define LOG_ERROR TRUE
#define LOG_GAME TRUE
// #define LOG_MISC
#define LOG_INFO
#define LOG_WARNING
#define LOG_ERROR
// #define LOG_TO_FILE
#define COMM_LOGGER "comm"
#define HOOKS_LOGGER "hooks"
@ -23,10 +21,12 @@ int log_misc(const char* caller, const char* format, ...);
int log_info(const char* caller, const char* format, ...);
int log_warning(const char* caller, const char* format, ...);
int log_error(const char* caller, const char* format, ...);
int log_game(const char* caller, const char* format, ...);
int vlog_misc(const char* caller, const char* format, va_list args);
int vlog_info(const char* caller, const char* format, va_list args);
int vlog_warning(const char* caller, const char* format, va_list args);
int vlog_error(const char* caller, const char* format, va_list args);
int vlog_game(const char* caller, const char* format, va_list args);
void setup_logging();

View File

@ -12,7 +12,7 @@ bool locate_file(char* path, size_t len, const char* exe) {
HANDLE hFind = NULL;
char work_path[2048];
sprintf(work_path, ".\\*.*");
snprintf(work_path, sizeof work_path, ".\\*.*");
if ((hFind = FindFirstFile(work_path, &fdFile)) == INVALID_HANDLE_VALUE) return false;

View File

@ -6,3 +6,4 @@
bool locate_exe(char* path, size_t len, const char* exe);
bool locate_game(char* path, size_t len);
bool locate_library(char* path, size_t len);

View File

@ -11,11 +11,11 @@ bool gametest = false;
char exe_name[MAX_PATH + 1] = "";
void print_help(char* exe) {
log_info(BOOT_LOGGER, "Usage: %s [-h] [-t] [-b executable.exe] [-d]", exe);
log_info(BOOT_LOGGER, " -h: Print this help message and exit");
log_info(BOOT_LOGGER, " -t: Start the game in test mode");
log_info(BOOT_LOGGER, " -b: Specify the game binary to use");
log_info(BOOT_LOGGER, " -d: Wait for a debugger to attach when starting");
fprintf(stderr, "Usage: %s [-h] [-t] [-b executable.exe] [-d]\n", exe);
fprintf(stderr, " -h: Print this help message and exit\n");
fprintf(stderr, " -t: Start the game in test mode\n");
fprintf(stderr, " -b: Specify the game binary to use\n");
fprintf(stderr, " -d: Wait for a debugger to attach when starting\n");
exit(0);
}
@ -25,7 +25,8 @@ void parse_cmdline(int argc, char* argv[]) {
print_help(argv[0]);
} else if (strcmp(argv[i], "-b") == 0) {
if (i + 1 == argc) print_help(argv[0]);
strcpy(exe_name, argv[++i]);
char* val = argv[++i];
memcpy(exe_name, val, strlen(val) + 1);
} else if (strcmp(argv[i], "-d") == 0) {
boot_delay = true;
} else if (strcmp(argv[i], "-t") == 0) {
@ -35,30 +36,29 @@ void parse_cmdline(int argc, char* argv[]) {
}
int main(int argc, char* argv[]) {
setup_logging();
log_info(BOOT_LOGGER, "Micetools version: %s", VERSION);
fprintf(stderr, "Micetools version: %s\n", VERSION);
parse_cmdline(argc, argv);
if (exe_name[0] == '\0') {
if (!locate_game(exe_name, MAX_PATH + 1)) {
log_error(BOOT_LOGGER, "Failed to locate a game");
fprintf(stderr, "Fatal: Failed to locate a game\n");
return 0;
}
} else {
DWORD dwAttrib = GetFileAttributes(exe_name);
if (dwAttrib == INVALID_FILE_ATTRIBUTES || dwAttrib & FILE_ATTRIBUTE_DIRECTORY) {
log_error(BOOT_LOGGER, "%s: no such file found", exe_name);
fprintf(stderr, "Fatal: %s: no such file found\n", exe_name);
return 0;
}
}
char* cmdline = gametest ? "gametest" : "";
log_info(BOOT_LOGGER, "%s %s", exe_name, cmdline);
char* cmdline = gametest ? ". gametest" : "";
fprintf(stderr, "exec: %s %s\n", exe_name, cmdline);
char micepath[MAX_PATH + 1];
if (!locate_library(micepath, MAX_PATH + 1)) {
log_error(BOOT_LOGGER, "Failed to locate micelib");
fprintf(stderr, "Fatal: Failed to locate micelib\n");
return 0;
}
@ -66,9 +66,9 @@ int main(int argc, char* argv[]) {
if (!game_proc) return -1;
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {
log_error(BOOT_LOGGER, "WaitForSingleObject failed: %03x", GetLastError());
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
} else {
log_info(BOOT_LOGGER, "Shutting down");
fprintf(stderr, "Shutting down\n");
CloseHandle(game_proc);
}
return 0;

View File

@ -1,7 +1,7 @@
rc = import('windows').compile_resources('mice.rc', depend_files: mice_ico)
executable(
'mice',
win_subsystem: 'console',
win_subsystem: subsystem,
sources: [
'locate.c',
'main.c',

View File

@ -1,11 +1,13 @@
#include "dmi.h"
#include <stdlib.h>
LPBYTE dmi_table = NULL;
WORD dmi_size = 0;
size_t _dmi_max = 0;
DMI_BIOS deafult_dmi_bios = {
.Head.Type = 0x00,
.Head.Type = 0x00,
.Head.Length = 0x12,
.Head.Handle = 0x0000,
.Vendor = 0x00,
@ -20,7 +22,7 @@ DMI_SYSTEM default_dmi_system = {
.Head.Type = 0x01,
.Head.Length = 0x08,
.Head.Handle = 0x0001,
// TODO: Are these used?
// TODO: Are these used?
.Manufacturer = 0x00,
.ProductName = 0x00,
.Version = 0x00,
@ -38,7 +40,7 @@ static void dmi_init(void) {
if (dmi_table) free(dmi_table);
_dmi_max = 0xff;
dmi_table = (LPBYTE)malloc(_dmi_max);
memset(dmi_table, 0, _dmi_max);
memset(dmi_table, 0, _dmi_max);
dmi_size = 0;
}
@ -64,7 +66,7 @@ static void dmi_append_with_strings(void* data, size_t size, int num_strings, ..
for (int i = 0; i < num_strings; i++) {
char* str = va_arg(args, char*);
int len = strlen(str);
strcpy((char*)dmi_table + dmi_size, str);
memcpy((char*)dmi_table + dmi_size, str, len + 1);
dmi_size += len + 1;
dmi_table[dmi_size - 1] = 0;
}

View File

@ -28,7 +28,6 @@
*/
#include "json.h"
#include "../util/hex.h"
#include <ctype.h>
#include <limits.h>
@ -38,6 +37,8 @@
#include <stdlib.h>
#include <string.h>
#include "../util/hex.h"
#define JSON_INT_MAX 9223372036854775807LL
typedef unsigned int json_uchar;
@ -194,7 +195,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
if (flags & flag_string) {
if (!b) {
sprintf(error, "%u:%u: Unexpected EOF in string", line_and_col);
snprintf(error, json_error_max, "%u:%u: Unexpected EOF in string", line_and_col);
goto e_failed;
}
@ -225,7 +226,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
(uc_b2 = hex_value(*++state.ptr)) == 0xFF ||
(uc_b3 = hex_value(*++state.ptr)) == 0xFF ||
(uc_b4 = hex_value(*++state.ptr)) == 0xFF) {
sprintf(error, "%u:%u: Invalid character value `%c`", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, b);
goto e_failed;
}
@ -241,7 +242,8 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
(uc_b2 = hex_value(*++state.ptr)) == 0xFF ||
(uc_b3 = hex_value(*++state.ptr)) == 0xFF ||
(uc_b4 = hex_value(*++state.ptr)) == 0xFF) {
sprintf(error, "%u:%u: Invalid character value `%c`", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col,
b);
goto e_failed;
}
@ -354,7 +356,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
if (flags & flag_block_comment) {
if (!b) {
sprintf(error, "%u:%u: Unexpected EOF in block comment", line_and_col);
snprintf(error, json_error_max, "%u:%u: Unexpected EOF in block comment", line_and_col);
goto e_failed;
}
@ -367,12 +369,12 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
}
} else if (b == '/') {
if (!(flags & (flag_seek_value | flag_done)) && top->type != json_object) {
sprintf(error, "%u:%u: Comment not allowed here", line_and_col);
snprintf(error, json_error_max, "%u:%u: Comment not allowed here", line_and_col);
goto e_failed;
}
if (++state.ptr == end) {
sprintf(error, "%u:%u: EOF unexpected", line_and_col);
snprintf(error, json_error_max, "%u:%u: EOF unexpected", line_and_col);
goto e_failed;
}
@ -386,7 +388,8 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
continue;
default:
sprintf(error, "%u:%u: Unexpected `%c` in comment opening sequence", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in comment opening sequence",
line_and_col, b);
goto e_failed;
};
}
@ -400,7 +403,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
continue;
default:
sprintf(error, "%u:%u: Trailing garbage: `%c`", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Trailing garbage: `%c`", line_and_col, b);
goto e_failed;
};
}
@ -414,7 +417,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
if (top && top->type == json_array)
flags = (flags & ~(flag_need_comma | flag_seek_value)) | flag_next;
else {
sprintf(error, "%u:%u: Unexpected `]`", line_and_col);
snprintf(error, json_error_max, "%u:%u: Unexpected `]`", line_and_col);
goto e_failed;
}
@ -426,7 +429,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
flags &= ~flag_need_comma;
continue;
} else {
sprintf(error, "%u:%u: Expected `,` before `%c`", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Expected `,` before `%c`", line_and_col, b);
goto e_failed;
}
@ -437,7 +440,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
flags &= ~flag_need_colon;
continue;
} else {
sprintf(error, "%u:%u: Expected `:` before `%c`", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Expected `:` before `%c`", line_and_col, b);
goto e_failed;
}
@ -535,7 +538,8 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
flags |= flag_num_negative;
continue;
} else {
sprintf(error, "%u:%u: Unexpected `%c` when seeking value", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Unexpected `%c` when seeking value",
line_and_col, b);
goto e_failed;
}
};
@ -548,7 +552,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
continue;
case '"':
if (flags & flag_need_comma) {
sprintf(error, "%u:%u: Expected `,` before `\"`", line_and_col);
snprintf(error, json_error_max, "%u:%u: Expected `,` before `\"`", line_and_col);
goto e_failed;
}
@ -570,7 +574,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
} /* FALLTHRU */
default:
sprintf(error, "%u:%u: Unexpected `%c` in object", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in object", line_and_col, b);
goto e_failed;
};
break;
@ -583,7 +587,8 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
if (top->type == json_integer || flags & flag_num_e) {
if (!(flags & flag_num_e)) {
if (flags & flag_num_zero) {
sprintf(error, "%u:%u: Unexpected `0` before `%c`", line_and_col, b);
snprintf(error, json_error_max, "%u:%u: Unexpected `0` before `%c`",
line_and_col, b);
goto e_failed;
}
@ -627,7 +632,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
json_int_t integer = top->u.integer;
if (!num_digits) {
sprintf(error, "%u:%u: Expected digit before `.`", line_and_col);
snprintf(error, json_error_max, "%u:%u: Expected digit before `.`", line_and_col);
goto e_failed;
}
@ -642,7 +647,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
if (!(flags & flag_num_e)) {
if (top->type == json_double) {
if (!num_digits) {
sprintf(error, "%u:%u: Expected digit after `.`", line_and_col);
snprintf(error, json_error_max, "%u:%u: Expected digit after `.`", line_and_col);
goto e_failed;
}
@ -665,7 +670,7 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
}
} else {
if (!num_digits) {
sprintf(error, "%u:%u: Expected digit after `e`", line_and_col);
snprintf(error, json_error_max, "%u:%u: Expected digit after `e`", line_and_col);
goto e_failed;
}
@ -731,23 +736,23 @@ json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t
return root;
e_unknown_value:
sprintf(error, "%u:%u: Unknown value", line_and_col);
snprintf(error, json_error_max, "%u:%u: Unknown value", line_and_col);
goto e_failed;
e_alloc_failure:
strcpy(error, "Memory allocation failure");
snprintf(error, json_error_max, "Memory allocation failure");
goto e_failed;
e_overflow:
sprintf(error, "%u:%u: Too long (caught overflow)", line_and_col);
snprintf(error, json_error_max, "%u:%u: Too long (caught overflow)", line_and_col);
goto e_failed;
e_failed:
if (error_buf) {
if (*error)
strcpy(error_buf, error);
memcpy(error_buf, error, json_error_max);
else
strcpy(error_buf, "Unknown error");
snprintf(error_buf, json_error_max, "Unknown error");
}
if (state.first_pass) alloc = root;

View File

@ -51,6 +51,9 @@ typedef struct pcpa {
// char* field_0x254;
pcp_parse_data_t recv_data;
pcp_send_data_t send_data;
// Our additions
pcpa_callback* before_cb;
} pcpa_t;
void pcpaClose(pcpa_t* stream);

View File

@ -0,0 +1,29 @@
unsigned int CRC_TABLE[256];
unsigned int CTC_TABLE_BUILT = 0;
#define CRC32_POLYNOMIAL 0xedb88320
void crc32_build_table() {
if (CTC_TABLE_BUILT) return;
CTC_TABLE_BUILT = 1;
for (int i = 0; i < 256; i++) {
unsigned int value = (~i & 1) - 1 & CRC32_POLYNOMIAL;
value = (((int)i >> 1 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
value = (((int)i >> 2 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
value = (((int)i >> 3 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
value = (((int)i >> 4 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
value = (((int)i >> 5 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
value = (((int)i >> 6 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
CRC_TABLE[i] = (((int)i >> 7 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
}
}
unsigned int crc32(int length, unsigned char *data, unsigned int initial) {
unsigned int value = ~initial;
while (length--) {
value = value >> 8 ^ CRC_TABLE[(*data ^ value) & 0xff];
data++;
}
return ~value;
}

View File

@ -0,0 +1,2 @@
void crc32_build_table();
unsigned int crc32(int length, unsigned char *data, unsigned int initial);

View File

@ -1,18 +1,17 @@
#include "exe.h"
#include "log.h"
bool inject_debug_wait(HANDLE process) {
BOOL present;
log_info(BOOT_LOGGER, "Waiting for debugger to attach.");
fprintf(stderr, "Waiting for debugger to attach.\n");
do {
Sleep(1000);
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
log_error(BOOT_LOGGER, "CheckRemoteDebuggerPresent failed: %03x", GetLastError());
fprintf(stderr, "Fatal: CheckRemoteDebuggerPresent failed: %03x\n", GetLastError());
return false;
}
} while (!present);
log_info(BOOT_LOGGER, "Debugger attached, resuming");
fprintf(stderr, "Debugger attached, resuming\n");
return true;
}
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) {
@ -20,33 +19,33 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) {
LPVOID arg_addr = VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (arg_addr == NULL) {
log_error(BOOT_LOGGER, "VirtualAllocEx failed: %03x", GetLastError());
fprintf(stderr, "Fatal: VirtualAllocEx failed: %03x\n", GetLastError());
return false;
}
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
log_error(BOOT_LOGGER, "WriteProcessMemory failed: %03x", GetLastError());
fprintf(stderr, "Fatal: WriteProcessMemory failed: %03x\n", GetLastError());
return false;
}
HANDLE remote_thread = CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
if (remote_thread == NULL) {
log_error(BOOT_LOGGER, "CreateRemoteThread failed: %03x", GetLastError());
fprintf(stderr, "Fatal: CreateRemoteThread failed: %03x\n", GetLastError());
return false;
}
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
log_error(BOOT_LOGGER, "WaitForSingleObject failed: %03x", GetLastError());
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
return false;
}
DWORD result;
if (FAILED(GetExitCodeThread(remote_thread, &result))) {
log_error(BOOT_LOGGER, "GetExitCodeThread failed: %03x", GetLastError());
fprintf(stderr, "Fatal: GetExitCodeThread failed: %03x\n", GetLastError());
return false;
}
if (result == 0) {
log_error(BOOT_LOGGER, "GetExitCodeThread failed: result == 0");
fprintf(stderr, "Fatal: GetExitCodeThread failed: result == 0\n");
return false;
}
@ -55,13 +54,13 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) {
bool inject_dll(HANDLE process, LPCSTR inject) {
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
if (kernel32 == NULL) {
log_error(BOOT_LOGGER, "GetModuleHandleA failed: %03x", GetLastError());
fprintf(stderr, "Fatal: GetModuleHandleA failed: %03x\n", GetLastError());
return false;
}
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
if (addr_LoadLibraryA == NULL) {
log_error(BOOT_LOGGER, "GetProcAddress failed: %03x", GetLastError());
fprintf(stderr, "Fatal: GetProcAddress failed: %03x\n", GetLastError());
return false;
}
@ -69,7 +68,6 @@ bool inject_dll(HANDLE process, LPCSTR inject) {
}
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) {
log_misc(BOOT_LOGGER, "Using %s for hooks", inject);
STARTUPINFOA startupInfo;
PROCESS_INFORMATION processInformation;
@ -83,14 +81,14 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) {
// Validate that we're not about to try something insane
DWORD found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
if (found == 0) {
log_error(BOOT_LOGGER, "Cannot inject %s: not found: %03x", inject, GetLastError());
fprintf(stderr, "Fatal: Cannot inject %s: not found: %03x\n", inject, GetLastError());
goto abort;
}
// Start the binary
if (FAILED(CreateProcessA(path, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo,
&processInformation))) {
log_error(BOOT_LOGGER, "CreateProcessA failed: %03x", GetLastError());
fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError());
goto abort;
}
@ -101,7 +99,7 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) {
// Injection completed, let the program continue execution
if (FAILED(ResumeThread(processInformation.hThread))) {
log_error(BOOT_LOGGER, "ResumeThread failed: %03x", GetLastError());
fprintf(stderr, "Fatal: ResumeThread failed: %03x\n", GetLastError());
goto abort;
}
@ -110,14 +108,14 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) {
abort:
if (processInformation.hProcess) {
if (FAILED(CloseHandle(processInformation.hThread)))
log_error(BOOT_LOGGER, "CloseHandle(hProcess) failed: %03x", GetLastError());
fprintf(stderr, "Fatal: CloseHandle(hProcess) failed: %03x\n", GetLastError());
if (FAILED(TerminateProcess(processInformation.hProcess, 1)))
log_error(BOOT_LOGGER, "TerminateProcess failed: %03x", GetLastError());
fprintf(stderr, "Fatal: TerminateProcess failed: %03x\n", GetLastError());
}
if (processInformation.hThread) {
if (FAILED(CloseHandle(processInformation.hThread)))
log_error(BOOT_LOGGER, "CloseHandle(hThread) failed: %03x", GetLastError());
fprintf(stderr, "Fatal: CloseHandle(hThread) failed: %03x\n", GetLastError());
}
return NULL;

View File

@ -1,5 +1,6 @@
#include <Windows.h>
#include <stdbool.h>
#include <stdio.h>
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay);

View File

@ -1,212 +0,0 @@
#include "log.h"
BOOL HAS_COLOUR = FALSE;
char _log_prelude[32];
char* log_prelude() {
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(_log_prelude, 32, "[%Y/%m/%d %H:%M:%S] ", timeinfo);
return _log_prelude;
}
HANDLE LOG_FILE = NULL;
VOID trace_hook(char* output);
CRITICAL_SECTION logger_lock;
int _do_log(const char* caller, const char* level, const char* format, va_list args, bool toStdout) {
EnterCriticalSection(&logger_lock);
int len = snprintf(NULL, 0, "%s%s:%s:", log_prelude(), level, caller) + vsnprintf(NULL, 0, format, args);
char* buf = (char*)malloc(len + 2);
if (!buf) {
LeaveCriticalSection(&logger_lock);
return 0;
}
int wrote_a = snprintf(buf, len, "%s%s:%s:", log_prelude(), level, caller);
int wrote_b = vsnprintf(buf + wrote_a, len - wrote_a + 1, format, args);
buf[len] = '\n';
buf[len + 1] = '\0';
// No +1 here to not get the \n
if (toStdout) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, len, NULL, NULL);
#ifdef LOG_TO_FILE
if (LOG_FILE && LOG_FILE != INVALID_HANDLE_VALUE) WriteFile(LOG_FILE, buf, len + 1, NULL, NULL);
#endif
free(buf);
LeaveCriticalSection(&logger_lock);
return wrote_b;
}
int vlog_misc(const char* caller, const char* format, va_list args) {
#ifdef LOG_MISC
if (HAS_COLOUR) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\033[90m", 5, NULL, NULL);
int ret = _do_log(caller, "M", format, args, true);
puts(HAS_COLOUR ? "\033[0m" : "");
return ret;
#else
return _do_log(caller, "M", format, args, false);
#endif
}
int log_misc(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_misc(caller, format, args);
va_end(args);
return ret;
}
int vlog_info(const char* caller, const char* format, va_list args) {
#ifdef LOG_INFO
if (HAS_COLOUR) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\033[97m", 5, NULL, NULL);
int ret = _do_log(caller, "I", format, args, true);
puts(HAS_COLOUR ? "\033[0m" : "");
return ret;
#else
return _do_log(caller, "I", format, args, false);
#endif
}
int log_info(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_info(caller, format, args);
va_end(args);
return ret;
}
int vlog_warning(const char* caller, const char* format, va_list args) {
#ifdef LOG_WARNING
if (HAS_COLOUR) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\033[33m", 5, NULL, NULL);
int ret = _do_log(caller, "W", format, args, true);
puts(HAS_COLOUR ? "\033[0m" : "");
return ret;
#else
return _do_log(caller, "W", format, args, false);
#endif
}
int log_warning(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_warning(caller, format, args);
va_end(args);
return ret;
}
int vlog_error(const char* caller, const char* format, va_list args) {
#ifdef LOG_ERROR
if (HAS_COLOUR) WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), "\033[91m", 5, NULL, NULL);
int ret = _do_log(caller, "E", format, args, true);
puts(HAS_COLOUR ? "\033[0m" : "");
return ret;
#else
return _do_log(caller, "E", format, args, false);
#endif
}
int log_error(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_error(caller, format, args);
va_end(args);
return ret;
}
// char format_buf[1024]; // Will do. We guard against overflow in
// Fake[f]printf int WINAPIV Fakeprintf(const char* _Format, ...) { int
// flen = strlen(_Format); if (flen == strcspn(_Format, "\n") + 1 && flen
// < (sizeof format_buf)) { strcpy_s(format_buf, flen, _Format);
// format_buf[flen - 1] = 0; _Format = format_buf;
// }
// va_list args;
// va_start(args, _Format);
// int ret = vlog_info("printf", _Format, args);
// va_end(args);
// return ret;
// };
// int WINAPIV Fakefprintf(FILE* _File, const char* _Format, ...) {
// int flen = strlen(_Format);
// if (flen == strcspn(_Format, "\n") + 1 && flen < (sizeof format_buf))
// { strcpy_s(format_buf, flen, _Format); format_buf[flen
// - 1] = 0; _Format = format_buf;
// }
// va_list args;
// va_start(args, _Format);
// int ret = vlog_error("fprintf", _Format, args);
// va_end(args);
// return ret;
// };
// int WINAPIV Fakefprintf_s(FILE* _Stream, const char* _Format, ...) {
// va_list args;
// va_start(args, _Format);
// int ret = vlog_error("fprintf_s", _Format, args);
// va_end(args);
// return ret;
// };
char* trim_string(char* string) {
size_t len = strlen(string) - 1;
DWORD oldProt;
while (len > 0 && (string[len] == '\n' || string[len] == '\r')) {
// TODO: Reassess this. Suspect it may be causing issues.
// Make sure we can write! This is a terrible hack, but it does work.
VirtualProtect(string + len, 1, PAGE_EXECUTE_READWRITE, &oldProt);
string[len--] = '\0';
VirtualProtect(string + len + 1, 1, oldProt, &oldProt);
}
return string;
}
HANDLE WINAPI FakeRegisterEventSourceA(LPCSTR lpUNCServerName, LPCSTR lpSourceName) { return (HANDLE)0xDEADBEEF; }
BOOL WINAPI FakeReportEventA(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid,
WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData) {
switch (wType) {
case EVENTLOG_SUCCESS:
case EVENTLOG_AUDIT_SUCCESS:
for (int i = 0; i < wNumStrings; i++) log_misc("evtlog", trim_string((char*)lpStrings[i]));
break;
case EVENTLOG_AUDIT_FAILURE:
case EVENTLOG_ERROR_TYPE:
for (int i = 0; i < wNumStrings; i++) log_error("evtlog", trim_string((char*)lpStrings[i]));
break;
case EVENTLOG_WARNING_TYPE:
for (int i = 0; i < wNumStrings; i++) log_warning("evtlog", trim_string((char*)lpStrings[i]));
break;
case EVENTLOG_INFORMATION_TYPE:
default:
for (int i = 0; i < wNumStrings; i++) log_info("evtlog", trim_string((char*)lpStrings[i]));
break;
}
return TRUE;
};
BOOL WINAPI FakeDeregisterEventSource(HANDLE hEventLog) { return TRUE; }
static VOID(WINAPI* TrueOutputDebugStringA)(LPCSTR lpOutputString);
VOID WINAPI FakeOutputDebugStringA(LPCSTR lpOutputString) { log_info("debug", "%s", lpOutputString); }
VOID trace_hook(char* output) {
output[strcspn(output, "\n")] = 0;
log_error("trace", output);
}
void setup_logging() {
// Enable colour in CMD
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
if (GetConsoleMode(hConsole, &dwMode))
HAS_COLOUR = SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
InitializeCriticalSection(&logger_lock);
if (LOG_FILE == NULL)
LOG_FILE = CreateFileA("log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA, &TrueRegisterEventSourceA);
hook("Advapi32.dll", "ReportEventA", FakeReportEventA, &TrueReportEventA);
hook("Advapi32.dll", "DeregisterEventSource", FakeDeregisterEventSource, &TrueDeregisterEventSource);
}

View File

@ -1,10 +1,10 @@
mice_lib = static_library(
'mice',
sources: [
'hook.c',
'log.c',
'exe.c',
'patch.c',
'crc.c',
'ringbuf.c',
],
link_with: [
json_lib,

View File

@ -1,5 +1,8 @@
#include "hook.h"
#include <Windows.h>
#include <stdlib.h>
#include "ioctl.h"
#include "log.h"
#include "exe.h"
#include "patch.h"
#include "crc.h"
#include "ringbuf.h"

View File

@ -1,5 +1,8 @@
#include "patch.h"
#include <stdlib.h>
#include <string.h>
bool fetch(json_value* object, char* name, json_value** value) {
if (object->type != json_object) return false;
for (size_t j = 0; j < object->u.object.length; j++) {
@ -47,9 +50,10 @@ void free_patches(patches_t* patches) {
}
json_value* load_json_from_file(char* path, char* error) {
FILE* fp = fopen(path, "r");
FILE* fp;
fopen_s(&fp, path, "r");
if (fp == NULL) {
if (error != NULL) sprintf(error, "Failed to open patch file");
if (error != NULL) snprintf(error, json_error_max, "Failed to open patch file");
return NULL;
}
@ -59,18 +63,18 @@ json_value* load_json_from_file(char* path, char* error) {
char* json_buf = (char*)malloc(sz);
if (json_buf == NULL) {
if (error != NULL) sprintf(error, "Failed to allocate file buffer");
if (error != NULL) snprintf(error, json_error_max, "Failed to allocate file buffer");
fclose(fp);
return NULL;
}
if (!(sz = fread(json_buf, 1, sz, fp))) {
if (error != NULL) sprintf(error, "Failed to read file");
if (error != NULL) snprintf(error, json_error_max, "Failed to read file");
fclose(fp);
return NULL;
};
fclose(fp);
json_settings settings = {0};
json_settings settings = { 0 };
return json_parse_ex(&settings, json_buf, sz, error);
}
@ -112,11 +116,11 @@ bool parse_patches(patches_t* patches, json_value** set_json, int set_count, cha
char load_error[json_error_max];
set_patches = load_json_from_file(patches_file_path, load_error);
if (set_patches == NULL) {
log_warning("patcher", "Failed to load '%s': %s", patches_file_path, load_error);
fprintf(stderr, "W: patcher: Failed to load '%s': %s\n", patches_file_path, load_error);
continue;
}
if (set_patches->type != json_array) {
log_warning("patcher", "Failed to load '%s': not an array", patches_file_path);
fprintf(stderr, "W: patcher: Failed to load '%s': not an array\n", patches_file_path);
continue;
}
} else {
@ -214,7 +218,7 @@ bool load_patches(patches_t* patches, char* path, char* error) {
loaded_patches = 1;
patches_json = &parsed;
} else {
sprintf(error, "Patch file format error");
snprintf(error, json_error_max, "Patch file format error");
json_value_free(parsed);
return false;
}

View File

@ -0,0 +1,58 @@
#include "ringbuf.h"
#include <memory.h>
void ringbuf_purge(ring_buffer_t* ring) {
ring->read = 0;
ring->write = 0;
}
short ringbuf_available(ring_buffer_t* ring) {
short populated = ring->write - ring->read;
if (populated < 0) populated += RING_BUFFER_SIZE;
return populated;
}
bool ringbuf_write(ring_buffer_t* ring, unsigned const char* data, short bytes) {
short unpopulated = ring->read - ring->write;
if (unpopulated < 0) unpopulated += RING_BUFFER_SIZE;
bool overflow = unpopulated < bytes;
while (bytes > 0) {
short chunk;
if (bytes + ring->write > RING_BUFFER_SIZE)
chunk = RING_BUFFER_SIZE - ring->write;
else
chunk = bytes;
memcpy(ring->buffer + ring->write, data, chunk);
data += chunk;
bytes -= chunk;
ring->write = (ring->write + chunk) % RING_BUFFER_SIZE;
}
return overflow;
}
short ringbuf_read(ring_buffer_t* ring, unsigned char* data, short bytes) {
short populated = ring->write - ring->read;
if (populated < 0) populated += RING_BUFFER_SIZE;
// Underflow
if (populated < bytes) bytes = populated;
short left = bytes;
while (left > 0) {
short chunk;
if (left + ring->read > RING_BUFFER_SIZE)
chunk = RING_BUFFER_SIZE - ring->read;
else
chunk = left;
memcpy(data, ring->buffer + ring->read, chunk);
data += chunk;
left -= chunk;
ring->read = (ring->read + chunk) % RING_BUFFER_SIZE;
}
return bytes;
}

View File

@ -0,0 +1,16 @@
#pragma once
#include <stdbool.h>
// We use shorts for indexes so the max allowed here is 0x7fff
#define RING_BUFFER_SIZE 2048
typedef struct ring_buffer {
unsigned char buffer[RING_BUFFER_SIZE];
short read;
short write;
} ring_buffer_t;
bool ringbuf_write(ring_buffer_t* ring, unsigned const char* data, short bytes);
short ringbuf_read(ring_buffer_t* ring, unsigned char* data, short bytes);
short ringbuf_available(ring_buffer_t* ring);
void ringbuf_purge(ring_buffer_t* ring);

View File

@ -1,3 +1,5 @@
#include <ctype.h>
unsigned char hex_value(char c) {
if (isdigit((unsigned char)c)) return c - '0';

View File

@ -4,3 +4,5 @@ subdir('micepatch')
subdir('micekeychip')
subdir('launcher')
subdir('dll')
subdir('micetest')

View File

@ -1,9 +1,8 @@
#include "../config.h"
#include "../lib/libpcp/libpcp.h"
#include "callbacks.h"
void mxkPcpAbGameId(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, AB_GAMEID, Config.appboot_gameid);
}
void mxkPcpAbGameId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, AB_GAMEID, Config.appboot_gameid); }
void mxkPcpAbSystemFlag(pcpa_t* stream, void* data) {
char sf[3];
snprintf(sf, 3, "%02X", Config.appboot_systemflag);
@ -11,17 +10,17 @@ void mxkPcpAbSystemFlag(pcpa_t* stream, void* data) {
}
void mxkPcpAbModelType(pcpa_t* stream, void* data) {
char mt[16];
snprintf(mt, 16, "%d", Config.appboot_modeltype);
snprintf(mt, 16, "%02X", Config.appboot_modeltype);
pcpaSetSendPacket(stream, AB_MODELTYPE, mt);
}
void mxkPcpAbFormatType(pcpa_t* stream, void* data) {
char ft[16];
snprintf(ft, 16, "%d", Config.appboot_formattype);
snprintf(ft, 16, "%02X", Config.appboot_formattype);
pcpaSetSendPacket(stream, AB_FORMATTYPE, ft);
}
void mxkPcpAbRegion(pcpa_t* stream, void* data) {
char rg[16];
snprintf(rg, 16, "%d", Config.appboot_region);
snprintf(rg, 16, "%02X", Config.appboot_region);
pcpaSetSendPacket(stream, AB_REGION, rg);
}
void mxkPcpAbPlatformId(pcpa_t* stream, void* data) {
@ -32,7 +31,7 @@ void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) {
}
void mxkPcpAbDvd(pcpa_t* stream, void* data) {
char dvd[16];
snprintf(dvd, 16, "%d", Config.appboot_dvdflag);
snprintf(dvd, 16, "%02X", Config.appboot_dvdflag);
pcpaSetSendPacket(stream, AB_DVD, dvd);
}
@ -41,7 +40,8 @@ byte SEED_BUF[SEED_BUF_MAX];
int SEED_BUF_LEN = 0;
void mxkPcpAbSeed(pcpa_t* stream, void* data) {
if (SEED_BUF_LEN == 0) {
FILE* fCert = fopen(Config.appboot_seed, "r");
FILE* fCert;
fopen_s(&fCert, Config.appboot_seed, "r");
if (fCert == NULL)
SEED_BUF_LEN = -1;
else {
@ -72,6 +72,6 @@ void mxkPcpAbSeed(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, AB_SEED, "0");
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16]; // todo: nicer lol
itoa(SEED_BUF_LEN, sSize, 10);
_itoa(SEED_BUF_LEN, sSize, 10);
pcpaAddSendPacket(stream, "size", sSize);
}

View File

@ -1,12 +1,9 @@
#include "../config.h"
#include "../lib/libpcp/libpcp.h"
#include "callbacks.h"
void mxkPcpPbKeyId(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, BIL_KEYID, Config.billing_keyid);
}
void mxkPcpPbMainId(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, BIL_MAINID, Config.billing_mainid);
}
void mxkPcpPbKeyId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_KEYID, Config.billing_keyid); }
void mxkPcpPbMainId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_MAINID, Config.billing_mainid); }
void mxkPcpPbPlayCount(pcpa_t* stream, void* data) {
char pc[9];
snprintf(pc, sizeof pc, "%08X", Config.billing_playcount);
@ -36,7 +33,8 @@ byte PUBKEY_BUF[PUBKEY_BUF_MAX];
int PUBKEY_LEN = 0;
void mxkPcpPbSignaturePubKey(pcpa_t* stream, void* data) {
if (PUBKEY_LEN == 0) {
FILE* fPubkey = fopen(Config.billing_pubkey, "r");
FILE* fPubkey;
fopen_s(&fPubkey, Config.billing_pubkey, "r");
if (fPubkey == NULL)
PUBKEY_LEN = -1;
else {
@ -76,7 +74,8 @@ byte CA_CERTIFICATION[CA_CERT_BUF_MAX];
int CA_CERT_LEN = 0;
void mxkPcpPbCaCertification(pcpa_t* stream, void* data) {
if (CA_CERT_LEN == 0) {
FILE* fCert = fopen(Config.billing_cacert, "r");
FILE* fCert;
fopen_s(&fCert, Config.billing_cacert, "r");
if (fCert == NULL)
CA_CERT_LEN = -1;
else {
@ -107,6 +106,6 @@ void mxkPcpPbCaCertification(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, BIL_CACERT, "0");
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16]; // todo: nicer lol
itoa(CA_CERT_LEN, sSize, 10);
_itoa(CA_CERT_LEN, sSize, 10);
pcpaAddSendPacket(stream, "size", sSize);
}

View File

@ -1,12 +1,12 @@
#include "callbacks.h"
void mxkPcpDsCompute(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, "code", "54");
}
void mxkPcpSsdProof(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, "code", "54");
}
void mxkPcpDsCompute(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, "code", "54"); }
void mxkPcpSsdProof(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, "code", "54"); }
void mxkPcpSsdHostProof(pcpa_t* stream, void* data) {}
void mkxPcpEncrypt(pcpa_t* stream, void* data) {}
void mxkPcpDecrypt(pcpa_t* stream, void* data) {}
void mxkPcpSetIv(pcpa_t* stream, void* data) {}
void mkxPcpEncrypt(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, KC_ENCRYPT, "B6787E941C3956EAC70095D6A91E635C");
}
void mxkPcpDecrypt(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, KC_DECRYPT, "68271898FB92ABFB49321FAF72F04FF1");
}
void mxkPcpSetIv(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, KC_SETIV, "1"); }

View File

@ -9,7 +9,8 @@ config_t Config = {
._keep_linter_happy = true};
void make_default_config() {
FILE *config_file = fopen(CONFIG_PATH, "w");
FILE *config_file;
fopen_s(&config_file, CONFIG_PATH, "w");
if (config_file == NULL) {
puts("Failed to create config file!");
return;
@ -21,10 +22,9 @@ void make_default_config() {
fprintf(config_file, "; (string) default = %s\n", default); \
fprintf(config_file, "%s = %s\n", #n, default);
#define CFG_bool(s, n, default, comment) \
if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \
fprintf(config_file, "; (bool) default = %s\n", \
default ? "true" : "false"); \
#define CFG_bool(s, n, default, comment) \
if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \
fprintf(config_file, "; (bool) default = %s\n", default ? "true" : "false"); \
fprintf(config_file, "%s = %s\n", #n, default ? "true" : "false");
#define CFG_int(s, n, default, comment) \
@ -32,10 +32,9 @@ void make_default_config() {
fprintf(config_file, "; (int) default = %d\n", default); \
fprintf(config_file, "%s = %d\n", #n, default);
#define CFG_hex(s, n, precision, default, comment) \
if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \
fprintf(config_file, "; (hex) default = %.*X\n", precision, \
0x##default); \
#define CFG_hex(s, n, precision, default, comment) \
if (strlen(comment) != 0) fprintf(config_file, "; %s\n", comment); \
fprintf(config_file, "; (hex) default = %.*X\n", precision, 0x##default); \
fprintf(config_file, "%s = %.*X\n", #n, precision, 0x##default);
#define SECTION(s, comment) \
@ -53,31 +52,26 @@ void make_default_config() {
fclose(config_file);
}
int handler(void *user, const char *section, const char *name,
const char *value) {
int handler(void *user, const char *section, const char *name, const char *value) {
config_t *cfg = (config_t *)user;
char *end;
if (false)
;
#define CFG_str(s, n, default, comment) \
else if (stricmp(section, #s) == 0 && stricmp(name, #n) == 0) \
cfg->s##_##n = strdup(value);
#define CFG_bool(s, n, default, comment) \
else if (stricmp(section, #s) == 0 && stricmp(name, #n) == 0) \
cfg->s##_##n = strcmp(value, "true") == 0;
#define CFG_int(s, n, default, comment) \
else if (stricmp(section, #s) == 0 && stricmp(name, #n) == 0) { \
cfg->s##_##n = strtol(value, &end, 10); \
if (end == value || *end != '\0' || errno == ERANGE) \
cfg->s##_##n = default; \
#define CFG_str(s, n, default, comment) \
else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) cfg->s##_##n = _strdup(value);
#define CFG_bool(s, n, default, comment) \
else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) cfg->s##_##n = strcmp(value, "true") == 0;
#define CFG_int(s, n, default, comment) \
else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \
cfg->s##_##n = strtol(value, &end, 10); \
if (end == value || *end != '\0' || errno == ERANGE) cfg->s##_##n = default; \
}
#define CFG_hex(s, n, precision, default, comment) \
else if (stricmp(section, #s) == 0 && stricmp(name, #n) == 0) { \
cfg->s##_##n = strtol(value, &end, 16); \
if (end == value || *end != '\0' || errno == ERANGE) \
cfg->s##_##n = 0x##default; \
#define CFG_hex(s, n, precision, default, comment) \
else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \
cfg->s##_##n = strtol(value, &end, 16); \
if (end == value || *end != '\0' || errno == ERANGE) cfg->s##_##n = 0x##default; \
}
#include "config.def"
@ -86,15 +80,12 @@ int handler(void *user, const char *section, const char *name,
}
void load_config() {
if (ini_parse(CONFIG_PATH, handler, &Config) < 0)
printf("Can't load '%s', using defaults\n", CONFIG_PATH);
if (ini_parse(CONFIG_PATH, handler, &Config) < 0) printf("Can't load '%s', using defaults\n", CONFIG_PATH);
}
int main() {
DWORD dwAttrib = GetFileAttributes(CONFIG_PATH);
if (dwAttrib == INVALID_FILE_ATTRIBUTES ||
(dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
make_default_config();
if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) make_default_config();
load_config();

View File

@ -13,7 +13,7 @@ endif
rc = import('windows').compile_resources('micekeychip.rc', depend_files: micekeychip_ico)
executable(
'micekeychip',
win_subsystem: 'console',
win_subsystem: subsystem,
sources: [
'main.c',
'mxk.c',

View File

@ -7,16 +7,13 @@ pcpa_cb_table_t CALLBACK_FUNCTION_BUFFER[40];
byte BINARY_DATA[4096];
size_t BINARY_DATA_LEN;
void mxkBinaryCallback(pcpa_t* stream, void* data) {
pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
}
void mxkBinaryCallback(pcpa_t* stream, void* data) { pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); }
int mxkInit() {
// Enable colour
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
if (GetConsoleMode(hConsole, &dwMode))
SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
if (GetConsoleMode(hConsole, &dwMode)) SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
WSADATA wsaData;
int err = WSAStartup(2, &wsaData);
@ -24,9 +21,19 @@ int mxkInit() {
return err;
}
void log_callback(struct pcpa* stream, void* data) {
FILE* log_file = fopen("pcp.log", "a");
if (log_file != NULL) {
fprintf(log_file, "%s\n", (char*)data);
fclose(log_file);
}
}
e_pcpa_t mxkPcpStreamInit() {
e_pcpa_t err;
PCP.before_cb = log_callback;
err = pcpaInitStream(&PCP);
if (err != e_pcpa_ok) {
printf("pcpaInitStream Error. Code:%d\n", err);
@ -34,8 +41,7 @@ e_pcpa_t mxkPcpStreamInit() {
}
err = pcpaSetCallbackFuncBuffer(&PCP, CALLBACK_FUNCTION_BUFFER,
(sizeof CALLBACK_FUNCTION_BUFFER) /
(sizeof CALLBACK_FUNCTION_BUFFER[0]));
(sizeof CALLBACK_FUNCTION_BUFFER) / (sizeof CALLBACK_FUNCTION_BUFFER[0]));
if (err != e_pcpa_ok) {
printf("pcpaSetCallBackFuncBuffer Error. Code:%d\n", err);
return err;
@ -58,8 +64,7 @@ e_pcpa_t mxkPcpStreamInit() {
pcpaSetCallbackFunc(&PCP, AB_FORMATTYPE, mxkPcpAbFormatType, NULL);
pcpaSetCallbackFunc(&PCP, AB_REGION, mxkPcpAbRegion, NULL);
pcpaSetCallbackFunc(&PCP, AB_PLATFORMID, mxkPcpAbPlatformId, NULL);
pcpaSetCallbackFunc(&PCP, AB_NETWORKADDRESS, mxkPcpAbNetworkAddress,
NULL);
pcpaSetCallbackFunc(&PCP, AB_NETWORKADDRESS, mxkPcpAbNetworkAddress, NULL);
pcpaSetCallbackFunc(&PCP, AB_DVD, mxkPcpAbDvd, NULL);
pcpaSetCallbackFunc(&PCP, AB_SEED, mxkPcpAbSeed, NULL);
// Billing
@ -101,21 +106,20 @@ e_pcpa_t mxkPcpStreamInit() {
}
int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_1;
err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port, binary_port,
300000);
err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port & 0xffff, binary_port & 0xffff, 300000);
if (err != e_pcpa_ok && err != e_pcpa_to) {
printf("pcpaOpenServerWithBinary Error. Code %d\n", err);
return e_pcpa_not_open;
}
if (open_mode == OPEN_MODE_GLOBAL)
printf("Listening on 0.0.0.0:%d (:%d)\n", text_port, binary_port);
printf("Listening on 0.0.0.0:%d (:%d)\n", text_port & 0xffff, binary_port & 0xffff);
else
printf("Listening on 127.0.0.1:%d (:%d)\n", text_port, binary_port);
printf("Listening on 127.0.0.1:%d (:%d)\n", text_port & 0xffff, binary_port & 0xffff);
return e_pcpa_ok;
}
#define TICK_MS 16
#define PRINT_DEBUG
// #define PRINT_DEBUG
#ifdef PRINT_DEBUG
// Larger TICK_MS for testing
#undef TICK_MS

View File

@ -19,7 +19,8 @@ void print_patches(patches_t* patches, char* filename) {
}
void apply_patches(patches_t* patches, char* filename) {
FILE* fp = fopen(filename, "r+b");
FILE* fp;
fopen_s(&fp, filename, "r+b");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s for modification\n", filename);
return;
@ -98,7 +99,7 @@ int main(int argc, char** argv) {
char error[json_error_max];
patches_t all_patches;
if (!load_patches(&all_patches, argv[1], error)) {
fprintf(stderr, "%s", error);
fprintf(stderr, "%s\n", error);
return -1;
}

View File

@ -1,7 +1,7 @@
rc = import('windows').compile_resources('micepatch.rc', depend_files: micepatch_ico)
micepatch = executable(
'micepatch',
win_subsystem: 'console',
win_subsystem: subsystem,
sources: [
'main.c',
rc,

View File

@ -0,0 +1,6 @@
#include "stdio.h"
int main() {
puts("Hello world");
return 0;
}

View File

@ -0,0 +1,7 @@
executable(
'micetest',
win_subsystem: subsystem,
sources: [
'main.c',
],
)