Quite a lot has happened; I lose track

This commit is contained in:
Bottersnike 2022-10-30 17:33:02 +00:00
parent 4464d9188f
commit f02db82030
88 changed files with 11499 additions and 5405 deletions

15
.gitignore vendored
View File

@ -1,10 +1,5 @@
dist/
build/
builddir/
srcdir/
.vscode/
# Don't distribute the libpcp sources
src/micetools/lib/libpcp/*.c
# And keep build artifacts out of git!
src/libpcp.lib
dist/
build/
builddir/
srcdir/
.vscode/

142
Makefile
View File

@ -1,63 +1,79 @@
BUILD_DIR := build
BUILD_DIR_32 := $(BUILD_DIR)/build32
BUILD_DIR_64 := $(BUILD_DIR)/build64
DIST_DIR := dist
BUILD_DRIVE := M:
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
.ONESHELL:
.PHONY: all
all: mice86 dist
mice86:
-@subst $(BUILD_DRIVE) .
@cd /D $(BUILD_DRIVE) \
& $(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
mice64:
-@subst $(BUILD_DRIVE) .
@cd $(BUILD_DRIVE) \
& $(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
.PHONY: clean
clean:
@del /S /F /Q $(BUILD_DIR)
@rmdir /S /Q $(BUILD_DIR)
@del /S /F /Q $(DIST_DIR)
@rmdir /S /Q $(DIST_DIR)
.PHONY: dist
dist:
@-mkdir $(DIST_DIR)
@copy /Y "$(BUILD_DIR_32)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/micepatch\micepatch.exe" "$(DIST_DIR)/micepatch.exe"
@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"
@xcopy /E /H /C /R /Q /Y src\system "$(DIST_DIR)\system/*"
@xcopy /E /H /C /R /Q /Y src\tools "$(DIST_DIR)\tools/*"
@xcopy /E /H /C /R /Q /Y src\patches "$(DIST_DIR)\patches/*"
BUILD_DIR := build
BUILD_DIR_32 := $(BUILD_DIR)/build32
BUILD_DIR_64 := $(BUILD_DIR)/build64
DIST_DIR := dist
BUILD_DRIVE := M:
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
.ONESHELL:
.PHONY: all
all: mice86 dist
mice86:
-@subst $(BUILD_DRIVE) .
@cd /D $(BUILD_DRIVE) \
& $(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
mice64:
-@subst $(BUILD_DRIVE) .
@cd $(BUILD_DRIVE) \
& $(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
.PHONY: clean
clean:
@del /S /F /Q $(BUILD_DIR)
@rmdir /S /Q $(BUILD_DIR)
@del /S /F /Q $(DIST_DIR)
@rmdir /S /Q $(DIST_DIR)
.PHONY: dist
dist:
@-mkdir $(DIST_DIR) > NUL 2>&1
@-mkdir $(DIST_DIR)\util > NUL 2>&1
@-mkdir $(DIST_DIR)\Execute > NUL 2>&1
@-mkdir $(DIST_DIR)\Execute\Z > NUL 2>&1
@-mkdir $(DIST_DIR)\Execute\S > NUL 2>&1
@copy /Y "$(BUILD_DIR_32)/src/micetools/micekeychip\micekeychip.exe" "$(DIST_DIR)/micekeychip.exe"
@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"
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\miceprestartup.exe" "$(DIST_DIR)/Execute/miceprestartup.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\micestartup.exe" "$(DIST_DIR)/Execute/micestartup.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\TrueCrypt.exe" "$(DIST_DIR)/Execute/TrueCrypt.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/miceboot\mxmaster.exe" "$(DIST_DIR)/Execute/S/mxmaster.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/micepatch\micepatch.exe" "$(DIST_DIR)/util/micepatch.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micedump.exe" "$(DIST_DIR)/util/micedump.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micetinker.exe" "$(DIST_DIR)/util/micetinker.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micemonitor.exe" "$(DIST_DIR)/util/micemonitor.exe"
@copy /Y "src/micetools/miceboot\TrueCrypt.cmd" "$(DIST_DIR)/Execute/TrueCrypt.cmd"
@xcopy /E /H /C /R /Q /Y src\system "$(DIST_DIR)\system/*"
@xcopy /E /H /C /R /Q /Y src\tools "$(DIST_DIR)\tools/*"
@xcopy /E /H /C /R /Q /Y src\patches "$(DIST_DIR)\patches/*"

62
assert_dd_blocks.py Normal file
View File

@ -0,0 +1,62 @@
MBR_LBA_GAP = 0x3f
BOOT_PARITION_SIZE = 0x300B85
RECOVER_PARTITION_SIZE = 0x300BC4
partitions = [
0x102d83,
0x403947,
0x403947,
0x48ed459,
0x20014aa,
]
ext_offset = 0
offsets = [0] * len(partitions)
extended_base = MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE
for i in range(len(partitions)):
offsets[i] = ext_offset + extended_base
ext_offset += partitions[i] + MBR_LBA_GAP
# (Start, end, data)
accounted_for = [
(0, 1, True), # MBR
(1, MBR_LBA_GAP, False),
(MBR_LBA_GAP, MBR_LBA_GAP + BOOT_PARITION_SIZE, True),
(MBR_LBA_GAP + BOOT_PARITION_SIZE, MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE, True),
]
for n, (i, j) in enumerate(zip(offsets, partitions)):
accounted_for.append((
i, i + 1, True
))
if n == 0:
# SBR
accounted_for.append((
i + 1, i + 4, True
))
accounted_for.append((
i + 4, i + MBR_LBA_GAP, False
))
else:
accounted_for.append((
i + 1, i + MBR_LBA_GAP, False
))
accounted_for.append((
i + MBR_LBA_GAP, i + MBR_LBA_GAP + j, True
))
assert accounted_for[-1][1] == 0x77fa1d7
last = 0
for i in accounted_for:
assert i[0] == last
last = i[1]
with open(r"G:\finale_dd\finale_dd.img", "rb") as finale_dd:
for i in accounted_for:
if i[2]:
continue
nbytes = i[1] - i[0]
finale_dd.seek(i[0] * 512)
print(f"Checking at {i[0] * 512:012x}-{i[1] * 512:012x}")
if any(finale_dd.read(nbytes * 512)):
print("!! FAIL")

View File

@ -1,30 +1,46 @@
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
language: 'c',
)
if winxp
add_project_arguments(
'/D_USING_V140_SDK71_',
'/DSFML_STATIC',
'/DYNAMICBASE:NO',
language: 'c',
)
endif
subdir('assets')
subdir('src')
project('micetools', 'c', default_options: [
'buildtype=minsize',
# ! Toggle /\ and \/ when building for XP (minsize=normal, static=XP)
# 'b_vscrt=static_from_buildtype',
'warning_level=3',
])
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
'/wd4706', # assignment within conditional expression
'/wd4214', # windns.h: nonstandard extension used: bit field types other than int
'/wd4201', # ewfapi.h: nameless struct/union
'/wd4200', # zero-sized arrays
'/wd4152', # hooks: function/data pointer conversion in expression
'/wd4100', # basically every hook causes "unreferenced formal parameter"
'/wd4206', # empty C files
'/wd4189', # lots of keychip functions aren't 100% implemented yet
'/we4047', # ... differs in levels of indirection from ...
'/we4057', # ... differs in levels of indirection (slightly) from ...
'/we4024', # ... different types for formal and actual paramter ...
'/we4013', # ... undefined; assuming extern returning int
language: 'c',
)
if winxp
add_project_arguments(
'/D_USING_V140_SDK71_',
'/DSFML_STATIC',
'/DYNAMICBASE:NO',
language: 'c',
)
endif
subdir('assets')
subdir('src')

159
mxinstaller.py Normal file
View File

@ -0,0 +1,159 @@
from pprint import pformat, pprint
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 12121))
slots = [
"original0",
"original1",
"patch0",
"patch1",
"os",
"app_data",
"originalf",
"originalb",
"patchf",
"patchb",
]
"""
slot 0: OS
os result=success&status=complete&id=AAS0&version=4524545&time=00000000000000&segcount=1745&segsize=262144&hw=AAS&instant=0&osver=4524545&ossegcount=0&orgtime=00000000000000&orgversion=4524545
slot 1: original0
original0 result=success&status=complete&id=SDEY&version=65633&time=20181029150736&segcount=65082&segsize=262144&hw=AAS&instant=0&osver=4524545&ossegcount=1745&orgtime=20181029150736&orgversion=65633
slot 2: ??
slot 3: ??
slot 4: ??
original1 result=error&status=error&code=40
patch0 result=success&status=empty
patch1 result=success&status=complete&id=SDEY&version=65634&time=20181116190448&segcount=173&segsize=262144&hw=AAS&instant=0&osver=0&ossegcount=0&orgtime=20181029150736&orgversion=65633
app_data result=invalid_parameter
originalf result=success&status=complete&id=SDEY&version=65633&time=20181029150736&segcount=65082&segsize=262144&hw=AAS&instant=0&osver=4524545&ossegcount=1745&orgtime=20181029150736&orgversion=65633
originalb result=error&status=error&code=40
patchf result=success&status=complete&id=SDEY&version=65634&time=20181116190448&segcount=173&segsize=262144&hw=AAS&instant=0&osver=0&ossegcount=0&orgtime=20181029150736&orgversion=65633
patchb result=success&status=empty
"""
def recv_pcp():
resp = s.recv(4096).decode().strip()
if resp == "?":
raise Exception("PCP Failed")
parts = resp.split("&")
return {i.split("=")[0]: i.split("=")[1] for i in parts}
def send_pcp(request, **kwargs):
req = f"request={request}"
if kwargs:
req += "&" + "&".join(f"{i}={kwargs[i]}" for i in kwargs)
assert s.recv(4096) == b">"
s.send(req.encode() + b"\r\n")
def pcp(request, **kwargs):
send_pcp(request, **kwargs)
ret = recv_pcp()
if ret["result"] != "success" or ret["response"] != request:
raise Exception(f"PCP Failed:\n{pformat(ret)}")
del ret["response"]
del ret["result"]
return ret
print("Query slots:")
for slot in slots:
assert s.recv(4096) == b">"
s.send(f"request=query_slot_status&slot={slot}\r\n".encode())
print(slot.ljust(20), s.recv(4096).decode().strip())
# assert s.recv(4096) == b">"
# s.send(f"request=check&slot={slot}\r\n".encode())
# print(slot.ljust(20), s.recv(4096).decode().strip())
print("-" * 10)
if pcp("query_semaphore_status")["semaphore"] != "1":
print("Unable to get semaphore!")
quit()
gsem = pcp("get_semaphore")
semid = gsem["semid"]
try:
spd = pcp("query_spd")
br = pcp("query_br")
bootslot = pcp("query_sbr_bootslot")
print("=== SPD ===")
order = spd.pop("order")
print(f"--- Order: {order}")
spd = list(spd.items())
spd.sort(key=lambda x: int(x[1]))
for i in spd:
# Values here are uk3 * block_size
print(f" - {(i[0] + ':').ljust(10)} {int(i[1]):016x}")
print(f"--- Bootslot: {bootslot['bootslot']}")
print("=== BR ===")
pprint(br)
quit()
assert s.recv(4096) == b">"
s.send((
b"request=check&"
b"slot=original0&"
b"segoffset=0&"
b"segcount=100000&"
b"force=1&"
b"semid=" + sem + b""
b"\r\n"
))
print(s.recv(4096).decode().strip())
assert s.recv(4096) == b">"
s.send((
b"request=release_semaphore&"
b"semid=" + sem + b""
b"\r\n"
))
print(s.recv(4096).decode().strip())
quit()
# assert s.recv(4096) == b">"
# s.send(b"request=set_sbr_bootslot&bootslot=cd\r\n")
# print(s.recv(4096).decode().strip())
assert s.recv(4096) == b">"
s.send(b"request=query_application_status\r\n")
print(s.recv(4096).decode().strip())
assert s.recv(4096) == b">"
s.send(b"request=query_br\r\n")
print(s.recv(4096).decode().strip())
assert s.recv(4096) == b">"
s.send((
b"request=appdata&"
b"slot=os&"
b"semid=" + sem + b"&"
b"\r\n"
))
# s.send((
# b"request=install&"
# b"slot=patch0&"
# b"segoffset=3&"
# b"id=SDEY&"
# b"version=010061&"
# b"time=20181029150736&"
# b"segcount=fe3a&"
# b"segsize=040000&"
# b"hw=AAS&"
# b"instant=3&"
# b"osver=450a01&"
# b"ossegcount=06d1&"
# b"orgtime=20181029150736&"
# b"orgversion=10061&"
# b"semid=" + sem + b"&"
# b"\r\n"
# ))
print(s.recv(4096).decode().strip())
finally:
pcp("release_semaphore", semid=semid)

View File

@ -1,116 +1,191 @@
#include "comdevice.h"
BOOL DevGetCommState(void* data, LPDCB lpDCB) { return TRUE; }
BOOL DevSetCommState(void* data, LPDCB lpDCB) { return TRUE; }
BOOL DevGetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
BOOL DevSetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
BOOL DevSetupComm(void* data, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
BOOL DevPurgeComm(void* data, DWORD dwFlags) {
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&((com_device_t*)data)->out);
return TRUE;
}
BOOL DevGetCommModemStatus(void* data, LPDWORD lpModelStat) {
// TODO: JVS SENSE
return TRUE;
}
BOOL DevWaitCommEvent(void* data, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
WaitForSingleObject(((com_device_t*)data)->event, INFINITE);
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
return TRUE;
}
BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) {
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;
com->GetCommTimeouts = DevGetCommTimeouts;
com->SetCommTimeouts = DevSetCommTimeouts;
com->SetupComm = DevSetupComm;
com->PurgeComm = DevPurgeComm;
com->GetCommModemStatus = DevGetCommModemStatus;
com->WaitCommEvent = DevWaitCommEvent;
com->ClearCommError = DevClearCommError;
file->ReadFile = DevReadFile;
file->WriteFile = DevWriteFile;
ringbuf_purge(&hook->in);
ringbuf_purge(&hook->out);
hook->event = CreateEventW(NULL, TRUE, FALSE, hook->com->wName);
hook_file(file);
hook_com(com);
free(com->virtual_handle);
com->virtual_handle = file->virtual_handle;
return hook;
}
#include "comdevice.h"
BOOL DevGetCommState(void* data, LPDCB lpDCB) { return TRUE; }
BOOL DevSetCommState(void* data, LPDCB lpDCB) { return TRUE; }
BOOL DevGetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
BOOL DevSetCommTimeouts(void* data, LPCOMMTIMEOUTS lpCommTimeouts) { return TRUE; }
BOOL DevSetupComm(void* data, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
BOOL DevPurgeComm(void* data, DWORD dwFlags) {
if (dwFlags & PURGE_RXCLEAR) ringbuf_purge(&((com_device_t*)data)->out);
return TRUE;
}
BOOL DevGetCommModemStatus(void* data, LPDWORD lpModelStat) {
// TODO: JVS SENSE
return TRUE;
}
BOOL DevWaitCommEvent(void* data, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
WaitForSingleObject(((com_device_t*)data)->event, INFINITE);
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
return TRUE;
}
BOOL DevClearCommError(void* data, LPDWORD lpErrors, LPCOMSTAT lpStat) {
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 ", ((LPBYTE)lpBuffer)[i]);
// }
// puts("");
}
return TRUE;
}
short comdev_read_blocking(com_device_t* com, unsigned char* buffer, short bytes) {
while (comdev_available(com) < bytes) SwitchToThread();
return ringbuf_read(&com->in, buffer, bytes);
}
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, const 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); }
BYTE comdev_peek(com_device_t* com) { return com->in.buffer[com->in.read]; }
BYTE one_byte;
// Read data from a com device, unescaping as we go
void comio_read(com_device_t* com, BYTE* data, BYTE len) {
for (; len; len--) {
comdev_read_blocking(com, &one_byte, 1);
if (one_byte == COMIO_MARK) {
comdev_read_blocking(com, &one_byte, 1);
one_byte++;
}
*(data++) = one_byte;
}
}
// Write data to a com device, escaping as we go
void comio_write(com_device_t* com, BYTE* data, BYTE len) {
for (; len; len--) {
one_byte = *(data++);
if (one_byte == COMIO_MARK || one_byte == COMIO_SYNC) {
BYTE mark = COMIO_MARK;
comdev_write(com, &mark, 1);
one_byte--;
}
comdev_write(com, &one_byte, 1);
}
}
void comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data) {
do {
if (comdev_available(com) < (sizeof *head + 1)) {
SwitchToThread();
continue;
}
comdev_read(com, &one_byte, 1);
if (one_byte != COMIO_SYNC) {
log_error("com", "Garbage on JVS: %02x", one_byte);
continue;
}
break;
} while (1);
comio_read(com, (LPBYTE)head, sizeof *head);
// TODO: Validate the sum? Do we care really?
comio_read(com, data, head->length);
unsigned char sum;
comio_read(com, &sum, 1);
}
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len,
BYTE* data) {
one_byte = COMIO_SYNC;
comdev_write(com, &one_byte, 1);
comio_resp_head_t resp = {
.frame_length = len + sizeof resp,
.src = req->dst,
.seq = req->seq,
.status = status,
.op = req->op,
.length = len,
};
// Header
comio_write(com, (LPBYTE)&resp, sizeof resp);
// Payload
if (len) // If len == 0, we allow data to be null
comio_write(com, data, len);
// Checksum
one_byte = 0;
for (BYTE i = 0; i < sizeof resp; i++)
one_byte += ((LPBYTE)&resp)[i];
for (BYTE i = 0; i < len; i++)
one_byte += data[i];
comio_write(com, &one_byte, 1);
}
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;
com->GetCommTimeouts = DevGetCommTimeouts;
com->SetCommTimeouts = DevSetCommTimeouts;
com->SetupComm = DevSetupComm;
com->PurgeComm = DevPurgeComm;
com->GetCommModemStatus = DevGetCommModemStatus;
com->WaitCommEvent = DevWaitCommEvent;
com->ClearCommError = DevClearCommError;
file->ReadFile = DevReadFile;
file->WriteFile = DevWriteFile;
ringbuf_purge(&hook->in);
ringbuf_purge(&hook->out);
hook->event = CreateEventW(NULL, TRUE, FALSE, hook->com->wName);
hook_file(file);
hook_com(com);
return hook;
}

View File

@ -1,23 +1,54 @@
#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;
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);
#pragma once
#include "common.h"
#include "hooks/com.h"
#include "hooks/files.h"
typedef struct com_device {
com_hook_t* com;
file_hook_t* file;
ring_buffer_t in;
ring_buffer_t out;
HANDLE event;
HANDLE thread;
} com_device_t;
typedef struct {
BYTE frame_length;
BYTE dst;
BYTE seq;
BYTE op;
BYTE length;
} comio_recv_head_t;
typedef struct {
BYTE frame_length;
BYTE src;
BYTE seq;
BYTE op;
BYTE status;
BYTE length;
} comio_resp_head_t;
#define COMIO_SYNC 0xE0
#define COMIO_MARK 0xD0
#define COMIO_STATUS_OK 0
#define COMIO_STATUS_NG 1
typedef DWORD(WINAPI FnComDeviceThread)(com_device_t* com);
short comdev_read_blocking(com_device_t* com, unsigned char* buffer, short bytes);
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes);
bool comdev_write(com_device_t* com, const unsigned char* buffer, short bytes);
short comdev_available(com_device_t* com);
BYTE comdev_peek(com_device_t* com);
void comio_read(com_device_t* com, BYTE* data, BYTE len);
void comio_write(com_device_t* com, BYTE* data, BYTE len);
void comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data);
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len, BYTE* data);
void com_device_thread(com_device_t* com, FnComDeviceThread* thread);
com_device_t* new_com_device(BYTE port);

View File

@ -1,24 +1,25 @@
#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"
#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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "../lib/mice/mice.h"
#include "./util/_util.h"

View File

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

View File

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

View File

@ -0,0 +1,90 @@
#include "_devices.h"
static BYTE read_one(com_device_t* dev) {
while (!comdev_available(dev)) Sleep(50);
BYTE data;
comdev_read(dev, &data, 1);
return data;
}
BYTE extra[0xff];
#define GetFWVersion 0x30
#define GetHWVersion 0x32
#define RadioOn 0x40
#define RadioOff 0x41
#define Poll 0x2
#define MifareSelectTag 0x43
#define Unknown1 0x44 // Present in code, not seen used
#define SetKeyBana 0x50
#define Unknown2 0x51 // Present in code, not seen used
#define ReadBlock 0x52
#define SetKeyAime 0x54
#define Authenticate 0x55
#define Unknown3 0x60 // Present in code, not seen used
#define Unknown4 0x61 // Present in code, not seen used
#define Reset 0x62
#define Unknown5 0x70 // Present in code, not seen used
#define FelicaEncap 0x71
#define LedReset 0xf5
#define LedGetInfo 0xf0
#define LedSetColour 0x81
#define FWVer "TN32MSEC003S F/W Ver1.2"
#define HWVer "TN32MSEC003S H/W Ver3.0"
DWORD WINAPI aime_bd_thread(com_device_t* dev) {
log_warning("aime_bd", "%ls woke up", dev->com->wName);
while (1) {
comio_recv_head_t req;
comio_next_req(dev, &req, extra);
log_info("aime_bd", "(%d) %02x", req.dst, req.op);
if (req.dst == 0x00 || req.dst == 0x01) {
// Aime readers
switch (req.op) {
case Reset:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case GetFWVersion:
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof FWVer - 1, (LPBYTE)FWVer);
break;
case GetHWVersion:
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof HWVer - 1, (LPBYTE)HWVer);
break;
case SetKeyAime:
log_info("aime_bd", "Aime key: %.*s", req.length, extra);
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case SetKeyBana:
log_info("aime_bd", "Bana key: %.*s", req.length, extra);
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
}
} else if (req.dst == 0x08 || req.dst == 0x09) {
// LED sub-boards
switch (req.op) {
case LedReset:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case LedGetInfo:
// TODO: I'm not sure what this actually means.
// 838-15084 is probably a part number
comio_reply(dev, &req, COMIO_STATUS_OK, 9, (BYTE*)"15084\xff\x10\x00\x12");
break;
case LedSetColour:
// No response expected here!
break;
}
}
Sleep(50);
}
}
void install_aime_bd() {
com_device_t* aime = new_com_device(2);
com_device_thread(aime, aime_bd_thread);
}

View File

@ -1,225 +1,222 @@
#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);
}
#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;
BYTE extra[0xff];
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, (unsigned char*)&head, sizeof head);
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, (unsigned char*)"\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, (unsigned char*)"\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, (unsigned char*)"\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, (unsigned char*)"\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, (unsigned char*)"\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, (unsigned char*)"\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, (unsigned char*)"\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, (unsigned char*)"\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, (unsigned char*)"\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, (unsigned char*)"\xe0\x01\x11\x04\x01\x7c\x01\x00\x94", 9);
// \/ causes 7b to be used
// comdev_write(dev, (unsigned char*)"\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, (unsigned char*)"\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;
}
}
}
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 = (int)(rect.right * positions[i][0]);
int y = (int)(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

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

View File

@ -1,84 +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);
}
#include "_devices.h"
static BYTE read_one(com_device_t* dev) {
while (!comdev_available(dev)) Sleep(50);
BYTE data;
comdev_read(dev, &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, (unsigned char*)"(@@@@@@@@@@@@)", 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,86 +1,95 @@
#include "common.h"
#include "devices/_devices.h"
#include "drivers/mx.h"
#include "hooks/_hooks.h"
WCHAR exePath[MAX_PATH + 1];
void enable_traces() {
patches_t patches;
char error[256];
if (!load_patches(&patches, "patches.json", error)) {
log_error(BOOT_LOGGER, "Failed to load patches file: %s", error);
} else {
char exePathC[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL);
for (size_t i = 0; i < patches.nopatchsets; i++) {
patchset_t* patchset = patches.patchsets[i];
// Require the binary explicitly named
if (patchset->binary_name == NULL || strcmp(patchset->binary_name, exePathC) != 0) {
continue;
}
if (!patchset->apply) continue;
for (size_t j = 0; j < patchset->nopatches; j++) {
patch_t patch = patchset->patches[j];
if (memcmp(patch.from, (void*)patch.offset, patch.count) != 0) {
log_error(BOOT_LOGGER, "Patch %s[%d] failed! from-value missmatch", patchset->name, j);
continue;
}
memcpy((void*)patch.offset, patch.to, patch.count);
log_misc(BOOT_LOGGER, "Patched %d bytes at %08x", patch.count, patch.offset);
}
}
}
free_patches(&patches);
}
void prebind_hooks() {
hook_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() {
// We're in a new context now, so need to reconfigure
setup_logging();
log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exePath);
enable_traces();
setup_columba();
setup_mxsram();
setup_mxsuperio();
setup_mxjvs();
setup_mxhwreset();
setup_mxsmbus();
if (!add_fake_device(&PLATFORM_GUID, L"\\\\.\\platform")) {
log_error("platform", "failed to install platform device");
}
// Must be the last thing called!
// register_devices();
prebind_hooks();
setup_hooks();
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
GetModuleFileNameW(NULL, exePath, MAX_PATH);
wcscpy_s(exePath, MAX_PATH + 1, PathFindFileNameW(exePath));
init_injection();
return TRUE;
}
#include "common.h"
#include "devices/_devices.h"
#include "drivers/mx.h"
#include "hooks/_hooks.h"
WCHAR exePath[MAX_PATH + 1];
void enable_traces() {
patches_t patches;
char error[256];
if (!load_patches(&patches, "patches.json", error)) {
log_error(BOOT_LOGGER, "Failed to load patches file: %s", error);
} else {
char exePathC[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL);
for (size_t i = 0; i < patches.nopatchsets; i++) {
patchset_t* patchset = patches.patchsets[i];
// Require the binary explicitly named
if (patchset->binary_name == NULL || strcmp(patchset->binary_name, exePathC) != 0) {
continue;
}
if (!patchset->apply) continue;
for (size_t j = 0; j < patchset->nopatches; j++) {
patch_t patch = patchset->patches[j];
if (memcmp(patch.from, (void*)patch.offset, patch.count) != 0) {
log_error(BOOT_LOGGER, "Patch %s[%d] failed! from-value missmatch", patchset->name, j);
continue;
}
memcpy((void*)patch.offset, patch.to, patch.count);
log_misc(BOOT_LOGGER, "Patched %d bytes at %08x", patch.count, patch.offset);
}
}
}
free_patches(&patches);
}
void prebind_hooks() {
hook_all();
install_devices();
// TODO: Figure out why we're needing to call this manually (medium priority)
if (wcscmp(exePath, L"ALLNetProc.exe") == 0) {
log_warning(BOOT_LOGGER, "Making explicit call to OPENSSL_add_all_algorithms_noconf");
// OPENSSL_add_all_algorithms_noconf
((void (*)(void))(0x00459770))();
}
}
void init_injection() {
// We're in a new context now, so need to reconfigure
setup_logging();
log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exePath);
enable_traces();
// Columba: Driver-level memory access, used to read the DMI tables
setup_columba();
// MX SRAM: SRAM-based nv memory
setup_mxsram();
// MX SuperIO: Communicate with the HW monitor chip
setup_mxsuperio();
// MX JVS: Interacting with JVS-based devices
setup_mxjvs();
// MX HW Reset: Forcibly reboot the machine
setup_mxhwreset();
// MX SMBus: Communicate over the LPC bus. This contains the EEPROM, and PCA9535
setup_mxsmbus();
if (!add_fake_device(&PLATFORM_GUID, L"\\\\.\\platform")) {
log_error("platform", "failed to install platform device");
}
// Must be the last thing called!
// register_devices();
prebind_hooks();
setup_hooks();
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
GetModuleFileNameW(NULL, exePath, MAX_PATH);
wcscpy_s(exePath, MAX_PATH + 1, PathFindFileNameW(exePath));
init_injection();
return TRUE;
}

View File

@ -1,73 +1,73 @@
#include "../lib/dmi/dmi.h"
#include "mx.h"
// Much easier than pulling in winddk.h
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
typedef struct {
PHYSICAL_ADDRESS addr;
DWORD data_type;
DWORD bytes;
} columba_request;
#define DMI_HEADER_START 0x000f0000
#define DMI_TABLES_START 0x000f1000
BOOL columba_DeviceIoControl(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",
"DeviceIoControl(<columba>, <read dmi>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
columba_request* request = (columba_request*)lpInBuffer;
log_info("columba", "Physical read: 0x%04x %ss at %08X", request->bytes,
request->data_type == 1 ? "byte"
: request->data_type == 2 ? "short"
: request->data_type == 4 ? "long"
: "void",
request->addr);
DWORD requested_size = request->data_type * request->bytes;
memset(lpOutBuffer, 0, nOutBufferSize);
if (request->addr.QuadPart == DMI_HEADER_START) {
DMI_HEADER dmi = {
.Signature = { '_', 'D', 'M', 'I', '_' },
.Checksum = 0,
.StructLength = dmi_size,
.StructAddr = DMI_TABLES_START,
.NumberOfStructs = 0x20,
.BCDRevision = 0,
.Reserved = 0,
};
dmi.Checksum = dmi_calc_checksum((char*)&dmi, 15);
memcpy(lpOutBuffer, &dmi, sizeof(DMI_HEADER));
if (lpBytesReturned) *lpBytesReturned = requested_size;
} else if (request->addr.QuadPart == DMI_TABLES_START) {
memcpy(lpOutBuffer, dmi_table, dmi_size);
if (lpBytesReturned) *lpBytesReturned = 0x10000;
} else {
log_error("columna", "Request to unmapped memory location: %08x", request->addr);
return FALSE;
}
break;
default:
log_warning("columba", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
void setup_columba() {
dmi_build_default();
file_hook_t* columba = new_file_hook(L"\\\\.\\columba");
columba->DeviceIoControl = &columba_DeviceIoControl;
hook_file(columba);
}
#include "../lib/dmi/dmi.h"
#include "mx.h"
// Much easier than pulling in winddk.h
typedef LARGE_INTEGER PHYSICAL_ADDRESS, *PPHYSICAL_ADDRESS;
typedef struct {
PHYSICAL_ADDRESS addr;
DWORD data_type;
DWORD bytes;
} columba_request;
#define DMI_HEADER_START 0x000f0000
#define DMI_TABLES_START 0x000f1000
BOOL columba_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
switch (dwIoControlCode) {
case IOCTL_COLUMBA_READ:
log_misc("columba", "DeviceIoControl(<columba>, <read>, 0x%p, 0x%x, -, 0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
columba_request* request = (columba_request*)lpInBuffer;
log_info("columba", "Physical read: 0x%04x %ss at %08X", request->bytes,
request->data_type == 1 ? "byte"
: request->data_type == 2 ? "short"
: request->data_type == 4 ? "long"
: "void",
request->addr);
DWORD requested_size = request->data_type * request->bytes;
memset(lpOutBuffer, 0, nOutBufferSize);
if (request->addr.QuadPart == DMI_HEADER_START) {
DMI_HEADER dmi = {
.Signature = { '_', 'D', 'M', 'I', '_' },
.Checksum = 0,
.StructLength = dmi_size,
.StructAddr = DMI_TABLES_START,
.NumberOfStructs = 0x20,
.BCDRevision = 0,
.Reserved = 0,
};
dmi.Checksum = dmi_calc_checksum((char*)&dmi, 15);
memcpy(lpOutBuffer, &dmi, sizeof(DMI_HEADER));
if (lpBytesReturned) *lpBytesReturned = requested_size;
} else if (request->addr.QuadPart == DMI_TABLES_START) {
memcpy(lpOutBuffer, dmi_table, dmi_size);
if (lpBytesReturned) *lpBytesReturned = 0x10000;
} else {
log_error("columba", "Request to unmapped memory location: %08x",
request->addr);
return FALSE;
}
break;
default:
// Observed: IOCTL_KSEC_RNG_REKEY
log_warning("columba", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
void setup_columba() {
dmi_build_default();
file_hook_t* columba = new_file_hook(L"\\\\.\\columba");
columba->DeviceIoControl = &columba_DeviceIoControl;
hook_file(columba);
}

View File

@ -1,27 +1,25 @@
#pragma once
#include "../hooks/_hooks.h"
#include "../common.h"
FnDeviceIoControl mxhwreset_DeviceIoControl;
void setup_mxhwreset();
FnDeviceIoControl mxjvs_DeviceIoControl;
void setup_mxjvs();
FnDeviceIoControl mxsmbus_DeviceIoControl;
void setup_mxsmbus();
FnDeviceIoControl mxsram_DeviceIoControl;
FnSetFilePointer mxsram_SetFilePointer;
FnWriteFile mxsram_WriteFile;
FnReadFile mxsram_ReadFile;
void setup_mxsram();
FnDeviceIoControl mxsuperio_DeviceIoControl;
void setup_mxsuperio();
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);
#pragma once
#include "../hooks/_hooks.h"
#include "../common.h"
#include "../../lib/am/amEeprom.h"
FnDeviceIoControl mxhwreset_DeviceIoControl;
void setup_mxhwreset();
FnDeviceIoControl mxjvs_DeviceIoControl;
void setup_mxjvs();
FnDeviceIoControl mxsmbus_DeviceIoControl;
void setup_mxsmbus();
FnDeviceIoControl mxsram_DeviceIoControl;
FnSetFilePointer mxsram_SetFilePointer;
FnWriteFile mxsram_WriteFile;
FnReadFile mxsram_ReadFile;
void setup_mxsram();
FnDeviceIoControl mxsuperio_DeviceIoControl;
void setup_mxsuperio();
FnDeviceIoControl columba_DeviceIoControl;
void setup_columba();

View File

@ -1,377 +1,394 @@
#include <Windows.h>
#include "../common.h"
#include "jvs.h"
#include "mx.h"
BOOL JVS_SENSE = false;
BOOL coin_solenoid = false;
BOOL test_btn = false;
// #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_misc("mxjvs",
"DeviceIoControl(<mxjvs>, <exchange>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
mxjvs_exchange(lpInBuffer, nInBufferSize & 0xffff, lpOutBuffer, nOutBufferSize, lpBytesReturned);
break;
default:
log_warning("mxjvs", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
BOOL mxjvs_SetupComm(void* com, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
BOOL mxjvs_PurgeComm(void* com, DWORD dwFlags) { return TRUE; }
BOOL mxjvs_GetCommState(void* com, LPDCB lpDCB) { return TRUE; }
BOOL mxjvs_SetCommTimeouts(void* com, LPCOMMTIMEOUTS lpDCB) { return TRUE; }
BOOL mxjvs_GetCommModemStatus(void* com, LPDWORD lpModelStat) {
*lpModelStat = !JVS_SENSE ? MS_DSR_ON : 0;
return TRUE;
}
BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) {
char PARITY[] = { 'N', 'O', 'E', 'M', 'S' };
char* STOP[] = { "1", "1.5", "2" };
log_info("mxjvs", "Switching to %d baud (%d%c%s)", lpDCB->BaudRate, lpDCB->ByteSize, PARITY[lpDCB->Parity],
STOP[lpDCB->StopBits]);
return TRUE;
}
void setup_mxjvs() {
file_hook_t* mxjvs = new_file_hook(L"\\\\.\\mxjvs");
mxjvs->DeviceIoControl = &mxjvs_DeviceIoControl;
com_hook_t* jvscom = new_com_hook(-1);
jvscom->GetCommState = mxjvs_GetCommState;
jvscom->SetCommState = mxjvs_SetCommState;
jvscom->SetCommTimeouts = mxjvs_SetCommTimeouts;
jvscom->SetupComm = mxjvs_SetupComm;
jvscom->PurgeComm = mxjvs_PurgeComm;
jvscom->GetCommModemStatus = mxjvs_GetCommModemStatus;
hook_file(mxjvs);
hook_com(jvscom);
free(jvscom->virtual_handle);
jvscom->virtual_handle = mxjvs->virtual_handle;
}
#include <Windows.h>
#include "../common.h"
#include "jvs.h"
#include "mx.h"
BOOL JVS_SENSE = false;
BOOL coin_solenoid = false;
BOOL test_btn = false;
// #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(unsigned char* paddedData, short length, unsigned 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(unsigned char* unpaddedData, short length, unsigned char* paddedData,
short paddedMax) {
short index = 0;
for (short i = 0; i < length; i++) {
if (i > paddedMax) return -1;
if (i != 0 && (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(unsigned char* paddedIn, short inCount, unsigned char* outData, short 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 = 0xff;
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_COIN:
jvs_write(JVS_REPORT_OK);
unsigned char coin_count;
jvs_read(coin_count);
for (; coin_count; coin_count--) {
jvs_write(0x00); // coin MSB
jvs_write(0x00); // coin LSB
}
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) & 0xFF; // 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_trace("mxjvs",
"DeviceIoControl(<mxjvs>, <exchange>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
mxjvs_exchange(lpInBuffer, nInBufferSize & 0xffff, lpOutBuffer, nOutBufferSize & 0xFFFF,
(int*)lpBytesReturned);
break;
default:
log_warning("mxjvs", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
BOOL mxjvs_SetupComm(void* com, DWORD dwInQueue, DWORD dwOutQueue) { return TRUE; }
BOOL mxjvs_PurgeComm(void* com, DWORD dwFlags) { return TRUE; }
BOOL mxjvs_GetCommState(void* com, LPDCB lpDCB) { return TRUE; }
BOOL mxjvs_SetCommTimeouts(void* com, LPCOMMTIMEOUTS lpDCB) { return TRUE; }
BOOL mxjvs_GetCommModemStatus(void* com, LPDWORD lpModelStat) {
*lpModelStat = !JVS_SENSE ? MS_DSR_ON : 0;
return TRUE;
}
BOOL mxjvs_SetCommState(void* com, LPDCB lpDCB) {
char PARITY[] = { 'N', 'O', 'E', 'M', 'S' };
char* STOP[] = { "1", "1.5", "2" };
log_info("mxjvs", "Switching to %d baud (%d%c%s)", lpDCB->BaudRate, lpDCB->ByteSize,
PARITY[lpDCB->Parity], STOP[lpDCB->StopBits]);
return TRUE;
}
void setup_mxjvs() {
file_hook_t* mxjvs = new_file_hook(L"\\\\.\\mxjvs");
mxjvs->DeviceIoControl = &mxjvs_DeviceIoControl;
com_hook_t* jvscom = new_com_hook(0);
wcscpy_s(jvscom->wName, sizeof jvscom->wName, L"\\\\.\\mxjvs");
wcscpy_s(jvscom->wDosName, sizeof jvscom->wDosName, L"\\\\.\\mxjvs");
jvscom->GetCommState = mxjvs_GetCommState;
jvscom->SetCommState = mxjvs_SetCommState;
jvscom->SetCommTimeouts = mxjvs_SetCommTimeouts;
jvscom->SetupComm = mxjvs_SetupComm;
jvscom->PurgeComm = mxjvs_PurgeComm;
jvscom->GetCommModemStatus = mxjvs_GetCommModemStatus;
hook_file(mxjvs);
hook_com(jvscom);
}

View File

@ -1,337 +1,365 @@
#include "../lib/dmi/dmi.h"
#include "../hooks/setupapi_.h"
#include "mx.h"
#include "smbus.h"
// PCA9535 (DIPSW)
#define PCA9535_WRITE 0x04
#define PCA9535_READ 0x05
#define PCA9535_IN0 0x00
#define PCA9535_IN1 0x01
#define PCA9535_OUT0 0x02
#define PCA9535_OUT1 0x03
#define PCA9535_INV0 0x04
#define PCA9535_INV1 0x05
#define PCA9535_CONF0 0x06
#define PCA9535_CONF1 0x07
#define 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 {
BYTE data[32];
} eeprom_reg_t;
typedef struct eeprom_bank {
eeprom_reg_t reg[0x100];
} eeprom_bank_t;
// 256 registers, 32 bytes each
eeprom_bank_t EEPROM_DATA;
/*
* Known registers:
* - Reg 0x00: Stores ??? in [00]
* - Reg 0x08: Stores LPC address in [00, 01]
* - Reg 0x16: Stores ??? in [00, 01]
* - Reg 0x0e: Stores
*/
void eeprom_dump() {
HANDLE dump = _CreateFileW(EEPROM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (dump == INVALID_HANDLE_VALUE) {
log_error("eeprom", "CreateFileA(EEPROM_DUMP) failed");
return;
}
_WriteFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, NULL, NULL);
FlushFileBuffers(dump);
_CloseHandle(dump);
}
void eeprom_restore() {
HANDLE dump =
_CreateFileW(EEPROM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (dump == INVALID_HANDLE_VALUE) return;
DWORD read;
if (!_ReadFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, &read, NULL))
log_error("eeprom", "failed to restore (%d)", GetLastError());
_CloseHandle(dump);
}
DWORD eeprom_crc(BYTE reg) {
if (reg == 0x04 || reg == 0x14 || reg == 0x80 || reg == 0x280) {
// Some registers are only treated as 16 byte values
crc32_build_table();
return crc32(12, EEPROM_DATA.reg[reg].data + 4, 0);
}
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();
for (BYTE i = index; i < index + length; i++) {
if (i > 0x1f) break;
BYTE byte = EEPROM_DATA.reg[reg].data[i];
// If register has a CRC
// if (reg == 0x00 || reg == 0x01 || reg == 0x02 || reg == 0x10 || reg
// == 0x11 || reg == 0x12 || reg == 0x200) {
if (true) {
// Intercept the read and inject a CRC instead
if (i == 0x00 || i == 0x01 || i == 0x02 || i == 0x03) {
DWORD crc = eeprom_crc(reg);
byte = crc >> 8 * i & 0xff;
}
}
data[i - index] = byte;
}
}
void eeprom_write(BYTE reg, BYTE index, BYTE* data, BYTE length) {
for (BYTE i = index; i < index + length; i++) {
if (i > 0x1f) break;
EEPROM_DATA.reg[reg].data[i] = data[i - index];
}
eeprom_dump();
}
BYTE eeprom_read_one(BYTE reg, BYTE index) {
BYTE data;
eeprom_read(reg, index, &data, 1);
return data;
}
void eeprom_write_one(BYTE reg, BYTE index, BYTE data) { eeprom_write(reg, index, &data, 1); }
BOOL mxsmbus_DeviceIoControl(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;
mxsmbus_request_packet* request_packet = (mxsmbus_request_packet*)lpInBuffer;
mxsmbus_request_packet* request_out = (mxsmbus_request_packet*)lpOutBuffer;
BYTE dlen;
switch (dwIoControlCode) {
case IOCTL_MXSMBUS_GET_VERSION:
log_misc("mxsmbus",
"DeviceIoControl(<mxsmbus>, <get version>, 0x%p, 0x%x, "
"-, 0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
((LPDWORD)lpOutBuffer)[0] = 0x01020001;
if (lpBytesReturned) *lpBytesReturned = 4;
break;
case IOCTL_MXSMBUS_REQUEST: // dip r/w
log_misc("mxsmbus",
"DeviceIoControl(<mxsmbus>, <request>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
// Game trace:
// 05 for 20
// ^[x3]
// 04 for 20
// ^[x3]
// 05 for 20
// 03 for 57
// ^[after every eeprom read/write]
// Address 0x20 = PCA9535 = DIP switches
// Address 0x30 = Keychip? "N2"
// Address 0x55 = Keychip?
// Address 0x57 = EEPROM
// dyn = 0x57
// 03: addr dyn: amEepromWait
// 04: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
// 05: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
//
// dyn2 = 0x20
// 04: addr dyn2: amDipswWriteByteInternal
// 05: addr dyn2: amDipswReadByteInternal[Ex]
// 0B: addr 0x20: amHmGetLPCChipId
// 0B: addr 0x21: amHmGetLPCChipId
// 48: addr 0x00: amHmGetLPCChipId
switch (i2c_packet->addr) {
case 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]);
break;
case PCA9535_INV0:
log_info("mxsmbus", "pca9535 INV0: %02x %02x", i2c_packet->data[0],
i2c_packet->data[1]);
break;
case PCA9535_INV1:
log_info("mxsmbus", "pca9535 INV1: %02x %02x", i2c_packet->data[0],
i2c_packet->data[1]);
break;
default:
log_error("mxsmbux",
"(write) Undefined pca9535 "
"register: 0x%02x",
i2c_packet->reg);
exit(1);
}
break;
case PCA9535_READ:
switch (i2c_packet->reg) {
case PCA9535_IN0: // DIPSW
i2c_packet->data[0] = 0x00;
break;
case PCA9535_IN1: // 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: // LEDs, probably
i2c_packet->data[0] = 0x00;
break;
default:
log_error("mxsmbux",
"(read) Undefined pca9535 "
"register: 0x%02x",
i2c_packet->reg);
exit(1);
}
i2c_packet->status = 0x00;
break;
default:
log_error("mxsmbux", "Unknown pca9535 command: 0x%02x", i2c_packet->prt);
exit(1);
}
break;
case SMBUS_EEPROM:
switch (i2c_packet->prt) {
case 3: // Wait
// 0x18 = wait, 0x00 = done
i2c_packet->status = 0;
break;
default:
log_error("mxsmbux", "Unknown eeprom command: 0x%02x", i2c_packet->prt);
exit(1);
}
break;
default:
log_error("mxsmbus", "Unknown smbus device: 0x%02x", i2c_packet->addr);
exit(1);
}
i2c_out->status = MXSBUS_OKAY;
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_i2c_packet);
break;
case IOCTL_MXSMBUS_I2C: // i2c r/w
log_misc("mxsmbus",
"DeviceIoControl(<mxsmbus>, <i2c>, 0x%p, 0x%x, -, 0x%x, "
"-, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
log_misc("mxsmbus", "SMBus I2C request for %02x: 0x%02x (%02x bytes @ %02x)", request_packet->addr,
request_packet->prt, request_packet->dlen, request_packet->reg);
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[0],
// dwordInBuffer[1], dwordInBuffer[2], dwordInBuffer[3]);
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[4],
// dwordInBuffer[5], dwordInBuffer[6], dwordInBuffer[7]);
// log_warning("eeprom", "%08x %08x", dwordInBuffer[8],
// dwordInBuffer[9]);
// for (int i = 0; i < nInBufferSize; i++) {
// printf("%02x ", ((LPBYTE)lpInBuffer)[i]);
// }
// puts("");
// prt = byteInBuffer[1];
// addr = wordInBuffer[1];
// reg = wordInBuffer[2] & 0xFF;
dlen = request_packet->dlen;
if (dlen > 0x20) dlen = 0x20;
/*
* Known addresses:
* - 0x57: EEPROM
**/
request_packet->status = MXSBUS_OKAY;
if (request_packet->status != 0) {
log_error("mxsmbus", "invalid i2c packet");
return FALSE;
}
if (request_packet->addr != SMBUS_EEPROM) {
log_error("mxsmbus", "Unexpected I2C device: 0x%02x", request_packet->addr);
exit(1);
}
// 04 = Write byte
// 05 = Read byte
//
// 08 = Write block
// 09 = Read block
if (request_packet->prt == 0x08) {
// Write
log_misc("mxsmbus", "eeprom write %02x (0x%04x)", dlen, request_packet->reg);
// for (int i = 0; i < dlen; i++) printf("%02x ",
// request_packet->data[i]); puts("");
eeprom_write(request_packet->reg >> 5, request_packet->reg & 0x1f, request_packet->data,
request_packet->dlen);
request_out->status = 0;
} else if (i2c_packet->prt == 0x09) {
// Read
log_misc("mxsmbus", "eeprom read %02x (0x%04x)", dlen, request_packet->reg);
eeprom_read(request_packet->reg >> 5, request_packet->reg & 0x1f, request_out->data, dlen);
// for (int i = 0; i < dlen; i++) printf("%02x ",
// request_out->data[i]); puts("");
request_out->status = 0;
} else {
log_warning("mxsmbus", "UNHANDLED MXSMBUS I2C %02x", request_packet->prt);
exit(1);
}
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_request_packet);
break;
default:
log_warning("mxsmbus", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
void setup_mxsmbus() {
file_hook_t* mxsmbus = new_file_hook(L"\\\\.\\mxsmbus");
mxsmbus->DeviceIoControl = &mxsmbus_DeviceIoControl;
hook_file(mxsmbus);
if (!add_fake_device(&MXSMBUS_GUID, L"\\\\.\\mxsmbus")) {
log_error("mxsmbus", "failed to install mxsmbus device");
}
}
#include "../hooks/setupapi_.h"
#include "../lib/dmi/dmi.h"
#include "mx.h"
#include "smbus.h"
#define EEPROM_DUMP L"dev/eeprom.bin"
typedef struct eeprom_reg {
BYTE data[32];
} eeprom_reg_t;
typedef struct eeprom_bank {
eeprom_reg_t reg[0x100];
} eeprom_bank_t;
// 256 registers, 32 bytes each
eeprom_bank_t EEPROM_DATA;
/*
* Known registers:
* - Reg 0x00: Stores ??? in [00]
* - Reg 0x08: Stores LPC address in [00, 01]
* - Reg 0x16: Stores ??? in [00, 01]
* - Reg 0x0e: Stores
*/
void eeprom_dump() {
HANDLE dump =
_CreateFileW(EEPROM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (dump == INVALID_HANDLE_VALUE) {
log_error("eeprom", "CreateFileA(EEPROM_DUMP) failed");
return;
} else {
log_info("eeprom", "Wrote eeprom to %s", EEPROM_DUMP);
}
_WriteFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, NULL, NULL);
FlushFileBuffers(dump);
_CloseHandle(dump);
}
void eeprom_restore() {
HANDLE dump = _CreateFileW(EEPROM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
if (dump == INVALID_HANDLE_VALUE) {
// Make the file, even though it'll probably be empty
eeprom_dump();
return;
}
DWORD read;
if (!_ReadFile(dump, &EEPROM_DATA, sizeof EEPROM_DATA, &read, NULL))
log_error("eeprom", "failed to restore (%d)", GetLastError());
_CloseHandle(dump);
}
DWORD eeprom_crc(BYTE reg) {
if (reg == 0x04 || reg == 0x14 || reg == 0x80 || reg == 0x280) {
// Some registers are only treated as 16 byte values
crc32_build_table();
return crc32(12, EEPROM_DATA.reg[reg].data + 4, 0);
}
crc32_build_table();
return crc32(28, EEPROM_DATA.reg[reg].data + 4, 0);
}
void eeprom_read(BYTE reg, BYTE index, BYTE* data, BYTE length) {
log_game("eeprom", "EEPROM READ %d %d %d", reg, index, length);
eeprom_restore();
for (BYTE i = index; i < index + length; i++) {
if (i > 0x1f) break;
BYTE byte = EEPROM_DATA.reg[reg].data[i];
// TODO: Reg 1 and 17 in the EEPROM are system info. We should fake these!
// If register has a CRC
// if (reg == 0x00 || reg == 0x01 || reg == 0x02 || reg == 0x10 || reg
// == 0x11 || reg == 0x12 || reg == 0x200) {
if (false) {
// Intercept the read and inject a CRC instead
if (i == 0x00 || i == 0x01 || i == 0x02 || i == 0x03) {
DWORD crc = eeprom_crc(reg);
byte = crc >> 8 * i & 0xff;
}
}
data[i - index] = byte;
}
}
void eeprom_write(BYTE reg, BYTE index, BYTE* data, BYTE length) {
log_game("eeprom", "EEPROM WRITE %d %d %d", reg, index, length);
for (BYTE i = index; i < index + length; i++) {
if (i > 0x1f) break;
EEPROM_DATA.reg[reg].data[i] = data[i - index];
}
eeprom_dump();
}
BYTE eeprom_read_one(BYTE reg, BYTE index) {
BYTE data;
eeprom_read(reg, index, &data, 1);
return data;
}
void eeprom_write_one(BYTE reg, BYTE index, BYTE data) { eeprom_write(reg, index, &data, 1); }
BOOL mxsmbus_DeviceIoControl(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;
mxsmbus_request_packet* request_packet = (mxsmbus_request_packet*)lpInBuffer;
mxsmbus_request_packet* request_out = (mxsmbus_request_packet*)lpOutBuffer;
BYTE dlen;
static uint16_t pca9535_config = 0xffff;
switch (dwIoControlCode) {
case IOCTL_MXSMBUS_GET_VERSION:
log_misc("mxsmbus",
"DeviceIoControl(<mxsmbus>, <get version>, 0x%p, 0x%x, "
"-, 0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
((LPDWORD)lpOutBuffer)[0] = 0x01020001;
if (lpBytesReturned) *lpBytesReturned = 4;
break;
case IOCTL_MXSMBUS_REQUEST: // dip r/w
log_trace("mxsmbus",
"DeviceIoControl(<mxsmbus>, <request>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
// Game trace:
// 05 for 20
// ^[x3]
// 04 for 20
// ^[x3]
// 05 for 20
// 03 for 57
// ^[after every eeprom read/write]
// Address 0x20 = PCA9535 = DIP switches
// Address 0x30 = Keychip? "N2"
// Address 0x55 = Keychip?
// Address 0x57 = EEPROM
// dyn = 0x57
// 03: addr dyn: amEepromWait
// 04: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
// 05: addr dyn: amHmI2CWriteByte (via IOCTL_MXSMBUS_I2C instead)
//
// dyn2 = 0x20
// 04: addr dyn2: amDipswWriteByteInternal
// 05: addr dyn2: amDipswReadByteInternal[Ex]
// 0B: addr 0x20: amHmGetLPCChipId
// 0B: addr 0x21: amHmGetLPCChipId
// 48: addr 0x00: amHmGetLPCChipId
switch (i2c_packet->addr) {
case SMBUS_PCA9535:
switch (i2c_packet->prt) {
case PCA9535_WRITE:
switch (i2c_packet->reg) {
case PCA9535_OUT0:
log_info("mxsmbus", "pca9535 OUT0: %02x", i2c_packet->data[0]);
break;
case PCA9535_OUT1:
log_info("mxsmbus", "pca9535 OUT1: %02x", i2c_packet->data[0]);
break;
case PCA9535_INV0:
log_info("mxsmbus", "pca9535 INV0: %02x", i2c_packet->data[0]);
break;
case PCA9535_INV1:
log_info("mxsmbus", "pca9535 INV1: %02x", i2c_packet->data[0]);
break;
case PCA9535_CONF0:
log_info("mxsmbus", "pca9535 CONF0: %02x", i2c_packet->data[0]);
pca9535_config =
(i2c_packet->data[0] << 8) | (pca9535_config & 0xff);
break;
case PCA9535_CONF1:
log_info("mxsmbus", "pca9535 CONF1: %02x", i2c_packet->data[0]);
pca9535_config =
i2c_packet->data[0] | (pca9535_config & 0xff00);
break;
default:
log_error("mxsmbus",
"(write) Undefined pca9535 register: 0x%02x",
i2c_packet->reg);
exit(1);
}
break;
case PCA9535_READ:
switch (i2c_packet->reg) {
case PCA9535_IN0: // DIPSW
/*
0: ?
1: ?
2: ?
3: Orientation
4: / \
5: | Resolution |
6: \ /
7: game specific
0b00001000 = landscape
*/
puts("dipsw");
i2c_packet->data[0] = 0b00001000;
break;
case PCA9535_IN1: // SW1/2 + extras
/*
0: unk
1: unk
2: ¬test
3: ¬service
4: unk
5: unk
6: unk
7: unk
*/
byte dip = 0x00;
if (GetAsyncKeyState('T') >= 0) {
dip |= 0x04;
}
if (GetAsyncKeyState('S') >= 0) {
dip |= 0x08;
}
i2c_packet->data[0] = dip;
break;
case PCA9535_INV0:
case PCA9535_INV1:
case PCA9535_OUT1: // LEDs, probably
i2c_packet->data[0] = 0x00;
break;
case PCA9535_CONF0:
i2c_packet->data[0] = pca9535_config >> 8;
break;
case PCA9535_CONF1:
i2c_packet->data[0] = pca9535_config & 0xff;
break;
default:
log_error("mxsmbus",
"(read) Undefined pca9535 "
"register: 0x%02x",
i2c_packet->reg);
exit(1);
}
i2c_packet->status = 0x00;
break;
default:
log_error("mxsmbus", "Unknown pca9535 command: 0x%02x",
i2c_packet->prt);
exit(1);
}
break;
case SMBUS_EEPROM:
switch (i2c_packet->prt) {
case 3: // Wait
// 0x18 = wait, 0x00 = done
i2c_packet->status = 0;
break;
default:
log_error("mxsmbus", "Unknown eeprom command: 0x%02x", i2c_packet->prt);
exit(1);
}
break;
default:
log_error("mxsmbus", "Unknown smbus device: 0x%02x", i2c_packet->addr);
exit(1);
}
i2c_out->status = MXSBUS_OKAY;
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_i2c_packet);
break;
case IOCTL_MXSMBUS_I2C: // i2c r/w
log_misc("mxsmbus",
"DeviceIoControl(<mxsmbus>, <i2c>, 0x%p, 0x%x, -, 0x%x, "
"-, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
log_misc("mxsmbus", "SMBus I2C request for %02x: 0x%02x (%02x bytes @ %02x)",
request_packet->addr, request_packet->prt, request_packet->dlen,
request_packet->reg);
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[0],
// dwordInBuffer[1], dwordInBuffer[2], dwordInBuffer[3]);
// log_warning("eeprom", "%08x %08x %08x %08x", dwordInBuffer[4],
// dwordInBuffer[5], dwordInBuffer[6], dwordInBuffer[7]);
// log_warning("eeprom", "%08x %08x", dwordInBuffer[8],
// dwordInBuffer[9]);
// for (int i = 0; i < nInBufferSize; i++) {
// printf("%02x ", ((LPBYTE)lpInBuffer)[i]);
// }
// puts("");
// prt = byteInBuffer[1];
// addr = wordInBuffer[1];
// reg = wordInBuffer[2] & 0xFF;
dlen = request_packet->dlen;
if (dlen > 0x20) dlen = 0x20;
/*
* Known addresses:
* - 0x57: EEPROM
**/
request_packet->status = MXSBUS_OKAY;
if (request_packet->status != 0) {
log_error("mxsmbus", "invalid i2c packet");
return FALSE;
}
if (request_packet->addr != SMBUS_EEPROM) {
log_error("mxsmbus", "Unexpected I2C device: 0x%02x", request_packet->addr);
exit(1);
}
// 04 = Write byte
// 05 = Read byte
//
// 08 = Write block
// 09 = Read block
if (request_packet->prt == 0x08) {
// Write
log_misc("mxsmbus", "eeprom write %02x (0x%04x)", dlen, request_packet->reg);
// for (int i = 0; i < dlen; i++) printf("%02x ",
// request_packet->data[i]); puts("");
eeprom_write((request_packet->reg >> 5) & 0xff, request_packet->reg & 0x1f,
request_packet->data, request_packet->dlen);
request_out->status = 0;
} else if (i2c_packet->prt == 0x09) {
// Read
log_misc("mxsmbus", "eeprom read %02x (0x%04x)", dlen, request_packet->reg);
eeprom_read((request_packet->reg >> 5) & 0xff, request_packet->reg & 0x1f,
request_out->data, dlen);
// for (int i = 0; i < dlen; i++) printf("%02x ",
// request_out->data[i]); puts("");
request_out->status = 0;
} else {
log_warning("mxsmbus", "UNHANDLED MXSMBUS I2C %02x", request_packet->prt);
exit(1);
}
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsmbus_request_packet);
break;
default:
log_warning("mxsmbus", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
void setup_mxsmbus() {
file_hook_t* mxsmbus = new_file_hook(L"\\\\.\\mxsmbus");
mxsmbus->DeviceIoControl = &mxsmbus_DeviceIoControl;
hook_file(mxsmbus);
if (!add_fake_device(&MXSMBUS_GUID, L"\\\\.\\mxsmbus")) {
log_error("mxsmbus", "failed to install mxsmbus device");
}
}

View File

@ -1,125 +1,126 @@
#include "mx.h"
#define SRAM_DUMP L"dev/sram.bin"
#define SRAM_SIZE 1024 * 2084
LPBYTE SRAM;
DWORD SRAM_POINTER = 0;
void sram_dump() {
HANDLE dump = _CreateFileW(SRAM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (dump == INVALID_HANDLE_VALUE) {
log_error("sram", "CreateFileA(SRAM_DUMP) failed");
return;
}
_WriteFile(dump, SRAM, SRAM_SIZE, NULL, NULL);
_CloseHandle(dump);
}
void sram_restore() {
HANDLE dump =
_CreateFileW(SRAM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (dump == INVALID_HANDLE_VALUE) return;
DWORD read;
if (!_ReadFile(dump, SRAM, SRAM_SIZE, &read, NULL)) log_error("sram", "failed to restore (%d)", GetLastError());
_CloseHandle(dump);
}
BOOL mxsram_DeviceIoControl(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
switch (dwIoControlCode) {
case IOCTL_MXSRAM_PING: // Get version
log_info("mxsram",
"DeviceIoControl(<mxsram>, <ping>, 0x%p, 0x%x, -, 0x%x, "
"-, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
((LPDWORD)lpOutBuffer)[0] = SRAM_VERSION;
if (lpBytesReturned) *lpBytesReturned = 4;
break;
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
log_info("mxsram",
"DeviceIoControl(<mxsram>, <get drive geom>, 0x%p, "
"0x%x, -, 0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
DISK_GEOMETRY out = *(PDISK_GEOMETRY)lpOutBuffer;
memset(&out, 0, sizeof(out));
out.Cylinders.QuadPart = 1;
out.MediaType = FixedMedia;
out.TracksPerCylinder = 224;
out.SectorsPerTrack = 32;
out.BytesPerSector = 1;
if (lpBytesReturned) *lpBytesReturned = sizeof(DISK_GEOMETRY);
break;
case IOCTL_MXSRAM_GET_SECTOR_SIZE:
log_info("mxsram",
"DeviceIoControl(<mxsram>, <get sector size>, 0x%p, "
"0x%x, -, 0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
((LPDWORD)lpOutBuffer)[0] = SRAM_SECTOR_SIZE;
if (lpBytesReturned) *lpBytesReturned = 4;
break;
default:
log_warning("mxsram", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
DWORD mxsram_SetFilePointer(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
if (dwMoveMethod == FILE_BEGIN) {
SRAM_POINTER = lDistanceToMove;
} else if (dwMoveMethod == FILE_CURRENT) {
SRAM_POINTER += lDistanceToMove;
}
return SRAM_POINTER;
}
BOOL mxsram_WriteFile(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) {
nNumberOfBytesToWrite = SRAM_SIZE - SRAM_POINTER;
}
memcpy(SRAM + SRAM_POINTER, lpBuffer, nNumberOfBytesToWrite);
sram_dump();
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
return TRUE;
}
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) {
nNumberOfBytesToRead = SRAM_SIZE - SRAM_POINTER;
}
sram_restore();
memcpy((LPVOID)lpBuffer, SRAM + SRAM_POINTER, nNumberOfBytesToRead);
*lpNumberOfBytesRead = nNumberOfBytesToRead;
return TRUE;
}
void setup_mxsram() {
// Allocate 2MB of SRAM
SRAM = (LPBYTE)malloc(SRAM_SIZE);
if (!SRAM) {
log_error(BOOT_LOGGER, "unable to allocate 2MiB for SRAM");
exit(1);
}
memset(SRAM, 0, SRAM_SIZE);
sram_restore();
file_hook_t* mxsram = new_file_hook(L"\\\\.\\mxsram");
mxsram->DeviceIoControl = &mxsram_DeviceIoControl;
mxsram->SetFilePointer = &mxsram_SetFilePointer;
mxsram->ReadFile = &mxsram_ReadFile;
mxsram->WriteFile = &mxsram_WriteFile;
hook_file(mxsram);
}
#include "mx.h"
#define SRAM_DUMP L"dev/sram.bin"
#define SRAM_SIZE 1024 * 2084
LPBYTE SRAM;
DWORD SRAM_POINTER = 0;
void sram_dump() {
HANDLE dump = _CreateFileW(SRAM_DUMP, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
if (dump == INVALID_HANDLE_VALUE) {
log_error("sram", "CreateFileA(SRAM_DUMP) failed");
return;
}
_WriteFile(dump, SRAM, SRAM_SIZE, NULL, NULL);
_CloseHandle(dump);
}
void sram_restore() {
HANDLE dump =
_CreateFileW(SRAM_DUMP, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (dump == INVALID_HANDLE_VALUE) return;
DWORD read;
if (!_ReadFile(dump, SRAM, SRAM_SIZE, &read, NULL)) log_error("sram", "failed to restore (%d)", GetLastError());
_CloseHandle(dump);
}
BOOL mxsram_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) {
DWORD SRAM_VERSION = 0x0001;
DWORD SRAM_SECTOR_SIZE = 4; // Max is 0x800
switch (dwIoControlCode) {
case IOCTL_MXSRAM_PING: // Get version
log_info("mxsram",
"DeviceIoControl(<mxsram>, <ping>, 0x%p, 0x%x, -, 0x%x, "
"-, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
((LPDWORD)lpOutBuffer)[0] = SRAM_VERSION;
if (lpBytesReturned) *lpBytesReturned = 4;
break;
case IOCTL_DISK_GET_DRIVE_GEOMETRY:
log_info("mxsram",
"DeviceIoControl(<mxsram>, <get drive geom>, 0x%p, "
"0x%x, -, 0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
DISK_GEOMETRY out = *(PDISK_GEOMETRY)lpOutBuffer;
memset(&out, 0, sizeof(out));
out.Cylinders.QuadPart = 256;
out.MediaType = FixedMedia;
out.TracksPerCylinder = 24;
out.SectorsPerTrack = 8;
out.BytesPerSector = 512;
if (lpBytesReturned) *lpBytesReturned = sizeof(DISK_GEOMETRY);
break;
case IOCTL_MXSRAM_GET_SECTOR_SIZE:
log_info("mxsram",
"DeviceIoControl(<mxsram>, <get sector size>, 0x%p, "
"0x%x, -, 0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
((LPDWORD)lpOutBuffer)[0] = SRAM_SECTOR_SIZE;
if (lpBytesReturned) *lpBytesReturned = 4;
break;
default:
log_warning("mxsram", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
DWORD mxsram_SetFilePointer(void* file, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
printf("MXSRSFP %08x\n", lDistanceToMove);
if (dwMoveMethod == FILE_BEGIN) {
SRAM_POINTER = lDistanceToMove;
} else if (dwMoveMethod == FILE_CURRENT) {
SRAM_POINTER += lDistanceToMove;
}
return SRAM_POINTER;
}
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) {
nNumberOfBytesToWrite = SRAM_SIZE - SRAM_POINTER;
}
memcpy(SRAM + SRAM_POINTER, lpBuffer, nNumberOfBytesToWrite);
sram_dump();
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
return TRUE;
}
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) {
nNumberOfBytesToRead = SRAM_SIZE - SRAM_POINTER;
}
sram_restore();
memcpy((LPVOID)lpBuffer, SRAM + SRAM_POINTER, nNumberOfBytesToRead);
*lpNumberOfBytesRead = nNumberOfBytesToRead;
return TRUE;
}
void setup_mxsram() {
// Allocate 2MB of SRAM
SRAM = (LPBYTE)malloc(SRAM_SIZE);
if (!SRAM) {
log_error(BOOT_LOGGER, "unable to allocate 2MiB for SRAM");
exit(1);
}
memset(SRAM, 0, SRAM_SIZE);
sram_restore();
file_hook_t* mxsram = new_file_hook(L"\\\\.\\mxsram");
mxsram->DeviceIoControl = &mxsram_DeviceIoControl;
mxsram->SetFilePointer = &mxsram_SetFilePointer;
mxsram->ReadFile = &mxsram_ReadFile;
mxsram->WriteFile = &mxsram_WriteFile;
hook_file(mxsram);
}

View File

@ -1,287 +1,395 @@
#include "mx.h"
#include "smbus.h"
#include "w83791d.h"
BYTE w83791d_bank = 0x00;
BYTE w83791d_config = W83791D_CONFIG_START;
BYTE w83791d_noncrit_t1 = 75; // C
BYTE w83791d_crit_t1 = 80; // C
BYTE w83791d_noncrit_t2 = 75; // C
BYTE w83791d_crit_t2 = 80; // C
BYTE w83791d_noncrit_t3 = 75; // C
BYTE w83791d_crit_t3 = 80; // C
BYTE w83791d_vbat_monitor_control = 0x00;
BOOL w83791d_4f_high = 0;
BOOL mxsuperio_DeviceIoControl(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;
switch (dwIoControlCode) {
case IOCTL_MXSUPERIO_PING:
log_misc("mxsuperio",
"DeviceIoControl(<mxsuperio>, <ping>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
((LPDWORD)lpOutBuffer)[0] = 0x01000001;
if (lpBytesReturned) *lpBytesReturned = 4;
break;
case IOCTL_MXSUPERIO_READ:
log_misc("mxsuperio",
"DeviceIoControl(<mxsuperio>, <read>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
/*
BYTE chipId = 0|1
BYTE ?? = 0x0b
BYTE ?? = 0x20|0x21
BYTE ret = 0
*/
switch (((LPBYTE)lpInBuffer)[2]) {
case 0x20:
((LPBYTE)lpInBuffer)[3] = 0xa0;
break;
case 0x21:
((LPBYTE)lpInBuffer)[3] = 0x20;
break;
default:
((LPBYTE)lpInBuffer)[3] = 0x00;
break;
}
if (lpBytesReturned) *lpBytesReturned = 4;
break;
case IOCTL_MXSUPERIO_HWMONITOR_LPC_READ: {
BYTE index = lpc_packet->index;
BYTE reg = lpc_packet->reg;
switch (w83791d_bank) {
case 0x00: {
switch (reg) {
case W83791D_REG_WCHIPID:
lpc_out->data = 0x71;
break;
case W83791D_REG_CHIPMAN:
if (w83791d_4f_high)
lpc_out->data = 0x5c; // High byte
else
lpc_out->data = 0xa3; // Low byte
break;
case W83791D_REG_I2C_ADDR:
lpc_out->data = 0x11;
break;
case W83791D_REG_BANK:
lpc_out->data = w83791d_bank;
break;
case W83791D_REG_CONFIG:
lpc_out->data = w83791d_config;
break;
case W83791D_REG_BEEP_CTRL_0:
lpc_out->data = 0xff; // All the beeps! (see main.h)
break;
case W83791D_REG_TEMP1_0:
lpc_out->data = 0x00; // TODO: Figure out the temp val lol
break;
case W83791D_RAM_VCOREA:
case W83791D_RAM_VNIR0:
case W83791D_RAM_12VIN:
lpc_out->data = 0x00; // TODO: Figure out the batt val
break;
case W83791D_RAM_FAN1:
case W83791D_RAM_FAN2:
case W83791D_RAM_FAN3:
lpc_out->data = 0x00; // Fan no spinny!
break;
case W83791D_VID_FAN_DIV:
// Boths fans divide by 2 (01), VDD 5 latched
// good.
lpc_out->data = 0b01011111; // Let's not /0!
break;
case W83791D_VBAT_MONITOR_CONTROL:
lpc_out->data = w83791d_vbat_monitor_control;
break;
default:
log_error("mxsuperio", "Unknown HM b0 register: 0x%02x", reg);
exit(1);
}
} break;
case 0x01: {
switch (reg) {
case W83791D_REG_BANK:
lpc_out->data = w83791d_bank;
break;
case W83791D_NONCRIT_TEMP_1:
lpc_out->data = w83791d_noncrit_t1;
break;
case W83791D_CRIT_TEMP_1:
lpc_out->data = w83791d_crit_t1;
break;
case W83791D_NONCRIT_TEMP_2:
lpc_out->data = w83791d_noncrit_t2;
break;
case W83791D_CRIT_TEMP_2:
lpc_out->data = w83791d_crit_t2;
break;
case W83791D_NONCRIT_TEMP_3:
lpc_out->data = w83791d_noncrit_t3;
break;
case W83791D_CRIT_TEMP_3:
lpc_out->data = w83791d_crit_t3;
break;
case W83791D_VIN0:
lpc_out->data = W83791D_ENTITY_CPU;
break;
case W83791D_VIN1:
lpc_out->data = W83791D_ENTITY_SYSTEM;
break;
default:
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
exit(1);
}
} break;
case 0x05: {
switch (reg) {
case W83791D_REG_BANK:
lpc_out->data = w83791d_bank;
break;
// Used in amHmReadVoltageInternal
// What are these??
case 0x51:
case 0x40:
lpc_out->data = 0xff;
break;
default:
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
return FALSE;
// exit(1);
}
} break;
default:
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
exit(1);
}
// reg 0x48 = LPC Chip ID
// index = 0,1
// data > 0x0f, data < 0x70
// lpc_out->data = eeprom_read_one(reg, index);
log_misc("mxsuperio", "amHmLpcReadByte Index=0x%02x Reg=0x%02x Data=0x%02x", index, reg, lpc_out->data);
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsuperio_lpc_packet);
} break;
case IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE: {
BYTE index = lpc_packet->index;
BYTE reg = lpc_packet->reg;
log_misc("mxsuperio", "amHmLpcWriteByte Index=0x%02x Reg=0x%02x Data=0x%02b", index, reg, lpc_packet->data);
switch (w83791d_bank) {
case 0x00: {
switch (reg) {
case W83791D_REG_BEEP_CTRL_0:
// Ignore for now
break;
case W83791D_REG_BANK:
w83791d_4f_high = !!(lpc_packet->data & 0x80);
w83791d_bank = lpc_packet->data & 7;
break;
case W83791D_REG_CONFIG:
w83791d_config = lpc_packet->data;
break;
case W83791D_VBAT_MONITOR_CONTROL:
w83791d_vbat_monitor_control = lpc_packet->data;
break;
default:
log_error("mxsuperio", "Unknown HM b0 register: 0x%02x", reg);
exit(1);
}
break;
}
case 0x01: {
switch (reg) {
case W83791D_REG_BANK:
w83791d_4f_high = !!(lpc_packet->data & 0x80);
w83791d_bank = lpc_packet->data & 7;
break;
case W83791D_NONCRIT_TEMP_1:
w83791d_noncrit_t1 = lpc_packet->data;
break;
case W83791D_CRIT_TEMP_1:
w83791d_crit_t1 = lpc_packet->data;
break;
case W83791D_NONCRIT_TEMP_2:
w83791d_noncrit_t2 = lpc_packet->data;
break;
case W83791D_CRIT_TEMP_2:
w83791d_crit_t2 = lpc_packet->data;
break;
case W83791D_NONCRIT_TEMP_3:
w83791d_noncrit_t3 = lpc_packet->data;
break;
case W83791D_CRIT_TEMP_3:
w83791d_crit_t3 = lpc_packet->data;
break;
default:
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
exit(1);
}
} break;
case 0x05: {
switch (reg) {
case W83791D_REG_BANK:
w83791d_4f_high = !!(lpc_packet->data & 0x80);
w83791d_bank = lpc_packet->data & 7;
break;
// Used in amHmReadVoltageInternal
// What is this??
case 0x40:
break;
default:
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
return FALSE;
// exit(1);
}
} break;
default:
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
exit(1);
}
if (lpBytesReturned) *lpBytesReturned = 0;
} break;
default:
log_warning("mxsuperio", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
void setup_mxsuperio() {
file_hook_t* mxsuperio = new_file_hook(L"\\\\.\\mxsuperio");
mxsuperio->DeviceIoControl = &mxsuperio_DeviceIoControl;
hook_file(mxsuperio);
}
#include "mx.h"
#include "smbus.h"
#include "w83791d.h"
#include "w83627uhg.h"
BYTE w83791d_bank = 0x00;
BYTE w83791d_config = W83791D_CONFIG_START;
BYTE w83791d_noncrit_t1 = 75; // C
BYTE w83791d_crit_t1 = 80; // C
BYTE w83791d_noncrit_t2 = 75; // C
BYTE w83791d_crit_t2 = 80; // C
BYTE w83791d_noncrit_t3 = 75; // C
BYTE w83791d_crit_t3 = 80; // C
BYTE w83791d_vbat_monitor_control = 0x00;
BOOL w83791d_4f_high = 0;
BYTE w83627uhg_fanconf = 0x01;
BYTE w83627uhg_fanconf_2 = 0x00;
BYTE w83627uhg_cpufanout_src_slct = 0x2d;
BYTE w83627uhg_sysfanout_src_slct = 0x00;
BYTE w83627uhg_systin_target = 0x00;
BYTE w83627uhg_cputin_target = 0x00;
BYTE w83627uhg_target_tolerance = 0x00;
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;
switch (dwIoControlCode) {
case IOCTL_MXSUPERIO_PING:
log_misc("mxsuperio",
"DeviceIoControl(<mxsuperio>, <ping>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
((LPDWORD)lpOutBuffer)[0] = 0x01000001;
if (lpBytesReturned) *lpBytesReturned = 4;
break;
case IOCTL_MXSUPERIO_READ: {
BYTE chip = ((LPBYTE)lpInBuffer)[0];
BYTE device = ((LPBYTE)lpInBuffer)[1];
BYTE index = ((LPBYTE)lpInBuffer)[2];
BYTE* data = &((LPBYTE)lpInBuffer)[3];
log_misc("mxsuperio", "read: chip:%d device:%d index:%02x", chip, device, index);
/*
{
IN BYTE chip select (0 = base 0x2e, 1 = base 0x4e)
IN BYTE logical device (0 = FDC, 11 = HW mon)
IN BYTE index
OUT BYTE read value
}
The 846-5004D I have here is at base address 0x4e
*/
/*
from micedump:
0.20: 00 0b 20 ff
0.21: 00 0b 21 ff
1.20: 01 0b 20 a2
1.21: 01 0b 21 32
*/
*data = 0xff;
if (chip == 1) {
if (device == 11) {
switch (index) {
case 0x20:
*data = 0xa2;
break;
case 0x21:
*data = 0x32;
break;
}
}
}
if (lpBytesReturned) *lpBytesReturned = 4;
break;
}
case IOCTL_MXSUPERIO_WRITE:
log_misc("mxsuperio",
"DeviceIoControl(<mxsuperio>, <write>, 0x%p, 0x%x, -, "
"0x%x, -, -)",
lpInBuffer, nInBufferSize, nOutBufferSize);
/*
{
IN BYTE chip select (0 = base 0x2e, 1 = base 0x4e)
IN BYTE logical device (0 = FPC, 11 = HW mon)
IN BYTE index
IN BYTE write value
}
*/
if (lpBytesReturned) *lpBytesReturned = 4;
break;
case IOCTL_MXSUPERIO_HWMONITOR_LPC_READ: {
// TODO: This code is all for W83791D, however W83627UHG is more appropriate in some
// cases. Is this an AAL vs AAM difference? Where was the W83791D usage derived from?
BYTE index = lpc_packet->index;
BYTE reg = lpc_packet->reg;
switch (w83791d_bank) {
case 0x00: {
switch (reg) {
case W83627UHG_REG_FAN_CONF:
lpc_out->data = w83627uhg_fanconf;
break;
case W83627UHG_REG_FAN_CONF_2:
lpc_out->data = w83627uhg_fanconf_2;
break;
case W83627UHG_REG_CPUFANOUT_TEMP_SRC_SLCT:
lpc_out->data = w83627uhg_cpufanout_src_slct;
break;
case W83627UHG_REG_SYSFANOUT_TEMP_SRC_SLCT:
lpc_out->data = w83627uhg_sysfanout_src_slct;
break;
case W83627UHG_REG_SYSTIN_TARGET_TEMP:
lpc_out->data = w83627uhg_systin_target;
break;
case W83627UHG_REG_CPUTIN_TARGET_TEMP:
lpc_out->data = w83627uhg_cputin_target;
break;
case W83627UHG_REG_TARGET_TEMP_TOLERANCE:
lpc_out->data = w83627uhg_target_tolerance;
break;
case W83791D_REG_WCHIPID:
lpc_out->data = 0x71; // Observed: c1
break;
case W83791D_REG_CHIPMAN:
if (w83791d_4f_high)
lpc_out->data = 0x5c; // High byte
else
lpc_out->data = 0xa3; // Low byte
break;
case W83791D_REG_I2C_ADDR:
lpc_out->data = 0x11; // Observed: 2d
break;
case W83791D_REG_BANK:
lpc_out->data = w83791d_bank;
break;
case W83791D_REG_CONFIG:
lpc_out->data = w83791d_config;
break;
case W83791D_REG_BEEP_CTRL_0:
// No beeping :(
lpc_out->data = 0x00;
break;
// TODO: No idea how to read any of these. Pulled from real system
case W83791D_REG_TEMP1_0:
lpc_out->data = 0x1a;
break;
case W83791D_RAM_VCOREA:
lpc_out->data = 0x76;
break;
case W83791D_RAM_VNIR0:
lpc_out->data = 0x86;
break;
case W83791D_RAM_VDD5:
lpc_out->data = 0x94;
break;
case W83791D_RAM_12VIN:
lpc_out->data = 0xbe;
break;
case W83791D_RAM_N12VIN:
lpc_out->data = 0xd1;
break;
case W83791D_RAM_FAN1:
case W83791D_RAM_FAN2:
case W83791D_RAM_FAN3:
lpc_out->data = 0x00; // Fan no spinny!
break;
case W83791D_VID_FAN_DIV:
// Boths fans divide by 2 (01)
lpc_out->data = 0b00000101;
break;
case W83791D_VBAT_MONITOR_CONTROL:
lpc_out->data = w83791d_vbat_monitor_control;
break;
default:
log_error("mxsuperio", "Unknown HM b0 register: read 0x%02x", reg);
return FALSE;
// exit(1);
}
} break;
case 0x01: {
switch (reg) {
case W83791D_REG_BANK:
lpc_out->data = w83791d_bank;
break;
case W83791D_NONCRIT_TEMP_1:
lpc_out->data = w83791d_noncrit_t1;
break;
case W83791D_CRIT_TEMP_1:
lpc_out->data = w83791d_crit_t1;
break;
case W83791D_NONCRIT_TEMP_2:
lpc_out->data = w83791d_noncrit_t2;
break;
case W83791D_CRIT_TEMP_2:
lpc_out->data = w83791d_crit_t2;
break;
case W83791D_NONCRIT_TEMP_3:
lpc_out->data = w83791d_noncrit_t3;
break;
case W83791D_CRIT_TEMP_3:
lpc_out->data = w83791d_crit_t3;
break;
case W83791D_VIN0:
lpc_out->data = W83791D_ENTITY_CPU;
break;
case W83791D_VIN1:
lpc_out->data = W83791D_ENTITY_SYSTEM;
break;
default:
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
exit(1);
}
} break;
case 0x05: {
switch (reg) {
case W83791D_REG_BANK:
lpc_out->data = w83791d_bank;
break;
// Used in amHmReadVoltageInternal
// What are these??
case 0x51:
case 0x40:
lpc_out->data = 0xff;
break;
default:
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
return FALSE;
// exit(1);
}
} break;
default:
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
exit(1);
}
// reg 0x48 = LPC Chip ID
// index = 0,1
// data > 0x0f, data < 0x70
// lpc_out->data = eeprom_read_one(reg, index);
log_misc("mxsuperio", "amHmLpcReadByte Index=0x%02x Reg=0x%02x Data=0x%02x", index, reg,
lpc_out->data);
if (lpBytesReturned) *lpBytesReturned = sizeof(mxsuperio_lpc_packet);
} break;
case IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE: {
BYTE index = lpc_packet->index;
BYTE reg = lpc_packet->reg;
log_misc("mxsuperio", "amHmLpcWriteByte Index=0x%02x Reg=0x%02x Data=0x%02b", index,
reg, lpc_packet->data);
switch (w83791d_bank) {
case 0x00: {
switch (reg) {
case W83627UHG_REG_FAN_CONF:
w83627uhg_fanconf = lpc_packet->data;
break;
case W83627UHG_REG_FAN_CONF_2:
w83627uhg_fanconf_2 = lpc_packet->data;
break;
case W83627UHG_REG_CPUFANOUT_VALUE_SELECT:
// Just no-op this
break;
case W83627UHG_REG_CPUFANOUT_TEMP_SRC_SLCT:
w83627uhg_cpufanout_src_slct = lpc_packet->data;
break;
case W83627UHG_REG_SYSFANOUT_TEMP_SRC_SLCT:
w83627uhg_sysfanout_src_slct = lpc_packet->data;
break;
case W83627UHG_REG_SYSTIN_TARGET_TEMP:
w83627uhg_systin_target = lpc_packet->data;
break;
case W83627UHG_REG_CPUTIN_TARGET_TEMP:
w83627uhg_cputin_target = lpc_packet->data;
break;
case W83627UHG_REG_TARGET_TEMP_TOLERANCE:
w83627uhg_target_tolerance = lpc_packet->data;
break;
case W83627UHG_REG_SYSFANOUT_STOP_VALUE:
case W83627UHG_REG_SYSFANOUT_START_VALUE:
break;
case W83791D_REG_BEEP_CTRL_0:
// Ignore for now
break;
case W83791D_REG_BANK:
w83791d_4f_high = !!(lpc_packet->data & 0x80);
w83791d_bank = lpc_packet->data & 7;
break;
case W83791D_REG_CONFIG:
w83791d_config = lpc_packet->data;
break;
case W83791D_VBAT_MONITOR_CONTROL:
w83791d_vbat_monitor_control = lpc_packet->data;
break;
default:
log_error("mxsuperio", "Unknown HM b0 register: write 0x%02x", reg);
// exit(1);
}
break;
}
case 0x01: {
switch (reg) {
case W83791D_REG_BANK:
w83791d_4f_high = !!(lpc_packet->data & 0x80);
w83791d_bank = lpc_packet->data & 7;
break;
case W83791D_NONCRIT_TEMP_1:
w83791d_noncrit_t1 = lpc_packet->data;
break;
case W83791D_CRIT_TEMP_1:
w83791d_crit_t1 = lpc_packet->data;
break;
case W83791D_NONCRIT_TEMP_2:
w83791d_noncrit_t2 = lpc_packet->data;
break;
case W83791D_CRIT_TEMP_2:
w83791d_crit_t2 = lpc_packet->data;
break;
case W83791D_NONCRIT_TEMP_3:
w83791d_noncrit_t3 = lpc_packet->data;
break;
case W83791D_CRIT_TEMP_3:
w83791d_crit_t3 = lpc_packet->data;
break;
default:
log_error("mxsuperio", "Unknown HM b1 register: 0x%02x", reg);
exit(1);
}
} break;
case 0x05: {
switch (reg) {
case W83791D_REG_BANK:
w83791d_4f_high = !!(lpc_packet->data & 0x80);
w83791d_bank = lpc_packet->data & 7;
break;
// Used in amHmReadVoltageInternal
// What is this??
case 0x40:
break;
default:
log_error("mxsuperio", "Unknown HM b5 register: 0x%02x", reg);
return FALSE;
// exit(1);
}
} break;
default:
log_error("mxsuperio", "Unknown HM bank: 0x%02x", w83791d_bank);
exit(1);
}
if (lpBytesReturned) *lpBytesReturned = 0;
} break;
default:
log_warning("mxsuperio", "unhandled 0x%08x", dwIoControlCode);
return FALSE;
}
return TRUE;
}
void setup_mxsuperio() {
file_hook_t* mxsuperio = new_file_hook(L"\\\\.\\mxsuperio");
mxsuperio->DeviceIoControl = &mxsuperio_DeviceIoControl;
hook_file(mxsuperio);
}

View File

@ -0,0 +1,38 @@
# com.c
Generic hooks for com devices. The main COMs used are:
- COM 1: Camera
- COM 2: NFC
- COM 3: Touch
- COM 5-8: LEDs
These are defined in devices/
# files.c
Redirection hooks for files. These are used to redirect a number of locations to relative paths, and for `\\\\.\\driver` files.
# gui.c
Hooks for drawing over the game
# logging.c
Hooks for `[f]printf[_s]`, and event sources.
# network.c
Network hooks used to log when outbound TCP connections are made, and to redirect DNS.
# processes.c
(Disabled) hooks CreateProcess to re-inject ourself into any child processes too
# setupapi.c
Hooks the Setup API functions to inject fake devices (used for amPlatform and amEeprom)
# time.c
Hooks a handful of time-setting functions to NOP them

View File

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

View File

@ -1,12 +1,14 @@
#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();
#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"
#include "registry.h"
#include "drive.h"
void hook_all();

View File

@ -1,204 +1,181 @@
#include "com.h"
com_hook_t* com_hook_list = NULL;
com_hook_t* new_com_hook(BYTE port) {
com_hook_t* hook = (com_hook_t*)malloc(sizeof *hook);
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;
hook->SetCommState = NULL;
hook->GetCommTimeouts = NULL;
hook->SetCommTimeouts = NULL;
hook->SetupComm = NULL;
hook->PurgeComm = NULL;
hook->GetCommModemStatus = NULL;
hook->WaitCommEvent = NULL;
hook->ClearCommError = NULL;
return hook;
};
void hook_com(com_hook_t* hook) {
hook->next = NULL;
hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE));
*hook->virtual_handle = NULL;
if (com_hook_list == NULL) {
com_hook_list = hook;
return;
}
com_hook_t* hl = com_hook_list;
while (hl->next != NULL) hl = hl->next;
hl->next = hook;
};
BOOL WINAPI FakeGetCommState(HANDLE hFile, LPDCB lpDCB) {
log_misc(COMM_LOGGER, "GetCommState(0x%p, 0x%p)", hFile, lpDCB);
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->GetCommState == NULL) {
log_error(COMM_LOGGER, "GetCommState(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->GetCommState(hook->data, lpDCB);
}
hook = hook->next;
}
return TrueGetCommState(hFile, lpDCB);
}
BOOL WINAPI FakeSetCommState(HANDLE hFile, LPDCB lpDCB) {
log_misc(COMM_LOGGER, "SetCommState(0x%p, 0x%p)", hFile, lpDCB);
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->SetCommState == NULL) {
log_error(COMM_LOGGER, "SetCommState(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->SetCommState(hook->data, lpDCB);
}
hook = hook->next;
}
return TrueSetCommState(hFile, lpDCB);
}
BOOL WINAPI FakeGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
log_misc(COMM_LOGGER, "GetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->GetCommTimeouts == NULL) {
log_error(COMM_LOGGER, "GetCommTimeouts(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->GetCommTimeouts(hook->data, lpCommTimeouts);
}
hook = hook->next;
}
return TrueGetCommTimeouts(hFile, lpCommTimeouts);
}
BOOL WINAPI FakeSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
log_misc(COMM_LOGGER, "SetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->SetCommTimeouts == NULL) {
log_error(COMM_LOGGER, "SetCommTimeouts(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->SetCommTimeouts(hook->data, lpCommTimeouts);
}
hook = hook->next;
}
return TrueSetCommTimeouts(hFile, lpCommTimeouts);
}
BOOL WINAPI FakeSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) {
log_misc(COMM_LOGGER, "SetupCom(0x%p, 0x%08x, 0x%08x)", hFile, dwInQueue, dwOutQueue);
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->SetupComm == NULL) {
log_error(COMM_LOGGER, "SetupComm(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->SetupComm(hook->data, dwInQueue, dwOutQueue);
}
hook = hook->next;
}
return TrueSetupComm(hFile, dwInQueue, dwOutQueue);
}
BOOL WINAPI FakePurgeComm(HANDLE hFile, DWORD dwFlags) {
log_misc(COMM_LOGGER, "PurgeComm(0x%p, 0x%08x)", hFile, dwFlags);
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->PurgeComm == NULL) {
log_error(COMM_LOGGER, "PurgeComm(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->PurgeComm(hook->data, dwFlags);
}
hook = hook->next;
}
return TruePurgeComm(hFile, dwFlags);
}
BOOL WINAPI FakeGetCommModemStatus(HANDLE hFile, LPDWORD lpModelStat) {
log_misc(COMM_LOGGER, "GetCommModemStatus(0x%p, 0x%p)", hFile, lpModelStat);
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->GetCommModemStatus == NULL) {
log_error(COMM_LOGGER, "GetCommModemStatus(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->GetCommModemStatus(hook->data, lpModelStat);
}
hook = hook->next;
}
return TrueGetCommModemStatus(hFile, lpModelStat);
}
BOOL WINAPI FakeWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
log_misc(COMM_LOGGER, "WaitCommEvent");
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->WaitCommEvent == NULL) {
log_error(COMM_LOGGER, "WaitCommEvent(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->WaitCommEvent(hook->data, lpEvtMask, lpOverlapped);
}
hook = hook->next;
}
return TrueWaitCommEvent(hFile, lpEvtMask, lpOverlapped);
}
BOOL WINAPI FakeClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) {
log_misc(COMM_LOGGER, "ClearCommError");
com_hook_t* hook = com_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->ClearCommError == NULL) {
log_error(COMM_LOGGER, "ClearCommError(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->ClearCommError(hook->data, lpErrors, lpStat);
}
hook = hook->next;
}
return TrueClearCommError(hFile, lpErrors, lpStat);
}
void hook_commio() {
hook("Kernel32.dll", "GetCommState", FakeGetCommState, (void**)&TrueGetCommState, 6);
hook("Kernel32.dll", "SetCommState", FakeSetCommState, (void**)&TrueSetCommState, 6);
hook("Kernel32.dll", "GetCommTimeouts", FakeGetCommTimeouts, (void**)&TrueGetCommTimeouts, 6);
hook("Kernel32.dll", "SetCommTimeouts", FakeSetCommTimeouts, (void**)&TrueSetCommTimeouts, 6);
hook("Kernel32.dll", "SetupComm", FakeSetupComm, (void**)&TrueSetupComm, 6);
hook("Kernel32.dll", "PurgeComm", FakePurgeComm, (void**)&TruePurgeComm, 6);
hook("Kernel32.dll", "GetCommModemStatus", FakeGetCommModemStatus, (void**)&TrueGetCommModemStatus, 6);
hook("Kernel32.dll", "WaitCommEvent", FakeWaitCommEvent, (void**)&TrueWaitCommEvent, 6);
hook("Kernel32.dll", "ClearCommError", FakeClearCommError, (void**)&TrueClearCommError, 6);
#include "com.h"
#include "files.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;
hook->SetCommState = NULL;
hook->GetCommTimeouts = NULL;
hook->SetCommTimeouts = NULL;
hook->SetupComm = NULL;
hook->PurgeComm = NULL;
hook->GetCommModemStatus = NULL;
hook->WaitCommEvent = NULL;
hook->ClearCommError = NULL;
return hook;
}
void hook_com(com_hook_t* hook) {
hook->next = NULL;
hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE));
*hook->virtual_handle = NULL;
if (com_hook_list == NULL) {
com_hook_list = hook;
return;
}
com_hook_t* hl = com_hook_list;
while (hl->next != NULL) hl = hl->next;
hl->next = hook;
}
BOOL WINAPI FakeGetCommState(HANDLE hFile, LPDCB lpDCB) {
com_hook_t* hook = get_handle_com_hook(hFile);
log_misc(COMM_LOGGER, "GetCommState(0x%p, 0x%p) (%08x)", hFile, lpDCB, hook);
if (hook != NULL) {
if (hook->GetCommState == NULL) {
log_error(COMM_LOGGER, "GetCommState(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->GetCommState(hook->data, lpDCB);
}
return TrueGetCommState(hFile, lpDCB);
}
BOOL WINAPI FakeSetCommState(HANDLE hFile, LPDCB lpDCB) {
log_misc(COMM_LOGGER, "SetCommState(0x%p, 0x%p)", hFile, lpDCB);
com_hook_t* hook = get_handle_com_hook(hFile);
if (hook != NULL) {
if (hook->SetCommState == NULL) {
log_error(COMM_LOGGER, "SetCommState(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->SetCommState(hook->data, lpDCB);
}
return TrueSetCommState(hFile, lpDCB);
}
BOOL WINAPI FakeGetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
log_misc(COMM_LOGGER, "GetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
com_hook_t* hook = get_handle_com_hook(hFile);
if (hook != NULL) {
if (hook->GetCommTimeouts == NULL) {
log_error(COMM_LOGGER, "GetCommTimeouts(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->GetCommTimeouts(hook->data, lpCommTimeouts);
}
return TrueGetCommTimeouts(hFile, lpCommTimeouts);
}
BOOL WINAPI FakeSetCommTimeouts(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts) {
log_misc(COMM_LOGGER, "SetCommTimeouts(0x%p, 0x%p)", hFile, lpCommTimeouts);
com_hook_t* hook = get_handle_com_hook(hFile);
if (hook != NULL) {
if (hook->SetCommTimeouts == NULL) {
log_error(COMM_LOGGER, "SetCommTimeouts(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->SetCommTimeouts(hook->data, lpCommTimeouts);
}
return TrueSetCommTimeouts(hFile, lpCommTimeouts);
}
BOOL WINAPI FakeSetupComm(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue) {
log_misc(COMM_LOGGER, "SetupCom(0x%p, 0x%08x, 0x%08x)", hFile, dwInQueue, dwOutQueue);
com_hook_t* hook = get_handle_com_hook(hFile);
if (hook != NULL) {
if (hook->SetupComm == NULL) {
log_error(COMM_LOGGER, "SetupComm(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->SetupComm(hook->data, dwInQueue, dwOutQueue);
}
return TrueSetupComm(hFile, dwInQueue, dwOutQueue);
}
BOOL WINAPI FakePurgeComm(HANDLE hFile, DWORD dwFlags) {
log_misc(COMM_LOGGER, "PurgeComm(0x%p, 0x%08x)", hFile, dwFlags);
com_hook_t* hook = get_handle_com_hook(hFile);
if (hook != NULL) {
if (hook->PurgeComm == NULL) {
log_error(COMM_LOGGER, "PurgeComm(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->PurgeComm(hook->data, dwFlags);
}
return TruePurgeComm(hFile, dwFlags);
}
BOOL WINAPI FakeGetCommModemStatus(HANDLE hFile, LPDWORD lpModelStat) {
log_misc(COMM_LOGGER, "GetCommModemStatus(0x%p, 0x%p)", hFile, lpModelStat);
com_hook_t* hook = get_handle_com_hook(hFile);
if (hook != NULL) {
if (hook->GetCommModemStatus == NULL) {
log_error(COMM_LOGGER, "GetCommModemStatus(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->GetCommModemStatus(hook->data, lpModelStat);
}
return TrueGetCommModemStatus(hFile, lpModelStat);
}
BOOL WINAPI FakeWaitCommEvent(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped) {
log_misc(COMM_LOGGER, "WaitCommEvent(0x%p)", hFile);
com_hook_t* hook = get_handle_com_hook(hFile);
if (hook != NULL) {
if (hook->WaitCommEvent == NULL) {
log_error(COMM_LOGGER, "WaitCommEvent(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->WaitCommEvent(hook->data, lpEvtMask, lpOverlapped);
}
return TrueWaitCommEvent(hFile, lpEvtMask, lpOverlapped);
}
BOOL WINAPI FakeClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat) {
log_trace(COMM_LOGGER, "ClearCommError(0x%p)", hFile);
com_hook_t* hook = get_handle_com_hook(hFile);
if (hook != NULL) {
if (hook->ClearCommError == NULL) {
log_error(COMM_LOGGER, "ClearCommError(%ls) unimplemented", hook->wName);
return FALSE;
}
return hook->ClearCommError(hook->data, lpErrors, lpStat);
}
return TrueClearCommError(hFile, lpErrors, lpStat);
}
void hook_commio() {
hook("Kernel32.dll", "GetCommState", FakeGetCommState, (void**)&TrueGetCommState, 6);
hook("Kernel32.dll", "SetCommState", FakeSetCommState, (void**)&TrueSetCommState, 6);
hook("Kernel32.dll", "GetCommTimeouts", FakeGetCommTimeouts, (void**)&TrueGetCommTimeouts, 6);
hook("Kernel32.dll", "SetCommTimeouts", FakeSetCommTimeouts, (void**)&TrueSetCommTimeouts, 6);
hook("Kernel32.dll", "SetupComm", FakeSetupComm, (void**)&TrueSetupComm, 6);
hook("Kernel32.dll", "PurgeComm", FakePurgeComm, (void**)&TruePurgeComm, 6);
hook("Kernel32.dll", "GetCommModemStatus", FakeGetCommModemStatus,
(void**)&TrueGetCommModemStatus, 6);
hook("Kernel32.dll", "WaitCommEvent", FakeWaitCommEvent, (void**)&TrueWaitCommEvent, 6);
hook("Kernel32.dll", "ClearCommError", FakeClearCommError, (void**)&TrueClearCommError, 6);
}

View File

@ -1,49 +1,51 @@
#pragma once
#include "../common.h"
static BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB);
static BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB);
static BOOL(WINAPI* TrueGetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
static BOOL(WINAPI* TrueSetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
static BOOL(WINAPI* TrueSetupComm)(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue);
static BOOL(WINAPI* TruePurgeComm)(HANDLE hFile, DWORD dwFlags);
static BOOL(WINAPI* TrueGetCommModemStatus)(HANDLE hFile, LPDWORD lpModelStat);
static BOOL(WINAPI* TrueWaitCommEvent)(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
static BOOL(WINAPI* TrueClearCommError)(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat);
typedef BOOL(FnGetCommState)(void* com, LPDCB lpDCB);
typedef BOOL(FnSetCommState)(void* com, LPDCB lpDCB);
typedef BOOL(FnGetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
typedef BOOL(FnSetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
typedef BOOL(FnSetupComm)(void* com, DWORD dwInQueue, DWORD dwOutQueue);
typedef BOOL(FnPurgeComm)(void* com, DWORD dwFlags);
typedef BOOL(FnGetCommModemStatus)(void* com, LPDWORD lpModelStat);
typedef BOOL(FnWaitCommEvent)(void* com, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat);
typedef struct com_hook {
LPHANDLE virtual_handle;
WCHAR wName[7]; // max is "COM255"
WCHAR wDosName[11]; // max is "\\\\.\\COM255"
BYTE com;
FnGetCommState* GetCommState;
FnSetCommState* SetCommState;
FnGetCommTimeouts* GetCommTimeouts;
FnSetCommTimeouts* SetCommTimeouts;
FnSetupComm* SetupComm;
FnPurgeComm* PurgeComm;
FnGetCommModemStatus* GetCommModemStatus;
FnWaitCommEvent* WaitCommEvent;
FnClearCommError* ClearCommError;
void* data;
struct com_hook* next;
} com_hook_t;
com_hook_t* new_com_hook(BYTE port);
void hook_com(com_hook_t* hook);
void hook_commio();
#pragma once
#include "../common.h"
static BOOL(WINAPI* TrueGetCommState)(HANDLE hFile, LPDCB lpDCB);
static BOOL(WINAPI* TrueSetCommState)(HANDLE hFile, LPDCB lpDCB);
static BOOL(WINAPI* TrueGetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
static BOOL(WINAPI* TrueSetCommTimeouts)(HANDLE hFile, LPCOMMTIMEOUTS lpCommTimeouts);
static BOOL(WINAPI* TrueSetupComm)(HANDLE hFile, DWORD dwInQueue, DWORD dwOutQueue);
static BOOL(WINAPI* TruePurgeComm)(HANDLE hFile, DWORD dwFlags);
static BOOL(WINAPI* TrueGetCommModemStatus)(HANDLE hFile, LPDWORD lpModelStat);
static BOOL(WINAPI* TrueWaitCommEvent)(HANDLE hFile, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
static BOOL(WINAPI* TrueClearCommError)(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat);
typedef BOOL(FnGetCommState)(void* com, LPDCB lpDCB);
typedef BOOL(FnSetCommState)(void* com, LPDCB lpDCB);
typedef BOOL(FnGetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
typedef BOOL(FnSetCommTimeouts)(void* com, LPCOMMTIMEOUTS lpCommTimeouts);
typedef BOOL(FnSetupComm)(void* com, DWORD dwInQueue, DWORD dwOutQueue);
typedef BOOL(FnPurgeComm)(void* com, DWORD dwFlags);
typedef BOOL(FnGetCommModemStatus)(void* com, LPDWORD lpModelStat);
typedef BOOL(FnWaitCommEvent)(void* com, LPDWORD lpEvtMask, LPOVERLAPPED lpOverlapped);
typedef BOOL(FnClearCommError)(void* com, LPDWORD lpErrors, LPCOMSTAT lpStat);
typedef struct com_hook {
LPHANDLE virtual_handle;
WCHAR wName[16];
WCHAR wDosName[16];
BYTE com;
FnGetCommState* GetCommState;
FnSetCommState* SetCommState;
FnGetCommTimeouts* GetCommTimeouts;
FnSetCommTimeouts* SetCommTimeouts;
FnSetupComm* SetupComm;
FnPurgeComm* PurgeComm;
FnGetCommModemStatus* GetCommModemStatus;
FnWaitCommEvent* WaitCommEvent;
FnClearCommError* ClearCommError;
void* data;
struct com_hook* next;
} com_hook_t;
extern com_hook_t* com_hook_list;
com_hook_t* new_com_hook(BYTE port);
void hook_com(com_hook_t* hook);
void hook_commio();

View File

@ -0,0 +1,398 @@
#include "drive.h"
#include "./files.h"
BOOL c_drive_DeviceIoControl(void* file, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
log_trace("C", "DeviceIOControl %08x", dwIoControlCode);
memset(lpOutBuffer, 0, nInBufferSize);
switch (dwIoControlCode) {
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK;
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceNumber = 0;
return TRUE;
case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
((VOLUME_DISK_EXTENTS*)lpOutBuffer)->NumberOfDiskExtents = 1;
((VOLUME_DISK_EXTENTS*)lpOutBuffer)->Extents[0].StartingOffset.QuadPart = 0;
DWORD a = (sizeof(*((VOLUME_DISK_EXTENTS*)lpOutBuffer)));
return TRUE;
default:
return FALSE;
}
}
LARGE_INTEGER pd0_file_pointer;
BOOL pd0_SetFilePointerEx(void* file, LARGE_INTEGER liDistanceToMove,
PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) {
log_trace("pd0", "Seek 0x%08x", liDistanceToMove.QuadPart);
if (dwMoveMethod == FILE_BEGIN)
pd0_file_pointer = liDistanceToMove;
else
pd0_file_pointer.QuadPart += liDistanceToMove.QuadPart;
if (lpNewFilePointer) lpNewFilePointer->QuadPart = pd0_file_pointer.QuadPart;
return TRUE;
}
DWORD pd0_SetFilePointer(void* file, LONG liDistanceToMove, PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod) {
if (lpDistanceToMoveHigh && *lpDistanceToMoveHigh)
log_trace("pd0", "Seek 0x%x%08x", *lpDistanceToMoveHigh, liDistanceToMove);
else
log_trace("pd0", "Seek 0x%08x", liDistanceToMove);
if (dwMoveMethod == FILE_BEGIN) {
if (lpDistanceToMoveHigh)
pd0_file_pointer.HighPart = *lpDistanceToMoveHigh;
else
pd0_file_pointer.HighPart = 0;
pd0_file_pointer.LowPart = liDistanceToMove;
} else {
pd0_file_pointer.QuadPart += liDistanceToMove;
if (lpDistanceToMoveHigh) pd0_file_pointer.HighPart += *lpDistanceToMoveHigh;
}
return pd0_file_pointer.LowPart;
}
void write_chs(BYTE* chs, WORD cylinder, BYTE head, BYTE sector) {
chs[0] = head;
chs[1] = sector | ((cylinder >> 8) << 6);
chs[2] = cylinder & 0xff;
}
#pragma pack(1)
typedef struct spd {
uint32_t crc;
uint8_t version;
uint8_t _[11];
#pragma pack(1)
struct {
/*
(BCD)
1.0 = original0
1.1 = original1
2.0 = patch0
2.1 = patch1
3.0 = os
4.0 = app_data
*/
spd_slot_t slot_content;
/*
Guess: Filesystem type
0: Encrypted FAT16
1: Decrypted NTFS
*/
uint8_t uk1;
uint16_t block_size;
uint32_t block_count;
uint8_t __[8];
} slots[31];
} spd_t;
#pragma pack(1)
typedef struct {
uint16_t year;
uint8_t mon;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint8_t _;
} slot_time_t;
#pragma pack(1)
typedef struct {
char id[4];
slot_time_t time;
uint32_t version;
uint32_t _[2];
uint32_t segcount;
uint32_t segsize;
char hw[3];
uint8_t instant;
slot_time_t orgtime;
uint32_t orgversion;
uint32_t osver;
uint32_t ossegcount;
uint8_t __[8];
} sbr_slot_t;
#pragma pack(1)
enum {
Slot_Check = 0x00, // status=error
Slot_Install = 0x01, // status=install -> FAILED TO READ PREMADE BLOCK!!
Slot_Complete = 0x02, // status=complete
Slot_Empty = 0x03, // status=error
Slot_Error = 0x04, // status=error
Slot_Invalid = 0xff,
};
typedef uint8_t slot_status_t;
#pragma pack(1)
typedef struct {
uint32_t crc;
uint8_t version;
uint8_t _[11 + 16 + 32];
uint8_t bootslot;
uint8_t __[2];
slot_status_t slot_status[5];
uint8_t ___[8 + 16 + 32 + 64];
sbr_slot_t slot_os;
sbr_slot_t slot_original0;
sbr_slot_t slot_appdata;
sbr_slot_t slot_patch0;
sbr_slot_t slot_patch1;
} sbr_t;
sbr_t SegaBootRecord = {
.version = SBR_VERSION,
.bootslot = 0x02,
.slot_status = { Slot_Complete, Slot_Complete, Slot_Invalid, Slot_Check, Slot_Complete },
.slot_os = {
// Starts at 0xc5469400
// i.e. [partition 6] - (segcount * segsize)
// i.e. partition 5 = [dead space] [slot_os]
.id = {'A', 'A', 'S', '0'},
.time = { 0 },
.version = 0x450a01,
.segcount = 1745,
.segsize = 0x40000,
.hw = { 'A', 'A', 'S' },
.instant = 0,
.osver = 0x450a01,
.ossegcount = 0,
.orgtime = { 0 },
.orgversion = 0x450a01,
},
.slot_original0 = {
// Starts at 0xb065bae00
// i.e. [end of disk] - (segcount * segsize)
// i.e. partition 9 = [dead space] [slot_original0]
.id = {'S', 'D', 'E', 'Y'},
.time = { 2018, 10, 29, 15, 7, 36 },
.version = 0x10061,
.segcount = 65082,
.segsize = 0x40000,
.hw = { 'A', 'A', 'S' },
.instant = 0,
.osver = 0x450a01,
.ossegcount = 1745,
.orgtime = { 2018, 10, 29, 15, 7, 36 },
.orgversion = 0x10061,
},
.slot_appdata = { 0 },
.slot_patch0 = {
// Starts at 0x15e49a000
// i.e. [partition 7] - (segcount * segsize)
// i.e. partition 6 = [dead space] [something] [patch0]
.id = { 'S', 'D', 'D', 'Z' },
.time = { 2018, 6, 21, 13, 46, 24 },
.version = 0x10060,
.segcount = 173,
.segsize = 0x40000,
.hw = { 'A', 'A', 'S' },
.instant = 0,
.osver = 0,
.ossegcount = 0,
.orgtime = { 2018, 5, 16, 20, 7, 12 },
.orgversion = 0x01005f,
},
.slot_patch1 = {
// Starts at 0x1debcac00
// i.e. [partition 8] - (segcount * segsize)
// i.e. partition 7 = [dead space] [something] [patch0]
.id = { 'S', 'D', 'E', 'Y' },
.time = { 2018, 11, 16, 19, 4, 48},
.version = 0x10062,
.segcount = 173,
.segsize = 0x40000,
.hw = { 'A', 'A', 'S' },
.instant = 0,
.osver = 0,
.ossegcount = 0,
.orgtime = { 2018, 10, 29, 15, 7, 36 },
.orgversion = 0x10061,
},
};
#define BOOT_PARITION_SIZE 0x300B85 // 1.5GB
#define RECOVER_PARTITION_SIZE 0x300BC4 // 1.5GB
typedef struct {
uint32_t size;
uint8_t type;
spd_slot_t content;
} partition_t;
partition_t partitions[] = {
{ 0x102d83, MBR_FS_FAT16, SPD_OS }, // 512MB OS update
{ 0x403947, MBR_FS_FAT16, SPD_Patch0 }, // 2GB patch0
{ 0x403947, MBR_FS_FAT16, SPD_Patch1 }, // 2GB patch1
{ 0x48ed459, MBR_FS_NTFS, SPD_AppData }, // 40GB something
{ 0x20014aa, MBR_FS_FAT16, SPD_Original0 }, // 16GB game
};
#define NUM_PARITIONS (sizeof partitions / sizeof partitions[0])
#define MBR_LBA_GAP 0x3f // 1 track worth of sectors is claimed for the MBR
#define BLOCKSIZE 512ll
#define SPD_OFFSET ((extended_base * BLOCKSIZE) + sizeof(mbr_t))
#define SBR0_OFFSET (SPD_OFFSET + sizeof (spd_t))
#define SBR1_OFFSET (SBR0_OFFSET + sizeof SegaBootRecord)
BOOL pd0_ReadFile(void* file, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
log_info("pd0", "Read %d @ %llx", nNumberOfBytesToRead, pd0_file_pointer.QuadPart);
uint32_t ext_offset = 0;
uint32_t offsets[NUM_PARITIONS];
uint32_t extended_base = MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE;
for (int i = 0; i < NUM_PARITIONS; i++) {
offsets[i] = ext_offset;
ext_offset += partitions[i].size + MBR_LBA_GAP;
}
printf("%08x\n", offsets[0]);
printf("%08x\n", extended_base);
// MBR (C+Recover+Extend)
if (pd0_file_pointer.QuadPart == 0) {
mbr_t* mbr = (mbr_t*)lpBuffer;
memset(mbr, 0, sizeof *mbr);
mbr->sig[0] = 0x55;
mbr->sig[1] = 0xAA;
// 1.5GB C parition
mbr->partitions[0].status = MBR_FLAG_BOOTABLE;
mbr->partitions[0].type = MBR_FS_NTFS;
mbr->partitions[0].lba = MBR_LBA_GAP;
mbr->partitions[0].sectors = BOOT_PARITION_SIZE;
// 1.5GB Recovery
mbr->partitions[1].status = MBR_FLAG_NONE;
mbr->partitions[1].type = MBR_FS_NTFS;
mbr->partitions[1].lba = MBR_LBA_GAP + BOOT_PARITION_SIZE;
mbr->partitions[1].sectors = RECOVER_PARTITION_SIZE;
// Everything else is in an extended
mbr->partitions[2].status = MBR_FLAG_NONE;
mbr->partitions[2].type = MBR_FS_EXT_LBA;
mbr->partitions[2].lba = MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE;
mbr->partitions[2].sectors = ext_offset;
*lpNumberOfBytesRead = sizeof *mbr;
return TRUE;
}
// Extended partitions
for (int i = 0; i < NUM_PARITIONS; i++) {
if (pd0_file_pointer.QuadPart != ((extended_base + offsets[i]) * BLOCKSIZE)) continue;
mbr_t* mbr = (mbr_t*)lpBuffer;
memset(mbr, 0, sizeof *mbr);
mbr->sig[0] = 0x55;
mbr->sig[1] = 0xAA;
mbr->partitions[0].status = MBR_FLAG_NONE;
mbr->partitions[0].type = partitions[i].type;
mbr->partitions[0].lba = MBR_LBA_GAP;
mbr->partitions[0].sectors = partitions[i].size;
if (i != NUM_PARITIONS - 1) {
mbr->partitions[1].status = MBR_FLAG_NONE;
mbr->partitions[1].type = MBR_FS_EXT_CHS;
mbr->partitions[1].lba = offsets[i + 1];
mbr->partitions[1].sectors = partitions[i + 1].size + MBR_LBA_GAP;
}
*lpNumberOfBytesRead = sizeof *mbr;
return TRUE;
}
crc32_build_table();
SegaBootRecord.crc = crc32(sizeof SegaBootRecord - 4, &SegaBootRecord.version, 0);
// SEGA Partition Description
if (pd0_file_pointer.QuadPart == SPD_OFFSET) {
spd_t* spd = (spd_t*)lpBuffer;
spd->version = SPD_VERSION;
for (uint8_t i = 0; i < NUM_PARITIONS; i++) {
spd->slots[i].block_size = BLOCKSIZE;
spd->slots[i].block_count = partitions[i].size;
spd->slots[i].slot_content = partitions[i].content;
spd->slots[i].uk1 = partitions[i].type == MBR_FS_FAT16 ? 0 : 1;
}
spd->crc = crc32(sizeof *spd - 4, &(spd->version), 0);
*lpNumberOfBytesRead = sizeof *spd;
return TRUE;
}
// SEGA Boot Record 0 and 1. The two are a redundant copy of each other
if (pd0_file_pointer.QuadPart == SBR0_OFFSET || pd0_file_pointer.QuadPart == SBR1_OFFSET) {
memcpy(lpBuffer, &SegaBootRecord, sizeof SegaBootRecord);
*lpNumberOfBytesRead = sizeof SegaBootRecord;
return TRUE;
}
// Read within a partition
if (pd0_file_pointer.QuadPart < MBR_LBA_GAP * BLOCKSIZE) {
log_error("pd0", "Read performed within the first track of disk!");
} else if (pd0_file_pointer.QuadPart < (MBR_LBA_GAP + BOOT_PARITION_SIZE) * BLOCKSIZE) {
log_warning("pd0", "Game attempting to read windows partition!");
} else if (pd0_file_pointer.QuadPart <
(MBR_LBA_GAP + BOOT_PARITION_SIZE + RECOVER_PARTITION_SIZE) * BLOCKSIZE) {
log_warning("pd0", "Game attempting to read recovery partition!");
} else {
for (int i = 0; i < NUM_PARITIONS; i++) {
if (pd0_file_pointer.QuadPart <
(offsets[i] + MBR_LBA_GAP + extended_base) * BLOCKSIZE) {
log_error("pd0", "Read performed within the first track of partition %d!", i + 5);
goto warned;
} else if (pd0_file_pointer.QuadPart <
(offsets[i] + MBR_LBA_GAP + partitions[i].size + extended_base) *
BLOCKSIZE) {
log_warning("pd0", "Read performed within partition %d", i + 5);
goto warned;
}
}
log_error("pd0", "Read to unmapped address: %llx (%d bytes)", pd0_file_pointer.QuadPart,
nNumberOfBytesToRead);
warned:;
}
return FALSE;
}
BOOL pd0_WriteFile(void* file, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
log_warning("pd0", "Write %d @ %llx", nNumberOfBytesToWrite, pd0_file_pointer.QuadPart);
for (DWORD i = 0; i < nNumberOfBytesToWrite; i += 32) {
for (int j = 0; j < 32; j++) {
printf("%02x ", ((BYTE*)lpBuffer)[i + j]);
}
puts("");
}
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
return TRUE;
}
void hook_drives() {
file_hook_t* c_drive = new_file_hook(L"\\\\.\\C:");
c_drive->DeviceIoControl = &c_drive_DeviceIoControl;
hook_file(c_drive);
file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive0");
// file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive2063598201");
// file_hook_t* physical_drive_0 = new_file_hook(L"\\\\.\\PhysicalDrive1811939950");
physical_drive_0->SetFilePointerEx = pd0_SetFilePointerEx;
physical_drive_0->SetFilePointer = pd0_SetFilePointer;
physical_drive_0->ReadFile = pd0_ReadFile;
physical_drive_0->WriteFile = pd0_WriteFile;
hook_file(physical_drive_0);
}

View File

@ -0,0 +1,43 @@
#pragma once
#include "common.h"
void hook_drives();
// MBR
#define MBR_FLAG_NONE 0x00
#define MBR_FLAG_BOOTABLE 0x80
#define MBR_FS_NONE 0x00
#define MBR_FS_EXT_CHS 0x05
#define MBR_FS_FAT16 0x06
#define MBR_FS_NTFS 0x07
#define MBR_FS_EXT_LBA 0x0F
#pragma pack(1)
typedef struct mbr {
BYTE bootstrap_code[446];
#pragma pack(1)
struct {
BYTE status;
BYTE start_chs[3];
BYTE type;
BYTE end_chs[3];
DWORD lba;
DWORD sectors;
} partitions[4];
BYTE sig[2];
} mbr_t;
// SEGA
#define SPD_VERSION 1
#define SBR_VERSION 1
enum spd_slot {
SPD_Original0 = 0x10,
SPD_Original1 = 0x11,
SPD_Patch0 = 0x20,
SPD_Patch1 = 0x21,
SPD_OS = 0x30,
SPD_AppData = 0x40,
};
typedef uint8_t spd_slot_t;

View File

@ -1,256 +1,365 @@
#include "files.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;
return hook;
}
void hook_file(file_hook_t* hook) {
hook->next = NULL;
hook->virtual_handle = (LPHANDLE)malloc(sizeof(HANDLE));
*hook->virtual_handle = NULL;
if (file_hook_list == NULL) {
file_hook_list = hook;
return;
}
file_hook_t* hl = file_hook_list;
while (hl->next != NULL) hl = hl->next;
hl->next = hook;
};
drive_redirect_t DRIVE_REDIRECT_TABLE[] = {
{ .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++) {
drive_redirect_t row = DRIVE_REDIRECT_TABLE[i];
if (strstr(path, row.drive)) {
log_misc(HOOKS_LOGGER, "Redirecting '%s' to '%s'", path, row.path);
size_t new_len = strlen(path) - strlen(row.drive) + strlen(row.path);
// TODO: Make this not leak memory!
char* new_str = (char*)malloc(new_len + 1);
strcpy_s(new_str, new_len + 1, row.path);
char* dst = new_str + strlen(row.path);
size_t len = strlen(path) - strlen(row.drive);
char* src = path + strlen(row.drive);
for (; len > 0; len--) (dst++)[0] = (src++)[0];
dst[0] = 0;
log_misc(HOOKS_LOGGER, "New filename: '%s'", new_str);
return new_str;
}
}
return path;
}
HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
HANDLE handle = NULL;
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
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;
}
if (handle == NULL) {
handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition,
dwFlagsAndAttributes, hTemplateFile);
}
log_misc(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
return handle;
}
HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) {
lpFileName = redirect_path((char*)lpFileName);
WCHAR wideFileName[MAX_PATH + 1];
MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, (LPWSTR)&wideFileName, MAX_PATH + 1);
HANDLE result = FakeCreateFileW((LPCWSTR)&wideFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
log_misc(HOOKS_LOGGER, "^-> CreateFileA(%s) -> 0x%p", lpFileName, result);
return result;
}
BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize,
LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped) {
log_misc(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice, dwIoControlCode,
lpInBuffer, nInBufferSize, nOutBufferSize);
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hDevice) {
if (hook->DeviceIoControl) {
// TODO: Less jank
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
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;
}
}
hook = hook->next;
}
// log_warning(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, -, -, -, -, 0, 0)", hDevice, dwIoControlCode);
return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, nOutBufferSize,
lpBytesReturned, lpOverlapped);
}
DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod) {
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->SetFilePointer) {
return hook->SetFilePointer(hook->data, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
} else {
log_error(HOOKS_LOGGER, "SetFilePointer(%ls) unimplemented", hook->filename);
return FALSE;
}
}
hook = hook->next;
}
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(hook->data, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten,
lpOverlapped);
} else {
log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", hook->filename);
return FALSE;
}
}
hook = hook->next;
}
return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
}
BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped) {
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (*hook->virtual_handle == hFile) {
if (hook->ReadFile) {
return hook->ReadFile(hook->data, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
} else {
log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", hook->filename);
return FALSE;
}
}
hook = hook->next;
}
return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}
BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
file_hook_t* hook = file_hook_list;
while (hook != NULL) {
if (hObject != NULL && *hook->virtual_handle == hObject) {
log_misc("file", "close %08x", hObject);
return TRUE;
}
hook = hook->next;
}
return TrueCloseHandle(hObject);
}
int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) {
path = redirect_path((char*)path);
return True_stat64i32(path, buffer);
};
void hook_io() {
hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl, 5);
hook("Kernel32.dll", "CreateFileA", FakeCreateFileA, (void**)&TrueCreateFileA, 6);
hook("Kernel32.dll", "CreateFileW", FakeCreateFileW, (void**)&TrueCreateFileW, 6);
hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6);
hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6);
hook("Kernel32.dll", "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);
}
#include "files.h"
open_hook_t* open_hooks_list = NULL;
HANDLE open_hook(file_hook_t* file_hook, com_hook_t* com_hook) {
open_hook_t* opened = (open_hook_t*)malloc(sizeof(open_hook_t));
memset(opened, 0, sizeof *opened);
opened->file_hook = file_hook;
opened->com_hook = com_hook;
CHAR path[MAX_PATH];
GetModuleFileNameA(NULL, path, MAX_PATH);
HANDLE handle =
_CreateFileA(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (handle == INVALID_HANDLE_VALUE) {
log_error(HOOKS_LOGGER, "Failed to create dummy handle: %03x", GetLastError());
return INVALID_HANDLE_VALUE;
}
opened->handle = handle;
opened->next = open_hooks_list;
open_hooks_list = opened;
return handle;
}
void close_hook(HANDLE handle) {
if (handle == INVALID_HANDLE_VALUE) return;
_CloseHandle(handle);
open_hook_t* opened = NULL;
open_hook_t* root = open_hooks_list;
if (open_hooks_list->handle == handle) {
open_hook_t* next = open_hooks_list->next;
free(open_hooks_list);
open_hooks_list = next;
return;
}
while (root != NULL) {
if (root->next && root->next->handle == handle) {
opened = root->next;
root->next = opened->next;
free(opened);
return;
}
root = root->next;
}
}
file_hook_t* get_handle_file_hook(HANDLE handle) {
open_hook_t* root = open_hooks_list;
while (root != NULL) {
if (root->handle == handle) return root->file_hook;
root = root->next;
}
return NULL;
}
com_hook_t* get_handle_com_hook(HANDLE handle) {
open_hook_t* root = open_hooks_list;
while (root != NULL) {
if (root->handle == handle) return root->com_hook;
root = root->next;
}
return NULL;
}
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 *hook);
hook->filename = filename;
return hook;
}
void hook_file(file_hook_t* hook) {
hook->next = NULL;
if (file_hook_list == NULL) {
file_hook_list = hook;
return;
}
file_hook_t* hl = file_hook_list;
while (hl->next != NULL) hl = hl->next;
hl->next = hook;
};
drive_redirect_t DRIVE_REDIRECT_TABLE[] = {
{ .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\\"},
{ .drive = "C:\\\\Windows\\\\System32\\", .path = "Sys32" },
{ .drive = "C:\\\\WINDOWS\\\\system32\\", .path = "Sys32" },
};
LPCSTR redirect_path(LPCSTR path) {
for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) {
drive_redirect_t row = DRIVE_REDIRECT_TABLE[i];
if (strstr(path, row.drive)) {
log_misc(HOOKS_LOGGER, "Redirecting '%s' to '%s'", path, row.path);
size_t new_len = strlen(path) - strlen(row.drive) + strlen(row.path);
// TODO: Make this not leak memory!
char* new_str = (char*)malloc(new_len + 1);
strcpy_s(new_str, new_len + 1, row.path);
char* dst = new_str + strlen(row.path);
size_t len = strlen(path) - strlen(row.drive);
const char* src = path + strlen(row.drive);
for (; len > 0; len--) (dst++)[0] = (src++)[0];
dst[0] = 0;
log_misc(HOOKS_LOGGER, "New filename: '%s'", new_str);
return new_str;
}
}
return path;
}
LPCWSTR redirect_path_w(LPCWSTR path) {
return path;
// TODO: THIS!!
for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) {
drive_redirect_t row = DRIVE_REDIRECT_TABLE[i];
if (wcsstr(path, row.drive)) {
log_misc(HOOKS_LOGGER, "Redirecting '%ls' to '%ls'", path, row.path);
size_t new_len = wcslen(path) - wcslen(row.drive) + wcslen(row.path);
// TODO: Make this not leak memory!
wchar_t* new_str = (wchar_t*)malloc((new_len + 1) * 2);
wcscpy_s(new_str, new_len + 1, row.path);
wchar_t* dst = new_str + wcslen(row.path) * 2;
size_t len = wcslen(path) - wcslen(row.drive);
const wchar_t* src = path + wcslen(row.drive) * 2;
for (; len > 0; len--) {
(dst++)[0] = (src++)[0];
(dst++)[0] = (src++)[0];
}
dst[0] = 0;
log_misc(HOOKS_LOGGER, "New filename: '%ls'", new_str);
return new_str;
}
}
return path;
}
void find_hooks(LPCWSTR lpFileName, file_hook_t** found_fh, com_hook_t** found_ch) {
file_hook_t* file_hook = file_hook_list;
while (file_hook != NULL) {
if (wcscmp(lpFileName, file_hook->filename) == 0 ||
(file_hook->altFilename != NULL && wcscmp(lpFileName, file_hook->altFilename) == 0)) {
*found_fh = file_hook;
break;
}
file_hook = file_hook->next;
}
com_hook_t* com_hook = com_hook_list;
while (com_hook != NULL) {
if (wcscmp(lpFileName, com_hook->wName) == 0 ||
wcscmp(lpFileName, com_hook->wDosName) == 0) {
*found_ch = com_hook;
break;
}
com_hook = com_hook->next;
}
};
HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile) {
file_hook_t* found_fh = NULL;
com_hook_t* found_ch = NULL;
find_hooks(lpFileName, &found_fh, &found_ch);
if (found_fh != NULL || found_ch != NULL) {
HANDLE handle = open_hook(found_fh, found_ch);
log_info(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
return handle;
}
lpFileName = redirect_path_w(lpFileName);
HANDLE handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
log_misc(HOOKS_LOGGER, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
return handle;
}
HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile) {
WCHAR wideFileName[MAX_PATH + 1];
MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, (LPWSTR)&wideFileName, MAX_PATH + 1);
file_hook_t* found_fh = NULL;
com_hook_t* found_ch = NULL;
find_hooks(wideFileName, &found_fh, &found_ch);
if (found_fh != NULL || found_ch != NULL) {
HANDLE handle = open_hook(found_fh, found_ch);
log_info(HOOKS_LOGGER, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
return handle;
}
lpFileName = redirect_path(lpFileName);
HANDLE handle = TrueCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
log_misc(HOOKS_LOGGER, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
return handle;
// lpFileName = redirect_path(lpFileName);
// HANDLE result =
// FakeCreateFileW((LPCWSTR)&wideFileName, dwDesiredAccess, dwShareMode,
// lpSecurityAttributes,
// dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
// log_trace(HOOKS_LOGGER, "^-> CreateFileA(%s) -> 0x%p", lpFileName, result);
// return result;
}
BOOL WINAPI FakeDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
file_hook_t* hook = get_handle_file_hook(hDevice);
if (hook != NULL) {
if (hook->DeviceIoControl) {
// TODO: Less jank
if (lpOverlapped != NULL) SetEvent(lpOverlapped->hEvent);
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;
}
}
log_trace(HOOKS_LOGGER, "DeviceIoControl(0x%p, 0x%08x, 0x%p, 0x%x, -, 0x%x, 0, 0)", hDevice,
dwIoControlCode, lpInBuffer, nInBufferSize, nOutBufferSize);
return TrueDeviceIoControl(hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
nOutBufferSize, lpBytesReturned, lpOverlapped);
}
DWORD WINAPI FakeSetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh,
DWORD dwMoveMethod) {
file_hook_t* hook = get_handle_file_hook(hFile);
if (hook != NULL) {
if (hook->SetFilePointer) {
return hook->SetFilePointer(hook->data, lDistanceToMove, lpDistanceToMoveHigh,
dwMoveMethod);
} else {
log_error(HOOKS_LOGGER, "SetFilePointer(%ls) unimplemented", hook->filename);
return FALSE;
}
}
return TrueSetFilePointer(hFile, lDistanceToMove, lpDistanceToMoveHigh, dwMoveMethod);
}
BOOL WINAPI FakeSetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove,
PLARGE_INTEGER lpNewFilePointer, DWORD dwMoveMethod) {
file_hook_t* hook = get_handle_file_hook(hFile);
if (hook != NULL) {
if (hook->SetFilePointerEx) {
return hook->SetFilePointerEx(hook->data, liDistanceToMove, lpNewFilePointer,
dwMoveMethod);
} else {
log_error(HOOKS_LOGGER, "SetFilePointerEx(%ls) unimplemented", hook->filename);
return FALSE;
}
}
return TrueSetFilePointerEx(hFile, liDistanceToMove, lpNewFilePointer, dwMoveMethod);
}
DWORD WINAPI FakeGetFileSizeEx(HANDLE hFile, PLARGE_INTEGER lpFileSize) {
file_hook_t* hook = get_handle_file_hook(hFile);
if (hook != NULL) {
if (hook->GetFileSizeEx) {
return hook->GetFileSizeEx(hook->data, lpFileSize);
} else {
log_error(HOOKS_LOGGER, "GetFileSizeEx(%ls) unimplemented", hook->filename);
return FALSE;
}
}
return TrueGetFileSizeEx(hFile, lpFileSize);
}
DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
log_trace("file", "WriteFile(%08x)", hFile);
file_hook_t* hook = get_handle_file_hook(hFile);
if (hook != NULL) {
if (hook->WriteFile) {
return hook->WriteFile(hook->data, lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten, lpOverlapped);
} else {
log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", hook->filename);
return FALSE;
}
}
return FALSE;
return TrueWriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten,
lpOverlapped);
}
BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
file_hook_t* hook = get_handle_file_hook(hFile);
if (hook != NULL) {
if (hook->ReadFile) {
return hook->ReadFile(hook->data, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
lpOverlapped);
} else {
log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", hook->filename);
return FALSE;
}
}
return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
}
BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
file_hook_t* hook = get_handle_file_hook(hObject);
if (hook != NULL) {
log_misc("file", "close %08x", hObject);
close_hook(hObject);
return TRUE;
}
return TrueCloseHandle(hObject);
}
int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) {
path = redirect_path((char*)path);
return True_stat64i32(path, buffer);
};
void hook_io() {
hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl, 5);
hook("Kernel32.dll", "CreateFileA", FakeCreateFileA, (void**)&TrueCreateFileA, 6);
hook("Kernel32.dll", "CreateFileW", FakeCreateFileW, (void**)&TrueCreateFileW, 6);
hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6);
hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6);
hook("Kernel32.dll", "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

@ -1,72 +1,98 @@
#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();
#pragma once
#include "../common.h"
#include "com.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);
typedef struct _stat64i32 _stat64i32_t;
static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer);
#define _WriteFile (TrueWriteFile ? TrueWriteFile : WriteFile)
#define _ReadFile (TrueReadFile ? TrueReadFile : ReadFile)
#define _CloseHandle (TrueCloseHandle ? TrueCloseHandle : CloseHandle)
#define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW)
#define _CreateFileA (TrueCreateFileA ? TrueCreateFileA : CreateFileA)
typedef struct drive_redirect {
const CHAR* drive;
const CHAR* path;
} drive_redirect_t;
typedef struct drive_redirect_w {
const WCHAR* drive;
const WCHAR* path;
} drive_redirect_w_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;
typedef struct open_hook {
HANDLE handle;
file_hook_t* file_hook;
com_hook_t* com_hook;
struct open_hook* next;
} open_hook_t;
extern file_hook_t* file_hook_list;
file_hook_t* new_file_hook(LPCWSTR filename);
void hook_file(file_hook_t* hook);
void hook_io();
void close_hook(HANDLE handle);
file_hook_t* get_handle_file_hook(HANDLE handle);
com_hook_t* get_handle_com_hook(HANDLE handle);

View File

@ -1,99 +1,103 @@
#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);
}
#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, ...) {
size_t 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 ret;
}
int WINAPIV Fakefprintf(FILE* _File, const char* _Format, ...) {
size_t 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;
}
int WINAPIV Fakevfprintf_s(FILE* _Stream, const char* _Format, va_list _ArgList) {
return vlog_game("vfprintf_s", _Format, _ArgList);
}
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("MSVCR90.DLL", "vfprintf_s", Fakevfprintf_s, (void**)&Truevfprintf_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

@ -1,16 +1,17 @@
#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();
#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, ...);
static int(WINAPIV* Truevfprintf_s)(FILE* _Stream, const char* _Format, va_list _ArgList);
void hook_logging();

View File

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

View File

@ -1,85 +1,133 @@
#include "network.h"
int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
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);
return True_connect(s, name, namelen);
}
DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) {
DWORD ret = TrueGetIfTable(pIfTable, pdwSize, bOrder);
if (ret == NO_ERROR) {
for (size_t i = 0; i < pIfTable->dwNumEntries; i++) {
pIfTable->table[i].bPhysAddr[0] = 0x00;
pIfTable->table[i].bPhysAddr[1] = 0xD0;
pIfTable->table[i].bPhysAddr[2] = 0xF1;
}
}
return ret;
}
const char* INTERCEPT_DNS[] = {
"naominet.jp", // Startup
"ib.naominet.jp", // Billing
"aime.naominet.jp", // Aime (duh)
"tenporouter.loc", // Routers
"bbrouter.loc", //
"mobirouter.loc", //
"dslrouter.loc", //
};
DNS_RECORDA dummy_record;
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) {
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 %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 =
(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);
}
#include "network.h"
int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
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);
return True_connect(s, name, namelen);
}
static uint8_t spoof_mac[6] = { 0xD8, 0xBB, 0xC1, 0x0A, 0x2F, 0x1D };
#define IF_INDEX 1
DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) {
log_info("network", "Injecting fake IfTable");
MIB_IFROW* row;
uint32_t nbytes;
if (pdwSize == NULL) return ERROR_INVALID_PARAMETER;
nbytes = *pdwSize;
*pdwSize = sizeof(*row) + sizeof(DWORD);
if (pIfTable == NULL || nbytes < sizeof(*row) + sizeof(DWORD)) {
return ERROR_INSUFFICIENT_BUFFER;
}
pIfTable->dwNumEntries = 1;
row = pIfTable->table;
memset(row, 0, sizeof(*row));
wcscpy_s(row->wszName, _countof(row->wszName), L"RING2 Ethernet");
row->dwIndex = IF_INDEX;
row->dwType = IF_TYPE_ETHERNET_CSMACD;
row->dwMtu = 4200;
row->dwSpeed = 1000000000;
row->dwPhysAddrLen = sizeof(spoof_mac);
memcpy(row->bPhysAddr, spoof_mac, sizeof(spoof_mac));
row->dwAdminStatus = 1;
row->dwOperStatus = IF_OPER_STATUS_OPERATIONAL;
return ERROR_SUCCESS;
// DWORD ret = TrueGetIfTable(pIfTable, pdwSize, bOrder);
// if (ret == NO_ERROR) {
// for (size_t i = 0; i < pIfTable->dwNumEntries; i++) {
// pIfTable->table[i].bPhysAddr[0] = 0x00;
// pIfTable->table[i].bPhysAddr[1] = 0xD0;
// pIfTable->table[i].bPhysAddr[2] = 0xF1;
// }
// }
// return ret;
}
typedef struct {
char* name;
unsigned char address[4];
} dns;
dns INTERCEPT_DNS[] = {
// Startup
{ "naominet.jp", { 192, 168, 103, 254 } },
// Billing
{ "ib.naominet.jp", { 192, 168, 103, 254 } },
// Aime
{ "aime.naominet.jp", { 192, 168, 103, 254 } },
// Routers (ping targets)
{ "tenporouter.loc", { 192, 168, 103, 254 } },
{ "bbrouter.loc", { 192, 168, 103, 254 } }, // Must match tenporouter
{ "mobirouter.loc", { 192, 168, 103, 254 } },
{ "dslrouter.loc", { 192, 168, 103, 254 } },
};
DNS_RECORDA dummy_record;
DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID pExtra,
PDNS_RECORDA* ppQueryResults, PVOID* pReserved) {
if (ppQueryResults) {
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(pszName, INTERCEPT_DNS[i].name) == 0) {
#define spoof (INTERCEPT_DNS[i].address)
log_info("dns", "Replacing %s with %hhu.%hhu.%hhu.%hhu", pszName, spoof[0],
spoof[1], spoof[2], spoof[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 =
(spoof[0]) | (spoof[1] << 8) | (spoof[2] << 16) | (spoof[3] << 24);
return ERROR_SUCCESS;
#undef spoof
}
}
}
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].name) == 0) {
#define spoof (INTERCEPT_DNS[i].address)
log_info("dns", "(WSA)Replacing %s with %hhu.%hhu.%hhu.%hhu", AddressString, spoof[0],
spoof[1], spoof[2], spoof[3]);
lpAddress->sa_family = AF_INET;
// ... :)
lpAddress->sa_data[2] = spoof[0];
lpAddress->sa_data[3] = spoof[1];
lpAddress->sa_data[4] = spoof[2];
lpAddress->sa_data[5] = spoof[3];
return ERROR_SUCCESS;
#undef spoof
}
}
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, 7);
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable, 5);
hook("Dnsapi.dll", "DnsQuery_A", FakeDnsQuery_A, (void**)&TrueDnsQuery_A, 5);
}

View File

@ -1,33 +1,43 @@
#include "processes.h"
const wchar_t* HOOK_BINARIES[] = {
L"app\\ALLNetProc.exe",
L"app\\CameraUploader.exe",
L"app\\GmSync.exe",
};
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation) {
log_info("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
CHAR applicationName[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName, NULL, NULL);
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);
}
#include "processes.h"
const wchar_t* HOOK_BINARIES[] = {
L"app\\ALLNetProc.exe",
L"app\\CameraUploader.exe",
L"app\\GmSync.exe",
};
#define DISABLE_PROC_SPAWNING
BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles,
DWORD dwCreationFlags, LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation) {
// #ifdef DISABLE_PROC_SPAWNING
// log_error("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
// return FALSE;
// #else
log_info("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
CHAR applicationName[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName,
NULL, NULL);
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 !FAILED(child);
// #endif
}
void hook_processes() {
hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6);
}

View File

@ -0,0 +1,5 @@
#include "registry.h"
void hook_registry() {
}

View File

@ -0,0 +1,4 @@
#pragma once
#include "common.h"
void hook_registry();

View File

@ -1,25 +1,26 @@
subdir('drivers')
subdir('devices')
subdir('hooks')
shared_library(
'mice',
name_prefix: '',
vs_module_defs: 'mice.def',
sources: [
'util/log.c',
'util/hook.c',
drivers_files,
devices_files,
hooks_files,
'comdevice.c',
'dllmain.c',
],
link_with: [
dmi_lib,
mice_lib,
]
)
subdir('drivers')
subdir('devices')
subdir('hooks')
shared_library(
'mice',
name_prefix: '',
vs_module_defs: 'mice.def',
sources: [
'util/log.c',
'util/hook.c',
drivers_files,
devices_files,
hooks_files,
'comdevice.c',
'dllmain.c',
],
link_with: [
dmi_lib,
mice_lib,
amlib,
]
)

View File

@ -1,30 +1,55 @@
#pragma once
#include "common.h"
#pragma pack(1)
typedef struct mxsmbus_request_packet_ {
BYTE status;
BYTE prt;
WORD addr;
WORD reg;
BYTE dlen;
BYTE data[32];
} mxsmbus_request_packet;
#pragma pack(1)
typedef struct mxsmbus_i2c_packet_ {
BYTE status;
BYTE prt;
BYTE addr;
BYTE reg;
BYTE dlen;
BYTE data[32];
} mxsmbus_i2c_packet;
#pragma pack(1)
typedef struct mxsuperio_lpc_packet_ {
BYTE index;
BYTE reg;
BYTE data;
} mxsuperio_lpc_packet;
enum mxsbus_status { MXSBUS_OKAY = 0 };
#pragma once
#include "common.h"
// PCA9535 (DIPSW)
#define PCA9535_WRITE 0x04
#define PCA9535_READ 0x05
#define PCA9535_IN0 0x00
#define PCA9535_IN1 0x01
#define PCA9535_OUT0 0x02
#define PCA9535_OUT1 0x03
#define PCA9535_INV0 0x04
#define PCA9535_INV1 0x05
#define PCA9535_CONF0 0x06
#define PCA9535_CONF1 0x07
#define 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!
#pragma pack(1)
typedef struct mxsmbus_request_packet_ {
BYTE status;
BYTE prt;
WORD addr;
WORD reg;
BYTE dlen;
BYTE data[32];
} mxsmbus_request_packet;
#pragma pack(1)
typedef struct mxsmbus_i2c_packet_ {
BYTE status;
BYTE prt;
BYTE addr;
BYTE reg;
BYTE dlen;
BYTE data[32];
} mxsmbus_i2c_packet;
#pragma pack(1)
typedef struct mxsuperio_lpc_packet_ {
BYTE index;
BYTE reg;
BYTE data;
} mxsuperio_lpc_packet;
enum mxsbus_status { MXSBUS_OKAY = 0 };

View File

@ -1,144 +1,186 @@
#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);
}
#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;
char* log_colours[] = {
"", // Always
"\033[96m", // Game
"\033[91m", // Error
"\033[33m", // Warning
"\033[97m", // Info
"\033[90m", // Misc
"\033[90m", // Trace
};
#define LOG_PREFIXES "!GEWIMT"
void logcb(LPCSTR param_1) { log_error("logcb", param_1); }
extern WCHAR exePath[MAX_PATH + 1];
int _do_log(BYTE log_level, const char* caller, const char* format, va_list args) {
if (wcscmp(exePath, L"mxnetwork.exe") == 0) {
// *((DWORD*)(0x004438e8)) = (DWORD)(&logcb);
*((DWORD*)(0x004438e8)) = 0x00000000;
}
char prefix = LOG_PREFIXES[log_level];
EnterCriticalSection(&logger_lock);
int len = snprintf(NULL, 0, "%s%c:%s:", log_prelude(), prefix, 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%c:%s:", log_prelude(), prefix, 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 (LOG_LEVEL >= log_level) {
HANDLE sout = GetStdHandle(STD_OUTPUT_HANDLE);
if (HAS_COLOUR)
(TrueWriteFile ? TrueWriteFile : WriteFile)(sout, log_colours[log_level],
strlen(log_colours[log_level]), 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_trace(const char* caller, const char* format, va_list args) {
return _do_log(LOG_TRACE, caller, format, args);
}
int log_trace(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_trace(caller, format, args);
va_end(args);
return ret;
}
int vlog_misc(const char* caller, const char* format, va_list args) {
return _do_log(LOG_MISC, caller, format, args);
}
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(LOG_INFO, caller, format, args);
}
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(LOG_WARNING, caller, format, args);
}
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(LOG_ERROR, caller, format, args);
}
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(LOG_GAME, caller, format, args);
}
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
// TODO: Is there a more robust way to check if we have a proper stdio?
AttachConsole(ATTACH_PARENT_PROCESS);
if (GetStdHandle(STD_ERROR_HANDLE) > (HANDLE)0x10) {
FILE* newstream;
if (GetStdHandle(STD_INPUT_HANDLE)) {
freopen_s(&newstream, "CONIN$", "r", stdin);
setvbuf(stdin, NULL, _IONBF, 0);
}
if (GetStdHandle(STD_OUTPUT_HANDLE)) {
freopen_s(&newstream, "CONOUT$", "w", stdout);
setvbuf(stdout, NULL, _IONBF, 0);
}
if (GetStdHandle(STD_ERROR_HANDLE)) {
freopen_s(&newstream, "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);
#ifdef LOG_TO_FILE
if (LOG_FILE == NULL)
LOG_FILE =
CreateFileA("log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL);
#endif
}

View File

@ -1,32 +1,37 @@
#pragma once
#include <Windows.h>
#include <stdio.h>
#define LOG_MISC FALSE
#define LOG_INFO TRUE
#define LOG_WARNING TRUE
#define LOG_ERROR TRUE
#define LOG_GAME TRUE
// #define LOG_TO_FILE
#define COMM_LOGGER "comm"
#define HOOKS_LOGGER "hooks"
#define BOOT_LOGGER "boot"
extern CRITICAL_SECTION logger_lock;
int log_misc(const char* caller, const char* format, ...);
int log_info(const char* caller, const char* format, ...);
int log_warning(const char* caller, const char* format, ...);
int log_error(const char* caller, const char* format, ...);
int 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();
#pragma once
#include <Windows.h>
#include <stdio.h>
#define LOG_GAME 1
#define LOG_ERROR 2
#define LOG_WARNING 3
#define LOG_INFO 4
#define LOG_MISC 5
#define LOG_TRACE 6
#define LOG_LEVEL LOG_TRACE
// #define LOG_TO_FILE
#define COMM_LOGGER "comm"
#define HOOKS_LOGGER "hooks"
#define BOOT_LOGGER "boot"
extern CRITICAL_SECTION logger_lock;
int log_trace(const char* caller, const char* format, ...);
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_trace(const char* caller, const char* format, va_list args);
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

@ -0,0 +1,46 @@
#define W83627UHG_REG_SYSFANOUT_FREQUENCY 0x00
#define W83627UHG_REG_SYSFANOUT_VALUE_SELECT 0x01
#define W83627UHG_REG_CPUFANOUT_FREQUENCY 0x02
#define W83627UHG_REG_CPUFANOUT_VALUE_SELECT 0x03
#define W83627UHG_REG_FAN_CONF 0x04
#define W83627UHG_REG_SYSTIN_TARGET_TEMP 0x05
#define W83627UHG_REG_CPUTIN_TARGET_TEMP 0x06
#define W83627UHG_REG_TARGET_TEMP_TOLERANCE 0x07
#define W83627UHG_REG_SYSFANOUT_STOP_VALUE 0x08
#define W83627UHG_REG_CPUFANOUT_STOP_VALUE 0x09
#define W83627UHG_REG_SYSFANOUT_START_VALUE 0x0a
#define W83627UHG_REG_CPUFANOUT_START_VALUE 0x0b
#define W83627UHG_REG_SYSFANOUT_STOP_TIME 0x0c
#define W83627UHG_REG_CPUFANOUT_STOP_TIME 0x0d
#define W83627UHG_REG_FANOUT_STEPDOWN_TIME 0x0e
#define W83627UHG_REG_FANOUT_STEPUP_TIME 0x0f
#define W83627UHG_REG_FAN_CONF_2 0x12
#define W83627UHG_REG_OVT_CONF 0x18
#define W83627UHG_REG_CONFIG 0x40
#define W83627UHG_REG_ISR_1 0x41
#define W83627UHG_REG_ISR_2 0x42
#define W83627UHG_REG_SMI_MASK_1 0x43
#define W83627UHG_REG_SMI_MASK_2 0x44
#define W83627UHG_REG_SMI_MASK_3 0x46
#define W83627UHG_REG_FAN_DIVISOR 0x47
#define W83627UHG_REG_SERIAL_BUS_ADDR 0x48
#define W83627UHG_REG_CPUFANOUT_TEMP_SRC_SLCT 0x49
#define W83627UHG_REG_SYSFANOUT_TEMP_SRC_SLCT 0x4a
#define W83627UHG_REG_FAN_DIVISOR_2 0x4b
#define W83627UHG_REG_SMI_OVT_CTRL 0x4c
#define W83627UHG_REG_FAN_IN_OUT_CTRL 0x4d
#define W83627UHG_REG_WINBOND_ID 0x4f
#define W83627UHG_REG_BEEP_CTRL_1 0x56
#define W83627UHG_REG_BEEP_CTRL_2 0x57
#define W83627UHG_REG_CHIP_ID 0x58
#define W83627UHG_REG_DIODE_SELECT_REG 0x59
#define W83627UHG_REG_VBAT_MON_CTRL 0x5d
#define W83627UHG_REG_CRIT_TEMP_EN 0x5e
#define W83627UHG_REG_CPUFANOUT_MAX_OUT 0x67
#define W83627UHG_REG_CPUFANOUT_OUT_STEP 0x68
#define W83627UHG_REG_SYSFANOUT_CRIT_TEMP 0x6b
#define W83627UHG_REG_CPUFANOUT_CRIT_TEMP 0x6c

View File

@ -1,75 +1,102 @@
#include <Windows.h>
#include <stdio.h>
#include "../lib/mice/mice.h"
#include "locate.h"
const char* VERSION = "0.0-pre";
bool boot_delay = false;
bool gametest = false;
char exe_name[MAX_PATH + 1] = "";
void print_help(char* exe) {
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);
}
void parse_cmdline(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-h") == 0) {
print_help(argv[0]);
} else if (strcmp(argv[i], "-b") == 0) {
if (i + 1 == argc) print_help(argv[0]);
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) {
gametest = true;
}
}
}
int main(int argc, char* argv[]) {
fprintf(stderr, "Micetools version: %s\n", VERSION);
parse_cmdline(argc, argv);
if (exe_name[0] == '\0') {
if (!locate_game(exe_name, MAX_PATH + 1)) {
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) {
fprintf(stderr, "Fatal: %s: no such file found\n", exe_name);
return 0;
}
}
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)) {
fprintf(stderr, "Fatal: Failed to locate micelib\n");
return 0;
}
HANDLE game_proc = start_and_inject(exe_name, cmdline, micepath, boot_delay);
if (!game_proc) return -1;
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
} else {
fprintf(stderr, "Shutting down\n");
CloseHandle(game_proc);
}
return 0;
}
#include <Windows.h>
#include <stdio.h>
#include "../lib/mice/mice.h"
#include "locate.h"
const char* VERSION = "0.0-pre";
bool boot_delay = false;
bool gametest = false;
bool designviewer = false;
bool spriteviewer = false;
bool noisetest = false;
char exe_name[MAX_PATH + 1] = "";
char commandline[MAX_PATH + 1] = "";
void print_help(char* exe) {
fprintf(stderr, "Usage: %s [-h] [-t] [-b executable.exe] [-d]\n", exe);
fprintf(stderr, " -h: Print this help message and exit\n");
fprintf(stderr, " -b: Specify the game binary to use\n");
fprintf(stderr, " -d: Wait for a debugger to attach when starting\n");
fprintf(stderr, " -t: Start the game in test mode\n");
fprintf(stderr, " -dv: Start the game in design viewer mode\n");
fprintf(stderr, " -sv: Start the game in sprite viewer mode\n");
fprintf(stderr, " -nt: Start the game in noisetest mode\n");
exit(0);
}
void parse_cmdline(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-h") == 0) {
print_help(argv[0]);
} else if (strcmp(argv[i], "-b") == 0) {
if (i + 1 == argc) print_help(argv[0]);
char* val = argv[++i];
memcpy(exe_name, val, strlen(val) + 1);
} else if (strcmp(argv[i], "--mice-d") == 0) {
boot_delay = true;
} else if (strcmp(argv[i], "-t") == 0) {
gametest = true;
} else if (strcmp(argv[i], "-dv") == 0) {
designviewer = true;
} else if (strcmp(argv[i], "-sv") == 0) {
spriteviewer = true;
} else if (strcmp(argv[i], "-nt") == 0) {
noisetest = true;
} else {
if (commandline[0] == 0)
strncpy_s(commandline, strlen(argv[i]), argv[i], sizeof commandline);
else
snprintf(commandline, sizeof commandline, "%s %s", commandline, argv[i]);
}
}
}
int main(int argc, char* argv[]) {
fprintf(stderr, "Micetools version: %s\n", VERSION);
parse_cmdline(argc, argv);
if (exe_name[0] == '\0') {
if (!locate_game(exe_name, MAX_PATH + 1)) {
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) {
fprintf(stderr, "Fatal: %s: no such file found\n", exe_name);
return 0;
}
}
char* cmdline_mode = gametest ? ". gametest"
: designviewer ? ". designviewer"
: spriteviewer ? ". spriteviewer"
: noisetest ? ". noisetest"
: "";
char cmdline[MAX_PATH + 1];
if (commandline[0] == 0)
snprintf(cmdline, sizeof cmdline, "%s", cmdline_mode);
else
snprintf(cmdline, sizeof cmdline, "%s %s", cmdline_mode, commandline);
fprintf(stderr, "exec: %s %s\n", exe_name, cmdline);
char micepath[MAX_PATH + 1];
if (!locate_library(micepath, MAX_PATH + 1)) {
fprintf(stderr, "Fatal: Failed to locate micelib\n");
return 0;
}
HANDLE game_proc = start_and_inject(exe_name, cmdline, micepath, boot_delay);
if (!game_proc) return -1;
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
} else {
fprintf(stderr, "Shutting down\n");
CloseHandle(game_proc);
}
return 0;
}

View File

@ -0,0 +1,88 @@
#include "amEeprom.h"
#include "../mice/crc.h"
HANDLE amEepromCreateDeviceFile(const GUID *guid, LPCSTR resource, DWORD member_index) {
SP_DEVICE_INTERFACE_DATA interface_data;
SP_DEVICE_INTERFACE_DETAIL_DATA_A interface_detail[204];
if (!guid) return INVALID_HANDLE_VALUE;
HDEVINFO DeviceInfoSet =
SetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (DeviceInfoSet == INVALID_HANDLE_VALUE) return INVALID_HANDLE_VALUE;
interface_data.cbSize = 0x1c;
BOOL s;
s = SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, guid, member_index, &interface_data);
if (!s) goto fail;
interface_detail[0].cbSize = 5;
s = SetupDiGetDeviceInterfaceDetailA(DeviceInfoSet, &interface_data, interface_detail,
sizeof interface_detail, NULL, NULL);
if (!s) goto fail;
char device_path[260];
strcpy_s(device_path, sizeof device_path, interface_detail[0].DevicePath);
if (resource != NULL) {
strcat_s(device_path, 4, "\\");
strcat_s(device_path, 4, resource);
}
printf("Using device located at %s\n", device_path);
HANDLE device =
CreateFileA(device_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_SUPPORTS_GHOSTING, NULL);
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return device;
fail:
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return INVALID_HANDLE_VALUE;
}
BOOL amEepromReadBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data) {
mxsmbus_request_packet smbus_req = {
.status = 0,
.prt = 0x09,
.addr = SMBUS_EEPROM,
.reg = reg << 5,
.dlen = len,
.data = { 0 },
};
DWORD _dummy;
BOOL s = DeviceIoControl(mxsmbus, (DWORD)IOCTL_MXSMBUS_I2C, &smbus_req, sizeof smbus_req,
&smbus_req, sizeof smbus_req, &_dummy, NULL);
if (!s) return FALSE;
if (smbus_req.status) return FALSE;
memcpy(data, smbus_req.data, len);
return TRUE;
}
BOOL amEepromWriteBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data) {
mxsmbus_request_packet smbus_req = {
.status = 0,
.prt = 0x08,
.addr = SMBUS_EEPROM,
.reg = reg << 5,
.dlen = len,
.data = { 0 },
};
memcpy(smbus_req.data, data, sizeof smbus_req.data);
DWORD _dummy;
BOOL s = DeviceIoControl(mxsmbus, (DWORD)IOCTL_MXSMBUS_I2C, &smbus_req, sizeof smbus_req,
&smbus_req, sizeof smbus_req, &_dummy, NULL);
if (!s) return FALSE;
if (smbus_req.status) return FALSE;
memcpy(data, smbus_req.data, len);
return TRUE;
}
void amEepromRepairChecksum(BYTE *data) {
crc32_build_table();
DWORD check = crc32(28, data + 4, 0);
((DWORD*)data)[0] = check;
}

View File

@ -0,0 +1,13 @@
#include <Windows.h>
#include "../../dll/smbus.h"
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);
HANDLE amEepromCreateDeviceFile(const GUID *guid, LPCSTR resource, DWORD member_index);
BOOL amEepromReadBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data);
BOOL amEepromWriteBlock(HANDLE mxsmbus, BYTE reg, BYTE len, BYTE *data);
void amEepromRepairChecksum(BYTE* data);

View File

@ -1,19 +1,19 @@
#include <amtimer.h>
int frequency_loaded = 0;
LARGE_INTEGER frequency;
amtime_t* amiTimerGet(amtime_t* time) {
LARGE_INTEGER counter;
if (time == NULL) return NULL;
if (frequency_loaded == 0) {
QueryPerformanceFrequency(&frequency);
frequency_loaded = 1;
}
QueryPerformanceCounter(&counter);
time->microseconds = (counter.QuadPart * 1000000) / frequency.QuadPart;
time->seconds = counter.QuadPart / frequency.QuadPart;
return time;
}
#include <amTimer.h>
int frequency_loaded = 0;
LARGE_INTEGER frequency;
amtime_t* amiTimerGet(amtime_t* time) {
LARGE_INTEGER counter;
if (time == NULL) return NULL;
if (frequency_loaded == 0) {
QueryPerformanceFrequency(&frequency);
frequency_loaded = 1;
}
QueryPerformanceCounter(&counter);
time->microseconds = (unsigned int)((counter.QuadPart * 1000000) / frequency.QuadPart);
time->seconds = (unsigned int)(counter.QuadPart / frequency.QuadPart);
return time;
}

View File

@ -1,6 +1,10 @@
amlib = static_library(
'am',
sources: [
'amtimer.c',
],
)
amlib = static_library(
'am',
sources: [
'amTimer.c',
'amEeprom.c',
],
link_with: [
mice_lib
],
)

View File

@ -1,111 +1,118 @@
#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.Length = 0x12,
.Head.Handle = 0x0000,
.Vendor = 0x00,
.Version = 0x00,
.StartSegment = 0x0000,
.ReleaseDate = 0x00,
.ROMSize = 0x00,
.Chars = 0x04,
};
DMI_SYSTEM default_dmi_system = {
.Head.Type = 0x01,
.Head.Length = 0x08,
.Head.Handle = 0x0001,
// TODO: Are these used?
.Manufacturer = 0x00,
.ProductName = 0x00,
.Version = 0x00,
.Serial = 0x00,
};
DMI_STRING deafult_dmi_string = {
.Head.Type = 0x0b,
.Head.Length = 0x05,
.Head.Handle = 0x0002,
.NoStrings = 0x00,
};
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);
dmi_size = 0;
}
static void dmi_append(void* data, size_t size) {
if (!dmi_table) return;
while (dmi_size + (size + 1) >= _dmi_max) {
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
if (!new_table) return;
dmi_table = new_table;
}
memcpy(dmi_table + dmi_size, data, size);
dmi_size += size;
dmi_table[dmi_size++] = 0;
dmi_table[dmi_size++] = 0;
}
static void dmi_append_with_strings(void* data, size_t size, int num_strings, ...) {
va_list args;
va_start(args, num_strings);
dmi_append(data, size);
dmi_size -= 2;
for (int i = 0; i < num_strings; i++) {
char* str = va_arg(args, char*);
int len = strlen(str);
memcpy((char*)dmi_table + dmi_size, str, len + 1);
dmi_size += len + 1;
dmi_table[dmi_size - 1] = 0;
}
dmi_table[dmi_size++] = 0;
va_end(args);
}
void dmi_build_default() {
dmi_init();
dmi_append(&deafult_dmi_bios, sizeof deafult_dmi_bios);
// Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2)
// Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3)
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 1, "Supermicro");
deafult_dmi_string.NoStrings = 3;
dmi_append_with_strings(&deafult_dmi_string, sizeof deafult_dmi_string,
// OEM strings:
// 0: ??
// 1: ??
// 2: Platform ID (AAL, AAM)
// AAL = Nvidia drivers
// AAM = AMD drivers
// *** = No dedicated drivers
// 3: ??
// 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech)
// If present -> makes board = 4
// AAL = 4
// AAM = 4
// Supermicro = 4
// Advantech = 4
5, ".", ".", "AAM", ".", "AAL");
}
BYTE dmi_calc_checksum(const char* buf, int len) {
int sum = 0;
int a;
for (a = 0; a < len; a++) sum += buf[a];
return (BYTE)(sum == 0);
#include "dmi.h"
#include <stdlib.h>
LPBYTE dmi_table = NULL;
WORD dmi_size = 0;
WORD _dmi_max = 0;
DMI_BIOS deafult_dmi_bios = {
.Head.Type = 0x00,
.Head.Length = 0x12,
.Head.Handle = 0x0000,
.Vendor = 0x01, // "American Megatrends Inc."
.Version = 0x02, // "080015 "
.StartSegment = 0x0000, // '00 f0'h
.ReleaseDate = 0x03, // "07/28/2011"
.ROMSize = 0x00, // 03h
.Chars = 0x1f, // '1F 90 DA 8B'h
.VerMajor = 0x08,
.VerMinor = 0x0f,
.ECVerMajor = 0xff,
.ECVerMinor = 0xff,
};
DMI_SYSTEM default_dmi_system = {
.Head.Type = 0x01,
.Head.Length = 0x08,
.Head.Handle = 0x0001,
.Manufacturer = 0x01, // "NEC"
.ProductName = 0x02, // "To Be Filled By O.E.M."
.Version = 0x03, // "To Be Filled By O.E.M."
.Serial = 0x04, // "To Be Filled By O.E.M."
};
DMI_STRING deafult_dmi_string = {
.Head.Type = 0x0b,
.Head.Length = 0x05,
.Head.Handle = 0x0002,
.NoStrings = 0x00,
};
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);
dmi_size = 0;
}
static void dmi_append(void* data, WORD size) {
if (!dmi_table) return;
while (dmi_size + (size + 1) >= _dmi_max) {
LPBYTE new_table = (LPBYTE)realloc(dmi_table, _dmi_max += 0xff);
if (!new_table) return;
dmi_table = new_table;
}
memcpy(dmi_table + dmi_size, data, size);
dmi_size += size;
dmi_table[dmi_size++] = 0;
dmi_table[dmi_size++] = 0;
}
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...) {
va_list args;
va_start(args, num_strings);
dmi_append(data, size);
dmi_size -= 2;
for (int i = 0; i < num_strings; i++) {
char* str = va_arg(args, char*);
WORD len = strlen(str) & 0xffff;
memcpy((char*)dmi_table + dmi_size, str, len + 1);
dmi_size += len + 1;
dmi_table[dmi_size - 1] = 0;
}
dmi_table[dmi_size++] = 0;
va_end(args);
}
void dmi_build_default() {
dmi_init();
dmi_append_with_strings(&deafult_dmi_bios, sizeof deafult_dmi_bios, 3,
"American Megatrends Inc.", "080015 ", "07/28/2011");
// Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2)
// Platform AAL: Board type one of "NEC"(=0) or "AAL2"(=3)
dmi_append_with_strings(&default_dmi_system, sizeof default_dmi_system, 4, "NEC",
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.",
"To Be Filled By O.E.M.");
deafult_dmi_string.NoStrings = 5;
dmi_append_with_strings(&deafult_dmi_string, sizeof deafult_dmi_string,
// OEM strings:
// 0: ??
// 1: ??
// 2: Platform ID (AAL, AAM)
// AAL = Nvidia drivers
// AAM = AMD drivers
// *** = No dedicated drivers
// 3: ??
// 4: Board type (AAL, NEC, AAL2, " ", AAM, Supermicro, Advantech)
// If present -> makes board = 4
// AAL = 4
// AAM = 4
// Supermicro = 4
// Advantech = 4
// These values are pulled from an 846-5004D
5, "DAC-BJ02", "DAC-BJ02", "AAL", "Advantech", "AAL2");
}
BYTE dmi_calc_checksum(const char* buf, int len) {
int sum = 0;
int a;
for (a = 0; a < len; a++) sum += buf[a];
return (BYTE)(sum == 0);
}

View File

@ -1,58 +1,62 @@
#include <Windows.h>
#include <stdint.h>
extern LPBYTE dmi_table;
extern WORD dmi_size;
// #define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
#pragma pack(1)
typedef struct {
BYTE Type;
BYTE Length;
WORD Handle;
} DMI_SECTION_HEADER;
#pragma pack(1)
typedef struct {
CHAR Signature[5];
BYTE Checksum;
WORD StructLength;
DWORD StructAddr;
WORD NumberOfStructs;
BYTE BCDRevision;
BYTE Reserved;
} DMI_HEADER;
#pragma pack(1)
typedef struct {
DMI_SECTION_HEADER Head;
BYTE Vendor;
BYTE Version;
WORD StartSegment;
BYTE ReleaseDate;
BYTE ROMSize;
uint64_t Chars;
} DMI_BIOS;
#pragma pack(1)
typedef struct {
DMI_SECTION_HEADER Head;
BYTE Manufacturer;
BYTE ProductName;
BYTE Version;
BYTE Serial;
} DMI_SYSTEM;
#pragma pack(1)
typedef struct {
DMI_SECTION_HEADER Head;
BYTE NoStrings;
} DMI_STRING;
static void dmi_init(void);
static void dmi_append(void* data, size_t size);
static void dmi_append_with_strings(void* data, size_t size, int num_strings, ...);
void dmi_build_default(void);
BYTE dmi_calc_checksum(const char* buf, int len);
#include <Windows.h>
#include <stdint.h>
extern LPBYTE dmi_table;
extern WORD dmi_size;
// #define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
#pragma pack(1)
typedef struct {
BYTE Type;
BYTE Length;
WORD Handle;
} DMI_SECTION_HEADER;
#pragma pack(1)
typedef struct {
CHAR Signature[5];
BYTE Checksum;
WORD StructLength;
DWORD StructAddr;
WORD NumberOfStructs;
BYTE BCDRevision;
BYTE Reserved;
} DMI_HEADER;
#pragma pack(1)
typedef struct {
DMI_SECTION_HEADER Head;
BYTE Vendor;
BYTE Version;
WORD StartSegment;
BYTE ReleaseDate;
BYTE ROMSize;
uint64_t Chars;
BYTE VerMajor;
BYTE VerMinor;
BYTE ECVerMajor;
BYTE ECVerMinor;
} DMI_BIOS;
#pragma pack(1)
typedef struct {
DMI_SECTION_HEADER Head;
BYTE Manufacturer;
BYTE ProductName;
BYTE Version;
BYTE Serial;
} DMI_SYSTEM;
#pragma pack(1)
typedef struct {
DMI_SECTION_HEADER Head;
BYTE NoStrings;
} DMI_STRING;
static void dmi_init(void);
static void dmi_append(void* data, WORD size);
static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...);
void dmi_build_default(void);
BYTE dmi_calc_checksum(const char* buf, int len);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
#include "libpcp.h"

View File

@ -1,23 +1,23 @@
compiler = meson.get_compiler('c')
ws2 = compiler.find_library('ws2_32', required: true)
sources = [
'libpcp.c',
'pcpt.c',
'pcpp.c',
'pcpa.c',
'pcp.c',
'util.c',
]
libpcp = static_library(
'pcp',
name_suffix: 'lib',
sources: sources,
dependencies: [
ws2,
],
link_with: [
amlib,
],
)
compiler = meson.get_compiler('c')
ws2 = compiler.find_library('ws2_32', required: true)
sources = [
'libpcp.c',
'pcpt.c',
'pcpp.c',
'pcpa.c',
'pcp.c',
'util.c',
]
libpcp = static_library(
'pcp',
name_suffix: 'lib',
sources: sources,
dependencies: [
ws2,
],
link_with: [
amlib,
],
)

View File

@ -0,0 +1,3 @@
#include "pcp.h"
char* LIBPCP_VERSION = "\nlibpcp Ver.1.08 Build:Aug 12 2012 00:13:32 (micetools bootleg)\n";

View File

@ -1,71 +1,73 @@
#pragma once
#define PCP_LOG(fmt, ...) printf("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__)
#define ZERO(x) memset(&(x), 0, sizeof(x))
#define ZERO_BUF(x) memset((x), 0, sizeof(*x))
#include <Winsock2.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "../am/amtimer.h"
#define PCP_CHAR_PROMPT '>'
#define PCP_CHAR_BINACK '$'
#define PCP_CHAR_HASH '#'
#define PCP_CHAR_UNKNOWN '?'
#define PCP_CHAR_SEP '&'
#define PCP_CHAR_EQU '='
#define PCP_CHAR_CR '\r'
#define PCP_CHAR_LF '\n'
#define PCP_CHAR_EOF '\0'
#define PCP_WHITESPACE(x) ((x) == ' ' || (x) == '\t')
extern char* LIBPCP_VERSION;
typedef unsigned int undefined4;
typedef unsigned char byte;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef int timeout_t;
#define PCP_BUF_MAX 256
#define PCP_CMDS_MAX 64
#define PCP_KEYWORD_MAX 32
#define PCP_SEND_BUF_MAX 8
typedef struct pcp_parse_data {
char strings[PCP_BUF_MAX];
byte keywords[PCP_CMDS_MAX];
byte values[PCP_CMDS_MAX];
uint cmd_count;
} pcp_parse_data_t;
typedef struct pcp_send_data {
char data[PCP_BUF_MAX];
size_t length;
} pcp_send_data_t;
// Errors
#define OPEN_MODE_GLOBAL 0
#define OPEN_MODE_1 1
// #define OPEN_MODE_2 2
typedef enum binary_mode {
binary_mode_none = 0,
binary_mode_send = 1,
binary_mode_recv = 2,
} binary_mode_t;
#define PCPT_CONFIG_0 0
#define PCPT_CONFIG_1 1
#define PCPT_SO_LINGER 2
#define PCPT_TCP_NODELAY 3
#define HANDLE_INVAL -1
#define TIMEOUT_NONE -1
#define PCPT_CLOSED 0
#define PCPT_LISTENING 1
#define PCPT_CONNECTED 2
#pragma once
#define PCP_LOG(fmt, ...) printf("%s:%d:" fmt, __func__, __LINE__, ##__VA_ARGS__)
#define ZERO(x) memset(&(x), 0, sizeof(x))
#define ZERO_BUF(x) memset((x), 0, sizeof(*x))
#include <Winsock2.h>
#include <ws2ipdef.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "../am/amtimer.h"
#define PCP_CHAR_PROMPT '>'
#define PCP_CHAR_BINACK '$'
#define PCP_CHAR_HASH '#'
#define PCP_CHAR_UNKNOWN '?'
#define PCP_CHAR_SEP '&'
#define PCP_CHAR_EQU '='
#define PCP_CHAR_CR '\r'
#define PCP_CHAR_LF '\n'
#define PCP_CHAR_EOF '\0'
#define PCP_WHITESPACE(x) ((x) == ' ' || (x) == '\t')
extern char* LIBPCP_VERSION;
typedef unsigned int undefined4;
typedef unsigned char byte;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned int timeout_t;
#define PCP_BUF_MAX 256
#define PCP_CMDS_MAX 64
#define PCP_KEYWORD_MAX 32
#define PCP_SEND_BUF_MAX 8
typedef struct pcp_parse_data {
char strings[PCP_BUF_MAX];
byte keywords[PCP_CMDS_MAX];
byte values[PCP_CMDS_MAX];
uint cmd_count;
} pcp_parse_data_t;
typedef struct pcp_send_data {
unsigned char data[PCP_BUF_MAX];
size_t length;
} pcp_send_data_t;
// Errors
#define OPEN_MODE_GLOBAL 0
#define OPEN_MODE_1 1
// #define OPEN_MODE_2 2
typedef enum binary_mode {
binary_mode_none = 0,
binary_mode_send = 1,
binary_mode_recv = 2,
} binary_mode_t;
#define PCPT_CONFIG_0 0
#define PCPT_CONFIG_1 1
#define PCPT_SO_LINGER 2
#define PCPT_TCP_NODELAY 3
#define SOCKET_INVAL ((SOCKET)-1)
#define HANDLE_INVAL -1
#define TIMEOUT_NONE ((DWORD)-1)
#define PCPT_CLOSED 0
#define PCPT_LISTENING 1
#define PCPT_CONNECTED 2

View File

@ -0,0 +1,630 @@
#include "pcpa.h"
e_pcpa_t _pcpaGetErrorFromPcpp(e_pcpp_t err) {
switch (err) {
case e_pcpp_ok:
return e_pcpa_ok;
case e_pcpp_to:
return e_pcpa_to;
case e_pcpp_closed:
return e_pcpa_closed;
case e_pcpp_no_client:
return e_pcpa_no_client;
case e_pcpp_wsa_noinit:
return e_pcpa_wsa_noinit;
case e_pcpp_inval_addr:
return e_pcpa_inval_addr;
case -14:
return (e_pcpa_t)-16;
case -13:
return (e_pcpa_t)-15;
case e_pcpp_timeout_open:
return e_pcpa_timeout_open;
case -11:
return (e_pcpa_t)-13;
case e_pcpp_recv_unset:
return e_pcpa_cb_table_full;
case -9:
return (e_pcpa_t)-7;
case -8:
return (e_pcpa_t)-6;
case -7:
return (e_pcpa_t)-3;
case e_pcpp_timeout_closed:
return e_pcpa_timeout_closed;
case e_pcpp_param_invalid:
return e_pcpa_param_invalid;
case -4:
return (e_pcpa_t)-8;
case e_pcpp_already_open:
return e_pcpa_already_open;
case e_pcpp_cannot_open:
return e_pcpa_cannot_open;
case e_pcpp_not_open:
return e_pcpa_not_open;
default:
return e_pcpa_closed;
}
}
void pcpaCloseBinary(pcpa_t *stream) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn't set\n");
return;
}
stream->binary_mode = binary_mode_none;
pcppCloseBinary(&stream->pcpp);
}
void pcpaClose(pcpa_t *stream) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return;
}
pcppClose(&stream->pcpp);
stream->err = e_pcpa_unknown;
stream->state = 0;
stream->callback_table = NULL;
stream->callback_max = 0;
stream->callback_count = 0;
stream->recv_buffer = NULL;
stream->recv_buffer_len = 0;
stream->send_buffer = NULL;
stream->send_buffer_len = 0;
stream->binary_mode = binary_mode_none;
stream->binary_mode_before_cb = NULL;
stream->binary_mode_after_cb = NULL;
stream->binary_mode_before_data = NULL;
stream->binary_mode_after_data = NULL;
memset(&stream->send_data, 0, sizeof stream->send_data);
(stream->send_data).length = 0;
}
e_pcpa_t pcpaInitStream(pcpa_t *stream) {
if (LIBPCP_VERSION == NULL) {
PCP_LOG("error PCPA version isn\'t set\n");
return e_pcpa_generic;
}
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
e_pcpp_t err = pcppInitStream(&stream->pcpp);
if (err != e_pcpp_ok) {
return err == e_pcpp_wsa_noinit ? e_pcpa_wsa_noinit : e_pcpa_param_invalid;
}
stream->err = e_pcpa_unknown;
stream->state = 0;
stream->callback_table = NULL;
stream->callback_max = 0;
stream->callback_count = 0;
stream->recv_buffer = NULL;
stream->recv_buffer_len = 0;
stream->send_buffer = NULL;
stream->send_buffer_len = 0;
stream->binary_mode = binary_mode_none;
stream->binary_mode_before_cb = NULL;
stream->binary_mode_after_cb = NULL;
stream->binary_mode_before_data = NULL;
stream->binary_mode_after_data = NULL;
ZERO(stream->recv_data);
ZERO(stream->send_data);
return e_pcpa_ok;
}
e_pcpa_t pcpaOpenServerWithBinary(pcpa_t *stream, int open_mode, u_short port, u_short binary_port,
undefined4 param_5) {
e_pcpa_t err;
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
switch (open_mode) {
case 0:
stream->err = err = _errP2A(pcppOpenServer(&stream->pcpp, 0, port, param_5));
if (err != e_pcpa_ok) {
PCP_LOG("error pcppOpenServer\n");
return err;
}
stream->err = err = _errP2A(pcppOpenBinaryServer(&stream->pcpp, 0, binary_port));
if (err != e_pcpa_ok) {
PCP_LOG("error pcppOpenBinaryServer\n");
return err;
}
break;
case 1:
stream->err = err = _errP2A(pcppOpenServer(&stream->pcpp, 1, port, param_5));
if (err != e_pcpa_ok) {
PCP_LOG("error pcppOpenServer\n");
return err;
}
stream->err = err = _errP2A(pcppOpenBinaryServer(&stream->pcpp, 1, binary_port));
if (err != e_pcpa_ok) {
PCP_LOG("error pcppOpenBinaryServer\n");
return err;
}
break;
default:
PCP_LOG("error Open Mode isn\'t set\n");
return stream->err = e_pcpa_generic;
}
stream->state = 0;
return e_pcpa_ok;
}
e_pcpa_t pcpaSetCallbackFunc(pcpa_t *stream, char *keyword, pcpa_callback *callback, void *data) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
if (keyword == NULL) {
PCP_LOG("error keyword isn\'t set\n");
return e_pcpa_generic;
}
if (callback == NULL) {
PCP_LOG("error Callback func isn\'t set\n");
return e_pcpa_generic;
}
if (stream->callback_table == NULL) {
PCP_LOG("error Callback_table buffer isn\'t set\n");
return e_pcpa_cb_table_unset;
}
if (strnlen(keyword, PCP_KEYWORD_MAX + 1) > PCP_KEYWORD_MAX) {
PCP_LOG("error a keyword is too long\n");
return e_pcpa_generic;
}
if (stream->callback_count >= stream->callback_max) return e_pcpa_cb_table_full;
sprintf_s(stream->callback_table[stream->callback_count].keyword, PCP_KEYWORD_MAX, "%s", keyword);
stream->callback_table[stream->callback_count].callback = callback;
stream->callback_table[stream->callback_count].data = data;
stream->callback_count++;
return stream->err = e_pcpa_ok;
}
e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t *stream, pcpa_cb_table_t *callback_table, uint callbacks_max) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
if (callback_table == NULL || callbacks_max == 0) return e_pcpa_timeout_closed;
stream->callback_max = callbacks_max;
stream->callback_table = callback_table;
stream->callback_count = 0;
stream->err = e_pcpa_ok;
return e_pcpa_ok;
}
pcp_send_data_t *pcpaSetSendPacket(pcpa_t *stream, char *keyword, char *value) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return NULL;
}
return pcppSetSendPacket(&stream->send_data, keyword, value);
}
char *pcpaGetCommand(pcpa_t *pcpa, char *command) {
if (pcpa == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return NULL;
}
return pcppGetCommand(&pcpa->recv_data, command);
}
e_pcpa_t pcpaServer(pcpa_t *stream, timeout_t timeout_ms) {
byte bVar1;
pcpa_callback *callback;
char *pbVar3;
int iVar3;
e_pcpa_t eVar4;
char *pbVar4;
uint ms;
e_pcpp_t iVar5;
bool bVar6;
uint local_14;
amtime_t time;
amtime_t time_start;
int timeout;
local_14 = timeout_ms;
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
amiTimerGet(&time_start);
timeout = timeout_ms;
do {
ms = 0;
switch (stream->state) {
case 0:
amiTimerGet(&time);
ms = _amTimeDelta(time, time_start);
if (timeout_ms != -1) {
if (ms < (uint)timeout_ms) {
timeout = timeout_ms - ms;
local_14 = timeout;
} else {
timeout = 0;
local_14 = timeout;
}
}
stream->state = 3;
iVar5 = pcppRecvRequest(&stream->pcpp, &stream->recv_data, timeout);
eVar4 = _errP2A(iVar5);
stream->err = eVar4;
timeout = local_14;
if (eVar4 != e_pcpa_to) {
if (eVar4 == e_pcpa_ok) {
stream->state = 10;
amiTimerGet(&time);
if (timeout_ms != -1) {
ms = _amTimeDelta(time, time_start);
goto joined_r0x00454a58;
}
} else {
stream->state = 0;
}
}
break;
default:
stream->err = e_pcpa_unknown;
goto LAB_00454d84;
case 3:
case 4:
case 9:
amiTimerGet(&time);
ms = _amTimeDelta(time, time_start);
if (timeout_ms != -1) {
if (ms < (uint)timeout_ms) {
timeout = timeout_ms - ms;
local_14 = timeout;
} else {
timeout = 0;
local_14 = timeout;
}
}
iVar5 = pcppIsBusy(&stream->pcpp, timeout);
eVar4 = _errP2A(iVar5);
stream->err = eVar4;
timeout = local_14;
if (eVar4 != e_pcpa_to) {
if (stream->state == 4) {
memset(&stream->send_data, 0, PCP_BUF_MAX);
(stream->send_data).length = 0;
}
if (stream->err == e_pcpa_ok) {
if (stream->binary_mode == binary_mode_none) {
stream->state = (stream->state != 3) - 1 & 10;
amiTimerGet(&time);
if (timeout_ms != -1) {
ms = _amTimeDelta(time, time_start);
joined_r0x00454a58:
if ((uint)timeout_ms <= ms) {
stream->err = e_pcpa_to;
return stream->err;
}
}
} else {
pcpaCloseBinary(stream);
stream->state = 0;
stream->binary_mode = binary_mode_none;
if (stream->binary_mode_after_cb != NULL) {
(*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data);
stream->binary_mode_after_cb = NULL;
}
amiTimerGet(&time);
if (timeout_ms != -1) {
ms = _amTimeDelta(time, time_start);
goto joined_r0x00454a58;
}
}
} else {
if ((stream->state == 9) && (stream->binary_mode != binary_mode_none)) {
pcpaCloseBinary(stream);
if (stream->binary_mode_after_cb != NULL) {
(*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data);
stream->binary_mode_after_cb = NULL;
}
stream->binary_mode = binary_mode_none;
}
stream->state = 0;
}
}
break;
case 7:
callback = stream->binary_mode_before_cb;
(stream->pcpp).last_active = _amTimeMs(time_start);
if (callback != NULL) {
(*callback)(stream, stream->binary_mode_before_data);
stream->binary_mode_before_cb = NULL;
}
amiTimerGet(&time);
ms = _amTimeDelta(time, time_start);
if (timeout_ms != -1) {
if (ms < (uint)timeout_ms) {
timeout = timeout_ms - ms;
local_14 = timeout;
} else {
timeout = 0;
local_14 = timeout;
}
}
eVar4 = pcpaSendBinary(stream, timeout);
stream->err = eVar4;
if (eVar4 == e_pcpa_to) {
stream->state = 9;
} else {
pcpaCloseBinary(stream);
if (stream->binary_mode_after_cb != NULL) {
(*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data);
stream->binary_mode_after_cb = NULL;
}
stream->binary_mode = binary_mode_none;
stream->state = 0;
if (stream->err == e_pcpa_ok) {
LAB_00454a1a:
amiTimerGet(&time);
if (timeout_ms != -1) {
ms = _amTimeDelta(time, time_start);
goto joined_r0x00454a58;
}
} else {
PCP_LOG("error pcpaSendBinary\n");
}
}
break;
case 8:
callback = stream->binary_mode_before_cb;
(stream->pcpp).last_active = _amTimeMs(time_start);
if (callback != NULL) {
(*callback)(stream, stream->binary_mode_before_data);
stream->binary_mode_before_cb = NULL;
}
amiTimerGet(&time);
ms = _amTimeDelta(time, time_start);
if (timeout_ms != -1) {
if (ms < (uint)timeout_ms) {
timeout = timeout_ms - ms;
local_14 = timeout;
} else {
timeout = 0;
local_14 = timeout;
}
}
eVar4 = pcpaRecvBinary(stream, timeout);
stream->err = eVar4;
if (eVar4 == e_pcpa_to) {
stream->state = 9;
} else {
pcpaCloseBinary(stream);
if (stream->binary_mode_after_cb != NULL) {
(*stream->binary_mode_after_cb)(stream, stream->binary_mode_after_data);
stream->binary_mode_after_cb = NULL;
}
stream->binary_mode = binary_mode_none;
stream->state = 0;
if (stream->err == e_pcpa_ok) goto LAB_00454a1a;
PCP_LOG("error pcpaRecvBinary\n");
}
break;
case 10:
if (stream->before_cb != NULL) {
stream->before_cb(stream, stream->pcpp.sock.recv_buf);
}
if (stream->callback_table == NULL) {
PCP_LOG("error Callback_table buffer isn\'t set\n");
stream->err = e_pcpa_cb_table_unset;
return stream->err;
}
if (stream->callback_count != 0) {
iVar5 = 0;
do {
pbVar3 = pcppGetKeyword(&stream->recv_data, 0);
pbVar4 = stream->callback_table->keyword + iVar5;
do {
bVar1 = *pbVar3;
bVar6 = bVar1 < (byte)*pbVar4;
if (bVar1 != *pbVar4) {
LAB_004547c8:
iVar3 = (1 - (uint)bVar6) - (uint)(bVar6 != 0);
goto LAB_004547cd;
}
if (bVar1 == 0) break;
bVar1 = ((byte *)pbVar3)[1];
bVar6 = bVar1 < ((byte *)pbVar4)[1];
if (bVar1 != ((byte *)pbVar4)[1]) goto LAB_004547c8;
pbVar3 = (char *)((byte *)pbVar3 + 2);
pbVar4 = (char *)((byte *)pbVar4 + 2);
} while (bVar1 != 0);
iVar3 = 0;
LAB_004547cd:
if (iVar3 == 0) {
(stream->callback_table[ms].callback)(stream, stream->callback_table[ms].data);
goto LAB_004547f1;
}
ms = ms + 1;
iVar5 = iVar5 + 40;
} while (ms < stream->callback_count);
}
pcppSetSendPacket(&stream->send_data, "?", 0);
LAB_004547f1:
amiTimerGet(&time);
ms = _amTimeDelta(time, time_start);
if (timeout_ms != -1) {
if (ms < (uint)timeout_ms) {
local_14 = timeout_ms - ms;
} else {
local_14 = 0;
}
}
iVar5 = pcppSendResponseTable(&stream->pcpp, &stream->send_data, local_14);
eVar4 = _errP2A(iVar5);
stream->err = eVar4;
if (eVar4 == e_pcpa_to) {
stream->state = 4;
} else {
memset(&stream->send_data, 0, PCP_BUF_MAX);
(stream->send_data).length = 0;
stream->state = 0;
}
if (stream->binary_mode != binary_mode_none) {
stream->state = (stream->binary_mode == binary_mode_send) ? 7 : 8;
}
amiTimerGet(&time);
timeout = local_14;
if (timeout_ms != TIMEOUT_NONE) {
ms = _amTimeDelta(time, time_start);
goto joined_r0x00454a58;
}
}
} while (stream->err == e_pcpa_ok);
LAB_00454d84:
return stream->err;
}
e_pcpa_t pcpaRecvBinary(pcpa_t *stream, uint something) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
if (stream->recv_buffer == NULL) {
PCP_LOG("error Recv buffer isn\'t set\n");
pcpaCloseBinary(stream);
pcpaClose(stream);
return stream->err = e_pcpa_cb_table_full;
}
stream->state = 8;
e_pcpa_t err;
stream->err = err = _errP2A(pcppRecvBinary(&stream->pcpp, stream->recv_buffer, stream->recv_buffer_len, something));
if (err != e_pcpa_to) stream->state = 0;
return err;
}
e_pcpa_t pcpaSendBinary(pcpa_t *stream, uint param_2) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
if (stream->send_buffer == NULL) {
PCP_LOG("error Send buffer isn\'t set\n");
stream->err = e_pcpa_cb_table_full;
pcpaCloseBinary(stream);
pcpaClose(stream);
return stream->err;
}
stream->state = 7;
e_pcpa_t err;
stream->err = err = _errP2A(pcppSendBinary(&stream->pcpp, stream->send_buffer, stream->send_buffer_len, param_2));
if (err != e_pcpa_to) stream->state = 0;
return err;
}
e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t *stream, byte *send_buffer, size_t len) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
if (send_buffer == NULL) {
PCP_LOG("error Send Buffer isn\'t set\n");
return e_pcpa_timeout_closed;
}
stream->send_buffer = send_buffer;
stream->send_buffer_len = len;
stream->err = e_pcpa_ok;
return e_pcpa_ok;
}
e_pcpa_t pcpaSetBeforeBinaryModeCallBackFunc(pcpa_t *stream, pcpa_callback *callback, void *data) {
if (stream == NULL) {
PCP_LOG("error don\'t set stream\n");
return e_pcpa_stream_unset;
}
if (callback == NULL) {
PCP_LOG("error Binary mode callback func isn\'t set\n");
return e_pcpa_generic;
}
stream->binary_mode_before_cb = callback;
stream->binary_mode_before_data = data;
stream->err = e_pcpa_ok;
return e_pcpa_ok;
}
e_pcpa_t pcpaSetAfterBinaryModeCallBackFunc(pcpa_t *stream, pcpa_callback *callback, void *data) {
if (stream == NULL) {
PCP_LOG("error don\'t set stream\n");
return e_pcpa_stream_unset;
}
if (callback == NULL) {
PCP_LOG("error Binary mode callback func isn\'t set\n");
return e_pcpa_generic;
}
stream->binary_mode_after_cb = callback;
stream->binary_mode_after_data = data;
stream->err = e_pcpa_ok;
return e_pcpa_ok;
}
e_pcpa_t pcpaSetBinaryMode(pcpa_t *stream, binary_mode_t binary_mode) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
if (pcppGetServerSocket(&stream->pcpp, 1) == HANDLE_INVAL) {
return stream->err = -19;
}
stream->binary_mode = binary_mode;
stream->err = e_pcpa_ok;
return e_pcpa_ok;
}
e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t *stream, byte *recv_buffer, size_t len) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return e_pcpa_stream_unset;
}
if (recv_buffer == NULL) {
PCP_LOG("error Recv Buffer isn\'t set\n");
return e_pcpa_timeout_closed;
}
stream->recv_buffer = recv_buffer;
stream->recv_buffer_len = len;
stream->err = e_pcpa_ok;
return e_pcpa_ok;
}
pcp_send_data_t *pcpaAddSendPacket(pcpa_t *stream, char *keyword, char *value) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return NULL;
}
return pcppAddSendPacket(&stream->send_data, keyword, value);
}
char *pcpaGetKeyword(pcpa_t *stream, uint keyword_num) {
if (stream == NULL) {
PCP_LOG("error PCPA stream isn\'t set\n");
return NULL;
}
return pcppGetKeyword(&stream->recv_data, keyword_num);
}

View File

@ -1,76 +1,76 @@
#include "pcpp.h"
typedef enum e_pcpa {
e_pcpa_ok = 0,
e_pcpa_to = 1,
e_pcpa_closed = 2,
e_pcpa_no_client = 3,
e_pcpa_not_open = -1,
e_pcpa_cannot_open = -2,
e_pcpa_generic = -3,
e_pcpa_param_invalid = -4,
e_pcpa_timeout_closed = -5, // TODO: This is wrong (see: pcpaSetCallbackFuncBuffer)
e_pcpa_cb_table_full = -9,
e_pcpa_stream_unset = -10,
e_pcpa_cb_table_unset = -11,
e_pcpa_timeout_open = -14,
e_pcpa_inval_addr = -17,
e_pcpa_already_open = -18,
e_pcpa_wsa_noinit = -20,
e_pcpa_unknown = -21,
} e_pcpa_t;
e_pcpa_t _pcpaGetErrorFromPcpp(e_pcpp_t err);
#define _errP2A(err) _pcpaGetErrorFromPcpp(err)
struct pcpa;
typedef void(pcpa_callback)(struct pcpa* stream, void* data);
typedef struct pcpa_cb_table {
char keyword[PCP_KEYWORD_MAX];
void* data;
pcpa_callback* callback;
} pcpa_cb_table_t;
typedef struct pcpa {
pcpp_t pcpp;
e_pcpa_t err;
uint state;
pcpa_cb_table_t* callback_table;
uint callback_max;
uint callback_count;
char* recv_buffer;
size_t recv_buffer_len;
char* send_buffer;
size_t send_buffer_len;
binary_mode_t binary_mode;
pcpa_callback* binary_mode_before_cb;
void* binary_mode_before_data;
pcpa_callback* binary_mode_after_cb;
void* binary_mode_after_data;
// 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);
void pcpaCloseBinary(pcpa_t* stream);
char* pcpaGetKeyword(pcpa_t* stream, uint keyword_num);
e_pcpa_t pcpaInitStream(pcpa_t* stream);
e_pcpa_t pcpaOpenServerWithBinary(pcpa_t* stream, int open_mode, ushort port, ushort binary_port, undefined4 param_5);
e_pcpa_t pcpaRecvBinary(pcpa_t* stream, undefined4 something);
e_pcpa_t pcpaSendBinary(pcpa_t* stream, undefined4 something);
e_pcpa_t pcpaServer(pcpa_t* stream, timeout_t timeout_ms);
e_pcpa_t pcpaSetAfterBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* callback, void* data);
e_pcpa_t pcpaSetBeforeBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* callback, void* data);
e_pcpa_t pcpaSetBinaryMode(pcpa_t* stream, binary_mode_t binary_mode);
e_pcpa_t pcpaSetCallbackFunc(pcpa_t* stream, char* keyword, pcpa_callback* callback, void* data);
e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t* stream, pcpa_cb_table_t* callback_table, uint callbacks_max);
e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t* stream, byte* recv_buffer, size_t len);
e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t* stream, byte* send_buffer, size_t len);
pcp_send_data_t* pcpaSetSendPacket(pcpa_t* stream, char* keyword, char* value);
pcp_send_data_t *pcpaAddSendPacket(pcpa_t *stream, char *keyword, char *value);
char* pcpaGetCommand(pcpa_t* pcpa, char* command);
#include "pcpp.h"
typedef enum e_pcpa {
e_pcpa_ok = 0,
e_pcpa_to = 1,
e_pcpa_closed = 2,
e_pcpa_no_client = 3,
e_pcpa_not_open = -1,
e_pcpa_cannot_open = -2,
e_pcpa_generic = -3,
e_pcpa_param_invalid = -4,
e_pcpa_timeout_closed = -5, // TODO: This is wrong (see: pcpaSetCallbackFuncBuffer)
e_pcpa_cb_table_full = -9,
e_pcpa_stream_unset = -10,
e_pcpa_cb_table_unset = -11,
e_pcpa_timeout_open = -14,
e_pcpa_inval_addr = -17,
e_pcpa_already_open = -18,
e_pcpa_wsa_noinit = -20,
e_pcpa_unknown = -21,
} e_pcpa_t;
e_pcpa_t _pcpaGetErrorFromPcpp(e_pcpp_t err);
#define _errP2A(err) _pcpaGetErrorFromPcpp(err)
struct pcpa;
typedef void(pcpa_callback)(struct pcpa* stream, void* data);
typedef struct pcpa_cb_table {
char keyword[PCP_KEYWORD_MAX];
void* data;
pcpa_callback* callback;
} pcpa_cb_table_t;
typedef struct pcpa {
pcpp_t pcpp;
e_pcpa_t err;
uint state;
pcpa_cb_table_t* callback_table;
uint callback_max;
uint callback_count;
unsigned char* recv_buffer;
size_t recv_buffer_len;
unsigned char* send_buffer;
size_t send_buffer_len;
binary_mode_t binary_mode;
pcpa_callback* binary_mode_before_cb;
void* binary_mode_before_data;
pcpa_callback* binary_mode_after_cb;
void* binary_mode_after_data;
// 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);
void pcpaCloseBinary(pcpa_t* stream);
char* pcpaGetKeyword(pcpa_t* stream, uint keyword_num);
e_pcpa_t pcpaInitStream(pcpa_t* stream);
e_pcpa_t pcpaOpenServerWithBinary(pcpa_t* stream, int open_mode, ushort port, ushort binary_port, undefined4 param_5);
e_pcpa_t pcpaRecvBinary(pcpa_t* stream, undefined4 something);
e_pcpa_t pcpaSendBinary(pcpa_t* stream, undefined4 something);
e_pcpa_t pcpaServer(pcpa_t* stream, timeout_t timeout_ms);
e_pcpa_t pcpaSetAfterBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* callback, void* data);
e_pcpa_t pcpaSetBeforeBinaryModeCallBackFunc(pcpa_t* stream, pcpa_callback* callback, void* data);
e_pcpa_t pcpaSetBinaryMode(pcpa_t* stream, binary_mode_t binary_mode);
e_pcpa_t pcpaSetCallbackFunc(pcpa_t* stream, char* keyword, pcpa_callback* callback, void* data);
e_pcpa_t pcpaSetCallbackFuncBuffer(pcpa_t* stream, pcpa_cb_table_t* callback_table, uint callbacks_max);
e_pcpa_t pcpaSetRecvBinaryBuffer(pcpa_t* stream, byte* recv_buffer, size_t len);
e_pcpa_t pcpaSetSendBinaryBuffer(pcpa_t* stream, byte* send_buffer, size_t len);
pcp_send_data_t* pcpaSetSendPacket(pcpa_t* stream, char* keyword, char* value);
pcp_send_data_t *pcpaAddSendPacket(pcpa_t *stream, char *keyword, char *value);
char* pcpaGetCommand(pcpa_t* pcpa, char* command);

File diff suppressed because it is too large Load Diff

View File

@ -1,87 +1,95 @@
#include "pcpt.h"
#define PCPP_CLOSED 0
#define PCPP_OPEN 1
typedef enum e_pcpp {
e_pcpp_ok = 0,
e_pcpp_to = 1,
e_pcpp_closed = 2,
e_pcpp_no_client = 3,
e_pcpp_not_open = -1,
e_pcpp_cannot_open = -2,
e_pcpp_already_open = -3,
e_pcpp_param_invalid = -5,
e_pcpp_timeout_closed = -6,
e_pcpp_recv_unset = -10,
e_pcpp_timeout_open = -12,
e_pcpp_inval_addr = -15,
e_pcpp_wsa_noinit = -16,
e_pcpp_unknown = -17,
} e_pcpp_t;
e_pcpp_t _pcppGetErrorFromPcpt(e_pcpt_t err);
#define _errT2P(err) _pcppGetErrorFromPcpt(err)
typedef struct pcpp {
pcpt_t sock;
pcpt_t data_sock;
uint field_0xb8; // Some sort of timeout
int last_active;
uint state;
e_pcpp_t err;
pcp_parse_data_t* recv_data_buffer;
char read_bytes_buf[PCP_BUF_MAX];
uint read_bytes_size;
uint read_bytes_num;
pcp_send_data_t* resp_buffer;
uint resp_buffer_len;
char send_buf[PCP_SEND_BUF_MAX];
size_t send_buf_len;
uint field_0x1e8;
char* send_binary_buf;
uint field_0x1f0;
char* recv_binary_buf;
size_t field_0x1f8;
uint field_0x1fc;
size_t recv_binary_buf_len;
// All some sort of timeout I think
uint field_0x204;
uint field_0x208;
uint field_0x20c;
uint field_0x210;
int field_0x214;
int open;
} pcpp_t;
pcp_send_data_t* pcppAddSendPacket(pcp_send_data_t* stream, char* key, char* value);
pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, int* lenout);
bool pcppCheckPrompt(pcpp_t* stream);
e_pcpp_t pcppCheckRecvMsg(char* recv_data, size_t buf_len, int param_3);
uint pcppCheckStr(char* param_1, uint* pcp_len, int* pcp_overflow);
void pcppClose(pcpp_t* stream);
void pcppCloseBinary(pcpp_t* stream);
e_pcpp_t pcppGetBlockingTime(uint param_1, int param_2, pcpp_t* stream, int param_4, uint* blocking_time);
char* pcppGetCommand(pcp_parse_data_t* pcpa, char* command);
char* pcppGetKeyword(pcp_parse_data_t* recvData, uint keyword_num);
SOCKET pcppGetServerSocket(pcpp_t* stream, int which);
e_pcpp_t pcppInitStream(pcpp_t* stream);
e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout);
e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port);
e_pcpp_t pcppOpenServer(pcpp_t* stream, int open_mode, ushort port, undefined4 param_4);
e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv);
e_pcpp_t pcppRecvBinary(pcpp_t* stream, char* recv_buf, size_t buf_len, uint param_4);
uint pcppRecvCheck(char* buf, int* found_at);
e_pcpp_t pcppRecvPrompt(pcpp_t* stream, undefined4 param_2, int param_3);
e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t timeout);
e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3);
e_pcpp_t pcppSendBinary(pcpp_t* stream, char* send_binary_buffer, size_t param_3, uint param_4);
e_pcpp_t pcppSendPrompt(pcpp_t* stream, uint param_2, int param_3);
e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, int param_3);
e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t buf_len, timeout_t timeout_ms);
e_pcpp_t pcppSendResponseTable(pcpp_t* stream, pcp_send_data_t* data, timeout_t timeout_ms);
pcp_send_data_t* pcppSetSendPacket(pcp_send_data_t* send_data, char* keyword, char* value);
e_pcpp_t pcpp_something(amtime_t* now, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, char* send_buf,
size_t* send_len, undefined4 param_7, undefined4 param_8, e_pcpp_t fallback_err);
void pcppResetRead(pcpp_t* param_1);
#include "pcpt.h"
#define PCPP_CLOSED 0
#define PCPP_OPEN 1
typedef enum e_pcpp {
e_pcpp_ok = 0,
e_pcpp_to = 1,
e_pcpp_closed = 2,
e_pcpp_no_client = 3,
e_pcpp_not_open = -1,
e_pcpp_cannot_open = -2,
e_pcpp_already_open = -3,
e_pcpp_param_invalid = -5,
e_pcpp_timeout_closed = -6,
e_pcpp_recv_unset = -10,
e_pcpp_timeout_open = -12,
e_pcpp_inval_addr = -15,
e_pcpp_wsa_noinit = -16,
e_pcpp_unknown = -17,
e_pcpp_uk1 = -14,
e_pcpp_uk2 = -13,
e_pcpp_uk3 = -11,
e_pcpp_uk4 = -9,
e_pcpp_uk5 = -8,
e_pcpp_uk6 = -7,
e_pcpp_uk7 = -4,
} e_pcpp_t;
e_pcpp_t _pcppGetErrorFromPcpt(e_pcpt_t err);
#define _errT2P(err) _pcppGetErrorFromPcpt(err)
typedef struct pcpp {
pcpt_t sock;
pcpt_t data_sock;
uint field_0xb8; // Some sort of timeout
int last_active;
uint state;
e_pcpp_t err;
pcp_parse_data_t* recv_data_buffer;
unsigned char read_bytes_buf[PCP_BUF_MAX];
uint read_bytes_size;
uint read_bytes_num;
pcp_send_data_t* resp_buffer;
uint resp_buffer_len;
unsigned char send_buf[PCP_SEND_BUF_MAX];
size_t send_buf_len;
uint field_0x1e8;
unsigned char* send_binary_buf;
uint field_0x1f0;
unsigned char* recv_binary_buf;
size_t field_0x1f8;
uint field_0x1fc;
size_t recv_binary_buf_len;
// All some sort of timeout I think
uint field_0x204;
uint field_0x208;
uint field_0x20c;
uint field_0x210;
int field_0x214;
int open;
} pcpp_t;
pcp_send_data_t* pcppAddSendPacket(pcp_send_data_t* stream, char* key, char* value);
pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, uint* lenout);
bool pcppCheckPrompt(pcpp_t* stream);
e_pcpp_t pcppCheckRecvMsg(unsigned char* recv_data, size_t buf_len, int param_3);
uint pcppCheckStr(unsigned char* param_1, uint* pcp_len, int* pcp_overflow);
void pcppClose(pcpp_t* stream);
void pcppCloseBinary(pcpp_t* stream);
e_pcpp_t pcppGetBlockingTime(uint param_1, timeout_t param_2, pcpp_t* stream, int param_4, uint* blocking_time);
char* pcppGetCommand(pcp_parse_data_t* pcpa, char* command);
char* pcppGetKeyword(pcp_parse_data_t* recvData, uint keyword_num);
SOCKET pcppGetServerSocket(pcpp_t* stream, int which);
e_pcpp_t pcppInitStream(pcpp_t* stream);
e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout);
e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port);
e_pcpp_t pcppOpenServer(pcpp_t* stream, int open_mode, ushort port, undefined4 param_4);
e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv);
e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, uint param_4);
uint pcppRecvCheck(unsigned char* buf, int* found_at);
e_pcpp_t pcppRecvPrompt(pcpp_t* stream, undefined4 param_2, int param_3);
e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t timeout);
e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3);
e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_t param_3, uint param_4);
e_pcpp_t pcppSendPrompt(pcpp_t* stream, uint param_2, timeout_t timeout_ms);
e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, timeout_t timeout_ms);
e_pcpp_t pcppSendResponse(pcpp_t* stream, pcp_send_data_t* resp_buffer, size_t buf_len, timeout_t timeout_ms);
e_pcpp_t pcppSendResponseTable(pcpp_t* stream, pcp_send_data_t* data, timeout_t timeout_ms);
pcp_send_data_t* pcppSetSendPacket(pcp_send_data_t* send_data, char* keyword, char* value);
e_pcpp_t pcpp_something(amtime_t* now, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, unsigned char* send_buf,
size_t* send_len, undefined4 param_7, undefined4 param_8, e_pcpp_t fallback_err);
void pcppResetRead(pcpp_t* param_1);

View File

@ -0,0 +1,758 @@
#include "pcpt.h"
e_pcpt_t _pcptGetErrorFromWin(int err) {
switch (err) {
case WSAEBADF:
case WSAEINVAL:
case WSAENOTSOCK:
case WSAEISCONN:
return e_pcpt_wsa2_generic;
case WSAEMFILE:
return e_pcpt_cannot_open;
case WSAEWOULDBLOCK:
case WSAETIMEDOUT:
return e_pcpt_to;
case WSAEADDRNOTAVAIL:
return e_pcpt_inval_addr;
case WSAECONNABORTED:
case WSAECONNRESET:
return e_pcpt_closed;
case WSAENOBUFS:
return e_pcpt_nobufs;
case WSANOTINITIALISED:
return e_pcpt_wsa_noinit;
default:
return e_pcpt_unknown;
}
}
e_pcpt_t pcptInitStream(pcpt_t *sock) {
SOCKET s;
if (sock == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == SOCKET_INVAL) return _errW2T(WSAGetLastError());
closesocket(s);
sock->client_open = 0;
sock->open = PCPT_CLOSED;
sock->client_event = NULL;
sock->server_event = NULL;
sock->send_buf = NULL;
sock->send_buf_count = NULL;
sock->recv_buf_count = NULL;
sock->recv_buf = NULL;
sock->server_sock = SOCKET_INVAL;
sock->client_sock = SOCKET_INVAL;
sock->err = e_pcpt_unknown;
memset(&sock->client_addr, 0, sizeof sock->client_addr);
sock->field_0x58 = 0;
sock->tcp_nodelay = 0;
sock->config_0 = 12000;
sock->config_1 = 5;
sock->so_linger = 1;
return e_pcpt_ok;
}
void pcptClose(pcpt_t *sock) {
if (sock == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return;
}
if (sock->server_sock != SOCKET_INVAL) {
WSAEventSelect(sock->server_sock, 0, 0);
WSACloseEvent(sock->server_event);
sock->server_event = NULL;
closesocket(sock->server_sock);
sock->server_sock = SOCKET_INVAL;
}
if (sock->client_sock != SOCKET_INVAL) {
WSAEventSelect(sock->client_sock, 0, 0);
WSACloseEvent(sock->client_event);
sock->client_event = NULL;
closesocket(sock->client_sock);
sock->client_sock = SOCKET_INVAL;
}
sock->client_open = 0;
sock->open = PCPT_CLOSED;
sock->err = e_pcpt_unknown;
if (sock->client_event != NULL) {
WSACloseEvent(sock->client_event);
sock->client_event = NULL;
}
if (sock->server_event != NULL) {
WSACloseEvent(sock->server_event);
sock->server_event = NULL;
}
sock->send_buf = NULL;
sock->send_buf_count = NULL;
sock->recv_buf_count = NULL;
sock->recv_buf = NULL;
memset(&sock->client_addr, 0, sizeof sock->client_addr);
sock->field_0x58 = 0;
}
void pcptCloseDataSock(pcpt_t *sock) {
if (sock == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return;
}
if (sock->field_0x58 != 0) {
sock->open = PCPT_LISTENING;
}
sock->client_open = 0;
if (sock->client_sock != SOCKET_INVAL) {
WSAEventSelect(sock->client_sock, 0, 0);
WSACloseEvent(sock->client_event);
sock->client_event = NULL;
closesocket(sock->client_sock);
sock->client_sock = SOCKET_INVAL;
}
}
e_pcpt_t pcptAcceptServer(pcpt_t *stream, timeout_t timeout_ms) {
if (stream == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
e_pcpt_t err = pcptCheckEvent(stream->server_event, timeout_ms, stream->server_sock, FD_ACCEPT);
if (err != e_pcpt_ok) return err;
int addrlen = 16;
SOCKET client = accept(stream->server_sock, &stream->client_addr, &addrlen);
stream->client_sock = client;
if (client == SOCKET_INVAL) return _errW2T(GetLastError());
WSAEVENT event = WSACreateEvent();
stream->client_event = event;
if (event == NULL) {
closesocket(stream->client_sock);
stream->client_sock = SOCKET_INVAL;
return e_pcpt_unknown;
}
WSAEventSelect(stream->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE);
uint so_linger = (uint)(!!stream->so_linger);
setsockopt(stream->client_sock, SOL_SOCKET, SO_LINGER, (void *)&so_linger, sizeof so_linger);
uint nodelay = (uint)(!stream->tcp_nodelay);
setsockopt(stream->client_sock, IPPROTO_TCP, TCP_NODELAY, (void *)&nodelay, sizeof nodelay);
return e_pcpt_ok;
}
e_pcpt_t pcptCheckConnectAble(pcpt_t *stream, timeout_t timeout_ms) {
DWORD DVar1;
uint uVar3;
HANDLE event;
bool bVar5;
e_pcpt_t local_44;
u_long local_40;
amtime_t now;
amtime_t start;
if (stream == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
amiTimerGet(&start);
DVar1 = timeout_ms;
if (timeout_ms == TIMEOUT_NONE) DVar1 = TIMEOUT_NONE;
while (DVar1 = WaitForSingleObject(stream->client_event, DVar1), DVar1 == WAIT_TIMEOUT) {
LAB_004589c8:
amiTimerGet(&now);
uVar3 = _amTimeDelta(now, start);
if (timeout_ms <= uVar3) return e_pcpt_to;
DVar1 = timeout_ms - uVar3;
}
if (DVar1 == 0) {
WSANETWORKEVENTS net_events;
if (FAILED(WSAEnumNetworkEvents(stream->client_sock, stream->client_event, &net_events))) {
bVar5 = WSAGetLastError() == WSAEWOULDBLOCK;
} else {
if ((net_events.lNetworkEvents & 0x10) != 0 &&
net_events.iErrorCode[FD_CONNECT_BIT] == 0) {
local_44 = e_pcpt_ok;
goto LAB_00458a1e;
}
if (WSAGetLastError() == WSAEWOULDBLOCK) goto LAB_004589c8;
bVar5 = net_events.iErrorCode[FD_CONNECT_BIT] == WSAECONNREFUSED;
}
if (bVar5) goto LAB_004589c8;
}
local_44 = e_pcpt_wsa2_generic;
LAB_00458a1e:
local_40 = 0;
WSAEventSelect(stream->client_sock, 0, 0);
WSACloseEvent(stream->client_event);
stream->client_event = NULL;
if (local_44 != e_pcpt_ok) {
closesocket(stream->client_sock);
stream->client_sock = SOCKET_INVAL;
return local_44;
}
ioctlsocket(stream->client_sock, FIONBIO, &local_40);
event = WSACreateEvent();
stream->client_event = event;
if (event != NULL) {
WSAEventSelect(stream->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE);
return e_pcpt_ok;
}
closesocket(stream->client_sock);
stream->client_sock = SOCKET_INVAL;
return e_pcpt_unknown;
}
e_pcpt_t pcptCheckEvent(HANDLE event, timeout_t timeout_ms, SOCKET socket, uint event_mask) {
amtime_t now;
amtime_t start;
WSANETWORKEVENTS networkEvents;
amiTimerGet(&start);
now.seconds = start.seconds;
now.microseconds = start.microseconds;
DWORD wait_timeout = timeout_ms;
if (timeout_ms == TIMEOUT_NONE) wait_timeout = TIMEOUT_NONE;
if (event == NULL) {
PCP_LOG("Error : EVENT HANDLE error\n");
return e_pcpt_pointer_unset;
}
event_mask &= 0xffffffdf;
while (1) {
DWORD err = WaitForSingleObject(event, wait_timeout);
if ((err != WAIT_TIMEOUT && err != 0) || FAILED(err)) {
return e_pcpt_wsa2_generic;
}
if (err != WAIT_TIMEOUT) {
if (FAILED(WSAEnumNetworkEvents(socket, event, &networkEvents)))
return e_pcpt_wsa2_generic;
if ((networkEvents.lNetworkEvents & 0x20) != 0) return e_pcpt_closed;
if ((event_mask & networkEvents.lNetworkEvents) != 0) return e_pcpt_ok;
}
if (timeout_ms != TIMEOUT_NONE) {
amiTimerGet(&now);
uint elapsed = _amTimeDelta(now, start);
if ((uint)timeout_ms <= elapsed) return e_pcpt_to;
wait_timeout = timeout_ms - elapsed;
}
}
}
e_pcpt_t pcptOpenDataSockServer(pcpt_t *sock, timeout_t timeout_ms) {
if (sock == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
if (sock->open == PCPT_CONNECTED) return e_pcpt_already_open;
if (sock->open == PCPT_CLOSED) return e_pcpt_not_open;
if ((sock->client_sock == SOCKET_INVAL)) {
e_pcpt_t err = pcptAcceptServer(sock, timeout_ms);
if (err != e_pcpt_ok) return err;
}
sock->open = PCPT_CONNECTED;
return e_pcpt_ok;
}
e_pcpt_t pcptOpenServer(pcpt_t *stream, int open_mode, ushort port) {
e_pcpt_t err;
if (stream == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
if (stream->server_sock != SOCKET_INVAL || stream->client_sock != SOCKET_INVAL)
return stream->err = e_pcpt_already_open;
amtime_t start;
amiTimerGet(&start);
stream->field_0x58 = 1;
stream->open = PCPT_CLOSED;
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
stream->server_sock = s;
if (s == SOCKET_INVAL) return stream->err = _errW2T(GetLastError());
uint reuseaddr = 1;
if (FAILED(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&reuseaddr, 4))) {
err = _errW2T(GetLastError());
closesocket(stream->server_sock);
stream->server_sock = SOCKET_INVAL;
return stream->err = err;
}
SOCKADDR_IN addr = { .sin_family = AF_INET,
.sin_port = ntohs(port),
.sin_addr.s_addr = ntohl(0) };
if (open_mode != OPEN_MODE_GLOBAL) {
INT len = sizeof &addr.sin_addr.s_addr;
WSAStringToAddressW(L"127.0.0.1", AF_INET, NULL, (LPSOCKADDR)&addr.sin_addr.s_addr, &len);
}
if (FAILED(bind(stream->server_sock, (SOCKADDR *)&addr, sizeof addr))) {
err = _errW2T(GetLastError());
closesocket(stream->server_sock);
stream->server_sock = SOCKET_INVAL;
return stream->err = err;
}
if (FAILED(listen(stream->server_sock, 128))) {
err = _errW2T(GetLastError());
closesocket(stream->server_sock);
stream->server_sock = SOCKET_INVAL;
return stream->err = err;
}
WSAEVENT event = WSACreateEvent();
stream->server_event = event;
if (event != NULL) {
WSAEventSelect(stream->server_sock, event, FD_CLOSE | FD_ACCEPT);
stream->open = PCPT_LISTENING;
stream->client_open = 0;
return stream->err = e_pcpt_ok;
}
closesocket(stream->server_sock);
stream->server_sock = SOCKET_INVAL;
return stream->err = e_pcpt_unknown;
}
e_pcpt_t pcptRecv(pcpt_t *sock, unsigned char *recv_buf, size_t *recv_buf_len,
timeout_t timeout_ms) {
e_pcpt_t err;
amtime_t now;
amtime_t start;
if (sock == NULL || recv_buf == NULL || recv_buf_len == NULL) {
printf("%p %p %p\n", sock, recv_buf, recv_buf_len);
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
if (sock->open == PCPT_CLOSED) return sock->err = e_pcpt_not_open;
if (sock->client_open != 0) return sock->err = e_pcpt_already_connected;
sock->recv_buf = recv_buf;
sock->recv_buf_count = recv_buf_len;
sock->client_open = 3;
if (sock->open == PCPT_LISTENING && sock->field_0x58 != 0) {
amiTimerGet(&start);
sock->err = err = pcptOpenDataSockServer(sock, timeout_ms);
if (err == e_pcpt_to) return e_pcpt_to;
if (err != e_pcpt_ok) {
pcptCloseDataSock(sock);
return sock->err;
}
if (timeout_ms != TIMEOUT_NONE) {
amiTimerGet(&now);
uint elapsed = _amTimeDelta(now, start);
if (elapsed < timeout_ms)
timeout_ms = timeout_ms - elapsed;
else
timeout_ms = 0;
}
}
sock->err = err = pcptCheckEvent(sock->client_event, timeout_ms, sock->client_sock, FD_READ);
if (err == e_pcpt_to) return e_pcpt_to;
sock->client_open = 0;
if (err == e_pcpt_ok) {
size_t recv_count =
recv(sock->client_sock, (char *)sock->recv_buf, *sock->recv_buf_count, 0);
if (0 < (int)recv_count) {
*recv_buf_len = recv_count;
sock->err = e_pcpt_ok;
return e_pcpt_ok;
}
if (recv_count == 0) {
pcptCloseDataSock(sock);
return sock->err = e_pcpt_closed;
}
sock->err = _errW2T(GetLastError());
}
pcptCloseDataSock(sock);
return sock->err;
}
e_pcpt_t pcptSend(pcpt_t *sock, unsigned char *send_buf, size_t *send_len, uint param_4,
timeout_t timeout_ms) {
e_pcpt_t err;
amtime_t now;
amtime_t start_time;
if (sock == NULL || send_buf == NULL || send_len == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
if (sock->open == PCPT_CLOSED) return sock->err = e_pcpt_not_open;
if (sock->client_open != 0) return sock->err = e_pcpt_already_connected;
sock->send_buf_count = send_len;
sock->send_buf = send_buf;
sock->client_open = 2;
sock->field_0x14 = param_4;
sock->field_0x54 = 0;
if (sock->open == PCPT_LISTENING && sock->field_0x58 != 0) {
amiTimerGet(&start_time);
err = pcptOpenDataSockServer(sock, timeout_ms);
sock->err = err;
if (err == e_pcpt_to) return e_pcpt_to;
if (err == e_pcpt_ok) {
amiTimerGet(&now);
uint elapsed = _amTimeDelta(now, start_time);
if (timeout_ms != TIMEOUT_NONE) {
if (elapsed < timeout_ms)
timeout_ms = timeout_ms - elapsed;
else
timeout_ms = 0;
}
goto LAB_0045930e;
}
} else {
LAB_0045930e:
err = pcptSendAllMsg(sock, timeout_ms);
sock->err = err;
if (err == e_pcpt_to) {
return e_pcpt_to;
}
sock->client_open = 0;
if (err == e_pcpt_ok) return err;
}
pcptCloseDataSock(sock);
return sock->err;
}
e_pcpt_t pcptSendAllMsg(pcpt_t *sock, timeout_t timeout_ms) {
size_t sVar1;
bool bVar2;
e_pcpt_t err;
bool bVar3;
amtime_t now;
amtime_t start;
if (sock == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
if (sock->send_buf == NULL || sock->send_buf_count == NULL) {
PCP_LOG("error send buffer isn\'t set\n");
return e_pcpt_pointer_unset;
}
bVar3 = sock->field_0x54 == 0;
amiTimerGet(&start);
sVar1 = *sock->send_buf_count;
while (1) {
if (sVar1 == 0) {
sock->field_0x54 = 0;
return e_pcpt_ok;
}
bVar2 = false;
amiTimerGet(&now);
uint elapsed = _amTimeDelta(now, start);
if (timeout_ms != TIMEOUT_NONE && timeout_ms < elapsed) return e_pcpt_to;
uint wait_time;
if (bVar3) {
wait_time = timeout_ms;
if (timeout_ms != TIMEOUT_NONE) wait_time = timeout_ms - elapsed;
} else {
if ((timeout_ms == TIMEOUT_NONE) ||
(wait_time = timeout_ms - elapsed,
sock->field_0x14 <= wait_time && wait_time != sock->field_0x14)) {
wait_time = sock->field_0x14;
bVar2 = true;
}
}
int sent = send(sock->client_sock, (char *)sock->send_buf, *sock->send_buf_count, 0);
if (sent == -1) {
err = _errW2T(GetLastError());
if (err != e_pcpt_to) return err;
err = pcptCheckEvent(sock->client_event, wait_time, sock->client_sock, FD_WRITE);
if (err == e_pcpt_to) {
if (!bVar2) return e_pcpt_to;
sock->field_0x54 = 0;
return e_pcpt_NO_IDEA_WHAT_THIS_IS;
}
if (err != e_pcpt_ok) return err;
} else {
sock->send_buf = sock->send_buf + sent;
sock->field_0x54 = 1;
*sock->send_buf_count = *sock->send_buf_count - sent;
}
bVar3 = false;
sVar1 = *sock->send_buf_count;
}
}
void pcptSetConfig(pcpt_t *stream, uint config, uint value) {
if (stream == NULL) {
PCP_LOG("error don\'t set stream\n");
return;
}
switch (config) {
case PCPT_CONFIG_0:
stream->config_0 = value;
break;
case PCPT_CONFIG_1:
stream->config_1 = value;
break;
case PCPT_SO_LINGER:
stream->so_linger = value;
break;
case PCPT_TCP_NODELAY:
stream->tcp_nodelay = value;
break;
}
}
// TODO: TIDY
e_pcpt_t pcptIsBusy(pcpt_t *sock, timeout_t timeout_ms) {
bool bVar1;
bool bVar2;
uint uVar3;
uint uVar4;
SOCKET SVar5;
WSAEVENT event;
int iVar7;
e_pcpt_t eVar8;
u_long timeout_ms_00;
uint uVar10;
amtime_t local_18;
amtime_t local_10;
amtime_t local_8;
timeout_ms_00 = timeout_ms;
if (sock == NULL) {
PCP_LOG("error PCP stream isn\'t set\n");
return e_pcpt_pointer_unset;
}
switch (sock->client_open) {
case 0:
sock->err = e_pcpt_no_client;
return sock->err;
case 1:
if (sock->open != PCPT_CLOSED) {
sock->err = e_pcpt_cannot_open;
sock->client_open = 0;
return sock->err;
}
amiTimerGet(&local_10);
uVar10 = timeout_ms_00;
do {
bVar1 = false;
bVar2 = false;
amiTimerGet(&local_18);
if (uVar10 != TIMEOUT_NONE) {
uVar3 = _amTimeDelta(local_18, local_10);
if (uVar3 < uVar10) {
timeout_ms_00 = uVar10 - uVar3;
} else {
bVar2 = true;
timeout_ms_00 = 0;
}
}
amiTimerGet(&local_18);
uVar4 = _amTimeMs(local_18) - sock->field_0x40;
uVar3 = sock->config_0;
if (uVar3 < uVar4) {
timeout_ms_00 = 0;
LAB_00459626:
bVar1 = true;
} else {
if ((uVar10 == TIMEOUT_NONE) || (uVar3 < timeout_ms_00)) {
timeout_ms_00 = uVar3 - uVar4;
goto LAB_00459626;
}
}
eVar8 = pcptCheckConnectAble(sock, timeout_ms_00);
sock->err = eVar8;
if (eVar8 != e_pcpt_to) {
sock->client_open = 0;
if (eVar8 == e_pcpt_ok) {
sock->open = PCPT_CONNECTED;
return sock->err;
}
break;
}
if (bVar1) {
WSAEventSelect(sock->client_sock, 0, 0);
WSACloseEvent(sock->client_event);
sock->client_event = NULL;
closesocket(sock->client_sock);
sock->client_sock = SOCKET_INVAL;
SVar5 = socket(2, 1, 0);
sock->client_sock = SVar5;
if (SVar5 == SOCKET_INVAL) goto LAB_004599cf;
event = WSACreateEvent();
sock->client_event = event;
if (event == NULL) {
closesocket(sock->client_sock);
sock->err = e_pcpt_unknown;
sock->client_sock = SOCKET_INVAL;
return sock->err;
}
WSAEventSelect(sock->client_sock, event, FD_CONNECT | FD_CLOSE);
iVar7 = connect(sock->client_sock, &sock->client_addr, 16);
if (iVar7 != -1) {
WSAEventSelect(sock->client_sock, 0, 0);
WSACloseEvent(sock->client_event);
sock->client_event = NULL;
timeout_ms = 0;
ioctlsocket(sock->client_sock, FIONBIO, (u_long *)&timeout_ms);
event = WSACreateEvent();
sock->client_event = event;
if (event != NULL) {
WSAEventSelect(sock->client_sock, event, FD_READ | FD_WRITE | FD_CLOSE);
sock->err = e_pcpt_ok;
sock->client_open = 0;
sock->open = PCPT_CONNECTED;
return e_pcpt_ok;
}
closesocket(sock->client_sock);
sock->err = e_pcpt_unknown;
sock->client_sock = SOCKET_INVAL;
return sock->err;
}
amiTimerGet(&local_8);
sock->field_0x40 = _amTimeMs(local_8);
} else {
if (bVar2) {
sock->err = e_pcpt_to;
return e_pcpt_to;
}
}
uVar10 = timeout_ms;
} while (sock->err == e_pcpt_to);
break;
case 2:
if (sock->open == PCPT_CLOSED) {
sock->err = e_pcpt_not_open;
return e_pcpt_not_open;
}
if ((sock->open == PCPT_LISTENING) && (sock->field_0x58 != 0)) {
amiTimerGet(&local_10);
eVar8 = pcptOpenDataSockServer(sock, timeout_ms_00);
sock->err = eVar8;
if (eVar8 == e_pcpt_to) {
return e_pcpt_to;
}
if (eVar8 != e_pcpt_ok) {
LAB_0045997d:
pcptCloseDataSock(sock);
return sock->err;
}
amiTimerGet(&local_18);
if (timeout_ms_00 != TIMEOUT_NONE) {
iVar7 = (local_18.microseconds - local_10.microseconds) / 1000;
if (timeout_ms_00 <
(uint)((local_18.seconds - local_10.seconds) * 1000 + iVar7)) {
timeout_ms_00 =
((local_10.seconds - local_18.seconds) * 1000 - iVar7) + timeout_ms_00;
} else {
timeout_ms_00 = 0;
}
}
}
eVar8 = pcptSendAllMsg(sock, timeout_ms_00);
sock->err = eVar8;
if (eVar8 != e_pcpt_to) {
if (eVar8 != e_pcpt_ok) {
pcptCloseDataSock(sock);
}
sock->client_open = 0;
return sock->err;
}
break;
case 3:
if (sock->open == PCPT_CLOSED) {
sock->err = e_pcpt_not_open;
return sock->err;
}
if ((sock->open == PCPT_LISTENING) && (sock->field_0x58 != 0)) {
amiTimerGet(&local_10);
eVar8 = pcptOpenDataSockServer(sock, timeout_ms_00);
sock->err = eVar8;
if (eVar8 == e_pcpt_to) {
return e_pcpt_to;
}
if (eVar8 != e_pcpt_ok) goto LAB_0045997d;
amiTimerGet(&local_18);
if (timeout_ms_00 != TIMEOUT_NONE) {
iVar7 = (local_18.microseconds - local_10.microseconds) / 1000;
if (timeout_ms_00 <
(uint)((local_18.seconds - local_10.seconds) * 1000 + iVar7)) {
timeout_ms_00 =
((local_10.seconds - local_18.seconds) * 1000 - iVar7) + timeout_ms_00;
} else {
timeout_ms_00 = 0;
}
}
}
eVar8 = pcptCheckEvent(sock->client_event, timeout_ms_00, sock->client_sock, 1);
sock->err = eVar8;
if (eVar8 == e_pcpt_to) break;
sock->client_open = 0;
if (eVar8 != e_pcpt_ok) goto LAB_0045997d;
if (sock->recv_buf == NULL || sock->recv_buf_count == NULL) {
PCP_LOG("error Recv buffer isn\'t set\n");
return sock->err = e_pcpt_recv_unset;
}
size_t received =
recv(sock->client_sock, (char *)sock->recv_buf, *sock->recv_buf_count, 0);
if (received < 1) {
pcptCloseDataSock(sock);
if (received == 0) {
sock->err = e_pcpt_closed;
return e_pcpt_closed;
}
LAB_004599cf:
return sock->err = _errW2T(GetLastError());
}
*sock->recv_buf_count = received;
default:
sock->err = e_pcpt_ok;
}
return sock->err;
}

View File

@ -1,65 +1,65 @@
#include "pcp.h"
typedef enum e_pcpt {
e_pcpt_ok = 0,
e_pcpt_to = 1,
e_pcpt_closed = 2,
e_pcpt_no_client = 3,
e_pcpt_not_open = -1,
// TODO: Check if these two are the wrong way round!
e_pcpt_already_open = -2,
e_pcpt_already_connected = -3,
e_pcpt_pointer_unset = -4,
e_pcpt_cannot_open = -8,
e_pcpt_nobufs = -9,
e_pcpt_wsa2_generic = -10,
e_pcpt_inval_addr = -12,
e_pcpt_NO_IDEA_WHAT_THIS_IS = -13,
e_pcpt_recv_unset = -15,
e_pcpt_wsa_noinit = -16,
e_pcpt_unknown = -17,
} e_pcpt_t;
e_pcpt_t _pcptGetErrorFromWin(int err);
#define _errW2T(err) _pcptGetErrorFromWin(err)
typedef struct pcpt {
SOCKET server_sock;
SOCKET client_sock;
int client_open;
int open;
e_pcpt_t err;
uint field_0x14;
uint config_0;
uint config_1;
uint so_linger;
uint tcp_nodelay;
WSAEVENT client_event;
WSAEVENT server_event;
char* send_buf;
size_t* send_buf_count;
char* recv_buf;
size_t* recv_buf_count;
uint field_0x40;
SOCKADDR client_addr;
int field_0x54;
int field_0x58;
} pcpt_t;
e_pcpt_t pcptInitStream(pcpt_t* sock);
void pcptClose(pcpt_t* sock);
void pcptCloseDataSock(pcpt_t* sock);
e_pcpt_t pcptAcceptServer(pcpt_t* stream, timeout_t timeout_ms);
e_pcpt_t pcptCheckConnectAble(pcpt_t* sock, timeout_t timeout_ms);
e_pcpt_t pcptCheckEvent(HANDLE event, timeout_t timeout_ms, SOCKET socket, uint event_mask);
e_pcpt_t pcptIsBusy(pcpt_t* sock, timeout_t timeout_ms);
e_pcpt_t pcptOpenDataSockServer(pcpt_t* sock, timeout_t timeout_ms);
e_pcpt_t pcptOpenServer(pcpt_t* sock, int open_mode, ushort port);
e_pcpt_t pcptRecv(pcpt_t* sock, char* recv_buf, size_t* recv_buf_len, timeout_t timeout_ms);
e_pcpt_t pcptSend(pcpt_t* sock, char* send_buf, size_t* send_len, uint param_4, timeout_t timeout_ms);
e_pcpt_t pcptSendAllMsg(pcpt_t* sock, timeout_t timeout_ms);
void pcptSetConfig(pcpt_t* sock, uint config, uint value);
#include "pcp.h"
typedef enum e_pcpt {
e_pcpt_ok = 0,
e_pcpt_to = 1,
e_pcpt_closed = 2,
e_pcpt_no_client = 3,
e_pcpt_not_open = -1,
// TODO: Check if these two are the wrong way round!
e_pcpt_already_open = -2,
e_pcpt_already_connected = -3,
e_pcpt_pointer_unset = -4,
e_pcpt_cannot_open = -8,
e_pcpt_nobufs = -9,
e_pcpt_wsa2_generic = -10,
e_pcpt_inval_addr = -12,
e_pcpt_NO_IDEA_WHAT_THIS_IS = -13,
e_pcpt_recv_unset = -15,
e_pcpt_wsa_noinit = -16,
e_pcpt_unknown = -17,
} e_pcpt_t;
e_pcpt_t _pcptGetErrorFromWin(int err);
#define _errW2T(err) _pcptGetErrorFromWin(err)
typedef struct pcpt {
SOCKET server_sock;
SOCKET client_sock;
int client_open;
int open;
e_pcpt_t err;
uint field_0x14;
uint config_0;
uint config_1;
uint so_linger;
uint tcp_nodelay;
WSAEVENT client_event;
WSAEVENT server_event;
unsigned char* send_buf;
size_t* send_buf_count;
unsigned char* recv_buf;
size_t* recv_buf_count;
uint field_0x40;
SOCKADDR client_addr;
int field_0x54;
int field_0x58;
} pcpt_t;
e_pcpt_t pcptInitStream(pcpt_t* sock);
void pcptClose(pcpt_t* sock);
void pcptCloseDataSock(pcpt_t* sock);
e_pcpt_t pcptAcceptServer(pcpt_t* stream, timeout_t timeout_ms);
e_pcpt_t pcptCheckConnectAble(pcpt_t* sock, timeout_t timeout_ms);
e_pcpt_t pcptCheckEvent(HANDLE event, timeout_t timeout_ms, SOCKET socket, uint event_mask);
e_pcpt_t pcptIsBusy(pcpt_t* sock, timeout_t timeout_ms);
e_pcpt_t pcptOpenDataSockServer(pcpt_t* sock, timeout_t timeout_ms);
e_pcpt_t pcptOpenServer(pcpt_t* sock, int open_mode, ushort port);
e_pcpt_t pcptRecv(pcpt_t* sock, unsigned char* recv_buf, size_t* recv_buf_len, timeout_t timeout_ms);
e_pcpt_t pcptSend(pcpt_t* sock, unsigned char* send_buf, size_t* send_len, uint param_4, timeout_t timeout_ms);
e_pcpt_t pcptSendAllMsg(pcpt_t* sock, timeout_t timeout_ms);
void pcptSetConfig(pcpt_t* sock, uint config, uint value);

View File

@ -0,0 +1,87 @@
#include "pcpa.h"
void pcptPrint(pcpt_t* stream, char* name) {
printf(" PCPT %s STATUS\n", name);
printf(" Current errno: %d\n", stream->err);
printf(" Server socket: %08X (%d)\n", stream->server_sock, stream->open);
printf(" Client socket: %08X (%d)\n", stream->client_sock, stream->client_open);
if (stream->send_buf)
printf(" Send buffer: %.*s\n", *stream->send_buf_count, stream->send_buf);
else
puts(" Send buffer: -");
if (stream->recv_buf)
printf(" Recv buffer: %.*s\n", *stream->recv_buf_count, stream->recv_buf);
else
puts(" Recv buffer: -");
}
void pcppPrint(pcpp_t* stream) {
puts("PCPP STATUS");
printf(" Current errno: %d state: %d\n", stream->err, stream->state);
printf(" Open: %d at %d\n", stream->open, stream->last_active);
printf(" Read buf: %.*s\n", stream->read_bytes_num, stream->read_bytes_buf);
printf(" Send buf: %.*s\n", stream->send_buf_len, stream->send_buf);
printf(" Send binary: %p (%d[?])\n", stream->send_binary_buf, stream->field_0x1f8);
printf(" Recv binary: %p (%d)\n", stream->recv_binary_buf, stream->recv_binary_buf_len);
pcptPrint(&stream->sock, "TEXT");
pcptPrint(&stream->data_sock, "BINARY");
}
void pcpaPrint(pcpa_t* stream) {
puts("PCPA STATUS");
amtime_t now;
amiTimerGet(&now);
printf("Now: %d\n", _amTimeMs(now));
printf("Current errno: %d\n", stream->err);
printf("%d/%d callbacks registered at %p\n", stream->callback_count, stream->callback_max, stream->callback_table);
printf("Binary mode: %d (%p/%p)\n", stream->binary_mode, stream->binary_mode_before_cb,
stream->binary_mode_after_cb);
if (stream->recv_buffer)
printf("Recv buffer: %.*s\n", stream->recv_buffer_len, stream->recv_buffer);
else
puts("Recv buffer: -");
if (stream->send_buffer)
printf("Send buffer: %.*s\n", stream->send_buffer_len, stream->send_buffer);
else
puts("Send buffer: -");
pcppPrint(&stream->pcpp);
printf("Send data: %.*s\n", stream->send_data.length, stream->send_data.data);
puts("Parse data:");
printf(" %d commands:\n", stream->recv_data.cmd_count);
for (size_t i = 0; i < stream->recv_data.cmd_count; i++) {
byte kwd = stream->recv_data.keywords[i];
if (kwd != 0) kwd++;
printf(" & %02d '%s'\n", kwd, stream->recv_data.strings + kwd);
byte value = stream->recv_data.values[i];
if (value != 0) value++;
printf(" = %02d '%s'\n", value, stream->recv_data.strings + value);
if (stream->recv_data.strings[kwd] == 0) break;
}
puts(" Raw strings table:");
for (size_t i = 0; i < PCP_BUF_MAX; i = i + 32) {
printf(" ");
for (size_t j = i; j < i + 32; j++) {
printf("%02X ", stream->recv_data.strings[j]);
if (j % 16 == 15)
printf(" ");
else if (j % 8 == 7)
printf(" ");
}
printf(" ");
for (size_t j = i; j < i + 32; j++) {
char chr = stream->recv_data.strings[j];
if (' ' <= chr && chr <= '~')
printf("%c", chr);
else
printf(".");
if (j % 16 == 15) printf(" ");
}
puts("");
}
}

View File

@ -1,16 +1,8 @@
subdir('util') # This is the only lib that should ever be link_with'd by another lib
subdir('json')
subdir('am')
subdir('dmi')
subdir('mice')
fs = import('fs')
# Handle the fact we aren't distributing the libpcp source
if fs.exists('libpcp/libpcp.c')
subdir('libpcp')
libpcp_is_static = true
else
libpcp = meson.get_compiler('c').find_library('libpcp', dirs: libs_dir, required: false)
assert(libpcp.found(), 'Unable to locate libpcp.lib. Make sure to place it in the src/ folder prior to building.')
libpcp_is_static = false
endif
subdir('util') # This is the only lib that should ever be link_with'd by another lib
subdir('json')
subdir('dmi')
subdir('mice')
subdir('am')
fs = import('fs')
subdir('libpcp')

View File

@ -1,122 +1,129 @@
#include "exe.h"
bool inject_debug_wait(HANDLE process) {
BOOL present;
fprintf(stderr, "Waiting for debugger to attach.\n");
do {
Sleep(1000);
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
fprintf(stderr, "Fatal: CheckRemoteDebuggerPresent failed: %03x\n", GetLastError());
return false;
}
} while (!present);
fprintf(stderr, "Debugger attached, resuming\n");
return true;
}
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) {
int nchars = strlen(argument);
LPVOID arg_addr = VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (arg_addr == NULL) {
fprintf(stderr, "Fatal: VirtualAllocEx failed: %03x\n", GetLastError());
return false;
}
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
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) {
fprintf(stderr, "Fatal: CreateRemoteThread failed: %03x\n", GetLastError());
return false;
}
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
return false;
}
DWORD result;
if (FAILED(GetExitCodeThread(remote_thread, &result))) {
fprintf(stderr, "Fatal: GetExitCodeThread failed: %03x\n", GetLastError());
return false;
}
if (result == 0) {
fprintf(stderr, "Fatal: GetExitCodeThread failed: result == 0\n");
return false;
}
return true;
}
bool inject_dll(HANDLE process, LPCSTR inject) {
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
if (kernel32 == NULL) {
fprintf(stderr, "Fatal: GetModuleHandleA failed: %03x\n", GetLastError());
return false;
}
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
if (addr_LoadLibraryA == NULL) {
fprintf(stderr, "Fatal: GetProcAddress failed: %03x\n", GetLastError());
return false;
}
return remote_call(process, addr_LoadLibraryA, inject);
}
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) {
STARTUPINFOA startupInfo;
PROCESS_INFORMATION processInformation;
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
// char real_inject_path[MAX_PATH + 1];
// snprintf(real_inject_path, MAX_PATH + 1, ".\\%s", inject);
// GetFullPathNameA(real_inject_path, MAX_PATH + 1, &real_inject_path, NULL);
// Validate that we're not about to try something insane
DWORD found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
if (found == 0) {
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))) {
fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError());
goto abort;
}
if (delay) {
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
}
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
// Injection completed, let the program continue execution
if (FAILED(ResumeThread(processInformation.hThread))) {
fprintf(stderr, "Fatal: ResumeThread failed: %03x\n", GetLastError());
goto abort;
}
return processInformation.hProcess;
abort:
if (processInformation.hProcess) {
if (FAILED(CloseHandle(processInformation.hThread)))
fprintf(stderr, "Fatal: CloseHandle(hProcess) failed: %03x\n", GetLastError());
if (FAILED(TerminateProcess(processInformation.hProcess, 1)))
fprintf(stderr, "Fatal: TerminateProcess failed: %03x\n", GetLastError());
}
if (processInformation.hThread) {
if (FAILED(CloseHandle(processInformation.hThread)))
fprintf(stderr, "Fatal: CloseHandle(hThread) failed: %03x\n", GetLastError());
}
return NULL;
}
#include "exe.h"
bool inject_debug_wait(HANDLE process) {
BOOL present;
fprintf(stderr, "Waiting for debugger to attach.\n");
do {
Sleep(1000);
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
fprintf(stderr, "Fatal: CheckRemoteDebuggerPresent failed: %03x\n", GetLastError());
return false;
}
} while (!present);
fprintf(stderr, "Debugger attached, resuming\n");
return true;
}
bool remote_call(HANDLE process, LPVOID function, LPCSTR argument) {
int nchars = strlen(argument);
LPVOID arg_addr = VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (arg_addr == NULL) {
fprintf(stderr, "Fatal: VirtualAllocEx failed: %03x\n", GetLastError());
return false;
}
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
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) {
fprintf(stderr, "Fatal: CreateRemoteThread failed: %03x\n", GetLastError());
return false;
}
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
fprintf(stderr, "Fatal: WaitForSingleObject failed: %03x\n", GetLastError());
return false;
}
DWORD result;
if (FAILED(GetExitCodeThread(remote_thread, &result))) {
fprintf(stderr, "Fatal: GetExitCodeThread failed: %03x\n", GetLastError());
return false;
}
if (result == 0) {
fprintf(stderr, "Fatal: GetExitCodeThread failed: result == 0\n");
return false;
}
return true;
}
bool inject_dll(HANDLE process, LPCSTR inject) {
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
if (kernel32 == NULL) {
fprintf(stderr, "Fatal: GetModuleHandleA failed: %03x\n", GetLastError());
return false;
}
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
if (addr_LoadLibraryA == NULL) {
fprintf(stderr, "Fatal: GetProcAddress failed: %03x\n", GetLastError());
return false;
}
return remote_call(process, addr_LoadLibraryA, inject);
}
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL delay) {
STARTUPINFOA startupInfo;
PROCESS_INFORMATION processInformation = { 0 };
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.cb = sizeof(startupInfo);
// char real_inject_path[MAX_PATH + 1];
// snprintf(real_inject_path, MAX_PATH + 1, ".\\%s", inject);
// GetFullPathNameA(real_inject_path, MAX_PATH + 1, &real_inject_path, NULL);
DWORD found;
// Does the exe we're starting exist?
found = SearchPathA(NULL, path, NULL, 0, NULL, NULL);
if (found == 0) {
fprintf(stderr, "Fatal: Cannot start %s: not found\n", path);
goto abort;
}
// Does the DLL we want to inject exist?
found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
if (found == 0) {
fprintf(stderr, "Fatal: Cannot inject %s: not found\n", inject);
goto abort;
}
// Start the binary
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo,
&processInformation)) {
fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError());
goto abort;
}
if (delay) {
if (!inject_debug_wait(processInformation.hProcess)) goto abort;
}
if (!inject_dll(processInformation.hProcess, inject)) goto abort;
// Injection completed, let the program continue execution
if (FAILED(ResumeThread(processInformation.hThread))) {
fprintf(stderr, "Fatal: ResumeThread failed: %03x\n", GetLastError());
goto abort;
}
return processInformation.hProcess;
abort:
if (processInformation.hProcess) {
if (!CloseHandle(processInformation.hThread))
fprintf(stderr, "Fatal: CloseHandle(hProcess) failed: %03x\n", GetLastError());
if (!TerminateProcess(processInformation.hProcess, 1))
fprintf(stderr, "Fatal: TerminateProcess failed: %03x\n", GetLastError());
}
if (processInformation.hThread) {
if (!CloseHandle(processInformation.hThread))
fprintf(stderr, "Fatal: CloseHandle(hThread) failed: %03x\n", GetLastError());
}
return INVALID_HANDLE_VALUE;
}

View File

@ -1,56 +1,69 @@
#include <winioctl.h>
#define FILE_DEVICE_SEGA 0x9c40
// amSramInit
#define IOCTL_MXSRAM_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
// amSramInit
#define IOCTL_MXSRAM_GET_SECTOR_SIZE CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXSRAM_GET_VERSION CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
// EEPROM uses MXSMBUS_GUID device class
// DIPSW uses MXSMBUS_GUID device class
// Platform uses PLATFORM_GUID device class
// amDipswRequestReadByteInternal
// amDipswReadByteInternal
// amDipswWriteByteInternal
// /\ all either use SUPERIO or SMBUS. Which is unknown atm. All use 0x801
//
// amDipswGetDriverVersion
// /\ uses either SUPERIO or SMBUS. Which is unknown atm. Uses 0x802
// Same as IOCTL_MXSRAM_PING
// amHmProbeSuperIoDevice
#define IOCTL_MXSUPERIO_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
// amHmGetLPCChipId
#define IOCTL_MXSUPERIO_READ CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_MXSUPERIO_UNKNOWN CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
// amHmLpcReadByte
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_READ CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
// amHmLpcWriteByte
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXJVS_EXCHANGE CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Same as IOCTL_MXSUPERIO_READ
// amHmI2CReadByte,amHmI2CWriteByte,amEepromWait
#define IOCTL_MXSMBUS_REQUEST CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
// amEepromGetDriverVerision
#define IOCTL_MXSMBUS_GET_VERSION CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
// amEepromI2CReadBlock,amEepromI2CWriteBlock,amHmGetLPCChipId
#define IOCTL_MXSMBUS_I2C CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_MXSMBUS_IDK CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_COLUMBA_READ_DMI CTL_CODE(FILE_DEVICE_SEGA, 0x841, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXHWRESET_RESET CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_MXPARALLEL_WRITE_DATA CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXPARALLEL_READ_DATA CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXPARALLEL_WRITE_STATUS CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXPARALLEL_READ_STATUS CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXPARALLEL_WRITE_CTRL_PORT CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXPARALLEL_READ_CTRL_PORT CTL_CODE(FILE_DEVICE_SEGA, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXPARALLEL_WRITE_FLAGS CTL_CODE(FILE_DEVICE_SEGA, 0x806, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXPARALLEL_READ_FLAGS CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
#include <winioctl.h>
#define FILE_DEVICE_SEGA 0x9c40
// amSramInit
#define IOCTL_MXSRAM_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
// amSramInit
#define IOCTL_MXSRAM_GET_SECTOR_SIZE \
CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXSRAM_GET_VERSION \
CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
// EEPROM uses MXSMBUS_GUID device class
// DIPSW uses MXSMBUS_GUID device class
// Platform uses PLATFORM_GUID device class
// amDipswRequestReadByteInternal
// amDipswReadByteInternal
// amDipswWriteByteInternal
// /\ all either use SUPERIO or SMBUS. Which is unknown atm. All use 0x801
//
// amDipswGetDriverVersion
// /\ uses either SUPERIO or SMBUS. Which is unknown atm. Uses 0x802
// Same as IOCTL_MXSRAM_PING
// amHmProbeSuperIoDevice
#define IOCTL_MXSUPERIO_PING CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_READ_ACCESS)
// amHmGetLPCChipId
#define IOCTL_MXSUPERIO_READ CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_MXSUPERIO_WRITE CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
// amHmLpcReadByte
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_READ \
CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
// amHmLpcWriteByte
#define IOCTL_MXSUPERIO_HWMONITOR_LPC_WRITE \
CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXJVS_EXCHANGE CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
// Same as IOCTL_MXSUPERIO_READ
// amHmI2CReadByte,amHmI2CWriteByte,amEepromWait
#define IOCTL_MXSMBUS_REQUEST CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
// amEepromGetDriverVerision
#define IOCTL_MXSMBUS_GET_VERSION \
CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_READ_ACCESS)
// amEepromI2CReadBlock,amEepromI2CWriteBlock,amHmGetLPCChipId
#define IOCTL_MXSMBUS_I2C CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_MXSMBUS_IDK CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_COLUMBA_READ CTL_CODE(FILE_DEVICE_SEGA, 0x841, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXHWRESET_RESET CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_MXPARALLEL_WRITE_DATA \
CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXPARALLEL_READ_DATA \
CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXPARALLEL_WRITE_STATUS \
CTL_CODE(FILE_DEVICE_SEGA, 0x802, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXPARALLEL_READ_STATUS \
CTL_CODE(FILE_DEVICE_SEGA, 0x803, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXPARALLEL_WRITE_CTRL_PORT \
CTL_CODE(FILE_DEVICE_SEGA, 0x804, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXPARALLEL_READ_CTRL_PORT \
CTL_CODE(FILE_DEVICE_SEGA, 0x805, METHOD_BUFFERED, FILE_READ_ACCESS)
#define IOCTL_MXPARALLEL_WRITE_FLAGS \
CTL_CODE(FILE_DEVICE_SEGA, 0x806, METHOD_BUFFERED, FILE_WRITE_ACCESS)
#define IOCTL_MXPARALLEL_READ_FLAGS \
CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)

View File

@ -1,228 +1,228 @@
#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++) {
json_object_entry* entry = &(object->u.object.values[j]);
if (strncmp(name, entry->name, entry->name_length) == 0) {
*value = entry->value;
return true;
}
}
return false;
}
bool fetch_string(json_value* object, char* name, char** value) {
json_value* fetched;
if (!fetch(object, name, &fetched)) return false;
if (fetched->type != json_string) return false;
*value = fetched->u.string.ptr;
return true;
}
bool fetch_int(json_value* object, char* name, size_t* value) {
json_value* fetched;
if (!fetch(object, name, &fetched)) return false;
if (fetched->type != json_integer) return false;
*value = fetched->u.integer;
return true;
}
bool fetch_bool(json_value* object, char* name, bool* value) {
json_value* fetched;
if (!fetch(object, name, &fetched)) return false;
if (fetched->type != json_boolean) return false;
*value = fetched->u.boolean;
return true;
}
void free_patches(patches_t* patches) {
if (patches->nopatchsets == 0) return;
for (int i = patches->nopatchsets - 1; i >= 0; i--) {
if (patches->patchsets[i] != NULL) {
for (int j = 0; j < patches->patchsets[i]->nopatches; j++) {
if (patches->patchsets[i]->patches[j].from != NULL) free(patches->patchsets[i]->patches[j].from);
if (patches->patchsets[i]->patches[j].to != NULL) free(patches->patchsets[i]->patches[j].to);
}
free(patches->patchsets[i]);
}
}
patches->nopatchsets = 0;
}
json_value* load_json_from_file(char* path, char* error) {
FILE* fp;
fopen_s(&fp, path, "r");
if (fp == NULL) {
if (error != NULL) snprintf(error, json_error_max, "Failed to open patch file");
return NULL;
}
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
rewind(fp);
char* json_buf = (char*)malloc(sz);
if (json_buf == NULL) {
if (error != NULL) 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) snprintf(error, json_error_max, "Failed to read file");
fclose(fp);
return NULL;
};
fclose(fp);
json_settings settings = { 0 };
return json_parse_ex(&settings, json_buf, sz, error);
}
bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error) {
patches->nopatchsets = set_count;
patches->patchsets = (patchset_t**)malloc(set_count * sizeof(patchset_t*));
for (int i = 0; i < set_count; i++) patches->patchsets[i] = NULL;
error[0] = '\0';
for (int i = 0; i < set_count; i++) {
patchset_t* patchset = (patchset_t*)malloc(sizeof(patchset_t));
patches->patchsets[i] = patchset;
patchset->name = NULL;
patchset->description = NULL;
patchset->binary_name = NULL;
patchset->apply = false;
patchset->nopatches = 0;
char *name, *description, *binary_name;
if (!fetch_string(set_json[i], "name", &name)) {
snprintf(error, json_error_max, "'name' missing for patch %d", i);
goto failed;
}
if (!fetch_string(set_json[i], "description", &description)) {
snprintf(error, json_error_max, "'description' missing for patch %d (%s)", i, name);
goto failed;
}
if (!fetch_string(set_json[i], "binary_name", &binary_name)) binary_name = NULL;
bool apply;
if (!fetch_bool(set_json[i], "apply", &apply)) {
snprintf(error, json_error_max, "'apply' missing for patch %d (%s)", i, name);
goto failed;
}
json_value* set_patches;
if (!fetch(set_json[i], "patches", &set_patches) || set_patches->type != json_array) {
char* patches_file_path;
if (fetch_string(set_json[i], "patches_file", &patches_file_path)) {
char load_error[json_error_max];
set_patches = load_json_from_file(patches_file_path, load_error);
if (set_patches == NULL) {
fprintf(stderr, "W: patcher: Failed to load '%s': %s\n", patches_file_path, load_error);
continue;
}
if (set_patches->type != json_array) {
fprintf(stderr, "W: patcher: Failed to load '%s': not an array\n", patches_file_path);
continue;
}
} else {
snprintf(error, json_error_max, "Neither 'patches' nor 'patchs_file' in patch %d (%s)", i, name);
goto failed;
}
}
int count = set_patches->u.array.length;
patchset = (patchset_t*)realloc(patchset, sizeof(patchset_t) + (sizeof(patch_t) * count));
patches->patchsets[i] = patchset;
patchset->name = name;
patchset->description = description;
patchset->binary_name = binary_name;
patchset->apply = apply;
patchset->nopatches = count;
memset(patchset->patches, 0, count * (sizeof(patch_t)));
for (int j = 0; j < count; j++) {
json_value* this_patch = set_patches->u.array.values[j];
size_t at;
char *from, *to;
if (!fetch_int(this_patch, "at", &at)) {
char* at_str;
if (!fetch_string(this_patch, "at", &at_str)) {
snprintf(error, json_error_max, "'at' missing for patch %s[%d]", name, j);
goto failed;
}
if (strlen(at_str) > 8) {
snprintf(error, json_error_max, "invalid 'at' value for patch %s[%d]", name, j);
goto failed;
}
hex_to_bin(at_str, (void*)&at, 8);
at = _byteswap_ulong(at); // Endianess!
}
if (!fetch_string(this_patch, "from", &from)) {
snprintf(error, json_error_max, "'from' missing for patch %s[%d]", name, j);
goto failed;
}
if (!fetch_string(this_patch, "to", &to)) {
snprintf(error, json_error_max, "'to' missing for patch %s[%d]", name, j);
goto failed;
}
char* patch_name;
if (!fetch_string(this_patch, "name", &patch_name)) patch_name = NULL;
patchset->patches[j].name = patch_name;
patchset->patches[j].offset = at;
size_t size = strlen(from);
if (size != strlen(to)) {
snprintf(error, json_error_max, "'from' and 'to' lengths differ in patch %s[%d]", name, j);
goto failed;
}
if (size % 2 != 0) {
snprintf(error, json_error_max, "invalid hex string in patch %s[%d]", name, j);
goto failed;
}
char* bin_from = patchset->patches[j].from = (char*)malloc(size / 2);
char* bin_to = patchset->patches[j].to = (char*)malloc(size / 2);
if (!hex_to_bin(from, bin_from, size)) {
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].from", name, j);
goto failed;
};
if (!hex_to_bin(to, bin_to, size)) {
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].to", name, j);
goto failed;
};
patchset->patches[j].count = size / 2;
}
}
return true;
failed:
free_patches(patches);
return false;
}
bool load_patches(patches_t* patches, char* path, char* error) {
patches->nopatchsets = 0;
json_value* parsed = load_json_from_file(path, error);
if (parsed == NULL) return false;
int loaded_patches = 0;
json_value** patches_json;
if (parsed->type == json_array) {
loaded_patches = parsed->u.array.length;
patches_json = parsed->u.array.values;
} else if (parsed->type == json_object) {
loaded_patches = 1;
patches_json = &parsed;
} else {
snprintf(error, json_error_max, "Patch file format error");
json_value_free(parsed);
return false;
}
if (!parse_patches(patches, patches_json, loaded_patches, error)) return false;
return true;
}
#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++) {
json_object_entry* entry = &(object->u.object.values[j]);
if (strncmp(name, entry->name, entry->name_length) == 0) {
*value = entry->value;
return true;
}
}
return false;
}
bool fetch_string(json_value* object, char* name, char** value) {
json_value* fetched;
if (!fetch(object, name, &fetched)) return false;
if (fetched->type != json_string) return false;
*value = fetched->u.string.ptr;
return true;
}
bool fetch_int(json_value* object, char* name, size_t* value) {
json_value* fetched;
if (!fetch(object, name, &fetched)) return false;
if (fetched->type != json_integer) return false;
*value = (size_t)fetched->u.integer;
return true;
}
bool fetch_bool(json_value* object, char* name, bool* value) {
json_value* fetched;
if (!fetch(object, name, &fetched)) return false;
if (fetched->type != json_boolean) return false;
*value = fetched->u.boolean;
return true;
}
void free_patches(patches_t* patches) {
if (patches->nopatchsets == 0) return;
for (int i = patches->nopatchsets - 1; i >= 0; i--) {
if (patches->patchsets[i] != NULL) {
for (size_t j = 0; j < patches->patchsets[i]->nopatches; j++) {
if (patches->patchsets[i]->patches[j].from != NULL) free(patches->patchsets[i]->patches[j].from);
if (patches->patchsets[i]->patches[j].to != NULL) free(patches->patchsets[i]->patches[j].to);
}
free(patches->patchsets[i]);
}
}
patches->nopatchsets = 0;
}
json_value* load_json_from_file(char* path, char* error) {
FILE* fp;
fopen_s(&fp, path, "r");
if (fp == NULL) {
if (error != NULL) snprintf(error, json_error_max, "Failed to open patch file");
return NULL;
}
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
rewind(fp);
char* json_buf = (char*)malloc(sz);
if (json_buf == NULL) {
if (error != NULL) 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) snprintf(error, json_error_max, "Failed to read file");
fclose(fp);
return NULL;
};
fclose(fp);
json_settings settings = { 0 };
return json_parse_ex(&settings, json_buf, sz, error);
}
bool parse_patches(patches_t* patches, json_value** set_json, int set_count, char* error) {
patches->nopatchsets = set_count;
patches->patchsets = (patchset_t**)malloc(set_count * sizeof(patchset_t*));
for (int i = 0; i < set_count; i++) patches->patchsets[i] = NULL;
error[0] = '\0';
for (int i = 0; i < set_count; i++) {
patchset_t* patchset = (patchset_t*)malloc(sizeof(patchset_t));
patches->patchsets[i] = patchset;
patchset->name = NULL;
patchset->description = NULL;
patchset->binary_name = NULL;
patchset->apply = false;
patchset->nopatches = 0;
char *name, *description, *binary_name;
if (!fetch_string(set_json[i], "name", &name)) {
snprintf(error, json_error_max, "'name' missing for patch %d", i);
goto failed;
}
if (!fetch_string(set_json[i], "description", &description)) {
snprintf(error, json_error_max, "'description' missing for patch %d (%s)", i, name);
goto failed;
}
if (!fetch_string(set_json[i], "binary_name", &binary_name)) binary_name = NULL;
bool apply;
if (!fetch_bool(set_json[i], "apply", &apply)) {
snprintf(error, json_error_max, "'apply' missing for patch %d (%s)", i, name);
goto failed;
}
json_value* set_patches;
if (!fetch(set_json[i], "patches", &set_patches) || set_patches->type != json_array) {
char* patches_file_path;
if (fetch_string(set_json[i], "patches_file", &patches_file_path)) {
char load_error[json_error_max];
set_patches = load_json_from_file(patches_file_path, load_error);
if (set_patches == NULL) {
fprintf(stderr, "W: patcher: Failed to load '%s': %s\n", patches_file_path, load_error);
continue;
}
if (set_patches->type != json_array) {
fprintf(stderr, "W: patcher: Failed to load '%s': not an array\n", patches_file_path);
continue;
}
} else {
snprintf(error, json_error_max, "Neither 'patches' nor 'patchs_file' in patch %d (%s)", i, name);
goto failed;
}
}
int count = set_patches->u.array.length;
patchset = (patchset_t*)realloc(patchset, sizeof(patchset_t) + (sizeof(patch_t) * count));
patches->patchsets[i] = patchset;
patchset->name = name;
patchset->description = description;
patchset->binary_name = binary_name;
patchset->apply = apply;
patchset->nopatches = count;
memset(patchset->patches, 0, count * (sizeof(patch_t)));
for (int j = 0; j < count; j++) {
json_value* this_patch = set_patches->u.array.values[j];
size_t at;
char *from, *to;
if (!fetch_int(this_patch, "at", &at)) {
char* at_str;
if (!fetch_string(this_patch, "at", &at_str)) {
snprintf(error, json_error_max, "'at' missing for patch %s[%d]", name, j);
goto failed;
}
if (strlen(at_str) > 8) {
snprintf(error, json_error_max, "invalid 'at' value for patch %s[%d]", name, j);
goto failed;
}
hex_to_bin(at_str, (void*)&at, 8);
at = _byteswap_ulong(at); // Endianess!
}
if (!fetch_string(this_patch, "from", &from)) {
snprintf(error, json_error_max, "'from' missing for patch %s[%d]", name, j);
goto failed;
}
if (!fetch_string(this_patch, "to", &to)) {
snprintf(error, json_error_max, "'to' missing for patch %s[%d]", name, j);
goto failed;
}
char* patch_name;
if (!fetch_string(this_patch, "name", &patch_name)) patch_name = NULL;
patchset->patches[j].name = patch_name;
patchset->patches[j].offset = at;
size_t size = strlen(from);
if (size != strlen(to)) {
snprintf(error, json_error_max, "'from' and 'to' lengths differ in patch %s[%d]", name, j);
goto failed;
}
if (size % 2 != 0) {
snprintf(error, json_error_max, "invalid hex string in patch %s[%d]", name, j);
goto failed;
}
unsigned char* bin_from = patchset->patches[j].from = (unsigned char*)malloc(size / 2);
unsigned char* bin_to = patchset->patches[j].to = (unsigned char*)malloc(size / 2);
if (!hex_to_bin(from, bin_from, size)) {
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].from", name, j);
goto failed;
};
if (!hex_to_bin(to, bin_to, size)) {
snprintf(error, json_error_max, "invalid hex string in patch %s[%d].to", name, j);
goto failed;
};
patchset->patches[j].count = size / 2;
}
}
return true;
failed:
free_patches(patches);
return false;
}
bool load_patches(patches_t* patches, char* path, char* error) {
patches->nopatchsets = 0;
json_value* parsed = load_json_from_file(path, error);
if (parsed == NULL) return false;
int loaded_patches = 0;
json_value** patches_json;
if (parsed->type == json_array) {
loaded_patches = parsed->u.array.length;
patches_json = parsed->u.array.values;
} else if (parsed->type == json_object) {
loaded_patches = 1;
patches_json = &parsed;
} else {
snprintf(error, json_error_max, "Patch file format error");
json_value_free(parsed);
return false;
}
if (!parse_patches(patches, patches_json, loaded_patches, error)) return false;
return true;
}

View File

@ -1,8 +1,8 @@
subdir('lib')
subdir('micepatch')
subdir('micekeychip')
subdir('launcher')
subdir('dll')
subdir('micetest')
subdir('lib')
subdir('micepatch')
subdir('micekeychip')
subdir('launcher')
subdir('dll')
subdir('miceboot')
subdir('util')

View File

@ -0,0 +1,4 @@
@echo off
@REM "C:\Program Files (x86)\TrueCrypt\TrueCrypt.exe" %*
echo %*
pause

View File

@ -0,0 +1,150 @@
/****************************************************************************
Copyright (c) 2003 Microsoft Corporation
Module Name: ewfapi.h
Abstract: Defines the EWF APIs
Environment: User mode
Revision History:
****************************************************************************/
#ifndef __EWFAPI_H__
#define __EWFAPI_H__
#ifdef __cplusplus
extern "C" {
#endif
#ifndef EWFIMP
#define EWFIMP __declspec(dllimport)
#endif
typedef struct _EWF_VOLUME_NAME_ENTRY {
struct _EWF_VOLUME_NAME_ENTRY* Next;
WCHAR Name[1];
} EWF_VOLUME_NAME_ENTRY, *PEWF_VOLUME_NAME_ENTRY;
typedef enum {
EWF_NO_CMD = 0, // no pending command
EWF_ENABLE, // overlay will be enabled
EWF_DISABLE, // overlay will be disabled
EWF_SET_LEVEL, // overlay level will be set
EWF_COMMIT // current level will be committed to the protected volume
} EWF_CMD;
typedef enum {
EWF_ENABLED, // The overlay is enabled on the volume
EWF_DISABLED // The overlay is disabled on the volume
} EWF_STATE;
typedef enum {
EWF_DISK, // DISK overlay
EWF_RAM, // RAM overlay, with an associated overlay volume store
EWF_RAM_REG, // RAM overlay, without an associated overlay volume store
} EWF_TYPE,
*PEWF_TYPE;
#define EWF_MAX_DEVICE_NAME_LENGTH (256)
#define EWF_VOLUME_ID_SIZE (16)
typedef struct _EWF_VOLUME_DESC {
WCHAR DeviceName[EWF_MAX_DEVICE_NAME_LENGTH]; // Device name of the volume
UCHAR VolumeID[EWF_VOLUME_ID_SIZE]; // 16 byte volume identifier
} EWF_VOLUME_DESC, *PEWF_VOLUME_DESC;
//
// This is a variable size structure depending on how many protected overlay
// volumes there are.
//
typedef struct _EWF_OVERLAY_STORE_CONFIG {
ULONG FormatVersion; // Version of Overlay-Store format
LONGLONG VolumeSize; // Size of the overlay volume in bytes
ULONG NumSegments; // Number of segments that the volume is divided into
ULONG FreeSegments; // Number of segments that are free
ULONG SegmentSize; // Size of each segment in bytes
ULONG MaxVolumes; // Maximum number of protected volumes
ULONG NumVolumes; // Number of currently protected volumes
USHORT MaxLevels; // Maximum number of overlay levels
EWF_VOLUME_DESC VolumeDescArray[1];
// The array holds NumVolume count volume descriptions
} EWF_OVERLAY_STORE_CONFIG, *PEWF_OVERLAY_STORE_CONFIG;
typedef struct _EWF_COMMAND {
EWF_CMD Command; // ENABLE, DISABLE, etc..
ULONG Param1; // command first parameter.
ULONG Param2; // command second parameter.
} EWF_COMMAND, *PEWF_COMMAND;
#define EWF_MAX_LEVEL_NAME_LENGTH (64)
typedef struct _EWF_LEVEL_DESC {
WCHAR LevelName[EWF_MAX_LEVEL_NAME_LENGTH];
// friendly name of the level
// If the length is equal to EWF_MAX_LEVEL_NAME_LENGTH
// then no null terminator is stored.
FILETIME LevelEndTime; // time at which the level was ended
LONGLONG LevelDataSize; // Size of the data in the level in bytes
} EWF_LEVEL_DESC, *PEWF_LEVEL_DESC;
#define EWF_MAX_PERSISTENT_DATA (32) // maximum number of bytes that can be persisted
typedef struct _EWF_VOLUME_CONFIG {
EWF_TYPE Type; // Type of overlay for this volume
EWF_STATE State; // state of the overlay for this volume, ENABLED or DISABLED
EWF_COMMAND BootCommand; // Command to execute on next restart
// Small amount of persistent data that survives a restore
UCHAR PersistentData[EWF_MAX_PERSISTENT_DATA];
USHORT MaxLevels; // Maximum number of checkpoint levels for this volume
ULONG ClumpSize; // 512 bytes
USHORT CurrentLevel; // Current checkpoint level
union {
struct {
LONGLONG DiskMapSize; // Size of the mapping data on disk
LONGLONG DiskDataSize; // Size of the data stored on disk for this protected volume
} DiskOverlay;
struct {
LONGLONG RamDataSize; // Size of the data stored in RAM for this protected volume
} RamOverlay;
};
ULONG MemMapSize; // Size of the mapping data in memory
EWF_VOLUME_DESC VolumeDesc; // volume device name, and volume ID
EWF_LEVEL_DESC LevelDescArray[1]; // Level descripton and end time, and level data size
} EWF_VOLUME_CONFIG, *PEWF_VOLUME_CONFIG;
EWFIMP WCHAR WINAPI EwfMgrGetDriveLetterFromVolumeName(IN LPCWSTR lpVolumeName);
EWFIMP BOOL WINAPI EwfMgrVolumeNameListIsEmpty(IN PEWF_VOLUME_NAME_ENTRY pVolumeNameList);
EWFIMP VOID WINAPI EwfMgrVolumeNameEntryPop(IN PEWF_VOLUME_NAME_ENTRY* ppVolumeNameList);
EWFIMP VOID WINAPI EwfMgrVolumeNameListDelete(IN PEWF_VOLUME_NAME_ENTRY pVolumeNameList);
EWFIMP HANDLE WINAPI EwfMgrOpenProtected(IN LPCWSTR lpVolume);
EWFIMP BOOL WINAPI EwfMgrClose(IN HANDLE hDevice);
EWFIMP BOOL WINAPI EwfMgrClearCommand(IN HANDLE hDevice);
EWFIMP BOOL WINAPI EwfMgrSetPersistentData(IN HANDLE hDevice, IN LPBYTE lpPersistentData, IN DWORD cbPersistentData);
EWFIMP BOOL WINAPI EwfMgrGetPersistentData(IN HANDLE hDevice, OUT LPBYTE lpPersistentData, IN DWORD cbPersistentData);
EWFIMP BOOL WINAPI EwfMgrCheckpoint(IN HANDLE hDevice, IN OPTIONAL LPCWSTR lpDescription);
EWFIMP BOOL WINAPI EwfMgrRestore(IN HANDLE hDevice);
EWFIMP BOOL WINAPI EwfMgrDisable(IN HANDLE hDevice, IN BOOL fCommit);
EWFIMP BOOL WINAPI EwfMgrEnable(IN HANDLE hDevice);
EWFIMP BOOL WINAPI EwfMgrCommit(IN HANDLE hDevice);
EWFIMP BOOL WINAPI EwfMgrCommitAndDisableLive(IN HANDLE hDevice);
EWFIMP BOOL WINAPI EwfMgrCommitFile(IN HANDLE hDevice, IN LPWSTR lpFile);
EWFIMP BOOL WINAPI EwfMgrSetLevel(IN HANDLE hDevice, IN OPTIONAL LPCWSTR lpDescription, IN int Level,
IN BOOL fDeleteLevel);
EWFIMP PEWF_VOLUME_CONFIG WINAPI EwfMgrGetProtectedVolumeConfig(IN HANDLE hDevice);
EWFIMP PEWF_VOLUME_NAME_ENTRY WINAPI EwfMgrGetProtectedVolumeList(VOID);
EWFIMP HANDLE WINAPI EwfMgrOpenOverlayStore(IN BOOL fOpenForAsyncIO);
EWFIMP PEWF_OVERLAY_STORE_CONFIG WINAPI EwfMgrGetOverlayStoreConfig(IN HANDLE hDevice);
EWFIMP BOOL WINAPI EwfMgrRegisterLowSpaceNotification(IN HANDLE hDevice, IN LONGLONG FreeBytesRemaining,
IN LPOVERLAPPED lpOverlapped);
#ifdef __cplusplus
}
#endif
#endif // __EWFAPI_H__

View File

@ -0,0 +1,31 @@
executable(
'miceprestartup',
win_subsystem: subsystem,
sources: [
'mxprestartup.c',
],
)
executable(
'micestartup',
win_subsystem: subsystem,
sources: [
'mxstartup.c',
],
)
executable(
'truecrypt',
win_subsystem: subsystem,
sources: [
'truecrypt.c',
],
)
executable(
'mxmaster',
win_subsystem: subsystem,
sources: [
'mxmaster.c',
],
)

View File

@ -0,0 +1,105 @@
#include <Windows.h>
typedef struct __EWF_LEVEL_DESC {
WCHAR
LevelName[EWF_MAX_LEVEL_NAME_LENGTH];
FILETIME
LevelEndTime;
LONGLONG
LevelDataSize;
} EWF_LEVEL_DESC, *PEWF_LEVEL_DESC;
typedef struct _EWF_OVERLAY_STORE_CONFIG {
ULONG
FormatVersion;
LONGLONG
VolumeSize;
ULONG
NumSegments;
ULONG
FreeSegments;
ULONG
SegmentSize;
ULONG
MaxVolumes;
ULONG
NumVolumes;
USHORT
MaxLevels;
EWF_VOLUME_DESC
VolumeDescArray[1];
} EWF_OVERLAY_STORE_CONFIG, *PEWF_OVERLAY_STORE_CONFIG;
typedef struct _EWF_VOLUME_CONFIG {
EWF_TYPE
Type;
EWF_STATE
State;
EWF_COMMAND
BootCommand;
UCHAR
PersistentData[EWF_MAX_PERSISTENT_DATA];
USHORT
MaxLevels;
ULONG
ClumpSize;
USHORT
CurrentLevel;
union {
struct {
LONGLONG
DiskMapSize;
LONGLONG
DiskDataSize;
} DiskOverlay;
struct {
LONGLONG
RamDataSize;
} RamOverlay;
};
ULONG
MemMapSize;
EWF_VOLUME_DESC
VolumeDesc;
EWF_LEVEL_DESC
LevelDescArray[1];
} EWF_VOLUME_CONFIG, *PEWF_VOLUME_CONFIG;
typedef struct _EWF_VOLUME_DESC {
WCHAR _ DeviceName[EWF_MAX_DEVICE_NAME_LENGTH];
UCHAR
VolumeID[EWF_VOLUME_ID_SIZE];
} EWF_VOLUME_DESC, *PEWF_VOLUME_DESC;
typedef struct _EWF_VOLUME_NAME_ENTRY {
struct _EWF_VOLUME_NAME_ENTRY* Next;
WCHAR
Name[1];
} EWF_VOLUME_NAME_ENTRY, *PEWF_VOLUME_NAME_ENTRY;
HRESULT WINAPI ConfigureEwf(VOID);
BOOL EwfMgrActivateHorm(HANDLE hDevice);
BOOL EwfMgrCheckpoint(HANDLE hDevice, OPTIONAL LPCWSTR lpDescription);
BOOL EwfMgrClearCommand(HANDLE hDevice);
BOOL EwfMgrClose(HANDLE hDevice);
BOOL EwfMgrCommit(HANDLE hDevice);
BOOL WINAPI EwfMgrCommitAndDisableLive(IN HANDLE hDevice, );
BOOL WINAPI EwfMgrCommitFile(IN HANDLE hDevice, IN LPWSTR lpFile);
BOOL EwfMgrDeactivateHorm(HANDLE hDevice);
BOOL EwfMgrDisable(HANDLE hDevice, BOOLfCommit);
BOOL EwfMgrEnable(HANDLE hDevice);
WCHAR EwfMgrGetDriveLetterFromVolumeName(LPCWSTR lpVolumeName);
PEWF_OVERLAY_STORE_CONFIG EwfMgrGetOverlayStoreConfig(HANDLE hDevice);
BOOL EwfMgrGetPeristentData(HANDLE hDevice, LPBYTElpPersistentData, DWORDcbPersistentData);
PEWF_VOLUME_CONFIG EwfMgrGetProtectedVolumeConfig(HANDLE hDevice);
PEWF_VOLUME_NAME_ENTRY EwfMgrGetProtectedVolumeList(VOID);
BOOL EwfMgrIsHormActivated(HANDLE hDevice);
HANDLE EwfMgrOpenOverlayStore(BOOL fOpenForAsyncIO);
HANDLE EwfMgrOpenProtected(LPCWSTR lpVolume);
BOOL EwfMgrRegisterLowSpaceNotification(HANDLE hDevice, LONGLONGFreeBytesRemaining, LPOVERLAPPEDlpOverlapped);
BOOL EwfMgrRestore(HANDLE hDevice);
BOOL EwfMgrSetLevel(HANDLE hDevice, OPTIONAL LPCWSTRlpDescription, intLevel, BOOLfDeleteLevel);
BOOL EwfMgrSetPeristentData(HANDLE hDevice, LPBYTE lpPersistentData, DWORD cbPersistentData);
VOID EwfMgrVolumeNameEntryPop(PEWF_VOLUME_NAME_ENTRY* ppVolumeNameList);
VOID EwfMgrVolumeNameListDelete(PEWF_VOLUME_NAME_ENTRY pVolumeNameList);
BOOL EwfMgrVolumeNameListIsEmpty(PEWF_VOLUME_NAME_ENTRY pVolumeNameList);

View File

@ -0,0 +1,8 @@
#include <Windows.h>
#include <stdio.h>
int main(int argc, char** argv) {
puts("mxmaster.exe dummy hit");
while (1) Sleep(1000);
}

View File

@ -0,0 +1,216 @@
/*
Currently unimplemented:
- Changing the screen resoltuion to something very small (lol)
- The UI that shows "NOW LOADING"
*/
#include <Windows.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define SYSTEM_USER "SystemUser"
#define MXSTARTUP "C:\\System\\Execute\\mxstartup.exe"
#define RETRIES 100
#define STR_INDIR(x) #x
#define STR(x) STR_INDIR(x)
/*
No debugger:
153815264b5839090b0d1c1a423c02241633130673071a1e38443912410b47380f213c1d
+ 2e0247311e162b666c6640393737724157001f56045b4b4f24333457335a26381f4c3349
= 'C:\Windows\System32\wbem\wmitemp.mof'
270a2a053b29042b261d1b22070d140c (wmitemp.mof)
+ 152c05381a141f494a48060223260d29 (key)
= '<6/=U=#tpe!$*3!5'
Has debugger:
d0b1c034a32243340505a343659517c121f0319583d205c593a690719604846000e062a6
+ 63f10541f0c201c0703022f332a13094b542f130c25491a1c280a65440831296e2563590
% 255 (not 256!)
= 34a3c57594e444f47535c53797374756d63323c546279667562737c5d68796f6e2379737
flip nibbles of each byte
= 'C:\\WINDOWS\\system32\\drivers\\mxio.sys'
9160e5c22392918371e43573f2b095b1 (mxio.sys)
+ 43368004f2a34211f4f12120b1b57151
% 255
= d49666c61636d39466d65693a4660703
flip nibbles of each byte
= 'Miflac=Ifme9Jfp0'
*/
#define PERFECT_RECREATION
#ifdef PERFECT_RECREATION
// C:\Windows\System32\wbem\wmitemp.mof (contains 270a2a053b29042b261d1b22070d140c)
// NOTE: On 64 bit windows this is going to be redirected to syswow64
#define PATH_NODEBUG_1 "153815264b5839090b0d1c1a423c02241633130673071a1e38443912410b47380f213c1d"
#define PATH_NODEBUG_2 "2e0247311e162b666c6640393737724157001f56045b4b4f24333457335a26381f4c3349"
// C:\WINDOWS\system32\drivers\mxio.sys (contains 9160e5c22392918371e43573f2b095b1)
// NOTE: On 64 bit windows this is going to be redirected to syswow64
#define PATH_DEBUG_1 "d0b1c034a32243340505a343659517c121f0319583d205c593a690719604846000e062a6"
#define PATH_DEBUG_2 "63f10541f0c201c0703022f332a13094b542f130c25491a1c280a65440831296e2563590"
#define NODEBUG_PSK "152c05381a141f494a48060223260d29"
#define DEBUG_PSK "43368004f2a34211f4f12120b1b57151"
#else
#define PASS_NODEBUG "Miflac=Ifme9Jfp0"
#define PASS_DEBUG "<6/=U=#tpe!$*3!5"
#endif
void reboot() {
puts("Starting the next hop failed.");
puts("We're not going to reboot, but mxprestartup normally would at this point.");
exit(1);
}
char* load_password(const char* path1, const char* path2, const char* psk, bool flip) {
char path[37];
path[36] = '\0';
char temp1[3] = { 0 };
char temp2[3] = { 0 };
char* pEnd;
for (int i = 0; i < 72; i += 2) {
temp1[0] = path1[i];
temp1[1] = path1[i + 1];
temp2[0] = path2[i];
temp2[1] = path2[i + 1];
uint8_t value = (strtol(temp1, &pEnd, 16) + strtol(temp2, &pEnd, 16)) % 0xff;
if (flip)
path[i >> 1] = ((value & 0xf0) >> 4) | ((value & 0x0f) << 4);
else
path[i >> 1] = value;
}
printf("Attempting to read key from %s\n", path);
FILE* key_file;
fopen_s(&key_file, path, "r");
if (!key_file) {
printf("! Failed to read file: %d\n", GetLastError());
return NULL;
}
char key2[32];
fread(key2, 1, 32, key_file);
fclose(key_file);
char* password = malloc(17);
password[16] = '\0';
for (int i = 0; i < 32; i += 2) {
temp1[0] = psk[i];
temp1[1] = psk[i + 1];
temp2[0] = key2[i];
temp2[1] = key2[i + 1];
uint8_t value = (strtol(temp1, &pEnd, 16) + strtol(temp2, &pEnd, 16)) % 0xff;
if (flip)
password[i >> 1] = ((value & 0xf0) >> 4) | ((value & 0x0f) << 4);
else
password[i >> 1] = value;
}
return password;
}
char* get_password() {
if (IsDebuggerPresent()) {
#ifdef PERFECT_RECREATION
return load_password(PATH_DEBUG_1, PATH_DEBUG_2, DEBUG_PSK, true);
#else
return PASS_DEBUG;
#endif
}
#ifdef PERFECT_RECREATION
return load_password(PATH_NODEBUG_1, PATH_NODEBUG_2, NODEBUG_PSK, false);
#else
return PASS_NODEBUG;
#endif
}
int main(int argc, char** argv) {
if (argc > 4) {
puts("Usage:");
printf(" %s\n", argv[0]);
printf(" %s <mxstartup.exe>\n", argv[0]);
printf(" %s <username> <password>\n", argv[0]);
printf(" %s <mxstartup.exe> <username> <password>\n", argv[0]);
exit(0);
}
PVOID old = NULL;
Wow64DisableWow64FsRedirection(&old);
BOOL spawned = FALSE;
STARTUPINFOW startup_info = {
.cb = 68,
.wShowWindow = SW_SHOW,
.dwFlags = STARTF_USESHOWWINDOW,
};
PROCESS_INFORMATION process = { 0 };
for (int i = 0; i < RETRIES; i++) {
char* password = argc == 3 ? argv[2] : argc == 4 ? argv[3] : get_password();
if (password) {
char* username = argc == 3 ? argv[1] : argc == 4 ? argv[2] : SYSTEM_USER;
char* binary = (argc == 2 || argc == 4) ? argv[1] : MXSTARTUP;
printf("Username: %s\n", username);
printf("Password: %s\n", password);
printf("Next hop: %s\n", binary);
size_t _;
wchar_t* wPassword = malloc((strlen(password) + 1) * (sizeof(wchar_t)));
wchar_t* wUser = malloc((strlen(username) + 1) * (sizeof(wchar_t)));
wchar_t* wBinary = malloc((strlen(binary) + 1) * (sizeof(wchar_t)));
mbstowcs_s(&_, wPassword, strlen(password) + 1, password, _TRUNCATE);
mbstowcs_s(&_, wUser, strlen(username) + 1, username, _TRUNCATE);
mbstowcs_s(&_, wBinary, strlen(binary) + 1, binary, _TRUNCATE);
spawned = CreateProcessWithLogonW(wUser, NULL, wPassword, 0, NULL, wBinary, HIGH_PRIORITY_CLASS, NULL, NULL,
&startup_info, &process);
free(wPassword);
if (spawned)
break;
else
puts("Failed to start next hop");
if (process.hProcess != NULL) {
CloseHandle(process.hProcess);
process.hProcess = NULL;
}
} else {
puts("Failed to get password");
}
Sleep(1000);
puts("------------------------");
printf("Retry %d\n", i + 1);
puts("------------------------");
}
if (process.hProcess != NULL) {
CloseHandle(process.hProcess);
process.hProcess = NULL;
}
if (!spawned) {
reboot();
}
return 0;
}

View File

@ -0,0 +1,410 @@
#include <Windows.h>
#include <shellapi.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "ewfapi.h"
typedef enum {
MxError_Unknown = -1,
MxError_None = 0,
MxError_Ewf = 501,
MxError_Version = 502,
MxError_NoKeyFile = 503,
MxError_DiskAccessPrivilege = 504,
MxError_SystemMount = 505,
MxError_MxMaster = 507,
MxError_SBR = 511,
MxError_SysKeyDelete = 512,
} MxError_t;
typedef enum {
Init = 0,
CheckEwf = 1,
EwfDisabled = 2,
GetSBR = 3,
NormalBoot = 4,
SystemUpdate2 = 5,
SystemUpdate3 = 6,
Done = 7,
} StartupStep_t;
#define VERSION_BUFFER 256
#define VERSION_FILE "C:\\System\\SystemVersion.txt"
#define DEFAULT_VERSION_FILE "C:\\System\\DefaultSystemVersion.txt"
#define SYSTEM_KEY_FILE "Z:\\SystemKeyFile"
#define OS_UPDATE_KEY_FILE "Z:\\UpdateKeyFile"
#define SYSTEM_VOLUME "C:\\System\\Execute\\System"
#define SYSTEM_MOUNT "S:"
#define NEXT_HOP_CWD SYSTEM_MOUNT "\\"
#define NEXT_HOP_MXMASTER NEXT_HOP_CWD "mxmaster.exe"
#define CACLS_REMPERM_EXECUTE "cacls c:\\system\\execute /t /e /p AppUser:N"
#define CACLS_REMPERM_Z "cacls z:\\ /t /e /p appuser:N"
#define CACLS_REMPERM_S "cacls s:\\ /t /e /p appuser:N"
// Rather than implement these sums in code, we're just going to use the
// presummed versions, because we have nothing to gain by obfuscating this.
// These two sum to TC_PASSWORD
#define TC_PASSWORD_1 "3d550a335d2557055d2b3d1444153348"
#define TC_PASSWORD_2 "36105d2e0b3c1b5f1336365f335a3f1c"
#define TC_PASSWORD "segahardpassword"
// These two sum to SYSTEM_KEYFILE_ADS
#define SYSTEM_KEYFILE_1 "041443255b204a3f054d1b4c352a22292f211b29440e1237591f2e49375d093967614d"
#define SYSTEM_KEYFILE_2 "3f26192e1e532a26680f2a2c3039534b363b2923082c41421a5537241408700d020b18"
#define SYSTEM_KEYFILE_ADS "C:\\System\\Execute\\DLL:SystemKeyFile"
// These two sum to OS_UPDATE_ADS
#define OS_UPDATE_KEYFILE_1 "4019582c56283006300b40042110143d603b3d3b1d012b5c0d5423152235163f624a43"
#define OS_UPDATE_KEYFILE_2 "03210427234b445f3d51057444536137052107112f392a14570d515029306307072222"
#define OS_UPDATE_KEYFILE_ADS "C:\\System\\Execute\\DLL:UpdateKeyFile"
int LOG_EN_PLATFORM = 0;
#define MX_LOG(...) log(__FUNCTION__, __LINE__, __VA_ARGS__)
void log(char* function, unsigned int line_number, char* fmt, ...) {
va_list args;
va_start(args, fmt);
printf("%s: Line%d ", function, line_number);
vprintf(fmt, args);
va_end(args);
}
// TODO: These two
bool InitGraphics() { return true; }
bool PopulateEventInfo() { return true; }
// TODO: These three
void AppendAsterisk(void){};
void setStrForStep2(void){};
void setStrForStep3(void){};
int osuExecProcess(char* command) {
PROCESS_INFORMATION processInformation = { 0 };
STARTUPINFOA startupInfo = {
.cb = 68,
.dwFlags = STARTF_USESHOWWINDOW,
.wShowWindow = SW_HIDE,
};
if (command == NULL) return -150;
BOOL spanwed = CreateProcessA(NULL, command, NULL, NULL, 0, 0, NULL, NULL, &startupInfo, &processInformation);
DWORD wait = WaitForSingleObject(processInformation.hProcess, INFINITE);
int ret;
if (!spanwed) {
ret = -140;
} else if (wait == WAIT_OBJECT_0) {
DWORD exitCode;
GetExitCodeProcess(processInformation.hProcess, &exitCode);
ret = exitCode == 0 ? 0 : -141;
} else {
ret = -141;
}
CloseHandle(processInformation.hProcess);
CloseHandle(processInformation.hThread);
return ret;
}
/* Read a version from a text file */
bool GetVersionText(char* version, char* path) {
char buffer[VERSION_BUFFER];
FILE* file;
memset(buffer, 0, sizeof buffer);
if (fopen_s(&file, path, "r") || file == NULL) {
MX_LOG("Error : GetVersionText error path = %s\n", path);
return false;
}
fgets(buffer, sizeof buffer, file);
fclose(file);
strncpy_s(version, VERSION_BUFFER, buffer, VERSION_BUFFER);
return true;
}
/* Get the currently running version of the system */
bool GetCurrentVersion(char* version) { return GetVersionText(version, VERSION_FILE); }
/* Get the default version of the system */
bool GetDefaultVersion(char* version) { return GetVersionText(version, DEFAULT_VERSION_FILE); }
/* Mount the system volume */
bool MountSystemVolume(void) {
char command[256];
snprintf(command, sizeof command, "TrueCrypt /p %s /k %s /v %s /l %s /w /s /q", TC_PASSWORD, SYSTEM_KEY_FILE,
SYSTEM_VOLUME, SYSTEM_MOUNT);
int ret = osuExecProcess(command);
if (ret == 0) return true;
MX_LOG("Error : osuExecProcess error. ret = %d\n", ret);
return false;
};
/* Try to mount the system volume with up to 100 retries */
bool TryMountSystemVolume(void) {
for (int i = 0; i < 100; i++) {
if (MountSystemVolume()) return true;
Sleep(200);
}
return false;
}
/* Copies the file at src to dst */
bool GetKeyFile(LPCSTR src, LPCSTR dst) {
HANDLE file_1 = CreateFileA(src, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (file_1 == INVALID_HANDLE_VALUE) {
MX_LOG("CreaterFile Src error\n");
return false;
}
HANDLE file_2 = CreateFileA(dst, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (file_2 == INVALID_HANDLE_VALUE) {
CloseHandle(file_1);
MX_LOG("Error : CreateFile Dst error\n");
return false;
}
CHAR readBuffer[260];
DWORD bytesRead;
if (!ReadFile(file_1, readBuffer, 255, &bytesRead, NULL)) {
CloseHandle(file_1);
CloseHandle(file_2);
MX_LOG("Error : ReadFile error\n");
return false;
}
readBuffer[bytesRead] = '\0';
DWORD written;
bool ret = WriteFile(file_2, readBuffer, strlen(readBuffer), &written, NULL) != 0;
if (!ret) MX_LOG("Error : WriteFile error\n");
CloseHandle(file_1);
CloseHandle(file_2);
return ret;
}
bool GetSystemKeyFile() { return GetKeyFile(SYSTEM_KEYFILE_ADS, SYSTEM_KEY_FILE); };
bool GetOOUpdateKeyFile() { return GetKeyFile(OS_UPDATE_KEYFILE_ADS, OS_UPDATE_KEY_FILE); };
bool SetDiskAccessPrivilege() {
int i;
for (i = 0; i < 100; i++) {
if (osuExecProcess(CACLS_REMPERM_EXECUTE) != -140) break;
Sleep(200);
}
if (i == 100) {
MX_LOG("Error : osuExecProcess error\n");
return false;
}
for (i = 0; i < 100; i++) {
if (osuExecProcess(CACLS_REMPERM_Z) != -140) break;
Sleep(200);
}
if (i == 100) {
MX_LOG("Error : osuExecProcess error\n");
return false;
}
for (i = 0; i < 100; i++) {
if (osuExecProcess(CACLS_REMPERM_S) != -140) break;
Sleep(200);
}
if (i == 100) {
MX_LOG("Error : osuExecProcess error\n");
return false;
}
return true;
};
bool ExecuteMxMaster() {
HINSTANCE ret = ShellExecuteA(NULL, NULL, NEXT_HOP_MXMASTER, NULL, NEXT_HOP_CWD, 0);
if ((int)ret < 33) {
MX_LOG("Error : ShellExecute ret = %d\n", ret);
return false;
}
return true;
};
bool MxInitStartup(int* diskNumber) { return false; }
bool CheckEwfState(EWF_STATE* state) {
// TODO: Consider a better implementation of this!
*state = EWF_ENABLED; // Nothing to do, boot the system
// *state = EWF_DISABLED; // We're in the middle of an update, so finish
return true;
}
bool GetSBRSlotOSState(int diskNumber, int* updateState) { return false; };
bool SystemUpdateStep2(int diskNumber) { return false; }
bool SystemUpdateStep3(int diskNumber) { return false; }
MxError_t NormalBootStep(void) {
AppendAsterisk();
if (!GetSystemKeyFile()) return MxError_NoKeyFile;
AppendAsterisk();
if (!TryMountSystemVolume()) return MxError_SystemMount;
AppendAsterisk();
if (!DeleteFileA(SYSTEM_KEY_FILE)) return MxError_SysKeyDelete;
AppendAsterisk();
if (!SetDiskAccessPrivilege()) return MxError_DiskAccessPrivilege;
AppendAsterisk();
if (!ExecuteMxMaster()) return MxError_MxMaster;
return MxError_None;
}
int DoStartup() {
StartupStep_t step = Init;
MxError_t error = MxError_None;
int diskNumber = 0;
while (step != Done) {
printf("Step: %d (%d)\n", step, error);
switch (step) {
case Init:
if (!MxInitStartup(&diskNumber))
step = CheckEwf;
else
step = Done;
break;
case CheckEwf: {
AppendAsterisk();
EWF_STATE state;
if (!CheckEwfState(&state)) {
error = MxError_Ewf;
step = Done;
break;
}
if (state == EWF_ENABLED)
step = NormalBoot;
else
step = EwfDisabled;
break;
}
case EwfDisabled: {
char versionString[VERSION_BUFFER];
char defaultVersionString[VERSION_BUFFER];
if (!GetCurrentVersion(versionString) || !GetDefaultVersion(defaultVersionString)) {
error = MxError_Version;
step = Done;
break;
}
if (strcmp(versionString, defaultVersionString) == 0)
step = GetSBR;
else
step = SystemUpdate3;
break;
}
case GetSBR: {
int updateState;
AppendAsterisk();
if (!GetSBRSlotOSState(diskNumber, &updateState)) {
error = MxError_SBR;
step = Done;
break;
}
if (updateState == 2)
step = SystemUpdate2;
else
step = SystemUpdate3;
break;
}
case NormalBoot:
error = NormalBootStep();
step = Done;
break;
case SystemUpdate2:
setStrForStep2();
error = SystemUpdateStep2(diskNumber);
step = Done;
break;
case SystemUpdate3:
setStrForStep3();
error = SystemUpdateStep3(diskNumber);
step = Done;
break;
default:
error = MxError_Unknown;
step = Done;
break;
}
}
return error;
}
int setEventSource(char** source) {
// if (WIN_EVENT->ready == 0) {
// return -3;
// }
// if (source == (char**)0x0) {
// return -2;
// }
// _memcpy_s(&WIN_EVENT->eventSource, 16, source, 16);
return 0;
}
void setLogFn(void* log_fn) {
// LOG_FUN = log_fn;
return;
}
int __cdecl logToEventlog(LPCSTR msg) {
//
return 0;
}
bool ExitGraphics(void) {
// int iVar1;
// iVar1 = FUN_0040b9e0((int)&hInstance);
// return iVar1 != 0;
return true;
}
int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) {
PVOID old = NULL;
Wow64DisableWow64FsRedirection(&old);
if (!InitGraphics(hInstance, nShowCmd)) {
MX_LOG("Error : InitGraphics failed.\n");
}
if (!PopulateEventInfo()) {
LOG_EN_PLATFORM = 1;
char* mxstartup = "mxstartup";
setEventSource(&mxstartup);
setLogFn(logToEventlog);
}
MxError_t err = DoStartup();
if (!err) {
if (!ExitGraphics()) {
MX_LOG("Error : ExitGraphics failed.\n");
}
// FUN_00408810();#
Sleep(1000000);
return 0;
}
printf("Fatal: %04d\n", err);
// while (1) {
// FUN_00424640();
// Sleep(100000);
//}
return 0;
}
int main() { return WinMain(NULL, NULL, NULL, 0); }

View File

@ -0,0 +1,5 @@
#include <stdio.h>
int main(int argc, char** argv) {
puts("TrueCrypt.exe dummy hit");
}

View File

@ -1,77 +1,77 @@
#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 mxkPcpAbSystemFlag(pcpa_t* stream, void* data) {
char sf[3];
snprintf(sf, 3, "%02X", Config.appboot_systemflag);
pcpaSetSendPacket(stream, AB_SYSTEMFLAG, sf);
}
void mxkPcpAbModelType(pcpa_t* stream, void* data) {
char mt[16];
snprintf(mt, 16, "%02X", Config.appboot_modeltype);
pcpaSetSendPacket(stream, AB_MODELTYPE, mt);
}
void mxkPcpAbFormatType(pcpa_t* stream, void* data) {
char ft[16];
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, "%02X", Config.appboot_region);
pcpaSetSendPacket(stream, AB_REGION, rg);
}
void mxkPcpAbPlatformId(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, AB_PLATFORMID, Config.appboot_platformid);
}
void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, AB_NETWORKADDRESS, Config.appboot_network);
}
void mxkPcpAbDvd(pcpa_t* stream, void* data) {
char dvd[16];
snprintf(dvd, 16, "%02X", Config.appboot_dvdflag);
pcpaSetSendPacket(stream, AB_DVD, dvd);
}
#define SEED_BUF_MAX 1024
byte SEED_BUF[SEED_BUF_MAX];
int SEED_BUF_LEN = 0;
void mxkPcpAbSeed(pcpa_t* stream, void* data) {
if (SEED_BUF_LEN == 0) {
FILE* fCert;
fopen_s(&fCert, Config.appboot_seed, "r");
if (fCert == NULL)
SEED_BUF_LEN = -1;
else {
fseek(fCert, 0, SEEK_END);
SEED_BUF_LEN = ftell(fCert);
if (SEED_BUF_LEN > SEED_BUF_MAX) SEED_BUF_LEN = SEED_BUF_MAX;
rewind(fCert);
fread(SEED_BUF, SEED_BUF_LEN, 1, fCert);
fclose(fCert);
}
}
if (SEED_BUF_LEN == -1) {
// TODO: Fix this maybe?
pcpaSetBinaryMode(stream, binary_mode_none);
pcpaSetSendPacket(stream, AB_SEED, "-1");
return;
}
pcpaSetBinaryMode(stream, binary_mode_send);
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
BINARY_DATA_LEN = SEED_BUF_LEN;
memcpy(BINARY_DATA, SEED_BUF, SEED_BUF_LEN);
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
pcpaSetSendPacket(stream, AB_SEED, "0");
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16]; // todo: nicer lol
_itoa(SEED_BUF_LEN, sSize, 10);
pcpaAddSendPacket(stream, "size", sSize);
}
#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 mxkPcpAbSystemFlag(pcpa_t* stream, void* data) {
char sf[3];
snprintf(sf, 3, "%02X", Config.appboot_systemflag);
pcpaSetSendPacket(stream, AB_SYSTEMFLAG, sf);
}
void mxkPcpAbModelType(pcpa_t* stream, void* data) {
char mt[16];
snprintf(mt, 16, "%02X", Config.appboot_modeltype);
pcpaSetSendPacket(stream, AB_MODELTYPE, mt);
}
void mxkPcpAbFormatType(pcpa_t* stream, void* data) {
char ft[16];
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, "%02X", Config.appboot_region);
pcpaSetSendPacket(stream, AB_REGION, rg);
}
void mxkPcpAbPlatformId(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, AB_PLATFORMID, Config.appboot_platformid);
}
void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, AB_NETWORKADDRESS, Config.appboot_network);
}
void mxkPcpAbDvd(pcpa_t* stream, void* data) {
char dvd[16];
snprintf(dvd, 16, "%02X", Config.appboot_dvdflag);
pcpaSetSendPacket(stream, AB_DVD, dvd);
}
#define SEED_BUF_MAX 1024
byte SEED_BUF[SEED_BUF_MAX];
int SEED_BUF_LEN = 0;
void mxkPcpAbSeed(pcpa_t* stream, void* data) {
if (SEED_BUF_LEN == 0) {
FILE* fCert;
fopen_s(&fCert, Config.appboot_seed, "r");
if (fCert == NULL)
SEED_BUF_LEN = -1;
else {
fseek(fCert, 0, SEEK_END);
SEED_BUF_LEN = ftell(fCert);
if (SEED_BUF_LEN > SEED_BUF_MAX) SEED_BUF_LEN = SEED_BUF_MAX;
rewind(fCert);
fread(SEED_BUF, SEED_BUF_LEN, 1, fCert);
fclose(fCert);
}
}
if (SEED_BUF_LEN == -1) {
// TODO: Fix this maybe?
pcpaSetBinaryMode(stream, binary_mode_none);
pcpaSetSendPacket(stream, AB_SEED, "-1");
return;
}
pcpaSetBinaryMode(stream, binary_mode_send);
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
BINARY_DATA_LEN = SEED_BUF_LEN;
memcpy(BINARY_DATA, SEED_BUF, SEED_BUF_LEN);
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
pcpaSetSendPacket(stream, AB_SEED, "0");
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16]; // todo: nicer lol
_itoa_s(SEED_BUF_LEN, sSize, sizeof sSize, 10);
pcpaAddSendPacket(stream, "size", sSize);
}

View File

@ -1,111 +1,111 @@
#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 mxkPcpPbPlayCount(pcpa_t* stream, void* data) {
char pc[9];
snprintf(pc, sizeof pc, "%08X", Config.billing_playcount);
pcpaSetSendPacket(stream, BIL_PLAYCOUNT, pc);
}
void mxkPcpPbPlayLimit(pcpa_t* stream, void* data) {
char pl[9];
snprintf(pl, sizeof pl, "%08X", Config.billing_playlimit);
char* playlimit = pcpaGetCommand(stream, BIL_PLAYLIMIT);
pcpaSetSendPacket(stream, BIL_PLAYLIMIT, pl);
if (!strcmp(playlimit, "?")) return;
// TODO: This
pcpaSetSendPacket(stream, "code", "-1");
}
void mxkPcpPbNearfull(pcpa_t* stream, void* data) {
char nf[9];
snprintf(nf, sizeof nf, "%08X", Config.billing_nearfull);
pcpaSetSendPacket(stream, BIL_NEARFUL, nf);
}
#define PUBKEY_BUF_MAX 1024
byte PUBKEY_BUF[PUBKEY_BUF_MAX];
int PUBKEY_LEN = 0;
void mxkPcpPbSignaturePubKey(pcpa_t* stream, void* data) {
if (PUBKEY_LEN == 0) {
FILE* fPubkey;
fopen_s(&fPubkey, Config.billing_pubkey, "r");
if (fPubkey == NULL)
PUBKEY_LEN = -1;
else {
fseek(fPubkey, 0, SEEK_END);
PUBKEY_LEN = ftell(fPubkey);
if (PUBKEY_LEN > PUBKEY_BUF_MAX) PUBKEY_LEN = PUBKEY_BUF_MAX;
rewind(fPubkey);
fread(PUBKEY_BUF, PUBKEY_LEN, 1, fPubkey);
fclose(fPubkey);
}
}
if (PUBKEY_LEN == -1) {
// TODO: Fix this maybe?
pcpaSetBinaryMode(stream, binary_mode_none);
pcpaSetSendPacket(stream, BIL_SIGNATURE, "-1");
return;
}
pcpaSetBinaryMode(stream, binary_mode_send);
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
BINARY_DATA_LEN = PUBKEY_LEN;
memcpy(BINARY_DATA, PUBKEY_BUF, PUBKEY_LEN);
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
pcpaSetSendPacket(stream, BIL_SIGNATURE, "0");
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16];
snprintf(sSize, 16, "%d", PUBKEY_LEN);
pcpaAddSendPacket(stream, "size", sSize);
}
#define CA_CERT_BUF_MAX 1024
byte CA_CERTIFICATION[CA_CERT_BUF_MAX];
int CA_CERT_LEN = 0;
void mxkPcpPbCaCertification(pcpa_t* stream, void* data) {
if (CA_CERT_LEN == 0) {
FILE* fCert;
fopen_s(&fCert, Config.billing_cacert, "r");
if (fCert == NULL)
CA_CERT_LEN = -1;
else {
fseek(fCert, 0, SEEK_END);
CA_CERT_LEN = ftell(fCert);
if (CA_CERT_LEN > CA_CERT_BUF_MAX) CA_CERT_LEN = CA_CERT_BUF_MAX;
rewind(fCert);
fread(CA_CERTIFICATION, CA_CERT_LEN, 1, fCert);
fclose(fCert);
}
}
if (CA_CERT_LEN == -1) {
// TODO: Fix this maybe?
pcpaSetBinaryMode(stream, binary_mode_none);
pcpaSetSendPacket(stream, BIL_CACERT, "-1");
return;
}
pcpaSetBinaryMode(stream, binary_mode_send);
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
BINARY_DATA_LEN = CA_CERT_LEN;
memcpy(BINARY_DATA, CA_CERTIFICATION, CA_CERT_LEN);
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
pcpaSetSendPacket(stream, BIL_CACERT, "0");
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16]; // todo: nicer lol
_itoa(CA_CERT_LEN, sSize, 10);
pcpaAddSendPacket(stream, "size", sSize);
}
#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 mxkPcpPbPlayCount(pcpa_t* stream, void* data) {
char pc[9];
snprintf(pc, sizeof pc, "%08X", Config.billing_playcount);
pcpaSetSendPacket(stream, BIL_PLAYCOUNT, pc);
}
void mxkPcpPbPlayLimit(pcpa_t* stream, void* data) {
char pl[9];
snprintf(pl, sizeof pl, "%08X", Config.billing_playlimit);
char* playlimit = pcpaGetCommand(stream, BIL_PLAYLIMIT);
pcpaSetSendPacket(stream, BIL_PLAYLIMIT, pl);
if (!strcmp(playlimit, "?")) return;
// TODO: This
pcpaSetSendPacket(stream, "code", "-1");
}
void mxkPcpPbNearfull(pcpa_t* stream, void* data) {
char nf[9];
snprintf(nf, sizeof nf, "%08X", Config.billing_nearfull);
pcpaSetSendPacket(stream, BIL_NEARFUL, nf);
}
#define PUBKEY_BUF_MAX 1024
byte PUBKEY_BUF[PUBKEY_BUF_MAX];
int PUBKEY_LEN = 0;
void mxkPcpPbSignaturePubKey(pcpa_t* stream, void* data) {
if (PUBKEY_LEN == 0) {
FILE* fPubkey;
fopen_s(&fPubkey, Config.billing_pubkey, "r");
if (fPubkey == NULL)
PUBKEY_LEN = -1;
else {
fseek(fPubkey, 0, SEEK_END);
PUBKEY_LEN = ftell(fPubkey);
if (PUBKEY_LEN > PUBKEY_BUF_MAX) PUBKEY_LEN = PUBKEY_BUF_MAX;
rewind(fPubkey);
fread(PUBKEY_BUF, PUBKEY_LEN, 1, fPubkey);
fclose(fPubkey);
}
}
if (PUBKEY_LEN == -1) {
// TODO: Fix this maybe?
pcpaSetBinaryMode(stream, binary_mode_none);
pcpaSetSendPacket(stream, BIL_SIGNATURE, "-1");
return;
}
pcpaSetBinaryMode(stream, binary_mode_send);
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
BINARY_DATA_LEN = PUBKEY_LEN;
memcpy(BINARY_DATA, PUBKEY_BUF, PUBKEY_LEN);
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
pcpaSetSendPacket(stream, BIL_SIGNATURE, "0");
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16];
snprintf(sSize, 16, "%d", PUBKEY_LEN);
pcpaAddSendPacket(stream, "size", sSize);
}
#define CA_CERT_BUF_MAX 1024
byte CA_CERTIFICATION[CA_CERT_BUF_MAX];
int CA_CERT_LEN = 0;
void mxkPcpPbCaCertification(pcpa_t* stream, void* data) {
if (CA_CERT_LEN == 0) {
FILE* fCert;
fopen_s(&fCert, Config.billing_cacert, "r");
if (fCert == NULL)
CA_CERT_LEN = -1;
else {
fseek(fCert, 0, SEEK_END);
CA_CERT_LEN = ftell(fCert);
if (CA_CERT_LEN > CA_CERT_BUF_MAX) CA_CERT_LEN = CA_CERT_BUF_MAX;
rewind(fCert);
fread(CA_CERTIFICATION, CA_CERT_LEN, 1, fCert);
fclose(fCert);
}
}
if (CA_CERT_LEN == -1) {
// TODO: Fix this maybe?
pcpaSetBinaryMode(stream, binary_mode_none);
pcpaSetSendPacket(stream, BIL_CACERT, "-1");
return;
}
pcpaSetBinaryMode(stream, binary_mode_send);
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
BINARY_DATA_LEN = CA_CERT_LEN;
memcpy(BINARY_DATA, CA_CERTIFICATION, CA_CERT_LEN);
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
pcpaSetSendPacket(stream, BIL_CACERT, "0");
pcpaAddSendPacket(stream, "port", "40107");
char sSize[16]; // todo: nicer lol
_itoa_s(CA_CERT_LEN, sSize, sizeof sSize, 10);
pcpaAddSendPacket(stream, "size", sSize);
}

View File

@ -1,35 +1,35 @@
#include "callbacks.h"
void mxkPcpTdRestore(pcpa_t* stream, void* data) {
char* sUpdate = pcpaGetCommand(stream, "update");
char* sRestart = pcpaGetCommand(stream, "restart");
bool update = sUpdate != NULL && strcmp(sUpdate, "1") == 0;
bool restart = sRestart != NULL && strcmp(sRestart, "1") == 0;
if (restart) {
pcpaSetSendPacket(stream, TRA_RESTORE, "1");
} else {
pcpaSetSendPacket(stream, TRA_RESTORE, "2");
}
}
void mxkPcpTdPut(pcpa_t* stream, void* data) {
char* sPut = pcpaGetCommand(stream, TRA_PUT);
if (strcmp(sPut, "?")) {
pcpaSetSendPacket(stream, TRA_PUT, "0");
return;
}
// Process packet maybe?
pcpaSetSendPacket(stream, TRA_PUT, "0");
}
void mxkPcpTdGet(pcpa_t* stream, void* data) {
// TODO: lol
pcpaSetSendPacket(stream, TRA_GET, "");
}
void mxkPcpTdLogicalErase(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, TRA_LOGICALERASE, "");
}
void mxkPcpTdSectorErase(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, TRA_SECTOREERASE, "");
}
#include "callbacks.h"
void mxkPcpTdRestore(pcpa_t* stream, void* data) {
char* sUpdate = pcpaGetCommand(stream, "update");
char* sRestart = pcpaGetCommand(stream, "restart");
bool update = sUpdate != NULL && strcmp(sUpdate, "1") == 0;
bool restart = sRestart != NULL && strcmp(sRestart, "1") == 0;
if (restart) {
pcpaSetSendPacket(stream, TRA_RESTORE, "1");
} else {
pcpaSetSendPacket(stream, TRA_RESTORE, "2");
}
}
void mxkPcpTdPut(pcpa_t* stream, void* data) {
char* sPut = pcpaGetCommand(stream, TRA_PUT);
if (strcmp(sPut, "?")) {
pcpaSetSendPacket(stream, TRA_PUT, "0");
return;
}
// Process packet maybe?
pcpaSetSendPacket(stream, TRA_PUT, "0");
}
void mxkPcpTdGet(pcpa_t* stream, void* data) {
// TODO: lol
pcpaSetSendPacket(stream, TRA_GET, "");
}
void mxkPcpTdLogicalErase(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, TRA_LOGICALERASE, "");
}
void mxkPcpTdSectorErase(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, TRA_SECTOREERASE, "");
}

View File

@ -1,30 +1,22 @@
dependencies = []
link_with = [inih.get_variable('lib_inih')]
# Depending on how we're getting access to libpcp, we need some extra work here
if libpcp_is_static
link_with += libpcp
else
link_with += amlib
dependencies += libpcp
dependencies += meson.get_compiler('c').find_library('ws2_32')
endif
rc = import('windows').compile_resources('micekeychip.rc', depend_files: micekeychip_ico)
executable(
'micekeychip',
win_subsystem: subsystem,
sources: [
'main.c',
'mxk.c',
'callbacks/appboot.c',
'callbacks/billing.c',
'callbacks/crypto.c',
'callbacks/misc.c',
'callbacks/tracedata.c',
'callbacks/storage.c',
rc,
],
link_with: link_with,
dependencies: dependencies,
)
dependencies = []
link_with = [inih.get_variable('lib_inih'), libpcp]
rc = import('windows').compile_resources('micekeychip.rc', depend_files: micekeychip_ico)
executable(
'micekeychip',
win_subsystem: subsystem,
sources: [
'main.c',
'mxk.c',
'callbacks/appboot.c',
'callbacks/billing.c',
'callbacks/crypto.c',
'callbacks/misc.c',
'callbacks/tracedata.c',
'callbacks/storage.c',
rc,
],
link_with: link_with,
dependencies: dependencies,
)

View File

@ -1,158 +1,159 @@
#include "mxk.h"
byte SERVER_STATE = 0;
pcpa_t PCP;
pcpa_cb_table_t CALLBACK_FUNCTION_BUFFER[40];
byte BINARY_DATA[4096];
size_t BINARY_DATA_LEN;
void mxkBinaryCallback(pcpa_t* stream, void* data) { pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); }
int mxkInit() {
// Enable colour
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
if (GetConsoleMode(hConsole, &dwMode)) SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
WSADATA wsaData;
int err = WSAStartup(2, &wsaData);
SERVER_STATE = 1;
return err;
}
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);
return err;
}
err = pcpaSetCallbackFuncBuffer(&PCP, CALLBACK_FUNCTION_BUFFER,
(sizeof CALLBACK_FUNCTION_BUFFER) / (sizeof CALLBACK_FUNCTION_BUFFER[0]));
if (err != e_pcpa_ok) {
printf("pcpaSetCallBackFuncBuffer Error. Code:%d\n", err);
return err;
}
// Misc
pcpaSetCallbackFunc(&PCP, KC_VERSION, mxkPcpVersion, NULL);
pcpaSetCallbackFunc(&PCP, KC_STATUS, mxkPcpStatus, NULL);
// Crypto
pcpaSetCallbackFunc(&PCP, DS_COMPUTE, mxkPcpDsCompute, NULL);
pcpaSetCallbackFunc(&PCP, SSD_PROOF, mxkPcpSsdProof, NULL);
pcpaSetCallbackFunc(&PCP, SSD_HOSTPROOF, mxkPcpSsdHostProof, NULL);
pcpaSetCallbackFunc(&PCP, KC_ENCRYPT, mkxPcpEncrypt, NULL);
pcpaSetCallbackFunc(&PCP, KC_DECRYPT, mxkPcpDecrypt, NULL);
pcpaSetCallbackFunc(&PCP, KC_SETIV, mxkPcpSetIv, NULL);
// Appboot
pcpaSetCallbackFunc(&PCP, AB_GAMEID, mxkPcpAbGameId, NULL);
pcpaSetCallbackFunc(&PCP, AB_SYSTEMFLAG, mxkPcpAbSystemFlag, NULL);
pcpaSetCallbackFunc(&PCP, AB_MODELTYPE, mxkPcpAbModelType, NULL);
pcpaSetCallbackFunc(&PCP, AB_FORMATTYPE, mxkPcpAbFormatType, NULL);
pcpaSetCallbackFunc(&PCP, AB_REGION, mxkPcpAbRegion, NULL);
pcpaSetCallbackFunc(&PCP, AB_PLATFORMID, mxkPcpAbPlatformId, NULL);
pcpaSetCallbackFunc(&PCP, AB_NETWORKADDRESS, mxkPcpAbNetworkAddress, NULL);
pcpaSetCallbackFunc(&PCP, AB_DVD, mxkPcpAbDvd, NULL);
pcpaSetCallbackFunc(&PCP, AB_SEED, mxkPcpAbSeed, NULL);
// Billing
pcpaSetCallbackFunc(&PCP, BIL_KEYID, mxkPcpPbKeyId, NULL);
pcpaSetCallbackFunc(&PCP, BIL_MAINID, mxkPcpPbMainId, NULL);
pcpaSetCallbackFunc(&PCP, BIL_PLAYCOUNT, mxkPcpPbPlayCount, NULL);
pcpaSetCallbackFunc(&PCP, BIL_PLAYLIMIT, mxkPcpPbPlayLimit, NULL);
pcpaSetCallbackFunc(&PCP, BIL_NEARFUL, mxkPcpPbNearfull, NULL);
pcpaSetCallbackFunc(&PCP, BIL_SIGNATURE, mxkPcpPbSignaturePubKey, NULL);
pcpaSetCallbackFunc(&PCP, BIL_CACERT, mxkPcpPbCaCertification, NULL);
// Tracedata
pcpaSetCallbackFunc(&PCP, TRA_RESTORE, mxkPcpTdRestore, NULL);
pcpaSetCallbackFunc(&PCP, TRA_PUT, mxkPcpTdPut, NULL);
pcpaSetCallbackFunc(&PCP, TRA_GET, mxkPcpTdGet, NULL);
pcpaSetCallbackFunc(&PCP, TRA_LOGICALERASE, mxkPcpTdLogicalErase, NULL);
pcpaSetCallbackFunc(&PCP, TRA_SECTOREERASE, mxkPcpTdSectorErase, NULL);
// Storage
pcpaSetCallbackFunc(&PCP, KC_EEPROM, mxkPcpEeprom, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM0, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM1, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM2, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM3, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM4, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM5, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM6, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM7, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM8, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM9, mxkPcpNvram, NULL);
long text_port = Config.pcp_control_port;
if (text_port > 0xffff) {
puts("PCP control port invalid");
exit(-1);
}
long binary_port = Config.pcp_binary_port;
if (binary_port > 0xffff) {
puts("PCP binary port invalid");
exit(-1);
}
int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_1;
err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port & 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 & 0xffff, binary_port & 0xffff);
else
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
#ifdef PRINT_DEBUG
// Larger TICK_MS for testing
#undef TICK_MS
#define TICK_MS 100
#endif
e_pcpa_t mxkPcpServer() {
int err;
if (SERVER_STATE == 1) {
err = mxkPcpStreamInit();
if (err == 0) {
SERVER_STATE = 2;
return err;
}
} else {
if (SERVER_STATE != 2) {
return (SERVER_STATE == 0) ? e_pcpa_cannot_open : e_pcpa_not_open;
}
err = pcpaServer(&PCP, TICK_MS);
if (err == e_pcpa_to || err == e_pcpa_closed) err = e_pcpa_ok;
if (err) {
printf("Error pcpaServer. Code %d\n", err);
pcpaClose(&PCP);
SERVER_STATE = 1;
}
}
#ifdef PRINT_DEBUG
puts("\033[H\033[J\033[H");
pcpaPrint(&PCP);
puts("\033[J");
#endif
return err;
#include "mxk.h"
byte SERVER_STATE = 0;
pcpa_t PCP;
pcpa_cb_table_t CALLBACK_FUNCTION_BUFFER[40];
byte BINARY_DATA[4096];
size_t BINARY_DATA_LEN;
void mxkBinaryCallback(pcpa_t* stream, void* data) { pcpaSetSendBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN); }
int mxkInit() {
// Enable colour
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
if (GetConsoleMode(hConsole, &dwMode)) SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
WSADATA wsaData;
int err = WSAStartup(2, &wsaData);
SERVER_STATE = 1;
return err;
}
void log_callback(struct pcpa* stream, void* data) {
FILE* log_file;
fopen_s(&log_file, "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);
return err;
}
err = pcpaSetCallbackFuncBuffer(&PCP, CALLBACK_FUNCTION_BUFFER,
(sizeof CALLBACK_FUNCTION_BUFFER) / (sizeof CALLBACK_FUNCTION_BUFFER[0]));
if (err != e_pcpa_ok) {
printf("pcpaSetCallBackFuncBuffer Error. Code:%d\n", err);
return err;
}
// Misc
pcpaSetCallbackFunc(&PCP, KC_VERSION, mxkPcpVersion, NULL);
pcpaSetCallbackFunc(&PCP, KC_STATUS, mxkPcpStatus, NULL);
// Crypto
pcpaSetCallbackFunc(&PCP, DS_COMPUTE, mxkPcpDsCompute, NULL);
pcpaSetCallbackFunc(&PCP, SSD_PROOF, mxkPcpSsdProof, NULL);
pcpaSetCallbackFunc(&PCP, SSD_HOSTPROOF, mxkPcpSsdHostProof, NULL);
pcpaSetCallbackFunc(&PCP, KC_ENCRYPT, mkxPcpEncrypt, NULL);
pcpaSetCallbackFunc(&PCP, KC_DECRYPT, mxkPcpDecrypt, NULL);
pcpaSetCallbackFunc(&PCP, KC_SETIV, mxkPcpSetIv, NULL);
// Appboot
pcpaSetCallbackFunc(&PCP, AB_GAMEID, mxkPcpAbGameId, NULL);
pcpaSetCallbackFunc(&PCP, AB_SYSTEMFLAG, mxkPcpAbSystemFlag, NULL);
pcpaSetCallbackFunc(&PCP, AB_MODELTYPE, mxkPcpAbModelType, NULL);
pcpaSetCallbackFunc(&PCP, AB_FORMATTYPE, mxkPcpAbFormatType, NULL);
pcpaSetCallbackFunc(&PCP, AB_REGION, mxkPcpAbRegion, NULL);
pcpaSetCallbackFunc(&PCP, AB_PLATFORMID, mxkPcpAbPlatformId, NULL);
pcpaSetCallbackFunc(&PCP, AB_NETWORKADDRESS, mxkPcpAbNetworkAddress, NULL);
pcpaSetCallbackFunc(&PCP, AB_DVD, mxkPcpAbDvd, NULL);
pcpaSetCallbackFunc(&PCP, AB_SEED, mxkPcpAbSeed, NULL);
// Billing
pcpaSetCallbackFunc(&PCP, BIL_KEYID, mxkPcpPbKeyId, NULL);
pcpaSetCallbackFunc(&PCP, BIL_MAINID, mxkPcpPbMainId, NULL);
pcpaSetCallbackFunc(&PCP, BIL_PLAYCOUNT, mxkPcpPbPlayCount, NULL);
pcpaSetCallbackFunc(&PCP, BIL_PLAYLIMIT, mxkPcpPbPlayLimit, NULL);
pcpaSetCallbackFunc(&PCP, BIL_NEARFUL, mxkPcpPbNearfull, NULL);
pcpaSetCallbackFunc(&PCP, BIL_SIGNATURE, mxkPcpPbSignaturePubKey, NULL);
pcpaSetCallbackFunc(&PCP, BIL_CACERT, mxkPcpPbCaCertification, NULL);
// Tracedata
pcpaSetCallbackFunc(&PCP, TRA_RESTORE, mxkPcpTdRestore, NULL);
pcpaSetCallbackFunc(&PCP, TRA_PUT, mxkPcpTdPut, NULL);
pcpaSetCallbackFunc(&PCP, TRA_GET, mxkPcpTdGet, NULL);
pcpaSetCallbackFunc(&PCP, TRA_LOGICALERASE, mxkPcpTdLogicalErase, NULL);
pcpaSetCallbackFunc(&PCP, TRA_SECTOREERASE, mxkPcpTdSectorErase, NULL);
// Storage
pcpaSetCallbackFunc(&PCP, KC_EEPROM, mxkPcpEeprom, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM0, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM1, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM2, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM3, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM4, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM5, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM6, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM7, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM8, mxkPcpNvram, NULL);
pcpaSetCallbackFunc(&PCP, KC_NVRAM9, mxkPcpNvram, NULL);
long text_port = Config.pcp_control_port;
if (text_port > 0xffff) {
puts("PCP control port invalid");
exit(-1);
}
long binary_port = Config.pcp_binary_port;
if (binary_port > 0xffff) {
puts("PCP binary port invalid");
exit(-1);
}
int open_mode = Config.pcp_bind_global ? OPEN_MODE_GLOBAL : OPEN_MODE_1;
err = pcpaOpenServerWithBinary(&PCP, open_mode, text_port & 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 & 0xffff, binary_port & 0xffff);
else
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
#ifdef PRINT_DEBUG
// Larger TICK_MS for testing
#undef TICK_MS
#define TICK_MS 100
#endif
e_pcpa_t mxkPcpServer() {
int err;
if (SERVER_STATE == 1) {
err = mxkPcpStreamInit();
if (err == 0) {
SERVER_STATE = 2;
return err;
}
} else {
if (SERVER_STATE != 2) {
return (SERVER_STATE == 0) ? e_pcpa_cannot_open : e_pcpa_not_open;
}
err = pcpaServer(&PCP, TICK_MS);
if (err == e_pcpa_to || err == e_pcpa_closed) err = e_pcpa_ok;
if (err) {
printf("Error pcpaServer. Code %d\n", err);
pcpaClose(&PCP);
SERVER_STATE = 1;
}
}
#ifdef PRINT_DEBUG
puts("\033[H\033[J\033[H");
pcpaPrint(&PCP);
puts("\033[J");
#endif
return err;
}

View File

@ -1,113 +1,113 @@
#include "../lib/mice/mice.h"
#include "string.h"
void print_patches(patches_t* patches, char* filename) {
for (int i = 0; i < patches->nopatchsets; i++) {
patchset_t* patchset = patches->patchsets[i];
bool skip = patchset->name != NULL && strcmp(patchset->name, filename) != 0;
printf("Patch: %s (%s)\n", patchset->name, skip ? "skipped" : patchset->apply ? "applied" : "unapplied");
printf("- %s\n", patchset->description);
if (!skip) {
for (int i = 0; i < patchset->nopatches; i++) {
printf(":: %d bytes at %08x\n", patchset->patches[i].count, patchset->patches[i].offset);
}
}
puts("======================");
}
}
void apply_patches(patches_t* patches, char* filename) {
FILE* fp;
fopen_s(&fp, filename, "r+b");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s for modification\n", filename);
return;
}
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
for (int i = 0; i < patches->nopatchsets; i++) {
patchset_t* patchset = patches->patchsets[i];
if (patchset->name != NULL && strcmp(patchset->name, filename) != 0) {
continue;
}
for (int j = 0; j < patchset->nopatches; j++) {
patch_t patch = patchset->patches[j];
if (patch.offset + patch.count > sz) {
fprintf(stderr, "E: Patch %s[%d] outside file bounds\n", patchset->name, j);
goto done;
}
fseek(fp, patch.offset, SEEK_SET);
bool matches_from = true;
bool matches_to = true;
for (int i = 0; i < patch.count; i++) {
unsigned char seen;
if (!fread(&seen, 1, 1, fp)) {
matches_from = false;
matches_to = false;
break;
}
if (seen != patch.from[i]) matches_from = false;
if (seen != patch.to[i]) matches_to = false;
if (!(matches_from || matches_to)) break;
}
printf("%s[%d]: ", patchset->name, j);
if (patchset->apply) {
if (matches_to) {
puts("Already applied");
continue;
}
if (!matches_from) {
puts("From value missmatch! Ignoring");
continue;
}
fseek(fp, patch.offset, SEEK_SET);
fwrite(patch.to, 1, patch.count, fp);
puts("Patch applied");
} else {
if (matches_from) {
puts("Not applied");
continue;
}
if (!matches_to) {
puts("We didn't perform this patch. Leaving patched");
continue;
}
fseek(fp, patch.offset, SEEK_SET);
fwrite(patch.from, 1, patch.count, fp);
puts("Patch removed");
}
}
}
done:
fclose(fp);
}
int main(int argc, char** argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <patch file> <exe>\n", argc > 0 ? argv[0] : "micepatch.exe");
return -1;
}
char error[json_error_max];
patches_t all_patches;
if (!load_patches(&all_patches, argv[1], error)) {
fprintf(stderr, "%s\n", error);
return -1;
}
puts("");
puts("Loaded patches:");
puts("---------------");
print_patches(&all_patches, argv[2]);
apply_patches(&all_patches, argv[2]);
free_patches(&all_patches);
return 0;
}
#include "../lib/mice/mice.h"
#include "string.h"
void print_patches(patches_t* patches, char* filename) {
for (size_t i = 0; i < patches->nopatchsets; i++) {
patchset_t* patchset = patches->patchsets[i];
bool skip = patchset->name != NULL && strcmp(patchset->name, filename) != 0;
printf("Patch: %s (%s)\n", patchset->name, skip ? "skipped" : patchset->apply ? "applied" : "unapplied");
printf("- %s\n", patchset->description);
if (!skip) {
for (size_t j = 0; j < patchset->nopatches; j++) {
printf(":: %d bytes at %08x\n", patchset->patches[j].count, patchset->patches[j].offset);
}
}
puts("======================");
}
}
void apply_patches(patches_t* patches, char* filename) {
FILE* fp;
fopen_s(&fp, filename, "r+b");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s for modification\n", filename);
return;
}
fseek(fp, 0L, SEEK_END);
size_t sz = ftell(fp);
for (size_t i = 0; i < patches->nopatchsets; i++) {
patchset_t* patchset = patches->patchsets[i];
if (patchset->name != NULL && strcmp(patchset->name, filename) != 0) {
continue;
}
for (size_t j = 0; j < patchset->nopatches; j++) {
patch_t patch = patchset->patches[j];
if (patch.offset + patch.count > sz) {
fprintf(stderr, "E: Patch %s[%d] outside file bounds\n", patchset->name, j);
goto done;
}
fseek(fp, patch.offset, SEEK_SET);
bool matches_from = true;
bool matches_to = true;
for (size_t k = 0; k < patch.count; k++) {
unsigned char seen;
if (!fread(&seen, 1, 1, fp)) {
matches_from = false;
matches_to = false;
break;
}
if (seen != patch.from[k]) matches_from = false;
if (seen != patch.to[k]) matches_to = false;
if (!(matches_from || matches_to)) break;
}
printf("%s[%d]: ", patchset->name, j);
if (patchset->apply) {
if (matches_to) {
puts("Already applied");
continue;
}
if (!matches_from) {
puts("From value missmatch! Ignoring");
continue;
}
fseek(fp, patch.offset, SEEK_SET);
fwrite(patch.to, 1, patch.count, fp);
puts("Patch applied");
} else {
if (matches_from) {
puts("Not applied");
continue;
}
if (!matches_to) {
puts("We didn't perform this patch. Leaving patched");
continue;
}
fseek(fp, patch.offset, SEEK_SET);
fwrite(patch.from, 1, patch.count, fp);
puts("Patch removed");
}
}
}
done:
fclose(fp);
}
int main(int argc, char** argv) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <patch file> <exe>\n", argc > 0 ? argv[0] : "micepatch.exe");
return -1;
}
char error[json_error_max];
patches_t all_patches;
if (!load_patches(&all_patches, argv[1], error)) {
fprintf(stderr, "%s\n", error);
return -1;
}
puts("");
puts("Loaded patches:");
puts("---------------");
print_patches(&all_patches, argv[2]);
apply_patches(&all_patches, argv[2]);
free_patches(&all_patches);
return 0;
}

View File

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

View File

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

View File

@ -0,0 +1,29 @@
executable(
'micedump',
win_subsystem: subsystem,
sources: [
'micedump.c',
],
link_with: [
amlib
],
)
executable(
'micetinker',
win_subsystem: subsystem,
sources: [
'micetinker.c',
],
link_with: [
amlib
],
)
executable(
'micemonitor',
win_subsystem: subsystem,
sources: [
'micemonitor.c',
],
)

View File

@ -0,0 +1,271 @@
#include <Windows.h>
#include <setupapi.h>
#include <shellapi.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "Setupapi.lib")
#include "../lib/am/amEeprom.h"
#define OpenDriver(x) \
CreateFileA("\\\\.\\" x, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)
#define RULE "-----------------------------------------"
#define SECTION_HEAD(x) \
puts(""); \
puts(RULE); \
puts(x); \
puts(RULE); \
puts("");
typedef struct {
uint64_t physAddr;
DWORD dType;
DWORD size;
} columba_request_t;
void scan_for_dmi(HANDLE columba, DWORD *stable_addr) {
DWORD bytesOut;
// short *stable_len;
columba_request_t request;
unsigned char readBuf[0x8010];
uint64_t search_addr = 0xf0000;
while (1) {
request.physAddr = search_addr;
request.dType = 1;
request.size = sizeof readBuf;
BOOL succ = DeviceIoControl(columba, (DWORD)IOCTL_COLUMBA_READ, &request,
sizeof request, &readBuf, sizeof readBuf, &bytesOut, NULL);
if (succ && bytesOut == sizeof readBuf) {
for (unsigned int offset = 0; offset < 0x8008; offset++) {
if (readBuf[offset] == '_' && readBuf[offset + 1] == 'D' &&
readBuf[offset + 2] == 'M' && readBuf[offset + 3] == 'I' &&
readBuf[offset + 4] == '_') {
*stable_addr = *(DWORD *)&readBuf[offset + 8];
return;
}
}
}
search_addr += 0x7ff0;
if (search_addr > 0xfffdf) return;
}
}
BOOL dump_columba() {
SECTION_HEAD("columba");
HANDLE columba = OpenDriver("columba");
if (columba == INVALID_HANDLE_VALUE) return FALSE;
DWORD stable_addr = 0;
scan_for_dmi(columba, &stable_addr);
if (stable_addr == 0) {
CloseHandle(columba);
return FALSE;
}
columba_request_t request;
unsigned char readBuf[0x10000];
printf("Found DMI at: %d\n", stable_addr);
request.physAddr = stable_addr;
request.dType = 1;
if (stable_addr + 0x10000 < 0x100001) {
request.size = 0x10000;
} else {
request.size = 0x100000 - stable_addr;
}
DWORD bytesReturned;
BOOL s = DeviceIoControl(columba, (DWORD)IOCTL_COLUMBA_READ, &request, sizeof request,
readBuf, sizeof readBuf, &bytesReturned, NULL);
if (!s || bytesReturned != sizeof readBuf) {
CloseHandle(columba);
return FALSE;
}
puts("DMI read sucessful.");
FILE *dmi;
fopen_s(&dmi, "dmi.bin", "wb");
fwrite(readBuf, 1, sizeof readBuf, dmi);
fclose(dmi);
puts(" -> Written to dmi.bin");
CloseHandle(columba);
return TRUE;
}
BOOL dump_eeprom() {
SECTION_HEAD("mxSMBus");
HANDLE mxsmbus = amEepromCreateDeviceFile(&MXSMBUS_GUID, NULL, 0);
if (mxsmbus == INVALID_HANDLE_VALUE) return FALSE;
DWORD _dummy;
DWORD version;
DeviceIoControl(mxsmbus, (DWORD)IOCTL_MXSMBUS_GET_VERSION, NULL, 0, &version, sizeof version,
&_dummy, NULL);
printf("mxSMBus version: %08x\n", version);
BYTE data[0x20];
for (WORD reg = 0; reg < 256; reg++) {
if (!amEepromReadBlock(mxsmbus, reg & 0xFF, 0x20, data)) continue;
printf("%02x: ", reg);
for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]);
puts("");
}
CloseHandle(mxsmbus);
return TRUE;
}
unsigned char sram_buf[1024 * 2048];
BOOL dump_sram() {
SECTION_HEAD("mxSRAM");
HANDLE mxsram = OpenDriver("mxsram");
if (mxsram == INVALID_HANDLE_VALUE) return FALSE;
DWORD _dummy;
BOOL s;
DWORD version;
s = DeviceIoControl(mxsram, (DWORD)IOCTL_MXSRAM_PING, NULL, 0, &version, sizeof version,
&_dummy, NULL);
if (!s) {
CloseHandle(mxsram);
return FALSE;
}
printf("mxSRAM version: %04x\n", version);
DISK_GEOMETRY geom;
s = DeviceIoControl(mxsram, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof geom, &_dummy,
NULL);
if (!s) {
CloseHandle(mxsram);
return FALSE;
}
puts("mxSRAM geometry:");
printf(":: Cylinders: %lld\n", geom.Cylinders.QuadPart);
printf(":: MediaType: %d\n", geom.MediaType);
printf(":: TracksPerCylinder: %d\n", geom.TracksPerCylinder);
printf(":: SectorsPerTrack: %d\n", geom.SectorsPerTrack);
printf(":: BytesPerSector: %d\n", geom.BytesPerSector);
DWORD ssize;
s = DeviceIoControl(mxsram, (DWORD)IOCTL_MXSRAM_GET_SECTOR_SIZE, NULL, 0, &ssize, sizeof ssize,
&_dummy, NULL);
if (!s) {
CloseHandle(mxsram);
return FALSE;
}
printf(":: Sector Size: %d\n", ssize);
DWORD read;
if (!ReadFile(mxsram, sram_buf, sizeof sram_buf, &read, NULL)) {
CloseHandle(mxsram);
return FALSE;
}
printf("Read %d bytes\n", read);
if (read != sizeof sram_buf) puts("W: incomplete");
FILE *sram;
fopen_s(&sram, "sram.bin", "wb");
fwrite(sram_buf, 1, sizeof sram_buf, sram);
fclose(sram);
puts(" -> Written to sram.bin");
CloseHandle(mxsram);
return TRUE;
}
BYTE superio_read(HANDLE mxsuperio, BYTE chip, BYTE device, BYTE index) {
DWORD _dummy;
BYTE payload[4] = { chip, device, index, 0 };
DeviceIoControl(mxsuperio, (DWORD)IOCTL_MXSUPERIO_READ, payload, sizeof payload, payload,
sizeof payload, &_dummy, NULL);
return payload[3];
}
#define SUPERIO_LD_FDC 0
#define SUPERIO_LD_PARALLEL 1
#define SUPERIO_LD_UART_A 2
#define SUPERIO_LD_UART_B 3
#define SUPERIO_LD_KEYBOARD 5
#define SUPERIO_LD_UART_C 6
#define SUPERIO_LD_GPIO34 7
#define SUPERIO_LD_WDTO_PLED_GPIO56 8
#define SUPERIO_LD_GPIO12_SUSLED 9
#define SUPERIO_LD_ACPI 10
#define SUPERIO_LD_HWMON 11
#define SUPERIO_LD_PECI_SST 12
#define SUPERIO_LD_UART_D 13
#define SUPERIO_LD_UART_E 14
#define SUPERIO_LD_UART_F 15
BOOL dump_superio() {
SECTION_HEAD("mxSuperIO");
HANDLE mxsuperio = OpenDriver("mxsuperio");
if (mxsuperio == INVALID_HANDLE_VALUE) return FALSE;
BOOL s;
DWORD _dummy;
DWORD version;
s = DeviceIoControl(mxsuperio, (DWORD)IOCTL_MXSUPERIO_PING, NULL, 0, &version, sizeof version,
&_dummy, NULL);
if (!s) {
CloseHandle(mxsuperio);
return FALSE;
}
printf("mxSuperIO version: %08x\n", version);
BYTE ver_msb;
ver_msb = superio_read(mxsuperio, 0, SUPERIO_LD_FDC, 0x20);
if (ver_msb != 0xff) {
puts(":: Chip 0 present");
printf(" -> Version: %02x%02x\n", ver_msb,
superio_read(mxsuperio, 0, SUPERIO_LD_FDC, 0x21));
} else
puts(":: Chip 0 unpopulated");
ver_msb = superio_read(mxsuperio, 1, SUPERIO_LD_FDC, 0x20);
if (ver_msb != 0xff) {
puts(":: Chip 1 present");
printf(" -> Version: %02x%02x\n", ver_msb,
superio_read(mxsuperio, 1, SUPERIO_LD_FDC, 0x21));
} else
puts(":: Chip 1 unpopulated");
puts(":: Super lazy dump of chip 1, bank 0:");
for (uint8_t reg = 0; reg < 0xff; reg++) {
unsigned char packet[3] = { 1, reg, 0 };
DeviceIoControl(mxsuperio, (DWORD)IOCTL_MXSUPERIO_HWMONITOR_LPC_READ, &packet,
sizeof packet, &packet, sizeof packet, &_dummy, NULL);
printf(" -> %02x: %02x\n", reg, packet[2]);
}
CloseHandle(mxsuperio);
return TRUE;
}
int main() {
// if (!dump_columba()) {
// printf("Failed to dump DMI: %03x\n", GetLastError());
// }
if (!dump_eeprom()) {
printf("Failed to dump EEPROM: %03x\n", GetLastError());
}
// if (!dump_sram()) {
// printf("Failed to dump SRAM: %03x\n", GetLastError());
// }
// if (!dump_superio()) {
// printf("Failed to dump SuperIO: %03x\n", GetLastError());
// }
return 0;
}

View File

@ -0,0 +1,14 @@
#include <Windows.h>
#include <stdio.h>
#define P2A_PATH "C:\\ProgramData\\boost_interprocess\\ALLNetComP2A"
#define A2P_PATH "C:\\ProgramData\\boost_interprocess\\ALLNetComA2P"
int main(int argc, char* argv) {
FILE* f;
fopen_s(&f, "./test.txt", "w");
fprintf(f, "count: %d", argc);
fclose(f);
return 0;
}

View File

@ -0,0 +1,57 @@
#include <Windows.h>
#include <setupapi.h>
#include <shellapi.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "Setupapi.lib")
#include "../lib/am/amEeprom.h"
BOOL change_region(BYTE region) {
HANDLE mxsmbus = amEepromCreateDeviceFile(&MXSMBUS_GUID, NULL, 0);
if (mxsmbus == INVALID_HANDLE_VALUE) return FALSE;
BYTE data[0x20];
if (!amEepromReadBlock(mxsmbus, 0, sizeof data, data)) {
printf("Failed to read block 0");
goto fail;
}
puts("Original content:");
for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]);
puts("");
data[12] = region;
amEepromRepairChecksum(data);
amEepromWriteBlock(mxsmbus, 0, sizeof data, data);
amEepromReadBlock(mxsmbus, 0, sizeof data, data);
puts("Tinkered content:");
for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]);
puts("");
CloseHandle(mxsmbus);
return TRUE;
fail:
CloseHandle(mxsmbus);
return FALSE;
}
int main(int argc, char** argv) {
if (argc != 2) {
printf("Usage: %s <region>\n", argv[0]);
return -1;
}
BYTE region = argv[1][0] - '0';
printf("Changing to region: %d\n", region);
if (!change_region(region)) {
printf("Failed to change region: %03x", GetLastError());
} else {
printf("Region changed!");
}
return 0;
}

View File

@ -0,0 +1,9 @@
[
{
"name": "LOG_EN_AMSRAM",
"at": "00465e54",
"from": "00000000",
"to": "01000000",
"count": 4
}
]

View File

@ -1,51 +1,58 @@
[
{
"name": "maimai Finale logs",
"description": "Enable logging facilities",
"binary_name": "maimai_dump_.exe",
"apply": true,
"patches_file": "maimai_dump_.patch.json"
},
{
"name": "mxnetwork logs",
"description": "Enable logging facilities",
"binary_name": "mxnetwork.exe",
"apply": true,
"patches_file": "mxnetwork.patch.json"
},
{
"name": "maimai 1.00 logs",
"description": "Enable logging facilities",
"binary_name": "Game.exe",
"apply": true,
"patches_file": "Game.patch.json"
},
{
"name": "ALLNetProc logs",
"description": "Enable logging facilities",
"binary_name": "ALLNetProc.exe",
"apply": true,
"patches_file": "ALLNetProc.patch.json"
},
{
"name": "ALLNetProc logs",
"description": "Enable logging facilities (alt filename)",
"binary_name": "ALLNetProc_win.exe",
"apply": true,
"patches_file": "ALLNetProc.patch.json"
},
{
"name": "mxsegaboot logs",
"description": "Enable logging facilities",
"binary_name": "mxsegaboot.exe",
"apply": true,
"patches_file": "mxsegaboot.patch.json"
},
{
"name": "mxsegaboot logs",
"description": "Enable logging facilities (alt filename)",
"binary_name": "ORIG_mxsegaboot.exe",
"apply": true,
"patches_file": "mxsegaboot.patch.json"
}
[
{
"name": "maimai Finale logs",
"description": "Enable logging facilities",
"binary_name": "maimai_dump_.exe",
"apply": true,
"patches_file": "maimai_dump_.patch.json"
},
{
"name": "mxnetwork logs",
"description": "Enable logging facilities",
"binary_name": "mxnetwork.exe",
"apply": true,
"patches_file": "mxnetwork.patch.json"
},
{
"name": "maimai 1.00 logs",
"description": "Enable logging facilities",
"binary_name": "Game.exe",
"apply": true,
"patches_file": "Game.patch.json"
},
{
"name": "ALLNetProc logs",
"description": "Enable logging facilities",
"binary_name": "ALLNetProc.exe",
"apply": true,
"patches_file": "ALLNetProc.patch.json"
},
{
"name": "ALLNetProc logs",
"description": "Enable logging facilities (alt filename)",
"binary_name": "ALLNetProc_win.exe",
"apply": true,
"patches_file": "ALLNetProc.patch.json"
},
{
"name": "mxsegaboot logs",
"description": "Enable logging facilities",
"binary_name": "mxsegaboot.exe",
"apply": true,
"patches_file": "mxsegaboot.patch.json"
},
{
"name": "mxsegaboot logs",
"description": "Enable logging facilities (alt filename)",
"binary_name": "ORIG_mxsegaboot.exe",
"apply": true,
"patches_file": "mxsegaboot.patch.json"
},
{
"name": "mxgfetcher logs",
"description": "Enable logging facilities",
"binary_name": "mxgfetcher.exe",
"apply": true,
"patches_file": "mxgfetcher.patch.json"
}
]