diff --git a/.gitignore b/.gitignore index 663a217..9927fcc 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/Makefile b/Makefile index 9fb600b..b8e3faa 100644 --- a/Makefile +++ b/Makefile @@ -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/*" diff --git a/assert_dd_blocks.py b/assert_dd_blocks.py new file mode 100644 index 0000000..a6c77aa --- /dev/null +++ b/assert_dd_blocks.py @@ -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") diff --git a/meson.build b/meson.build index c1ee10c..cd82b2e 100644 --- a/meson.build +++ b/meson.build @@ -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') diff --git a/mxinstaller.py b/mxinstaller.py new file mode 100644 index 0000000..6d40a57 --- /dev/null +++ b/mxinstaller.py @@ -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) \ No newline at end of file diff --git a/src/micetools/dll/comdevice.c b/src/micetools/dll/comdevice.c index 6818ccd..7fbe7f1 100644 --- a/src/micetools/dll/comdevice.c +++ b/src/micetools/dll/comdevice.c @@ -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; +} diff --git a/src/micetools/dll/comdevice.h b/src/micetools/dll/comdevice.h index 8787c6d..12a29c4 100644 --- a/src/micetools/dll/comdevice.h +++ b/src/micetools/dll/comdevice.h @@ -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); \ No newline at end of file diff --git a/src/micetools/dll/common.h b/src/micetools/dll/common.h index d236d23..f775843 100644 --- a/src/micetools/dll/common.h +++ b/src/micetools/dll/common.h @@ -1,24 +1,25 @@ -#pragma once - -#include -#include -#include -#include -#pragma comment(lib, "Shlwapi.lib") -#include -#pragma comment(lib, "d3d9.lib") -#include -#pragma comment(lib, "comctl32.lib") -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../lib/mice/mice.h" -#include "./util/_util.h" +#pragma once + +#include +#include +#include +#include +#pragma comment(lib, "Shlwapi.lib") +#include +#pragma comment(lib, "d3d9.lib") +#include +#pragma comment(lib, "comctl32.lib") +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../lib/mice/mice.h" +#include "./util/_util.h" diff --git a/src/micetools/dll/devices/_devices.c b/src/micetools/dll/devices/_devices.c index fa2c914..b68d40f 100644 --- a/src/micetools/dll/devices/_devices.c +++ b/src/micetools/dll/devices/_devices.c @@ -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(); +} diff --git a/src/micetools/dll/devices/_devices.h b/src/micetools/dll/devices/_devices.h index 8f5a335..5cda9f6 100644 --- a/src/micetools/dll/devices/_devices.h +++ b/src/micetools/dll/devices/_devices.h @@ -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(); \ No newline at end of file diff --git a/src/micetools/dll/devices/aime_bd.c b/src/micetools/dll/devices/aime_bd.c new file mode 100644 index 0000000..b6154e5 --- /dev/null +++ b/src/micetools/dll/devices/aime_bd.c @@ -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); +} diff --git a/src/micetools/dll/devices/led_bd.c b/src/micetools/dll/devices/led_bd.c index ab64a99..5594524 100644 --- a/src/micetools/dll/devices/led_bd.c +++ b/src/micetools/dll/devices/led_bd.c @@ -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); +} diff --git a/src/micetools/dll/devices/meson.build b/src/micetools/dll/devices/meson.build index d5fed29..da3d9a7 100644 --- a/src/micetools/dll/devices/meson.build +++ b/src/micetools/dll/devices/meson.build @@ -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', ) \ No newline at end of file diff --git a/src/micetools/dll/devices/touch_bd.c b/src/micetools/dll/devices/touch_bd.c index acaf57e..b518973 100644 --- a/src/micetools/dll/devices/touch_bd.c +++ b/src/micetools/dll/devices/touch_bd.c @@ -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 - // ( <> <> ) - response[1] = command[0]; - response[2] = command[1]; - thresh = command[3]; - - comdev_write(dev, response, 6); - } else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') { - BYTE sensor = get_touch_id(command[1]); - - // { t h } - log_misc("touch", "th-command recieved: %d", sensor); - - // Sensor == '@': failed - // ( <> ) - response[1] = command[0]; // 'L' or 'R' - response[2] = command[1]; // Sensor - response[4] = thresh; - - comdev_write(dev, response, 6); - } else { - log_error("touch", "Unhandled: {%.*s", 5, command); - } - } -} - -void install_touch_bd() { - com_device_t* touch = new_com_device(3); - com_device_thread(touch, touch_bd_thread); -} +#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 + // ( <> <> ) + response[1] = command[0]; + response[2] = command[1]; + thresh = command[3]; + + comdev_write(dev, response, 6); + } else if (command[2] == 't' && command[3] == 'h' && command[4] == '}') { + BYTE sensor = get_touch_id(command[1]); + + // { t h } + log_misc("touch", "th-command recieved: %d", sensor); + + // Sensor == '@': failed + // ( <> ) + response[1] = command[0]; // 'L' or 'R' + response[2] = command[1]; // Sensor + response[4] = thresh; + + comdev_write(dev, response, 6); + } else { + log_error("touch", "Unhandled: {%.*s", 5, command); + } + } +} + +void install_touch_bd() { + com_device_t* touch = new_com_device(3); + com_device_thread(touch, touch_bd_thread); +} diff --git a/src/micetools/dll/dllmain.c b/src/micetools/dll/dllmain.c index f9f035f..40c61a6 100644 --- a/src/micetools/dll/dllmain.c +++ b/src/micetools/dll/dllmain.c @@ -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; +} diff --git a/src/micetools/dll/drivers/columba.c b/src/micetools/dll/drivers/columba.c index f307276..4d43b33 100644 --- a/src/micetools/dll/drivers/columba.c +++ b/src/micetools/dll/drivers/columba.c @@ -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(, , 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(, , 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); +} diff --git a/src/micetools/dll/drivers/mx.h b/src/micetools/dll/drivers/mx.h index 8c54065..b252b7f 100644 --- a/src/micetools/dll/drivers/mx.h +++ b/src/micetools/dll/drivers/mx.h @@ -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(); diff --git a/src/micetools/dll/drivers/mxjvs.c b/src/micetools/dll/drivers/mxjvs.c index f778095..8e0c5c8 100644 --- a/src/micetools/dll/drivers/mxjvs.c +++ b/src/micetools/dll/drivers/mxjvs.c @@ -1,377 +1,394 @@ -#include - -#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(, , 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 + +#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(, , 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); +} diff --git a/src/micetools/dll/drivers/mxsmbus.c b/src/micetools/dll/drivers/mxsmbus.c index 8e65f07..2bca7cf 100644 --- a/src/micetools/dll/drivers/mxsmbus.c +++ b/src/micetools/dll/drivers/mxsmbus.c @@ -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(, , 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(, , 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(, , 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(, , 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(, , 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(, , 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"); + } +} diff --git a/src/micetools/dll/drivers/mxsram.c b/src/micetools/dll/drivers/mxsram.c index 0d7566f..6cd8fb6 100644 --- a/src/micetools/dll/drivers/mxsram.c +++ b/src/micetools/dll/drivers/mxsram.c @@ -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(, , 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(, , 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(, , 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(, , 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(, , 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(, , 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); +} diff --git a/src/micetools/dll/drivers/mxsuperio.c b/src/micetools/dll/drivers/mxsuperio.c index c1df90b..c80e5c8 100644 --- a/src/micetools/dll/drivers/mxsuperio.c +++ b/src/micetools/dll/drivers/mxsuperio.c @@ -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(, , 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(, , 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(, , 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(, , 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); +} diff --git a/src/micetools/dll/hooks/README.md b/src/micetools/dll/hooks/README.md new file mode 100644 index 0000000..d945df0 --- /dev/null +++ b/src/micetools/dll/hooks/README.md @@ -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 diff --git a/src/micetools/dll/hooks/_hooks.c b/src/micetools/dll/hooks/_hooks.c index 27eaa4d..2ff66c7 100644 --- a/src/micetools/dll/hooks/_hooks.c +++ b/src/micetools/dll/hooks/_hooks.c @@ -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(); +} diff --git a/src/micetools/dll/hooks/_hooks.h b/src/micetools/dll/hooks/_hooks.h index 20f8c8c..7643c6e 100644 --- a/src/micetools/dll/hooks/_hooks.h +++ b/src/micetools/dll/hooks/_hooks.h @@ -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(); diff --git a/src/micetools/dll/hooks/com.c b/src/micetools/dll/hooks/com.c index 284f118..b70f1c1 100644 --- a/src/micetools/dll/hooks/com.c +++ b/src/micetools/dll/hooks/com.c @@ -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); } \ No newline at end of file diff --git a/src/micetools/dll/hooks/com.h b/src/micetools/dll/hooks/com.h index 05be00d..9ced280 100644 --- a/src/micetools/dll/hooks/com.h +++ b/src/micetools/dll/hooks/com.h @@ -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(); diff --git a/src/micetools/dll/hooks/drive.c b/src/micetools/dll/hooks/drive.c new file mode 100644 index 0000000..466a48b --- /dev/null +++ b/src/micetools/dll/hooks/drive.c @@ -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); +} diff --git a/src/micetools/dll/hooks/drive.h b/src/micetools/dll/hooks/drive.h new file mode 100644 index 0000000..d221dd3 --- /dev/null +++ b/src/micetools/dll/hooks/drive.h @@ -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; \ No newline at end of file diff --git a/src/micetools/dll/hooks/files.c b/src/micetools/dll/hooks/files.c index 6046774..5b4933c 100644 --- a/src/micetools/dll/hooks/files.c +++ b/src/micetools/dll/hooks/files.c @@ -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); +} diff --git a/src/micetools/dll/hooks/files.h b/src/micetools/dll/hooks/files.h index 5219c91..38234d7 100644 --- a/src/micetools/dll/hooks/files.h +++ b/src/micetools/dll/hooks/files.h @@ -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); diff --git a/src/micetools/dll/hooks/logging.c b/src/micetools/dll/hooks/logging.c index 318ff89..dc20f66 100644 --- a/src/micetools/dll/hooks/logging.c +++ b/src/micetools/dll/hooks/logging.c @@ -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); +} diff --git a/src/micetools/dll/hooks/logging.h b/src/micetools/dll/hooks/logging.h index 1ec4c3e..11efa66 100644 --- a/src/micetools/dll/hooks/logging.h +++ b/src/micetools/dll/hooks/logging.h @@ -1,16 +1,17 @@ -#pragma once -// #include "../common.h" -#include -#include -#include - -static HANDLE(WINAPI* TrueRegisterEventSourceA)(LPCSTR lpUNCServerName, LPCSTR lpSourceName); -static BOOL(WINAPI* TrueReportEventA)(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, - WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData); -static BOOL(WINAPI* TrueDeregisterEventSource)(HANDLE hEventLog); - -int(WINAPIV* Trueprintf)(const char* _Format, ...); -static int(WINAPIV* Truefprintf)(FILE* _File, const char* _Format, ...); -static int(WINAPIV* Truefprintf_s)(FILE* _Stream, const char* _Format, ...); - -void hook_logging(); +#pragma once +// #include "../common.h" +#include +#include +#include + +static HANDLE(WINAPI* TrueRegisterEventSourceA)(LPCSTR lpUNCServerName, LPCSTR lpSourceName); +static BOOL(WINAPI* TrueReportEventA)(HANDLE hEventLog, WORD wType, WORD wCategory, DWORD dwEventID, PSID lpUserSid, + WORD wNumStrings, DWORD dwDataSize, LPCSTR* lpStrings, LPVOID lpRawData); +static BOOL(WINAPI* TrueDeregisterEventSource)(HANDLE hEventLog); + +int(WINAPIV* Trueprintf)(const char* _Format, ...); +static int(WINAPIV* Truefprintf)(FILE* _File, const char* _Format, ...); +static int(WINAPIV* Truefprintf_s)(FILE* _Stream, const char* _Format, ...); +static int(WINAPIV* Truevfprintf_s)(FILE* _Stream, const char* _Format, va_list _ArgList); + +void hook_logging(); diff --git a/src/micetools/dll/hooks/meson.build b/src/micetools/dll/hooks/meson.build index 5bc949c..9a9b526 100644 --- a/src/micetools/dll/hooks/meson.build +++ b/src/micetools/dll/hooks/meson.build @@ -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', ) \ No newline at end of file diff --git a/src/micetools/dll/hooks/network.c b/src/micetools/dll/hooks/network.c index 0741609..f145bc4 100644 --- a/src/micetools/dll/hooks/network.c +++ b/src/micetools/dll/hooks/network.c @@ -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); +} diff --git a/src/micetools/dll/hooks/processes.c b/src/micetools/dll/hooks/processes.c index 147433b..31700eb 100644 --- a/src/micetools/dll/hooks/processes.c +++ b/src/micetools/dll/hooks/processes.c @@ -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); +} diff --git a/src/micetools/dll/hooks/registry.c b/src/micetools/dll/hooks/registry.c new file mode 100644 index 0000000..75964d7 --- /dev/null +++ b/src/micetools/dll/hooks/registry.c @@ -0,0 +1,5 @@ +#include "registry.h" + +void hook_registry() { + +} diff --git a/src/micetools/dll/hooks/registry.h b/src/micetools/dll/hooks/registry.h new file mode 100644 index 0000000..5f812de --- /dev/null +++ b/src/micetools/dll/hooks/registry.h @@ -0,0 +1,4 @@ +#pragma once +#include "common.h" + +void hook_registry(); diff --git a/src/micetools/dll/meson.build b/src/micetools/dll/meson.build index 1af8cfd..7d5110a 100644 --- a/src/micetools/dll/meson.build +++ b/src/micetools/dll/meson.build @@ -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, + ] +) diff --git a/src/micetools/dll/smbus.h b/src/micetools/dll/smbus.h index a87e25d..7552244 100644 --- a/src/micetools/dll/smbus.h +++ b/src/micetools/dll/smbus.h @@ -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 }; diff --git a/src/micetools/dll/util/log.c b/src/micetools/dll/util/log.c index ccec806..6837315 100644 --- a/src/micetools/dll/util/log.c +++ b/src/micetools/dll/util/log.c @@ -1,144 +1,186 @@ -#include "log.h" - -#include -#include -#include -#include - -#include "../hooks/logging.h" - -extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, - LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); - -BOOL HAS_COLOUR = FALSE; - -char _log_prelude[64]; -char* log_prelude() { - time_t rawtime; - struct tm timeinfo; - - time(&rawtime); - localtime_s(&timeinfo, &rawtime); - - strftime(_log_prelude, sizeof _log_prelude, "[%Y/%m/%d %H:%M:%S] ", &timeinfo); - return _log_prelude; -} - -HANDLE LOG_FILE = NULL; -VOID trace_hook(char* output); -CRITICAL_SECTION logger_lock; - -int _do_log(const char* caller, const char* level, const char* format, va_list args, bool toStdout, char* colour) { - EnterCriticalSection(&logger_lock); - int len = snprintf(NULL, 0, "%s%s:%s:", log_prelude(), level, caller) + vsnprintf(NULL, 0, format, args); - char* buf = (char*)malloc(len + 2); - if (!buf) { - LeaveCriticalSection(&logger_lock); - return 0; - } - - int wrote_a = snprintf(buf, len, "%s%s:%s:", log_prelude(), level, caller); - int wrote_b = vsnprintf(buf + wrote_a, len - wrote_a + 1, format, args); - buf[len] = '\n'; - buf[len + 1] = '\0'; - - // No +1 here to not get the \n - if (toStdout) { - HANDLE sout = GetStdHandle(STD_OUTPUT_HANDLE); - if (HAS_COLOUR) (TrueWriteFile ? TrueWriteFile : WriteFile)(sout, colour, strlen(colour), NULL, NULL); - if (sout != INVALID_HANDLE_VALUE) (TrueWriteFile ? TrueWriteFile : WriteFile)(sout, buf, len, NULL, NULL); - puts(HAS_COLOUR ? "\033[0m" : ""); - } -#ifdef LOG_TO_FILE - if (LOG_FILE && LOG_FILE != INVALID_HANDLE_VALUE) - (TrueWriteFile ? TrueWriteFile : WriteFile)(LOG_FILE, buf, len + 1, NULL, NULL); -#endif - - free(buf); - - LeaveCriticalSection(&logger_lock); - return wrote_b; -} -int vlog_misc(const char* caller, const char* format, va_list args) { - return _do_log(caller, "M", format, args, LOG_MISC, "\033[90m"); -} -int log_misc(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_misc(caller, format, args); - va_end(args); - return ret; -} -int vlog_info(const char* caller, const char* format, va_list args) { - return _do_log(caller, "I", format, args, LOG_INFO, "\033[97m"); -} -int log_info(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_info(caller, format, args); - va_end(args); - return ret; -} -int vlog_warning(const char* caller, const char* format, va_list args) { - return _do_log(caller, "W", format, args, LOG_WARNING, "\033[33m"); -} -int log_warning(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_warning(caller, format, args); - va_end(args); - return ret; -} -int vlog_error(const char* caller, const char* format, va_list args) { - return _do_log(caller, "E", format, args, LOG_ERROR, "\033[91m"); -} -int log_error(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_error(caller, format, args); - va_end(args); - return ret; -} -int vlog_game(const char* caller, const char* format, va_list args) { - return _do_log(caller, "G", format, args, LOG_GAME, "\033[96m"); -} -int log_game(const char* caller, const char* format, ...) { - va_list args; - va_start(args, format); - int ret = vlog_game(caller, format, args); - va_end(args); - return ret; -} - -VOID trace_hook(char* output) { - output[strcspn(output, "\n")] = 0; - log_error("trace", output); -} - -void setup_logging() { - // Force stdio even for GUI applications - AttachConsole(ATTACH_PARENT_PROCESS); - if (GetStdHandle(STD_INPUT_HANDLE)) { - freopen("CONIN$", "r", stdin); - setvbuf(stdin, NULL, _IONBF, 0); - } - if (GetStdHandle(STD_OUTPUT_HANDLE)) { - freopen("CONOUT$", "w", stdout); - setvbuf(stdout, NULL, _IONBF, 0); - } - if (GetStdHandle(STD_ERROR_HANDLE)) { - freopen("CONOUT$", "w", stderr); - setvbuf(stderr, NULL, _IONBF, 0); - } - - // Enable colour in CMD - HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - DWORD dwMode = 0; - if (GetConsoleMode(hConsole, &dwMode)) - HAS_COLOUR = SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING); - - InitializeCriticalSection(&logger_lock); - - if (LOG_FILE == NULL) - LOG_FILE = CreateFileA("log.txt", GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); -} +#include "log.h" + +#include +#include +#include +#include + +#include "../hooks/logging.h" + +extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped); + +BOOL HAS_COLOUR = FALSE; + +char _log_prelude[64]; +char* log_prelude() { + time_t rawtime; + struct tm timeinfo; + + time(&rawtime); + localtime_s(&timeinfo, &rawtime); + + strftime(_log_prelude, sizeof _log_prelude, "[%Y/%m/%d %H:%M:%S] ", &timeinfo); + return _log_prelude; +} + +HANDLE LOG_FILE = NULL; +VOID trace_hook(char* output); +CRITICAL_SECTION logger_lock; + +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 +} diff --git a/src/micetools/dll/util/log.h b/src/micetools/dll/util/log.h index d7af4ed..406a4b6 100644 --- a/src/micetools/dll/util/log.h +++ b/src/micetools/dll/util/log.h @@ -1,32 +1,37 @@ -#pragma once - -#include -#include - -#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 +#include + +#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(); diff --git a/src/micetools/dll/w83627uhg.h b/src/micetools/dll/w83627uhg.h new file mode 100644 index 0000000..b3d55c5 --- /dev/null +++ b/src/micetools/dll/w83627uhg.h @@ -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 \ No newline at end of file diff --git a/src/micetools/launcher/main.c b/src/micetools/launcher/main.c index 406d65f..2557582 100644 --- a/src/micetools/launcher/main.c +++ b/src/micetools/launcher/main.c @@ -1,75 +1,102 @@ -#include -#include - -#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 +#include + +#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; +} diff --git a/src/micetools/lib/am/amEeprom.c b/src/micetools/lib/am/amEeprom.c new file mode 100644 index 0000000..eadd8fe --- /dev/null +++ b/src/micetools/lib/am/amEeprom.c @@ -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; +} diff --git a/src/micetools/lib/am/amEeprom.h b/src/micetools/lib/am/amEeprom.h new file mode 100644 index 0000000..0a8b7dc --- /dev/null +++ b/src/micetools/lib/am/amEeprom.h @@ -0,0 +1,13 @@ +#include + +#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); diff --git a/src/micetools/lib/am/amtimer.c b/src/micetools/lib/am/amtimer.c index d45d248..fee995f 100644 --- a/src/micetools/lib/am/amtimer.c +++ b/src/micetools/lib/am/amtimer.c @@ -1,19 +1,19 @@ -#include - -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 + +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; +} diff --git a/src/micetools/lib/am/meson.build b/src/micetools/lib/am/meson.build index 1ff4ae7..d51cb35 100644 --- a/src/micetools/lib/am/meson.build +++ b/src/micetools/lib/am/meson.build @@ -1,6 +1,10 @@ -amlib = static_library( - 'am', - sources: [ - 'amtimer.c', - ], -) +amlib = static_library( + 'am', + sources: [ + 'amTimer.c', + 'amEeprom.c', + ], + link_with: [ + mice_lib + ], +) diff --git a/src/micetools/lib/dmi/dmi.c b/src/micetools/lib/dmi/dmi.c index d233893..fd0c83b 100644 --- a/src/micetools/lib/dmi/dmi.c +++ b/src/micetools/lib/dmi/dmi.c @@ -1,111 +1,118 @@ -#include "dmi.h" - -#include - -LPBYTE dmi_table = NULL; -WORD dmi_size = 0; -size_t _dmi_max = 0; - -DMI_BIOS deafult_dmi_bios = { - .Head.Type = 0x00, - .Head.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 + +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); } \ No newline at end of file diff --git a/src/micetools/lib/dmi/dmi.h b/src/micetools/lib/dmi/dmi.h index 866e9ef..3f0cda0 100644 --- a/src/micetools/lib/dmi/dmi.h +++ b/src/micetools/lib/dmi/dmi.h @@ -1,58 +1,62 @@ -#include -#include - -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 +#include + +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); diff --git a/src/micetools/lib/json/json.c b/src/micetools/lib/json/json.c index 34d6dea..70834bc 100644 --- a/src/micetools/lib/json/json.c +++ b/src/micetools/lib/json/json.c @@ -1,818 +1,818 @@ -/* vim: set et ts=3 sw=3 sts=3 ft=c: - * - * Copyright (C) 2012-2021 the json-parser authors All rights reserved. - * https://github.com/json-parser/json-parser - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include "json.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "../util/hex.h" - -#define JSON_INT_MAX 9223372036854775807LL - -typedef unsigned int json_uchar; - -const struct _json_value json_value_none; - -static int would_overflow(json_int_t value, json_char b) { return ((JSON_INT_MAX - (b - '0')) / 10) < value; } - -typedef struct { - size_t used_memory; - - json_settings settings; - int first_pass; - - const json_char *ptr; - unsigned int cur_line, cur_col; -} json_state; - -static void *default_alloc(size_t size, int zero) { return zero ? calloc(1, size) : malloc(size); } - -static void *json_alloc(json_state *state, size_t size, int zero) { - if ((ULONG_MAX - 8 - state->used_memory) < size) return 0; - - if (state->settings.max_memory && (state->used_memory += size) > state->settings.max_memory) { - return 0; - } - - return default_alloc(size, zero); -} - -static int new_value(json_state *state, json_value **top, json_value **root, json_value **alloc, json_type type) { - json_value *value; - size_t values_size; - - if (!state->first_pass) { - value = *top = *alloc; - *alloc = (*alloc)->_reserved.next_alloc; - - if (!*root) *root = value; - - switch (value->type) { - case json_array: - if (value->u.array.length == 0) break; - if (!(value->u.array.values = - (json_value **)json_alloc(state, value->u.array.length * sizeof(json_value *), 0))) { - return 0; - } - value->u.array.length = 0; - break; - case json_object: - if (value->u.object.length == 0) break; - - values_size = sizeof(*value->u.object.values) * value->u.object.length; - - if (!(value->u.object.values = (json_object_entry *)json_alloc( - state, values_size + ((uintptr_t)value->u.object.values), 0))) { - return 0; - } - value->_reserved.object_mem = (void *)(((char *)value->u.object.values) + values_size); - value->u.object.length = 0; - break; - case json_string: - if (!(value->u.string.ptr = - (json_char *)json_alloc(state, (value->u.string.length + 1) * sizeof(json_char), 0))) { - return 0; - } - value->u.string.length = 0; - break; - default: - break; - }; - - return 1; - } - - if (!(value = (json_value *)json_alloc(state, sizeof(json_value) + state->settings.value_extra, 1))) { - return 0; - } - - if (!*root) *root = value; - - value->type = type; - value->parent = *top; - -#ifdef JSON_TRACK_SOURCE - value->line = state->cur_line; - value->col = state->cur_col; -#endif - - if (*alloc) (*alloc)->_reserved.next_alloc = value; - - *alloc = *top = value; - - return 1; -} - -#define whitespace \ - case '\n': \ - ++state.cur_line; \ - state.cur_col = 0; /* FALLTHRU */ \ - case ' ': /* FALLTHRU */ \ - case '\t': /* FALLTHRU */ \ - case '\r' - -#define string_add(b) \ - do { \ - if (!state.first_pass) string[string_length] = b; \ - ++string_length; \ - } while (0); - -#define line_and_col state.cur_line, state.cur_col - -static const long flag_next = 1 << 0, flag_reproc = 1 << 1, flag_need_comma = 1 << 2, flag_seek_value = 1 << 3, - flag_escaped = 1 << 4, flag_string = 1 << 5, flag_need_colon = 1 << 6, flag_done = 1 << 7, - flag_num_negative = 1 << 8, flag_num_zero = 1 << 9, flag_num_e = 1 << 10, - flag_num_e_got_sign = 1 << 11, flag_num_e_negative = 1 << 12, flag_line_comment = 1 << 13, - flag_block_comment = 1 << 14, flag_num_got_decimal = 1 << 15; - -json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t length, char *error_buf) { - char error[json_error_max]; - const json_char *end; - json_value *top, *root, *alloc = 0; - json_state state = {0}; - long flags = 0; - int num_digits = 0; - double num_e = 0, num_fraction = 0; - - /* Skip UTF-8 BOM - */ - if (length >= 3 && ((unsigned char)json[0]) == 0xEF && ((unsigned char)json[1]) == 0xBB && - ((unsigned char)json[2]) == 0xBF) { - json += 3; - length -= 3; - } - - error[0] = '\0'; - end = (json + length); - - memcpy(&state.settings, settings, sizeof(json_settings)); - - for (state.first_pass = 1; state.first_pass >= 0; --state.first_pass) { - json_uchar uchar; - unsigned char uc_b1, uc_b2, uc_b3, uc_b4; - json_char *string = 0; - unsigned int string_length = 0; - - top = root = 0; - flags = flag_seek_value; - - state.cur_line = 1; - - for (state.ptr = json;; ++state.ptr) { - json_char b = (state.ptr == end ? 0 : *state.ptr); - - if (flags & flag_string) { - if (!b) { - snprintf(error, json_error_max, "%u:%u: Unexpected EOF in string", line_and_col); - goto e_failed; - } - - if (string_length > UINT_MAX - 8) goto e_overflow; - - if (flags & flag_escaped) { - flags &= ~flag_escaped; - - switch (b) { - case 'b': - string_add('\b'); - break; - case 'f': - string_add('\f'); - break; - case 'n': - string_add('\n'); - break; - case 'r': - string_add('\r'); - break; - case 't': - string_add('\t'); - break; - case 'u': - - if (end - state.ptr <= 4 || (uc_b1 = hex_value(*++state.ptr)) == 0xFF || - (uc_b2 = hex_value(*++state.ptr)) == 0xFF || - (uc_b3 = hex_value(*++state.ptr)) == 0xFF || - (uc_b4 = hex_value(*++state.ptr)) == 0xFF) { - snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, b); - goto e_failed; - } - - uc_b1 = (uc_b1 << 4) | uc_b2; - uc_b2 = (uc_b3 << 4) | uc_b4; - uchar = (uc_b1 << 8) | uc_b2; - - if ((uchar & 0xF800) == 0xD800) { - json_uchar uchar2; - - if (end - state.ptr <= 6 || (*++state.ptr) != '\\' || (*++state.ptr) != 'u' || - (uc_b1 = hex_value(*++state.ptr)) == 0xFF || - (uc_b2 = hex_value(*++state.ptr)) == 0xFF || - (uc_b3 = hex_value(*++state.ptr)) == 0xFF || - (uc_b4 = hex_value(*++state.ptr)) == 0xFF) { - snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, - b); - goto e_failed; - } - - uc_b1 = (uc_b1 << 4) | uc_b2; - uc_b2 = (uc_b3 << 4) | uc_b4; - uchar2 = (uc_b1 << 8) | uc_b2; - - uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); - } - - if (sizeof(json_char) >= sizeof(json_uchar) || (uchar <= 0x7F)) { - string_add((json_char)uchar); - break; - } - - if (uchar <= 0x7FF) { - if (state.first_pass) - string_length += 2; - else { - string[string_length++] = 0xC0 | (uchar >> 6); - string[string_length++] = 0x80 | (uchar & 0x3F); - } - - break; - } - - if (uchar <= 0xFFFF) { - if (state.first_pass) - string_length += 3; - else { - string[string_length++] = 0xE0 | (uchar >> 12); - string[string_length++] = 0x80 | ((uchar >> 6) & 0x3F); - string[string_length++] = 0x80 | (uchar & 0x3F); - } - - break; - } - - if (state.first_pass) - string_length += 4; - else { - string[string_length++] = 0xF0 | (uchar >> 18); - string[string_length++] = 0x80 | ((uchar >> 12) & 0x3F); - string[string_length++] = 0x80 | ((uchar >> 6) & 0x3F); - string[string_length++] = 0x80 | (uchar & 0x3F); - } - - break; - - default: - string_add(b); - }; - - continue; - } - - if (b == '\\') { - flags |= flag_escaped; - continue; - } - - if (b == '"') { - if (!state.first_pass) string[string_length] = 0; - - flags &= ~flag_string; - string = 0; - - switch (top->type) { - case json_string: - top->u.string.length = string_length; - flags |= flag_next; - - break; - - case json_object: - if (state.first_pass) { - json_char **chars = (json_char **)&top->u.object.values; - chars[0] += string_length + 1; - } else { - top->u.object.values[top->u.object.length].name = - (json_char *)top->_reserved.object_mem; - - top->u.object.values[top->u.object.length].name_length = string_length; - - (*(json_char **)&top->_reserved.object_mem) += string_length + 1; - } - - flags |= flag_seek_value | flag_need_colon; - continue; - - default: - break; - }; - } else { - string_add(b); - continue; - } - } - - if (state.settings.settings & json_enable_comments) { - if (flags & (flag_line_comment | flag_block_comment)) { - if (flags & flag_line_comment) { - if (b == '\r' || b == '\n' || !b) { - flags &= ~flag_line_comment; - --state.ptr; /* so null can be reproc'd */ - } - - continue; - } - - if (flags & flag_block_comment) { - if (!b) { - snprintf(error, json_error_max, "%u:%u: Unexpected EOF in block comment", line_and_col); - goto e_failed; - } - - if (b == '*' && state.ptr < (end - 1) && state.ptr[1] == '/') { - flags &= ~flag_block_comment; - ++state.ptr; /* skip closing sequence */ - } - - continue; - } - } else if (b == '/') { - if (!(flags & (flag_seek_value | flag_done)) && top->type != json_object) { - snprintf(error, json_error_max, "%u:%u: Comment not allowed here", line_and_col); - goto e_failed; - } - - if (++state.ptr == end) { - snprintf(error, json_error_max, "%u:%u: EOF unexpected", line_and_col); - goto e_failed; - } - - switch (b = *state.ptr) { - case '/': - flags |= flag_line_comment; - continue; - - case '*': - flags |= flag_block_comment; - continue; - - default: - snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in comment opening sequence", - line_and_col, b); - goto e_failed; - }; - } - } - - if (flags & flag_done) { - if (!b) break; - - switch (b) { - whitespace: - continue; - - default: - snprintf(error, json_error_max, "%u:%u: Trailing garbage: `%c`", line_and_col, b); - goto e_failed; - }; - } - - if (flags & flag_seek_value) { - switch (b) { - whitespace: - continue; - - case ']': - if (top && top->type == json_array) - flags = (flags & ~(flag_need_comma | flag_seek_value)) | flag_next; - else { - snprintf(error, json_error_max, "%u:%u: Unexpected `]`", line_and_col); - goto e_failed; - } - - break; - - default: - if (flags & flag_need_comma) { - if (b == ',') { - flags &= ~flag_need_comma; - continue; - } else { - snprintf(error, json_error_max, "%u:%u: Expected `,` before `%c`", line_and_col, b); - - goto e_failed; - } - } - - if (flags & flag_need_colon) { - if (b == ':') { - flags &= ~flag_need_colon; - continue; - } else { - snprintf(error, json_error_max, "%u:%u: Expected `:` before `%c`", line_and_col, b); - - goto e_failed; - } - } - - flags &= ~flag_seek_value; - - switch (b) { - case '{': - if (!new_value(&state, &top, &root, &alloc, json_object)) goto e_alloc_failure; - - continue; - - case '[': - if (!new_value(&state, &top, &root, &alloc, json_array)) goto e_alloc_failure; - - flags |= flag_seek_value; - continue; - - case '"': - if (!new_value(&state, &top, &root, &alloc, json_string)) goto e_alloc_failure; - - flags |= flag_string; - - string = top->u.string.ptr; - string_length = 0; - - continue; - - case 't': - if ((end - state.ptr) <= 3 || *(++state.ptr) != 'r' || *(++state.ptr) != 'u' || - *(++state.ptr) != 'e') { - goto e_unknown_value; - } - - if (!new_value(&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; - - top->u.boolean = 1; - - flags |= flag_next; - break; - - case 'f': - if ((end - state.ptr) <= 4 || *(++state.ptr) != 'a' || *(++state.ptr) != 'l' || - *(++state.ptr) != 's' || *(++state.ptr) != 'e') { - goto e_unknown_value; - } - - if (!new_value(&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; - - flags |= flag_next; - break; - - case 'n': - if ((end - state.ptr) <= 3 || *(++state.ptr) != 'u' || *(++state.ptr) != 'l' || - *(++state.ptr) != 'l') { - goto e_unknown_value; - } - - if (!new_value(&state, &top, &root, &alloc, json_null)) goto e_alloc_failure; - - flags |= flag_next; - break; - default: - if (isdigit((unsigned char)b) || b == '-') { - if (!new_value(&state, &top, &root, &alloc, json_integer)) goto e_alloc_failure; - - if (!state.first_pass) { - while (isdigit((unsigned char)b) || b == '+' || b == '-' || b == 'e' || - b == 'E' || b == '.') { - if ((++state.ptr) == end) { - b = 0; - break; - } - - b = *state.ptr; - } - - flags |= flag_next | flag_reproc; - break; - } - - flags &= ~(flag_num_negative | flag_num_e | flag_num_e_got_sign | - flag_num_e_negative | flag_num_zero); - - num_digits = 0; - num_fraction = 0; - num_e = 0; - - if (b != '-') { - flags |= flag_reproc; - break; - } - - flags |= flag_num_negative; - continue; - } else { - snprintf(error, json_error_max, "%u:%u: Unexpected `%c` when seeking value", - line_and_col, b); - goto e_failed; - } - }; - }; - } else { - switch (top->type) { - case json_object: - switch (b) { - whitespace: - continue; - case '"': - if (flags & flag_need_comma) { - snprintf(error, json_error_max, "%u:%u: Expected `,` before `\"`", line_and_col); - goto e_failed; - } - - flags |= flag_string; - - string = (json_char *)top->_reserved.object_mem; - string_length = 0; - - break; - - case '}': - flags = (flags & ~flag_need_comma) | flag_next; - break; - - case ',': - if (flags & flag_need_comma) { - flags &= ~flag_need_comma; - break; - } /* FALLTHRU */ - - default: - snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in object", line_and_col, b); - goto e_failed; - }; - break; - - case json_integer: - case json_double: - if (isdigit((unsigned char)b)) { - ++num_digits; - - if (top->type == json_integer || flags & flag_num_e) { - if (!(flags & flag_num_e)) { - if (flags & flag_num_zero) { - snprintf(error, json_error_max, "%u:%u: Unexpected `0` before `%c`", - line_and_col, b); - goto e_failed; - } - - if (num_digits == 1 && b == '0') flags |= flag_num_zero; - } else { - flags |= flag_num_e_got_sign; - num_e = (num_e * 10) + (b - '0'); - continue; - } - - if (would_overflow(top->u.integer, b)) { - json_int_t integer = top->u.integer; - --num_digits; - --state.ptr; - top->type = json_double; - top->u.dbl = (double)integer; - continue; - } - - top->u.integer = (top->u.integer * 10) + (b - '0'); - continue; - } - - if (flags & flag_num_got_decimal) - num_fraction = (num_fraction * 10) + (b - '0'); - else - top->u.dbl = (top->u.dbl * 10) + (b - '0'); - - continue; - } - - if (b == '+' || b == '-') { - if ((flags & flag_num_e) && !(flags & flag_num_e_got_sign)) { - flags |= flag_num_e_got_sign; - - if (b == '-') flags |= flag_num_e_negative; - - continue; - } - } else if (b == '.' && top->type == json_integer) { - json_int_t integer = top->u.integer; - - if (!num_digits) { - snprintf(error, json_error_max, "%u:%u: Expected digit before `.`", line_and_col); - goto e_failed; - } - - top->type = json_double; - top->u.dbl = (double)integer; - - flags |= flag_num_got_decimal; - num_digits = 0; - continue; - } - - if (!(flags & flag_num_e)) { - if (top->type == json_double) { - if (!num_digits) { - snprintf(error, json_error_max, "%u:%u: Expected digit after `.`", line_and_col); - goto e_failed; - } - - top->u.dbl += num_fraction / pow(10.0, num_digits); - } - - if (b == 'e' || b == 'E') { - flags |= flag_num_e; - - if (top->type == json_integer) { - json_int_t integer = top->u.integer; - top->type = json_double; - top->u.dbl = (double)integer; - } - - num_digits = 0; - flags &= ~flag_num_zero; - - continue; - } - } else { - if (!num_digits) { - snprintf(error, json_error_max, "%u:%u: Expected digit after `e`", line_and_col); - goto e_failed; - } - - top->u.dbl *= pow(10.0, (flags & flag_num_e_negative ? -num_e : num_e)); - } - - if (flags & flag_num_negative) { - if (top->type == json_integer) - top->u.integer = -top->u.integer; - else - top->u.dbl = -top->u.dbl; - } - - flags |= flag_next | flag_reproc; - break; - - default: - break; - }; - } - - if (flags & flag_reproc) { - flags &= ~flag_reproc; - --state.ptr; - } - - if (flags & flag_next) { - flags = (flags & ~flag_next) | flag_need_comma; - - if (!top->parent) { - /* root value done */ - - flags |= flag_done; - continue; - } - - if (top->parent->type == json_array) flags |= flag_seek_value; - - if (!state.first_pass) { - json_value *parent = top->parent; - - switch (parent->type) { - case json_object: - parent->u.object.values[parent->u.object.length].value = top; - break; - case json_array: - parent->u.array.values[parent->u.array.length] = top; - break; - default: - break; - }; - } - - if ((++top->parent->u.array.length) > UINT_MAX - 8) goto e_overflow; - top = top->parent; - continue; - } - } - - alloc = root; - } - - return root; - -e_unknown_value: - snprintf(error, json_error_max, "%u:%u: Unknown value", line_and_col); - goto e_failed; - -e_alloc_failure: - snprintf(error, json_error_max, "Memory allocation failure"); - goto e_failed; - -e_overflow: - snprintf(error, json_error_max, "%u:%u: Too long (caught overflow)", line_and_col); - goto e_failed; - -e_failed: - if (error_buf) { - if (*error) - memcpy(error_buf, error, json_error_max); - else - snprintf(error_buf, json_error_max, "Unknown error"); - } - - if (state.first_pass) alloc = root; - - while (alloc) { - top = alloc->_reserved.next_alloc; - free(alloc); - alloc = top; - } - - if (!state.first_pass) json_value_free(root); - - return 0; -} - -json_value *json_parse(const json_char *json, size_t length) { - json_settings settings = {0}; - return json_parse_ex(&settings, json, length, 0); -} - -void json_value_free(json_value *value) { - json_value *cur_value; - - if (!value) return; - - value->parent = 0; - - while (value) { - switch (value->type) { - case json_array: - - if (!value->u.array.length) { - free(value->u.array.values); - break; - } - - value = value->u.array.values[--value->u.array.length]; - continue; - - case json_object: - - if (!value->u.object.length) { - free(value->u.object.values); - break; - } - - value = value->u.object.values[--value->u.object.length].value; - continue; - - case json_string: - - free(value->u.string.ptr); - break; - - default: - break; - }; - - cur_value = value; - value = value->parent; - free(cur_value); - } -} +/* vim: set et ts=3 sw=3 sts=3 ft=c: + * + * Copyright (C) 2012-2021 the json-parser authors All rights reserved. + * https://github.com/json-parser/json-parser + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "json.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "../util/hex.h" + +#define JSON_INT_MAX 9223372036854775807LL + +typedef unsigned int json_uchar; + +const struct _json_value json_value_none = { 0 }; + +static int would_overflow(json_int_t value, json_char b) { return ((JSON_INT_MAX - (b - '0')) / 10) < value; } + +typedef struct { + size_t used_memory; + + json_settings settings; + int first_pass; + + const json_char *ptr; + unsigned int cur_line, cur_col; +} json_state; + +static void *default_alloc(size_t size, int zero) { return zero ? calloc(1, size) : malloc(size); } + +static void *json_alloc(json_state *state, size_t size, int zero) { + if ((ULONG_MAX - 8 - state->used_memory) < size) return 0; + + if (state->settings.max_memory && (state->used_memory += size) > state->settings.max_memory) { + return 0; + } + + return default_alloc(size, zero); +} + +static int new_value(json_state *state, json_value **top, json_value **root, json_value **alloc, json_type type) { + json_value *value; + size_t values_size; + + if (!state->first_pass) { + value = *top = *alloc; + *alloc = (*alloc)->_reserved.next_alloc; + + if (!*root) *root = value; + + switch (value->type) { + case json_array: + if (value->u.array.length == 0) break; + if (!(value->u.array.values = + (json_value **)json_alloc(state, value->u.array.length * sizeof(json_value *), 0))) { + return 0; + } + value->u.array.length = 0; + break; + case json_object: + if (value->u.object.length == 0) break; + + values_size = sizeof(*value->u.object.values) * value->u.object.length; + + if (!(value->u.object.values = (json_object_entry *)json_alloc( + state, values_size + ((uintptr_t)value->u.object.values), 0))) { + return 0; + } + value->_reserved.object_mem = (void *)(((char *)value->u.object.values) + values_size); + value->u.object.length = 0; + break; + case json_string: + if (!(value->u.string.ptr = + (json_char *)json_alloc(state, (value->u.string.length + 1) * sizeof(json_char), 0))) { + return 0; + } + value->u.string.length = 0; + break; + default: + break; + }; + + return 1; + } + + if (!(value = (json_value *)json_alloc(state, sizeof(json_value) + state->settings.value_extra, 1))) { + return 0; + } + + if (!*root) *root = value; + + value->type = type; + value->parent = *top; + +#ifdef JSON_TRACK_SOURCE + value->line = state->cur_line; + value->col = state->cur_col; +#endif + + if (*alloc) (*alloc)->_reserved.next_alloc = value; + + *alloc = *top = value; + + return 1; +} + +#define whitespace \ + case '\n': \ + ++state.cur_line; \ + state.cur_col = 0; /* FALLTHRU */ \ + case ' ': /* FALLTHRU */ \ + case '\t': /* FALLTHRU */ \ + case '\r' + +#define string_add(b) \ + do { \ + if (!state.first_pass) string[string_length] = b; \ + ++string_length; \ + } while (0); + +#define line_and_col state.cur_line, state.cur_col + +static const long flag_next = 1 << 0, flag_reproc = 1 << 1, flag_need_comma = 1 << 2, flag_seek_value = 1 << 3, + flag_escaped = 1 << 4, flag_string = 1 << 5, flag_need_colon = 1 << 6, flag_done = 1 << 7, + flag_num_negative = 1 << 8, flag_num_zero = 1 << 9, flag_num_e = 1 << 10, + flag_num_e_got_sign = 1 << 11, flag_num_e_negative = 1 << 12, flag_line_comment = 1 << 13, + flag_block_comment = 1 << 14, flag_num_got_decimal = 1 << 15; + +json_value *json_parse_ex(json_settings *settings, const json_char *json, size_t length, char *error_buf) { + char error[json_error_max]; + const json_char *end; + json_value *top, *root, *alloc = 0; + json_state state = {0}; + long flags = 0; + int num_digits = 0; + double num_e = 0, num_fraction = 0; + + /* Skip UTF-8 BOM + */ + if (length >= 3 && ((unsigned char)json[0]) == 0xEF && ((unsigned char)json[1]) == 0xBB && + ((unsigned char)json[2]) == 0xBF) { + json += 3; + length -= 3; + } + + error[0] = '\0'; + end = (json + length); + + memcpy(&state.settings, settings, sizeof(json_settings)); + + for (state.first_pass = 1; state.first_pass >= 0; --state.first_pass) { + json_uchar uchar; + unsigned char uc_b1, uc_b2, uc_b3, uc_b4; + json_char *string = 0; + unsigned int string_length = 0; + + top = root = 0; + flags = flag_seek_value; + + state.cur_line = 1; + + for (state.ptr = json;; ++state.ptr) { + json_char b = (state.ptr == end ? 0 : *state.ptr); + + if (flags & flag_string) { + if (!b) { + snprintf(error, json_error_max, "%u:%u: Unexpected EOF in string", line_and_col); + goto e_failed; + } + + if (string_length > UINT_MAX - 8) goto e_overflow; + + if (flags & flag_escaped) { + flags &= ~flag_escaped; + + switch (b) { + case 'b': + string_add('\b'); + break; + case 'f': + string_add('\f'); + break; + case 'n': + string_add('\n'); + break; + case 'r': + string_add('\r'); + break; + case 't': + string_add('\t'); + break; + case 'u': + + if (end - state.ptr <= 4 || (uc_b1 = hex_value(*++state.ptr)) == 0xFF || + (uc_b2 = hex_value(*++state.ptr)) == 0xFF || + (uc_b3 = hex_value(*++state.ptr)) == 0xFF || + (uc_b4 = hex_value(*++state.ptr)) == 0xFF) { + snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, b); + goto e_failed; + } + + uc_b1 = (uc_b1 << 4) | uc_b2; + uc_b2 = (uc_b3 << 4) | uc_b4; + uchar = (uc_b1 << 8) | uc_b2; + + if ((uchar & 0xF800) == 0xD800) { + json_uchar uchar2; + + if (end - state.ptr <= 6 || (*++state.ptr) != '\\' || (*++state.ptr) != 'u' || + (uc_b1 = hex_value(*++state.ptr)) == 0xFF || + (uc_b2 = hex_value(*++state.ptr)) == 0xFF || + (uc_b3 = hex_value(*++state.ptr)) == 0xFF || + (uc_b4 = hex_value(*++state.ptr)) == 0xFF) { + snprintf(error, json_error_max, "%u:%u: Invalid character value `%c`", line_and_col, + b); + goto e_failed; + } + + uc_b1 = (uc_b1 << 4) | uc_b2; + uc_b2 = (uc_b3 << 4) | uc_b4; + uchar2 = (uc_b1 << 8) | uc_b2; + + uchar = 0x010000 | ((uchar & 0x3FF) << 10) | (uchar2 & 0x3FF); + } + + if (sizeof(json_char) >= sizeof(json_uchar) || (uchar <= 0x7F)) { + string_add((json_char)uchar); + break; + } + + if (uchar <= 0x7FF) { + if (state.first_pass) + string_length += 2; + else { + string[string_length++] = (char)(0xC0 | (uchar >> 6)); + string[string_length++] = (char)(0x80 | (uchar & 0x3F)); + } + + break; + } + + if (uchar <= 0xFFFF) { + if (state.first_pass) + string_length += 3; + else { + string[string_length++] = 0xE0 | (char)((uchar >> 12)); + string[string_length++] = 0x80 | (char)(((uchar >> 6) & 0x3F)); + string[string_length++] = 0x80 | (char)((uchar & 0x3F)); + } + + break; + } + + if (state.first_pass) + string_length += 4; + else { + string[string_length++] = 0xF0 | (char)((uchar >> 18)); + string[string_length++] = 0x80 | (char)(((uchar >> 12) & 0x3F)); + string[string_length++] = 0x80 | (char)(((uchar >> 6) & 0x3F)); + string[string_length++] = 0x80 | (char)((uchar & 0x3F)); + } + + break; + + default: + string_add(b); + }; + + continue; + } + + if (b == '\\') { + flags |= flag_escaped; + continue; + } + + if (b == '"') { + if (!state.first_pass) string[string_length] = 0; + + flags &= ~flag_string; + string = 0; + + switch (top->type) { + case json_string: + top->u.string.length = string_length; + flags |= flag_next; + + break; + + case json_object: + if (state.first_pass) { + json_char **chars = (json_char **)&top->u.object.values; + chars[0] += string_length + 1; + } else { + top->u.object.values[top->u.object.length].name = + (json_char *)top->_reserved.object_mem; + + top->u.object.values[top->u.object.length].name_length = string_length; + + (*(json_char **)&top->_reserved.object_mem) += string_length + 1; + } + + flags |= flag_seek_value | flag_need_colon; + continue; + + default: + break; + }; + } else { + string_add(b); + continue; + } + } + + if (state.settings.settings & json_enable_comments) { + if (flags & (flag_line_comment | flag_block_comment)) { + if (flags & flag_line_comment) { + if (b == '\r' || b == '\n' || !b) { + flags &= ~flag_line_comment; + --state.ptr; /* so null can be reproc'd */ + } + + continue; + } + + if (flags & flag_block_comment) { + if (!b) { + snprintf(error, json_error_max, "%u:%u: Unexpected EOF in block comment", line_and_col); + goto e_failed; + } + + if (b == '*' && state.ptr < (end - 1) && state.ptr[1] == '/') { + flags &= ~flag_block_comment; + ++state.ptr; /* skip closing sequence */ + } + + continue; + } + } else if (b == '/') { + if (!(flags & (flag_seek_value | flag_done)) && top->type != json_object) { + snprintf(error, json_error_max, "%u:%u: Comment not allowed here", line_and_col); + goto e_failed; + } + + if (++state.ptr == end) { + snprintf(error, json_error_max, "%u:%u: EOF unexpected", line_and_col); + goto e_failed; + } + + switch (b = *state.ptr) { + case '/': + flags |= flag_line_comment; + continue; + + case '*': + flags |= flag_block_comment; + continue; + + default: + snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in comment opening sequence", + line_and_col, b); + goto e_failed; + }; + } + } + + if (flags & flag_done) { + if (!b) break; + + switch (b) { + whitespace: + continue; + + default: + snprintf(error, json_error_max, "%u:%u: Trailing garbage: `%c`", line_and_col, b); + goto e_failed; + }; + } + + if (flags & flag_seek_value) { + switch (b) { + whitespace: + continue; + + case ']': + if (top && top->type == json_array) + flags = (flags & ~(flag_need_comma | flag_seek_value)) | flag_next; + else { + snprintf(error, json_error_max, "%u:%u: Unexpected `]`", line_and_col); + goto e_failed; + } + + break; + + default: + if (flags & flag_need_comma) { + if (b == ',') { + flags &= ~flag_need_comma; + continue; + } else { + snprintf(error, json_error_max, "%u:%u: Expected `,` before `%c`", line_and_col, b); + + goto e_failed; + } + } + + if (flags & flag_need_colon) { + if (b == ':') { + flags &= ~flag_need_colon; + continue; + } else { + snprintf(error, json_error_max, "%u:%u: Expected `:` before `%c`", line_and_col, b); + + goto e_failed; + } + } + + flags &= ~flag_seek_value; + + switch (b) { + case '{': + if (!new_value(&state, &top, &root, &alloc, json_object)) goto e_alloc_failure; + + continue; + + case '[': + if (!new_value(&state, &top, &root, &alloc, json_array)) goto e_alloc_failure; + + flags |= flag_seek_value; + continue; + + case '"': + if (!new_value(&state, &top, &root, &alloc, json_string)) goto e_alloc_failure; + + flags |= flag_string; + + string = top->u.string.ptr; + string_length = 0; + + continue; + + case 't': + if ((end - state.ptr) <= 3 || *(++state.ptr) != 'r' || *(++state.ptr) != 'u' || + *(++state.ptr) != 'e') { + goto e_unknown_value; + } + + if (!new_value(&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; + + top->u.boolean = 1; + + flags |= flag_next; + break; + + case 'f': + if ((end - state.ptr) <= 4 || *(++state.ptr) != 'a' || *(++state.ptr) != 'l' || + *(++state.ptr) != 's' || *(++state.ptr) != 'e') { + goto e_unknown_value; + } + + if (!new_value(&state, &top, &root, &alloc, json_boolean)) goto e_alloc_failure; + + flags |= flag_next; + break; + + case 'n': + if ((end - state.ptr) <= 3 || *(++state.ptr) != 'u' || *(++state.ptr) != 'l' || + *(++state.ptr) != 'l') { + goto e_unknown_value; + } + + if (!new_value(&state, &top, &root, &alloc, json_null)) goto e_alloc_failure; + + flags |= flag_next; + break; + default: + if (isdigit((unsigned char)b) || b == '-') { + if (!new_value(&state, &top, &root, &alloc, json_integer)) goto e_alloc_failure; + + if (!state.first_pass) { + while (isdigit((unsigned char)b) || b == '+' || b == '-' || b == 'e' || + b == 'E' || b == '.') { + if ((++state.ptr) == end) { + b = 0; + break; + } + + b = *state.ptr; + } + + flags |= flag_next | flag_reproc; + break; + } + + flags &= ~(flag_num_negative | flag_num_e | flag_num_e_got_sign | + flag_num_e_negative | flag_num_zero); + + num_digits = 0; + num_fraction = 0; + num_e = 0; + + if (b != '-') { + flags |= flag_reproc; + break; + } + + flags |= flag_num_negative; + continue; + } else { + snprintf(error, json_error_max, "%u:%u: Unexpected `%c` when seeking value", + line_and_col, b); + goto e_failed; + } + }; + }; + } else { + switch (top->type) { + case json_object: + switch (b) { + whitespace: + continue; + case '"': + if (flags & flag_need_comma) { + snprintf(error, json_error_max, "%u:%u: Expected `,` before `\"`", line_and_col); + goto e_failed; + } + + flags |= flag_string; + + string = (json_char *)top->_reserved.object_mem; + string_length = 0; + + break; + + case '}': + flags = (flags & ~flag_need_comma) | flag_next; + break; + + case ',': + if (flags & flag_need_comma) { + flags &= ~flag_need_comma; + break; + } /* FALLTHRU */ + + default: + snprintf(error, json_error_max, "%u:%u: Unexpected `%c` in object", line_and_col, b); + goto e_failed; + }; + break; + + case json_integer: + case json_double: + if (isdigit((unsigned char)b)) { + ++num_digits; + + if (top->type == json_integer || flags & flag_num_e) { + if (!(flags & flag_num_e)) { + if (flags & flag_num_zero) { + snprintf(error, json_error_max, "%u:%u: Unexpected `0` before `%c`", + line_and_col, b); + goto e_failed; + } + + if (num_digits == 1 && b == '0') flags |= flag_num_zero; + } else { + flags |= flag_num_e_got_sign; + num_e = (num_e * 10) + (b - '0'); + continue; + } + + if (would_overflow(top->u.integer, b)) { + json_int_t integer = top->u.integer; + --num_digits; + --state.ptr; + top->type = json_double; + top->u.dbl = (double)integer; + continue; + } + + top->u.integer = (top->u.integer * 10) + (b - '0'); + continue; + } + + if (flags & flag_num_got_decimal) + num_fraction = (num_fraction * 10) + (b - '0'); + else + top->u.dbl = (top->u.dbl * 10) + (b - '0'); + + continue; + } + + if (b == '+' || b == '-') { + if ((flags & flag_num_e) && !(flags & flag_num_e_got_sign)) { + flags |= flag_num_e_got_sign; + + if (b == '-') flags |= flag_num_e_negative; + + continue; + } + } else if (b == '.' && top->type == json_integer) { + json_int_t integer = top->u.integer; + + if (!num_digits) { + snprintf(error, json_error_max, "%u:%u: Expected digit before `.`", line_and_col); + goto e_failed; + } + + top->type = json_double; + top->u.dbl = (double)integer; + + flags |= flag_num_got_decimal; + num_digits = 0; + continue; + } + + if (!(flags & flag_num_e)) { + if (top->type == json_double) { + if (!num_digits) { + snprintf(error, json_error_max, "%u:%u: Expected digit after `.`", line_and_col); + goto e_failed; + } + + top->u.dbl += num_fraction / pow(10.0, num_digits); + } + + if (b == 'e' || b == 'E') { + flags |= flag_num_e; + + if (top->type == json_integer) { + json_int_t integer = top->u.integer; + top->type = json_double; + top->u.dbl = (double)integer; + } + + num_digits = 0; + flags &= ~flag_num_zero; + + continue; + } + } else { + if (!num_digits) { + snprintf(error, json_error_max, "%u:%u: Expected digit after `e`", line_and_col); + goto e_failed; + } + + top->u.dbl *= pow(10.0, (flags & flag_num_e_negative ? -num_e : num_e)); + } + + if (flags & flag_num_negative) { + if (top->type == json_integer) + top->u.integer = -top->u.integer; + else + top->u.dbl = -top->u.dbl; + } + + flags |= flag_next | flag_reproc; + break; + + default: + break; + }; + } + + if (flags & flag_reproc) { + flags &= ~flag_reproc; + --state.ptr; + } + + if (flags & flag_next) { + flags = (flags & ~flag_next) | flag_need_comma; + + if (!top->parent) { + /* root value done */ + + flags |= flag_done; + continue; + } + + if (top->parent->type == json_array) flags |= flag_seek_value; + + if (!state.first_pass) { + json_value *parent = top->parent; + + switch (parent->type) { + case json_object: + parent->u.object.values[parent->u.object.length].value = top; + break; + case json_array: + parent->u.array.values[parent->u.array.length] = top; + break; + default: + break; + }; + } + + if ((++top->parent->u.array.length) > UINT_MAX - 8) goto e_overflow; + top = top->parent; + continue; + } + } + + alloc = root; + } + + return root; + +e_unknown_value: + snprintf(error, json_error_max, "%u:%u: Unknown value", line_and_col); + goto e_failed; + +e_alloc_failure: + snprintf(error, json_error_max, "Memory allocation failure"); + goto e_failed; + +e_overflow: + snprintf(error, json_error_max, "%u:%u: Too long (caught overflow)", line_and_col); + goto e_failed; + +e_failed: + if (error_buf) { + if (*error) + memcpy(error_buf, error, json_error_max); + else + snprintf(error_buf, json_error_max, "Unknown error"); + } + + if (state.first_pass) alloc = root; + + while (alloc) { + top = alloc->_reserved.next_alloc; + free(alloc); + alloc = top; + } + + if (!state.first_pass) json_value_free(root); + + return 0; +} + +json_value *json_parse(const json_char *json, size_t length) { + json_settings settings = {0}; + return json_parse_ex(&settings, json, length, 0); +} + +void json_value_free(json_value *value) { + json_value *cur_value; + + if (!value) return; + + value->parent = 0; + + while (value) { + switch (value->type) { + case json_array: + + if (!value->u.array.length) { + free(value->u.array.values); + break; + } + + value = value->u.array.values[--value->u.array.length]; + continue; + + case json_object: + + if (!value->u.object.length) { + free(value->u.object.values); + break; + } + + value = value->u.object.values[--value->u.object.length].value; + continue; + + case json_string: + + free(value->u.string.ptr); + break; + + default: + break; + }; + + cur_value = value; + value = value->parent; + free(cur_value); + } +} diff --git a/src/micetools/lib/libpcp/libpcp.c b/src/micetools/lib/libpcp/libpcp.c new file mode 100644 index 0000000..41b3baa --- /dev/null +++ b/src/micetools/lib/libpcp/libpcp.c @@ -0,0 +1 @@ +#include "libpcp.h" diff --git a/src/micetools/lib/libpcp/meson.build b/src/micetools/lib/libpcp/meson.build index 8eaf761..5cd61d7 100644 --- a/src/micetools/lib/libpcp/meson.build +++ b/src/micetools/lib/libpcp/meson.build @@ -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, + ], +) diff --git a/src/micetools/lib/libpcp/pcp.c b/src/micetools/lib/libpcp/pcp.c new file mode 100644 index 0000000..73c7138 --- /dev/null +++ b/src/micetools/lib/libpcp/pcp.c @@ -0,0 +1,3 @@ +#include "pcp.h" + +char* LIBPCP_VERSION = "\nlibpcp Ver.1.08 Build:Aug 12 2012 00:13:32 (micetools bootleg)\n"; diff --git a/src/micetools/lib/libpcp/pcp.h b/src/micetools/lib/libpcp/pcp.h index 2e5c75a..427af75 100644 --- a/src/micetools/lib/libpcp/pcp.h +++ b/src/micetools/lib/libpcp/pcp.h @@ -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 -#include -#include -#include - -#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 +#include +#include +#include +#include + +#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 diff --git a/src/micetools/lib/libpcp/pcpa.c b/src/micetools/lib/libpcp/pcpa.c new file mode 100644 index 0000000..083f59a --- /dev/null +++ b/src/micetools/lib/libpcp/pcpa.c @@ -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); +} diff --git a/src/micetools/lib/libpcp/pcpa.h b/src/micetools/lib/libpcp/pcpa.h index 19d14fb..0f93891 100644 --- a/src/micetools/lib/libpcp/pcpa.h +++ b/src/micetools/lib/libpcp/pcpa.h @@ -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); diff --git a/src/micetools/lib/libpcp/pcpp.c b/src/micetools/lib/libpcp/pcpp.c new file mode 100644 index 0000000..fb6d418 --- /dev/null +++ b/src/micetools/lib/libpcp/pcpp.c @@ -0,0 +1,1758 @@ +#include "pcpp.h" + +int FUN_00459d00(amtime_t* t1, amtime_t* t2) { + if (t1 == NULL || t2 == NULL) return -1; + return ((t2->seconds - t1->seconds) * 1000000 - t1->microseconds) + t2->microseconds; // Swapped +} + +// TODO: Invert these conditions to be clearer +int pcpp_isValidChar(char chr) { + if (!isalnum(chr) && chr != '.' && chr != '_' && chr != '-' && chr != ':' && chr != '@' && chr != '%' && + chr != '/' && chr != '\\' && chr != '#' && chr != '{' && chr != '}') { + return 0; + } + return 1; +} + +e_pcpp_t _pcppGetErrorFromPcpt(int err) { + switch (err) { + case e_pcpt_ok: + return e_pcpp_ok; + case e_pcpt_to: + return e_pcpp_to; + case e_pcpt_closed: + return e_pcpp_closed; + case e_pcpt_no_client: + return e_pcpp_no_client; + case e_pcpt_wsa_noinit: + return e_pcpp_wsa_noinit; + case e_pcpt_recv_unset: + return e_pcpp_recv_unset; + case e_pcpt_NO_IDEA_WHAT_THIS_IS: + return (e_pcpp_t)-7; + case e_pcpt_inval_addr: + return e_pcpp_inval_addr; + case -11: + case e_pcpt_wsa2_generic: + case e_pcpt_nobufs: + case e_pcpt_cannot_open: + return e_pcpp_cannot_open; + case -7: + case e_pcpt_pointer_unset: + case e_pcpt_already_connected: + return e_pcpp_param_invalid; + case -6: + case e_pcpt_not_open: + return e_pcpp_not_open; + case -5: + case e_pcpt_already_open: + return e_pcpp_already_open; + default: + return e_pcpp_unknown; + } +} + +bool pcppCheckPrompt(pcpp_t* stream) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return false; + } + + uint max = stream->read_bytes_num; + bool found = false; + + for (uint cursor = 0; cursor < max; cursor++) { + unsigned char* pos = stream->read_bytes_buf + cursor; + if (stream->read_bytes_buf[cursor] == '>') { + if (cursor < stream->read_bytes_num) { + do { + *pos = pos[1]; + pos++; + } while (pos + (-204 - (int)stream) < (unsigned char*)stream->read_bytes_num); + } + + stream->read_bytes_num--; + stream->read_bytes_size++; + found = true; + } + } + + return found; +} + +e_pcpt_t pcppCheckRecvMsg(unsigned char* recv_data, size_t buf_len, int param_3) { + bool bVar1 = true; + int local_8 = 0; + + if (recv_data == NULL) { + PCP_LOG("pointer error\n"); + return e_pcpp_param_invalid; + } + + while (1) { + local_8 = buf_len - local_8; + uint recv_err = pcppRecvCheck(recv_data, &local_8); + + if (recv_err == 1) return e_pcpp_param_invalid; + if (recv_err == 8) { + if (!bVar1) return e_pcpp_param_invalid; + if (param_3 != 0) return e_pcpp_param_invalid; + } else { + if (recv_err == 7 && !bVar1) return e_pcpp_param_invalid; + } + + recv_data += local_8; + local_8++; + bVar1 = false; + + if (recv_err == 0 || recv_err == 6 || recv_err == 7 || recv_err == 8) { + return e_pcpp_ok; + } + } +} + +uint pcppCheckStr(unsigned char* recv_data, uint* found_at, int* find_failed) { + bool end = false; + bool bVar2 = false; + uint idx = 0; + + if (recv_data == NULL || find_failed == NULL || found_at == NULL) { + PCP_LOG("pointer error\n"); + return 0; + } + + *find_failed = 0; + if (*found_at == 0) return 0; + + do { + char chr = recv_data[idx]; + if (PCP_WHITESPACE(chr)) { + if (bVar2) end = true; + } else { + if (!pcpp_isValidChar(chr)) { + if (recv_data[idx] != PCP_CHAR_UNKNOWN) { + *found_at = idx + 1; + switch (recv_data[idx]) { + case PCP_CHAR_SEP: + return 5; + case PCP_CHAR_CR: + if (recv_data[idx + 1] != '\n') return 3; + *found_at = idx + 2; + return 4; + case PCP_CHAR_LF: + return 2; + case PCP_CHAR_EQU: + return 1; + default: + return 0; + } + } + if (bVar2 || end) { + *found_at = idx + 1; + return 0; + } + + *find_failed = 1; + } else { + if (end || *find_failed != 0) { + *found_at = idx + 1; + return 0; + } + bVar2 = true; + } + } + + idx++; + if (*found_at <= idx) return 0; + } while (true); +} + +void pcppClose(pcpp_t* stream) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return; + } + + pcptClose(&stream->sock); + pcptClose(&stream->data_sock); + + stream->field_0xb8 = 0; + stream->last_active = 0; + stream->state = 0; + stream->err = e_pcpp_unknown; + stream->recv_data_buffer = NULL; + memset(stream->read_bytes_buf, 0, sizeof stream->read_bytes_buf); + stream->read_bytes_size = sizeof stream->read_bytes_buf; + stream->read_bytes_num = 0; + stream->resp_buffer = NULL; + stream->resp_buffer_len = 0; + ZERO(stream->send_buf); + stream->send_buf_len = PCP_SEND_BUF_MAX; + stream->field_0x1e8 = 0; + stream->send_binary_buf = NULL; + stream->field_0x1f0 = 0; + stream->recv_binary_buf = NULL; + stream->field_0x1f8 = 0; + stream->recv_binary_buf_len = 0; + stream->field_0x1fc = 0; + stream->open = 0; + stream->field_0x214 = 0; +} + +void pcppCloseBinary(pcpp_t* stream) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return; + } + + pcptCloseDataSock(&stream->data_sock); + stream->read_bytes_size = sizeof stream->read_bytes_buf; + stream->read_bytes_num = 0; + memset(stream->read_bytes_buf, 0, sizeof stream->read_bytes_buf); + stream->resp_buffer = NULL; + stream->resp_buffer_len = 0; + + amtime_t time; + amiTimerGet(&time); + stream->last_active = _amTimeMs(time); + stream->state = 0; +} + +e_pcpp_t pcppGetBlockingTime(uint param_1, timeout_t timeout, pcpp_t* stream, int param_4, uint* blocking_time) { + byte bVar1; + uint uVar2; + uint uVar3; + amtime_t local_8; + + if (stream == NULL || blocking_time == NULL) { + PCP_LOG("pointer error\n"); + return 0; + } + + amiTimerGet(&local_8); + uVar2 = (local_8.seconds * 1000 - stream->last_active) + local_8.microseconds / 1000; // swapped + if (param_1 <= uVar2) { + *blocking_time = 0; + return 1; + } + if ((timeout == TIMEOUT_NONE) || (param_1 - uVar2 < (uint)timeout)) { + bVar1 = 1; + uVar2 = param_1 - uVar2; + } else { + bVar1 = 0; + uVar2 = timeout; + } + uVar3 = (local_8.seconds * 1000 - param_4) + local_8.microseconds / 1000; // Swapped + if (timeout != TIMEOUT_NONE) { + if ((uint)timeout <= uVar3) { + *blocking_time = 0; + return 0; + } + uVar3 = timeout - uVar3; + if (uVar3 < uVar2) { + *blocking_time = uVar3; + return 0; + } + } + *blocking_time = uVar2; + return (uint)bVar1; +} + +char* pcppGetCommand(pcp_parse_data_t* recv_data, char* command) { + if (recv_data == NULL || command == NULL) { + PCP_LOG("error Recv Data isn\'t set\n"); + return NULL; + } + + for (uint cmd = 0; cmd < recv_data->cmd_count; cmd++) { + if (!strcmp(recv_data->strings + recv_data->keywords[cmd], command)) { + if (recv_data->values[cmd] == 0) return NULL; + return recv_data->strings + recv_data->values[cmd]; + } + } + return NULL; +} + +char* pcppGetKeyword(pcp_parse_data_t* recvData, uint keywordNum) { + if (recvData == NULL) { + PCP_LOG("error Recv Data isn\'t set\n"); + return NULL; + } + + if ((keywordNum >= PCP_CMDS_MAX) && (keywordNum > recvData->cmd_count)) { + PCP_LOG("error keywordNum over\n"); + return NULL; + } + return recvData->strings + recvData->keywords[keywordNum]; +} + +SOCKET pcppGetServerSocket(pcpp_t* stream, int which) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return SOCKET_INVAL; + } + + switch (which) { + case 0: + return (stream->sock).server_sock; + case 1: + return (stream->data_sock).server_sock; + default: + return SOCKET_INVAL; + } +} + +e_pcpp_t pcppInitStream(pcpp_t* stream) { + if (stream == NULL) { + PCP_LOG("error don\'t set stream\n"); + return e_pcpp_param_invalid; + } + + e_pcpt_t err = pcptInitStream(&stream->sock); + if (err != e_pcpt_ok) return _errT2P(err); + + err = pcptInitStream(&stream->data_sock); + if (err != e_pcpt_ok) return _errT2P(err); + + pcptSetConfig(&stream->data_sock, PCPT_TCP_NODELAY, 1); + + stream->field_0xb8 = 0; + stream->last_active = 0; + stream->state = 0; + stream->err = e_pcpp_unknown; + stream->recv_data_buffer = NULL; + ZERO(stream->read_bytes_buf); + // memset(stream->read_bytes_buf, 0, sizeof stream->read_bytes_buf); + stream->read_bytes_size = sizeof stream->read_bytes_buf; + stream->read_bytes_num = 0; + stream->resp_buffer = NULL; + stream->resp_buffer_len = 0; + ZERO(stream->send_buf); + stream->field_0x1e8 = 0; + stream->send_binary_buf = NULL; + stream->field_0x1f0 = 0; + stream->recv_binary_buf = NULL; + stream->field_0x1f8 = 0; + stream->recv_binary_buf_len = 0; + stream->field_0x1fc = 0; + stream->open = 0; + stream->field_0x214 = 0; + stream->field_0x20c = 10000; + stream->field_0x208 = 10000; + stream->send_buf_len = PCP_SEND_BUF_MAX; + stream->field_0x204 = 1000; + stream->field_0x210 = 60000; + return e_pcpp_ok; +} + +e_pcpp_t pcppOpenBinaryServer(pcpp_t* stream, int open_mode, ushort port) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + + amtime_t time; + amiTimerGet(&time); + stream->last_active = _amTimeMs(time); + stream->state = 0; + if (open_mode != 0 && open_mode != 1) { + PCP_LOG("error Open Mode isn\'t set\n"); + stream->state = 0; + return stream->err = e_pcpp_param_invalid; + } + + e_pcpp_t err = _errT2P(pcptOpenServer(&stream->data_sock, open_mode, port)); + stream->err = err; + if (err != e_pcpp_ok) { + PCP_LOG("error pcptOpenBinaryServer\n"); + return err; + } + + amiTimerGet(&time); + stream->last_active = _amTimeMs(time); + return e_pcpp_ok; +} + +e_pcpp_t pcppOpenServer(pcpp_t* stream, int open_mode, u_short port, undefined4 param_4) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + stream->field_0xb8 = param_4; + if (open_mode != 0 && open_mode != 1) { + PCP_LOG("error Open Mode isn\'t set\n"); + + stream->err = e_pcpp_param_invalid; + stream->state = 0; + return e_pcpp_param_invalid; + } + + e_pcpp_t err = _errT2P(pcptOpenServer(&stream->sock, open_mode, port)); + stream->err = err; + if (err != e_pcpp_ok) { + PCP_LOG("error pcppOpenServer error = %d\n", err); + return err; + } + stream->open = 1; + + amtime_t time; + amiTimerGet(&time); + stream->last_active = _amTimeMs(time); + return e_pcpp_ok; +} + +pcp_send_data_t* pcppSetSendPacket(pcp_send_data_t* send_data, char* keyword, char* value) { + if (send_data == NULL || keyword == NULL) { + PCP_LOG("error Send Data isn\'t set\n"); + return NULL; + } + + memset(send_data->data, 0, sizeof *send_data->data); + send_data->length = 0; + size_t kwLen = strlen(keyword); + + if (value == NULL) { + if (kwLen + 2 < PCP_BUF_MAX) { + sprintf_s((char*)send_data->data, PCP_BUF_MAX, "%s\r\n", keyword); + send_data->length = kwLen & 0xff; + return send_data; + } + } else { + size_t valLen = strlen(value); + if (kwLen + 3 + valLen < PCP_BUF_MAX) { + sprintf_s((char*)send_data->data, PCP_BUF_MAX, "%s=%s\r\n", keyword, value); + send_data->length = kwLen + 1 + valLen; + return send_data; + } + } + return NULL; +} + +uint pcppRecvCheck(unsigned char* buf, int* found_at) { + uint uVar1; + uint uVar3; + int find_failed; + uint found_at_; + int local_4; + + uVar3 = 0; + find_failed = 0; + if (buf == NULL || found_at == NULL) { + PCP_LOG("pointer error\n"); + return 1; + } + + local_4 = *found_at; + *found_at = 0; + for (int uVar2 = 0; uVar2 < 2; uVar2++) { + found_at_ = local_4 - uVar3; + uVar1 = pcppCheckStr(&buf[uVar3], &found_at_, &find_failed); + *found_at = *found_at + found_at_; + + switch (uVar1) { + case 0: + return 1; + case 1: + if (uVar2) return 1; + uVar3 = found_at_; + if (find_failed) return 1; + break; + case 2: + case 3: + case 4: + if (uVar2) return find_failed ? 7 : 0; + return find_failed ? 8 : 6; + case 5: + if (uVar2) return find_failed ? 4 : 2; + return find_failed ? 5 : 3; + } + } + return 1; +} + +e_pcpp_t pcppSendResponseTable(pcpp_t* stream, pcp_send_data_t* data, timeout_t timeout_ms) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + if (data == NULL) { + PCP_LOG("error Response buffer isn\'t set\n"); + return e_pcpp_param_invalid; + } + + return pcppSendResponse(stream, data, data->length + 2, 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 err; + amtime_t time; + + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + if (resp_buffer == NULL) { + PCP_LOG("error Response buffer isn\'t set\n"); + return e_pcpp_param_invalid; + } + + if (buf_len > PCP_BUF_MAX - 1) { + return stream->err = e_pcpp_param_invalid; + } + + amiTimerGet(&time); + stream->err = err = pcppCheckRecvMsg(resp_buffer->data, buf_len, 0); + + if (err != e_pcpp_ok) { + stream->state = 0; + pcppResetRead(stream); + PCP_LOG("error Send message format error\n"); + return stream->err; + } + + stream->resp_buffer = resp_buffer; + stream->resp_buffer_len = buf_len; + stream->state = 6; + err = pcpp_something(&time, timeout_ms, stream, &stream->sock, resp_buffer->data, &stream->resp_buffer_len, + stream->field_0x204, stream->field_0x210, -6); + stream->err = err; + if (err != e_pcpp_to) { + stream->state = 0; + if (err != e_pcpp_ok) { + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + } + amiTimerGet(&time); + stream->last_active = _amTimeMs(time); + return stream->err; +} + +void pcppResetRead(pcpp_t* stream) { + stream->read_bytes_size = PCP_BUF_MAX; + stream->read_bytes_num = 0; + ZERO_BUF(stream->read_bytes_buf); + stream->resp_buffer = NULL; + stream->resp_buffer_len = 0; +} + +e_pcpp_t pcppRecvRequest(pcpp_t* stream, pcp_parse_data_t* recv_data, timeout_t timeout) { + e_pcpp_t err; + uint timeout_ms = timeout; + undefined4 uVar1; + amtime_t now; + amtime_t start; + amtime_t now2; + + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + if (recv_data == NULL) { + PCP_LOG("error Request buffer isn\'t set\n"); + return stream->err = e_pcpp_param_invalid; + } + + if ((stream->sock).open == PCPT_LISTENING) { + uVar1 = stream->field_0x210; + } else { + uVar1 = stream->field_0xb8; + } + stream->recv_data_buffer = recv_data; + amiTimerGet(&start); + stream->state = 2; + err = pcppSendPrompt(stream, uVar1, timeout_ms); + stream->err = err; + if (err != e_pcpp_to) { + stream->state = 0; + } + if (err == e_pcpp_ok) { + stream->open = 0; + amiTimerGet(&now); + stream->last_active = _amTimeMs(now); + stream->state = 5; + if (timeout_ms != TIMEOUT_NONE) { + uint elapsed = _amTimeDelta(now, start); + if (elapsed < timeout_ms) { + timeout_ms = timeout_ms - elapsed; + } else { + timeout_ms = 0; + } + } + + bool bReRecv; + err = pcppRecvRequestMain(stream, &bReRecv, timeout_ms); + stream->err = err; + if (err == e_pcpp_to) { + if (bReRecv) { + stream->state = 14; + return e_pcpp_to; + } + } else { + stream->state = 0; + if (err == e_pcpp_ok) { + amiTimerGet(&now2); + stream->last_active = _amTimeMs(now2); + } + } + err = stream->err; + } + return err; +} + +e_pcpp_t pcppRecvRequestMain(pcpp_t* stream, bool* bReRecv, undefined4 param_3) { + unsigned char* recv_data; + + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + + stream->field_0x214 = 0; + + e_pcpp_t err = pcppRecvAllMsg(param_3, stream, bReRecv); + if (err != e_pcpp_ok) return err; + + recv_data = stream->read_bytes_buf; + if (pcppCheckRecvMsg(recv_data, stream->read_bytes_num, 1) != e_pcpp_ok) { + pcppResetRead(stream); + return -9; + } + + uint local_4 = 0; + pcppChangeRequest(stream, &local_4); + + if (local_4 < stream->read_bytes_num) memcpy(recv_data + local_4, recv_data, stream->read_bytes_num); + + stream->read_bytes_num -= local_4; + stream->read_bytes_size += local_4; + stream->read_bytes_buf[stream->read_bytes_num] = '\0'; + return e_pcpp_ok; +} + +e_pcpp_t pcppSendPrompt(pcpp_t* stream, uint param_2, timeout_t timeout_ms) { + amtime_t now; + + bool has_timeout = false; + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + + amiTimerGet(&now); + uint since_open = _amTimeMs(now) - stream->last_active; + if (since_open > param_2) { + timeout_ms = 0; + } else { + if ((timeout_ms != -1) && ((uint)timeout_ms <= param_2 - since_open)) goto LAB_00456133; + timeout_ms = param_2 - since_open; + } + has_timeout = true; +LAB_00456133: + size_t* send_len = &stream->send_buf_len; + stream->send_buf[0] = '>'; + *send_len = 1; + if ((stream->sock).open == PCPT_LISTENING) stream->open = 1; + + e_pcpp_t err = _errT2P(pcptSend(&stream->sock, stream->send_buf, send_len, stream->field_0x204, timeout_ms)); + + if (has_timeout && err == e_pcpp_to) { + err = stream->open ? -12 : -6; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + if (stream->open == 0) PCP_LOG("Error : Time out error\n"); + } + amiTimerGet(&now); + stream->last_active = _amTimeMs(now); + return err; +} + +e_pcpp_t pcppRecvAllMsg(uint param_1, pcpp_t* stream, bool* bReRecv) { + uint* recv_buf_len; + int iVar1; + e_pcpt_t err; + e_pcpp_t eVar2; + undefined4 uVar3; + uint local_14; + amtime_t local_10; + amtime_t local_8; + + local_14 = param_1; + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + + if (bReRecv == NULL) { + PCP_LOG("error bReRecv isn\'t set\n"); + return e_pcpp_param_invalid; + } + *bReRecv = false; + amiTimerGet(&local_10); + if (stream->read_bytes_num != 0) { + for (size_t i = 0; i < stream->read_bytes_num; i++) { + if (stream->read_bytes_buf[i] == '\r' || stream->read_bytes_buf[i] == '\n') { + stream->field_0x214 = 0; + return e_pcpp_ok; + } + } + } + uVar3 = stream->field_0x214 == 0 ? stream->field_0xb8 : stream->field_0x204; + + iVar1 = pcppGetBlockingTime(uVar3, param_1, stream, _amTimeMs(local_10), &local_14); + recv_buf_len = &stream->read_bytes_size; + *recv_buf_len = PCP_BUF_MAX - stream->read_bytes_num; + err = pcptRecv(&stream->sock, (stream->read_bytes_buf + stream->read_bytes_num), recv_buf_len, local_14); + eVar2 = _errT2P(err); + if (eVar2 == e_pcpp_to) { + if (iVar1 == 0) { + return e_pcpp_to; + } + eVar2 = e_pcpp_timeout_closed - (uint)(stream->field_0x214 != 0); + pcptCloseDataSock(&stream->sock); + *recv_buf_len = PCP_BUF_MAX; + stream->read_bytes_num = 0; + ZERO_BUF(stream->read_bytes_buf); + stream->resp_buffer = NULL; + stream->resp_buffer_len = 0; + } + if (eVar2 != e_pcpp_ok) { + return eVar2; + } + stream->read_bytes_num = stream->read_bytes_num + *recv_buf_len; + *recv_buf_len = PCP_BUF_MAX - stream->read_bytes_num; + amiTimerGet(&local_8); + stream->last_active = _amTimeMs(local_8); + stream->field_0x214 = 1; + *bReRecv = true; + + if (stream->read_bytes_num != 0) { + for (size_t i = 0; i < stream->read_bytes_num; i++) { + if (stream->read_bytes_buf[i] == '\r' || stream->read_bytes_buf[i] == '\n') { + *bReRecv = false; + stream->field_0x214 = 0; + return e_pcpp_ok; + } + } + } + return e_pcpp_to; +} + +pcp_parse_data_t* pcppChangeRequest(pcpp_t* stream, uint* lenout) { + byte bVar5 = 0; + byte bVar6 = 0; + + if (stream == NULL || lenout == NULL) { + PCP_LOG("pointer error\n"); + return NULL; + } + + if (stream->recv_data_buffer == NULL) { + PCP_LOG("don\'t set recvData buffer\n"); + return NULL; + } + + if (stream->read_bytes_num > PCP_BUF_MAX) { + PCP_LOG("Buffer size error\n"); + return NULL; + } + + ZERO_BUF(stream->recv_data_buffer->strings); + ZERO_BUF(stream->recv_data_buffer->keywords); + ZERO_BUF(stream->recv_data_buffer->values); + + stream->recv_data_buffer->keywords[0] = 0; + stream->recv_data_buffer->cmd_count = 1; + + if (stream->read_bytes_num == 0) { + *lenout = 1; + return stream->recv_data_buffer; + } + + bool comment = false; + + size_t i; + for (i = 0; i < stream->read_bytes_num; i++) { + char chr = stream->read_bytes_buf[i]; + + if (chr == PCP_CHAR_CR || chr == PCP_CHAR_LF) { + stream->recv_data_buffer->strings[++bVar6] = PCP_CHAR_EOF; + if (i + 1 < stream->read_bytes_num && stream->read_bytes_buf[i] == PCP_CHAR_CR && + stream->read_bytes_buf[i + 1] == PCP_CHAR_LF) + i++; + + *lenout = i + 1; + return stream->recv_data_buffer; + } + + if (comment) { + if (chr == PCP_CHAR_HASH) comment = false; + continue; + } + + switch (chr) { + case PCP_CHAR_UNKNOWN: + stream->recv_data_buffer->strings[bVar6++] = PCP_CHAR_UNKNOWN; + break; + case PCP_CHAR_SEP: + if (stream->recv_data_buffer->cmd_count > PCP_CMDS_MAX) { + PCP_LOG("Buffer size error\n"); + return NULL; + } + stream->recv_data_buffer->strings[++bVar6] = PCP_CHAR_EOF; + stream->recv_data_buffer->keywords[stream->recv_data_buffer->cmd_count] = bVar6++; + stream->recv_data_buffer->cmd_count++; + bVar5 = bVar6; + break; + case PCP_CHAR_EQU: + if (stream->recv_data_buffer->cmd_count > PCP_CMDS_MAX) { + PCP_LOG("Buffer size error\n"); + return NULL; + } + stream->recv_data_buffer->strings[++bVar6] = PCP_CHAR_EOF; + stream->recv_data_buffer->keywords[stream->recv_data_buffer->cmd_count + PCP_CMDS_MAX - 1] = bVar6++; + bVar5 = bVar6; + break; + case PCP_CHAR_HASH: + comment = true; + break; + default: + bVar6 = bVar5; + if (pcpp_isValidChar(chr)) { + stream->recv_data_buffer->strings[bVar5++] = stream->read_bytes_buf[i]; + } + } + } + *lenout = i + 1; + return stream->recv_data_buffer; +} + +int pcppRecvPrompt(pcpp_t* stream, undefined4 param_2, int param_3) { + uint* recv_buf_len; + int iVar1; + + uint local_c = param_3; + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + + e_pcpp_t err; + amtime_t start; + amiTimerGet(&start); + while (true) { + if (pcppCheckPrompt(stream)) { + amiTimerGet(&start); + stream->last_active = _amTimeMs(start); + return e_pcpp_ok; + } + + iVar1 = pcppGetBlockingTime(param_2, param_3, stream, _amTimeMs(start), &local_c); + recv_buf_len = &stream->read_bytes_size; + err = _errT2P(pcptRecv(&stream->sock, stream->read_bytes_buf + stream->read_bytes_num, recv_buf_len, local_c)); + if (err == e_pcpp_to) break; + if (err != e_pcpp_ok) { + return err; + } + stream->read_bytes_num = stream->read_bytes_num + *recv_buf_len; + uint uVar3 = PCP_BUF_MAX - stream->read_bytes_num; + *recv_buf_len = uVar3; + if (uVar3 != 0) { + stream->read_bytes_buf[stream->read_bytes_num] = '\0'; + } + } + + if (iVar1 != 0) { + err = stream->open ? e_pcpp_timeout_open : e_pcpp_timeout_closed; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + return err; + } + return err; +} + +e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, timeout_t timeout_ms) { + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + + if (stream->resp_buffer == NULL) { + PCP_LOG("error Request buffer isn\'t set\n"); + return e_pcpp_param_invalid; + } + + amtime_t now; + amiTimerGet(&now); + + e_pcpp_t eVar1 = + pcpp_something(&now, timeout_ms, stream, (pcpt_t*)stream, stream->resp_buffer->data, &stream->resp_buffer_len, + stream->field_0x204, param_2, stream->open ? e_pcpp_timeout_open : e_pcpp_timeout_closed); + if (eVar1 != e_pcpp_to && eVar1 != e_pcpp_ok) { + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + amiTimerGet(&now); + stream->last_active = _amTimeMs(now); + return eVar1; +} + +// TODO: MINIMAL CLEANUP DONE HERE + +e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, uint param_4) { + size_t* psVar1; + unsigned char** send_buf; + int iVar2; + e_pcpt_t eVar3; + e_pcpp_t eVar4; + undefined4 uVar5; + bool bVar6; + uint recvb_local; + amtime_t now; + amtime_t local_10; + amtime_t local_8; + + recvb_local = param_4; + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + if (recv_buf == NULL) { + PCP_LOG("error Recv Bninary Buffer isn\'t set\n"); + return e_pcpp_param_invalid; + } + stream->field_0x214 = 0; + amiTimerGet(&now); + psVar1 = &stream->field_0x1f8; + stream->recv_binary_buf = recv_buf; + *psVar1 = buf_len; + stream->recv_binary_buf_len = buf_len; + stream->field_0x1fc = 0; + stream->state = 11; + memset(recv_buf, 0, buf_len); + do { + bVar6 = (stream->data_sock).open != PCPT_LISTENING; + if (bVar6) { + uVar5 = stream->field_0x208; + } else { + amiTimerGet(&local_8); + uVar5 = stream->field_0x210; + stream->last_active = _amTimeMs(local_8); + ; + } + iVar2 = pcppGetBlockingTime(uVar5, param_4, stream, _amTimeMs(now), &recvb_local); + stream->field_0x214 = 1; + eVar3 = pcptRecv(&stream->data_sock, stream->recv_binary_buf + stream->field_0x1fc, psVar1, recvb_local); + eVar4 = _errT2P(eVar3); + stream->err = eVar4; + if ((eVar4 == e_pcpp_to) && (iVar2 != 0)) { + stream->err = bVar6 ? -13 : -11; + pcptCloseDataSock(&stream->sock); + stream->read_bytes_size = PCP_BUF_MAX; + stream->read_bytes_num = 0; + memset(stream->read_bytes_buf, 0, PCP_BUF_MAX); + stream->resp_buffer = NULL; + stream->resp_buffer_len = 0; + } + eVar4 = stream->err; + if (eVar4 == e_pcpp_to) { + LAB_00455e91: + if (eVar4 != e_pcpp_ok) { + return eVar4; + } + } else { + if (eVar4 != e_pcpp_ok) { + stream->state = 0; + goto LAB_00455e91; + } + } + stream->field_0x1fc = stream->field_0x1fc + *psVar1; + *psVar1 = stream->recv_binary_buf_len - stream->field_0x1fc; + stream->field_0x214 = 0; + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + if (stream->recv_binary_buf_len < stream->field_0x1fc || stream->recv_binary_buf_len == stream->field_0x1fc) { + send_buf = (unsigned char**)&stream->send_buf; + psVar1 = &stream->send_buf_len; + stream->state = 12; + *send_buf[0] = PCP_CHAR_BINACK; + *psVar1 = 1; + iVar2 = pcppGetBlockingTime(stream->field_0x20c, param_4, stream, _amTimeMs(now), &recvb_local); + eVar3 = pcptSend(&stream->sock, *send_buf, psVar1, stream->field_0x208, recvb_local); + eVar4 = _errT2P(eVar3); + stream->err = eVar4; + if ((eVar4 == e_pcpp_to) && (iVar2 != 0)) { + stream->err = -14; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + eVar4 = stream->err; + if (eVar4 != e_pcpp_to) { + stream->state = 0; + } + if (eVar4 == e_pcpp_ok) { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + stream->state = 13; + iVar2 = pcppGetBlockingTime(stream->field_0x208, param_4, stream, _amTimeMs(now), &recvb_local); + *psVar1 = PCP_SEND_BUF_MAX; + ZERO(stream->send_buf); + eVar3 = pcptRecv(&stream->data_sock, *send_buf, psVar1, recvb_local); + eVar4 = _errT2P(eVar3); + stream->err = eVar4; + if ((iVar2 != 0) && (eVar4 == e_pcpp_to)) { + stream->err = -13; + } + if (stream->err != e_pcpp_to) { + stream->state = 0; + } + if (stream->err == e_pcpp_closed) { + stream->err = e_pcpp_ok; + } + eVar4 = stream->err; + } + return eVar4; + } + } while (true); +} + +e_pcpp_t pcppSendBinary(pcpp_t* stream, unsigned char* send_binary_buffer, size_t param_3, uint param_4) + +{ + size_t* psVar1; + uint pVar2; + e_pcpp_t eVar3; + int iVar4; + e_pcpt_t eVar5; + uint uVar6; + uint local_14; + amtime_t local_10; + amtime_t local_8; + + local_14 = param_4; + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + if (send_binary_buffer == NULL) { + PCP_LOG("error Send Bninary Buffer isn\'t set\n"); + return stream->err = e_pcpp_param_invalid; + } + amiTimerGet(&local_8); + pVar2 = (stream->data_sock).open; + psVar1 = &stream->field_0x1f0; + stream->state = 9; + *psVar1 = param_3; + stream->send_binary_buf = send_binary_buffer; + if (pVar2 == PCPT_LISTENING) { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + eVar3 = pcpp_something(&local_8, param_4, stream, &stream->data_sock, stream->send_binary_buf, psVar1, + stream->field_0x208, stream->field_0x210, -11); + stream->err = eVar3; + } else { + eVar5 = pcptSend(&stream->data_sock, send_binary_buffer, psVar1, stream->field_0x208, param_4); + eVar3 = _errT2P(eVar5); + iVar4 = (stream->data_sock).field_0x54; + stream->err = eVar3; + if (iVar4 != 0) { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + } + } + eVar3 = stream->err; + if (eVar3 != e_pcpp_to) { + stream->state = 0; + } + if (eVar3 == e_pcpp_ok) { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + stream->state = 10; + psVar1 = &stream->send_buf_len; + *psVar1 = 8; + ZERO(stream->send_buf); + stream->field_0x1e8 = 0; + iVar4 = pcppGetBlockingTime(stream->field_0x20c, param_4, stream, _amTimeMs(local_8), &local_14); + eVar5 = pcptRecv(&stream->sock, stream->send_buf, psVar1, local_14); + eVar3 = _errT2P(eVar5); + stream->err = eVar3; + if ((iVar4 != 0) && (eVar3 == e_pcpp_to)) { + stream->err = -14; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + eVar3 = stream->err; + if (eVar3 != e_pcpp_to) { + stream->state = 0; + } + if (eVar3 == e_pcpp_ok) { + stream->field_0x1e8 = stream->field_0x1e8 + *psVar1; + uVar6 = 0; + *psVar1 = 8 - stream->field_0x1e8; + stream->state = 0; + stream->err = -9; + if (stream->field_0x1e8 != 0) { + while (*(char*)((int)&stream->send_buf + uVar6) != PCP_CHAR_BINACK) { + uVar6 = uVar6 + 1; + if (stream->field_0x1e8 <= uVar6) { + return stream->err; + } + } + stream->err = e_pcpp_ok; + } + eVar3 = stream->err; + } + } + return eVar3; +} + +e_pcpp_t pcppIsBusy(pcpp_t* stream, timeout_t timeout) { + size_t* psVar1; + unsigned char** send_buf; + undefined4 uVar2; + int iVar3; + e_pcpt_t eVar4; + int iVar5; + uint uVar6; + e_pcpp_t eVar7; + unsigned char* pcVar8; + unsigned char* pcVar9; + uint uVar10; + uint uVar11; + bool bVar12; + bool local_24; + int local_20; + int local_1c; + amtime_t local_18; + amtime_t local_10; + amtime_t local_8; + pcpt_t* sock; + + uVar11 = timeout; + bVar12 = false; + local_20 = 0; + local_1c = 0; + local_24 = 0; + if (stream == NULL) { + PCP_LOG("error PCPP stream isn\'t set\n"); + return e_pcpp_param_invalid; + } + amiTimerGet(&local_18); + switch (stream->state) { + case 0: + stream->err = e_pcpp_no_client; + break; + case 1: + case 8: + if (stream->state == 1) { + if (stream->open == 0) { + uVar2 = stream->field_0x210; + } else { + uVar2 = stream->field_0xb8; + } + iVar3 = _amTimeMs(local_18); + } else { + iVar3 = _amTimeMs(local_18); + uVar2 = stream->field_0x210; + } + iVar3 = pcppGetBlockingTime(uVar2, uVar11, stream, iVar3, &timeout); + sock = &stream->sock; + if (stream->state != 1) { + sock = &stream->data_sock; + } + eVar4 = pcptIsBusy(sock, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if (eVar7 != e_pcpp_to) { + if (eVar7 == e_pcpp_ok) { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + if (stream->state != 8) { + if (stream->open != 0) { + stream->read_bytes_num = stream->read_bytes_num + stream->read_bytes_size; + stream->read_bytes_size = PCP_BUF_MAX - stream->read_bytes_num; + iVar3 = pcppCheckPrompt(stream); + if (iVar3 != 0) goto LAB_00457676; + stream->err = ~e_pcpp_no_client; + goto LAB_00457660; + } + stream->state = 3; + if (uVar11 != TIMEOUT_NONE) { + amiTimerGet(&local_8); + uVar6 = (local_8.microseconds - local_18.microseconds) / 1000 + + (local_8.seconds - local_18.seconds) * 1000; + if (uVar6 < uVar11) { + uVar11 = uVar11 - uVar6; + } else { + uVar11 = 0; + } + } + stream->open = 1; + eVar7 = pcppRecvPrompt(stream, stream->field_0xb8, uVar11); + stream->err = eVar7; + if (eVar7 != e_pcpp_to) { + amiTimerGet(&local_10); + stream->state = 0; + stream->last_active = _amTimeMs(local_10); + return stream->err; + } + } + break; + } + goto LAB_004577b4; + } + if (iVar3 == 0) break; + if (stream->state == 1) { + stream->err = 0xfffffff5 - (uint)(stream->open != 0); + } else { + stream->err = -11; + } + goto LAB_00457392; + case 2: + case 4: + case 6: + uVar6 = uVar11; + if ((stream->sock).field_0x54 != 0) { + bVar12 = (stream->sock).open != PCPT_LISTENING; + if (bVar12) { + uVar2 = stream->field_0xb8; + } else { + uVar2 = stream->field_0x210; + } + bVar12 = !bVar12; + local_20 = pcppGetBlockingTime(uVar2, uVar11, stream, _amTimeMs(local_18), &timeout); + uVar6 = timeout; + } + eVar4 = pcptIsBusy(&stream->sock, uVar6); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if (eVar7 != e_pcpp_to) { + if (eVar7 == e_pcpp_ok) { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + if (stream->state != 2) goto LAB_004577b4; + stream->open = 0; + amiTimerGet(&local_8); + stream->state = 5; + iVar3 = pcppGetBlockingTime(stream->field_0xb8, uVar11, stream, _amTimeMs(local_18), &timeout); + eVar7 = pcppRecvRequestMain(stream, &local_24, timeout); + stream->err = eVar7; + if ((eVar7 == e_pcpp_to) && (iVar3 != 0)) { + stream->err = e_pcpp_timeout_closed; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + if (stream->err == e_pcpp_to) { + if (local_24 != 0) { + stream->state = 14; + } + } else { + stream->state = 0; + } + if (stream->err == e_pcpp_ok) goto LAB_004574b8; + break; + } + goto LAB_004577af; + } + if (local_20 == 0) break; + stream->err = (-(uint)bVar12 & 0xfffffffb) - 6; + goto LAB_00457392; + case 3: + case 5: + case 7: + if (stream->field_0x214 == 0) { + uVar2 = stream->field_0xb8; + } else { + uVar2 = stream->field_0x204; + } + iVar3 = pcppGetBlockingTime(uVar2, uVar11, stream, _amTimeMs(local_18), &timeout); + uVar6 = timeout; + eVar4 = pcptIsBusy(&stream->sock, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if (eVar7 != e_pcpp_to) { + if (eVar7 != e_pcpp_ok) { + LAB_00457660: + stream->state = 0; + return stream->err; + } + stream->read_bytes_num = stream->read_bytes_num + stream->read_bytes_size; + stream->field_0x214 = 0; + stream->read_bytes_size = PCP_BUF_MAX - stream->read_bytes_num; + if (stream->state == 3) { + uVar6 = uVar11; + if (uVar11 != TIMEOUT_NONE) { + amiTimerGet(&local_8); + uVar6 = -(uint)((uint)((local_8.microseconds - local_18.microseconds) / 1000 + + (local_8.seconds - local_18.seconds) * 1000) < uVar11) & + uVar11; + } + eVar7 = pcppRecvPrompt(stream, stream->field_0xb8, uVar6); + stream->err = eVar7; + if (eVar7 != e_pcpp_to) { + if (eVar7 != e_pcpp_ok) goto LAB_00457660; + if (stream->open == 0) { + if (uVar11 != TIMEOUT_NONE) { + amiTimerGet(&local_8); + uVar11 = -(uint)((uint)((local_8.microseconds - local_18.microseconds) / 1000 + + (local_8.seconds - local_18.seconds) * 1000) < uVar11) & + uVar11; + } + stream->state = 4; + eVar7 = pcppSendRequestMain(stream, stream->field_0xb8, uVar11); + stream->err = eVar7; + if ((eVar7 != e_pcpp_to) && (eVar7 != e_pcpp_ok)) { + stream->state = 0; + return eVar7; + } + } + } + break; + } + if (stream->read_bytes_num == 0) { + LAB_0045848d: + amiTimerGet(&local_8); + stream->last_active = _amTimeMs(local_8); + uVar10 = _amTimeDelta(local_8, local_18); + stream->field_0x214 = 1; + if (uVar11 != TIMEOUT_NONE) { + if (uVar11 <= uVar10) { + stream->state = stream->state == 5 ? 14 : 15; + return stream->err = e_pcpp_to; + } + uVar6 = uVar11 - uVar10; + } + eVar7 = pcppRecvAllMsg(uVar6, stream, &local_24); + stream->err = eVar7; + if (eVar7 != e_pcpp_ok) { + if (eVar7 == e_pcpp_to) { + if (local_24 != 0) { + stream->state = stream->state == 5 ? 14 : 15; + return e_pcpp_to; + } + break; + } + goto LAB_0045739d; + } + } else { + uVar10 = stream->read_bytes_num; + pcVar8 = stream->read_bytes_buf; + iVar3 = local_1c; + do { + if ((*pcVar8 == '\r') || (*pcVar8 == '\n')) { + iVar3 = 1; + } + pcVar8 = pcVar8 + 1; + uVar10 = uVar10 - 1; + } while (uVar10 != 0); + if (iVar3 == 0) goto LAB_0045848d; + } + pcVar8 = stream->read_bytes_buf; + eVar7 = pcppCheckRecvMsg(pcVar8, stream->read_bytes_num, (uint)(stream->state == 5)); + stream->err = eVar7; + if (eVar7 == e_pcpp_ok) { + pcppChangeRequest(stream, &timeout); + uVar11 = timeout; + pcVar9 = pcVar8; + if (timeout < stream->read_bytes_num) { + do { + *pcVar9 = pcVar8[uVar11]; + uVar11 = uVar11 + 1; + pcVar9 = pcVar9 + 1; + } while (uVar11 < stream->read_bytes_num); + } + LAB_00458226: + stream->read_bytes_num = stream->read_bytes_num - timeout; + stream->read_bytes_size = stream->read_bytes_size + timeout; + stream->state = 0; + amiTimerGet(&local_18); + stream->last_active = _amTimeMs(local_18); + return stream->err; + } + stream->state = 0; + pcppResetRead(stream); + PCP_LOG("error Response format error\n"); + return stream->err; + } + if (iVar3 == 0) break; + if (stream->field_0x214 == 0) { + stream->err = (-(uint)(stream->open != 0) & 0xfffffffa) - 6; + } else { + stream->err = -7; + } + LAB_00457392: + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + LAB_0045739d: + stream->state = 0; + return stream->err; + case 9: + bVar12 = (stream->data_sock).open != PCPT_LISTENING; + if (bVar12) { + uVar2 = stream->field_0x208; + } else { + uVar2 = stream->field_0x210; + } + iVar5 = pcppGetBlockingTime(uVar2, uVar11, stream, _amTimeMs(local_18), &timeout); + eVar4 = pcptIsBusy(&stream->data_sock, timeout); + eVar7 = _errT2P(eVar4); + iVar3 = (stream->data_sock).field_0x54; + stream->err = eVar7; + if (iVar3 == 0) { + if ((iVar5 != 0) && (eVar7 == e_pcpp_to)) { + stream->err = (uint)!bVar12 * 2 + -13; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + } else { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + } + if (stream->err != e_pcpp_to) { + stream->state = 0; + } + if (stream->err == e_pcpp_ok) { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + stream->state = 10; + psVar1 = &stream->send_buf_len; + *psVar1 = PCP_SEND_BUF_MAX; + ZERO(stream->send_buf); + stream->field_0x1e8 = 0; + iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), &timeout); + eVar4 = pcptRecv(&stream->sock, stream->send_buf, psVar1, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) { + stream->err = -14; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + if (stream->err != e_pcpp_to) { + stream->state = 0; + } + if (stream->err == e_pcpp_ok) { + stream->field_0x1e8 = stream->field_0x1e8 + *psVar1; + uVar11 = 0; + *psVar1 = PCP_SEND_BUF_MAX - stream->field_0x1e8; + stream->state = 0; + stream->err = -9; + if (stream->field_0x1e8 != 0) { + do { + if (*(char*)((int)&stream->send_buf + uVar11) == PCP_CHAR_BINACK) { + stream->err = e_pcpp_ok; + break; + } + uVar11 = uVar11 + 1; + } while (uVar11 < stream->field_0x1e8); + } + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + return stream->err; + } + } + break; + case 10: + iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), &timeout); + eVar4 = pcptIsBusy(&stream->sock, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) { + stream->err = -14; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + if (stream->err != e_pcpp_to) { + stream->state = 0; + } + if (stream->err == e_pcpp_ok) { + amiTimerGet(&local_10); + stream->field_0x1e8 = stream->field_0x1e8 + stream->send_buf_len; + stream->last_active = _amTimeMs(local_10); + ; + uVar11 = 0; + stream->send_buf_len = PCP_SEND_BUF_MAX - stream->field_0x1e8; + stream->err = -9; + if (stream->field_0x1e8 != 0) { + while (*(char*)((int)&stream->send_buf + uVar11) != PCP_CHAR_BINACK) { + uVar11 = uVar11 + 1; + if (stream->field_0x1e8 <= uVar11) { + return stream->err; + } + } + LAB_00457676: + stream->err = e_pcpp_ok; + return e_pcpp_ok; + } + } + break; + case 11: + if (stream->field_0x214 != 0) { + bVar12 = (stream->data_sock).open != PCPT_LISTENING; + if (bVar12) { + uVar2 = stream->field_0x208; + } else { + uVar2 = stream->field_0x210; + } + iVar3 = pcppGetBlockingTime(uVar2, uVar11, stream, _amTimeMs(local_18), &timeout); + eVar4 = pcptIsBusy(&stream->data_sock, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((eVar7 == e_pcpp_to) && (iVar3 != 0)) { + stream->err = (uint)!bVar12 * 2 + -13; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + eVar7 = stream->err; + if (eVar7 == e_pcpp_to) { + LAB_00457b2e: + if (eVar7 != e_pcpp_ok) { + return eVar7; + } + } else { + if (eVar7 != e_pcpp_ok) { + stream->field_0x214 = 0; + stream->state = 0; + goto LAB_00457b2e; + } + } + stream->field_0x1fc = stream->field_0x1fc + stream->field_0x1f8; + stream->field_0x214 = 0; + stream->field_0x1f8 = stream->recv_binary_buf_len - stream->field_0x1fc; + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + } + if (stream->field_0x1fc <= stream->recv_binary_buf_len && + stream->recv_binary_buf_len != stream->field_0x1fc) { + psVar1 = &stream->field_0x1f8; + do { + iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), &timeout); + stream->field_0x214 = 1; + eVar4 = + pcptRecv(&stream->data_sock, stream->recv_binary_buf + stream->field_0x1fc, psVar1, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((eVar7 == e_pcpp_to) && (iVar3 != 0)) { + stream->err = -13; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + eVar7 = stream->err; + if (eVar7 == e_pcpp_to) { + LAB_00457c47: + if (eVar7 != e_pcpp_ok) goto switchD_004572ff_caseD_10; + } else { + if (eVar7 != e_pcpp_ok) { + stream->state = 0; + goto LAB_00457c47; + } + } + stream->field_0x1fc = stream->field_0x1fc + *psVar1; + stream->field_0x214 = 0; + *psVar1 = stream->recv_binary_buf_len - stream->field_0x1fc; + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + } while (stream->field_0x1fc <= stream->recv_binary_buf_len && + stream->recv_binary_buf_len != stream->field_0x1fc); + } + send_buf = (unsigned char**)&stream->send_buf; + psVar1 = &stream->send_buf_len; + stream->state = 12; + *send_buf[0] = PCP_CHAR_BINACK; + *psVar1 = 1; + local_20 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), &timeout); + eVar4 = pcptSend(&stream->sock, *send_buf, psVar1, stream->field_0x204, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((eVar7 == e_pcpp_to) && (local_20 != 0)) { + stream->err = -14; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + if (stream->err != e_pcpp_to) { + stream->state = 0; + } + if (stream->err == e_pcpp_ok) { + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + stream->state = 13; + iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), &timeout); + *psVar1 = PCP_SEND_BUF_MAX; + ZERO(stream->send_buf); + eVar4 = pcptRecv(&stream->data_sock, *send_buf, psVar1, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) { + stream->err = -13; + } + if (stream->err != e_pcpp_to) { + stream->state = 0; + } + if (stream->err == e_pcpp_closed) { + stream->err = e_pcpp_ok; + LAB_004574b8: + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + return stream->err; + } + } + break; + case 12: + iVar3 = pcppGetBlockingTime(stream->field_0x20c, uVar11, stream, _amTimeMs(local_18), &timeout); + eVar4 = pcptIsBusy(&stream->sock, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) { + stream->err = -14; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + if (stream->err != e_pcpp_to) { + stream->state = 0; + } + if (stream->err != e_pcpp_ok) break; + stream->state = 13; + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), &timeout); + stream->send_buf_len = PCP_SEND_BUF_MAX; + ZERO(stream->send_buf); + eVar4 = pcptRecv(&stream->data_sock, stream->send_buf, &stream->send_buf_len, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((iVar3 != 0) && (eVar7 == e_pcpp_to)) { + stream->err = -13; + pcptCloseDataSock(&stream->sock); + pcppResetRead(stream); + } + if (stream->err != e_pcpp_to) stream->state = 0; + + if (stream->err != e_pcpp_closed) break; + stream->err = e_pcpp_ok; + goto LAB_004574b8; + case 13: + iVar3 = pcppGetBlockingTime(stream->field_0x208, uVar11, stream, _amTimeMs(local_18), &timeout); + eVar4 = pcptIsBusy(&stream->data_sock, timeout); + eVar7 = _errT2P(eVar4); + stream->err = eVar7; + if ((iVar3 == 0) || (eVar7 != e_pcpp_to)) { + if (eVar7 == e_pcpp_closed) { + stream->err = e_pcpp_ok; + amiTimerGet(&local_10); + stream->last_active = _amTimeMs(local_10); + return stream->err; + } + break; + } + stream->err = -13; + pcptCloseDataSock(&stream->sock); + LAB_004577af: + pcppResetRead(stream); + LAB_004577b4: + stream->state = 0; + return stream->err; + case 14: + case 15: + amiTimerGet(&local_8); + uVar6 = _amTimeDelta(local_8, local_18); + stream->field_0x214 = 1; + if (uVar11 != TIMEOUT_NONE) { + if (uVar6 < uVar11) { + uVar11 = uVar11 - uVar6; + } else { + uVar11 = 0; + } + } + eVar7 = pcppRecvAllMsg(uVar11, stream, &local_24); + stream->err = eVar7; + if (eVar7 == e_pcpp_ok) { + pcVar8 = stream->read_bytes_buf; + eVar7 = pcppCheckRecvMsg(pcVar8, stream->read_bytes_num, (uint)(stream->state == 14)); + stream->err = eVar7; + if (eVar7 != e_pcpp_ok) { + stream->state = 0; + pcppResetRead(stream); + PCP_LOG("error Response format error\n"); + return stream->err; + } + pcppChangeRequest(stream, &timeout); + uVar11 = timeout; + pcVar9 = pcVar8; + if (timeout < stream->read_bytes_num) { + do { + *pcVar9 = pcVar8[uVar11]; + uVar11 = uVar11 + 1; + pcVar9 = pcVar9 + 1; + } while (uVar11 < stream->read_bytes_num); + } + goto LAB_00458226; + } + if (eVar7 == e_pcpp_to) { + if (local_24 == 0) { + stream->state = stream->state == 14 ? 5 : 7; + return stream->err; + } + break; + } + goto LAB_0045739d; + } +switchD_004572ff_caseD_10: + return stream->err; +} + +int pcpp_something(amtime_t* time, timeout_t timeout, pcpp_t* stream, pcpt_t* sock, unsigned char* send_buf, + size_t* send_len, undefined4 param_7, undefined4 param_8, int fallback_err) { + uint iVar1; + uint blocking_time; + amtime_t now; + e_pcpp_t err; + + iVar1 = pcppGetBlockingTime(param_8, timeout, stream, _amTimeMs(*time), &blocking_time); + err = _errT2P(pcptSend(sock, send_buf, send_len, param_7, blocking_time)); + if (err != e_pcpp_to) return err; + + if (sock->field_0x54 != 0) { + if (timeout == TIMEOUT_NONE) return _errT2P(pcptIsBusy(sock, TIMEOUT_NONE)); + + amiTimerGet(&now); + iVar1 = FUN_00459d00(time, &now); + if ((iVar1 / 1000) < timeout) { + return _errT2P(pcptIsBusy(sock, timeout - iVar1 / 1000)); + } + return _errT2P(pcptIsBusy(sock, 0)); + } + + if (iVar1 != 0) { + return fallback_err; + } + return err; +} + +pcp_send_data_t* pcppAddSendPacket(pcp_send_data_t* send_data, char* keyword, char* value) { + if (send_data == NULL || keyword == NULL) { + PCP_LOG("error Send Data isn\'t set\n"); + return NULL; + } + + size_t existing_length = send_data->length; + if (existing_length == 0) return pcppSetSendPacket(send_data, keyword, value); + + size_t kwLen = strlen(keyword); + if (value == NULL) { + if (existing_length + kwLen + 3 < PCP_BUF_MAX) { + sprintf_s((char*)&send_data->data[existing_length], PCP_BUF_MAX - existing_length, "&%s\r\n", keyword); + send_data->length += kwLen + 1; + return send_data; + } + } else { + size_t valLen = strlen(value); + if (existing_length + kwLen + valLen + 4 < PCP_BUF_MAX) { + sprintf_s((char*)&send_data->data[existing_length], PCP_BUF_MAX - existing_length, "&%s=%s\r\n", keyword, value); + send_data->length += valLen + kwLen + 2; + return send_data; + } + } + return NULL; +} diff --git a/src/micetools/lib/libpcp/pcpp.h b/src/micetools/lib/libpcp/pcpp.h index 6794e18..95efb22 100644 --- a/src/micetools/lib/libpcp/pcpp.h +++ b/src/micetools/lib/libpcp/pcpp.h @@ -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); diff --git a/src/micetools/lib/libpcp/pcpt.c b/src/micetools/lib/libpcp/pcpt.c new file mode 100644 index 0000000..82c40b6 --- /dev/null +++ b/src/micetools/lib/libpcp/pcpt.c @@ -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; +} diff --git a/src/micetools/lib/libpcp/pcpt.h b/src/micetools/lib/libpcp/pcpt.h index c63a411..0a67d4d 100644 --- a/src/micetools/lib/libpcp/pcpt.h +++ b/src/micetools/lib/libpcp/pcpt.h @@ -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); diff --git a/src/micetools/lib/libpcp/util.c b/src/micetools/lib/libpcp/util.c new file mode 100644 index 0000000..3796b00 --- /dev/null +++ b/src/micetools/lib/libpcp/util.c @@ -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(""); + } +} diff --git a/src/micetools/lib/meson.build b/src/micetools/lib/meson.build index 2670a41..da60a15 100644 --- a/src/micetools/lib/meson.build +++ b/src/micetools/lib/meson.build @@ -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') diff --git a/src/micetools/lib/mice/exe.c b/src/micetools/lib/mice/exe.c index 8ff23f1..71f1cef 100644 --- a/src/micetools/lib/mice/exe.c +++ b/src/micetools/lib/mice/exe.c @@ -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; +} diff --git a/src/micetools/lib/mice/ioctl.h b/src/micetools/lib/mice/ioctl.h index 4903361..4be9dc7 100644 --- a/src/micetools/lib/mice/ioctl.h +++ b/src/micetools/lib/mice/ioctl.h @@ -1,56 +1,69 @@ -#include - -#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 + +#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) diff --git a/src/micetools/lib/mice/patch.c b/src/micetools/lib/mice/patch.c index 35c7584..22d03d5 100644 --- a/src/micetools/lib/mice/patch.c +++ b/src/micetools/lib/mice/patch.c @@ -1,228 +1,228 @@ -#include "patch.h" - -#include -#include - -bool fetch(json_value* object, char* name, json_value** value) { - if (object->type != json_object) return false; - for (size_t j = 0; j < object->u.object.length; j++) { - 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 +#include + +bool fetch(json_value* object, char* name, json_value** value) { + if (object->type != json_object) return false; + for (size_t j = 0; j < object->u.object.length; j++) { + 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; +} diff --git a/src/micetools/meson.build b/src/micetools/meson.build index 4dff25f..b5f680a 100644 --- a/src/micetools/meson.build +++ b/src/micetools/meson.build @@ -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') diff --git a/src/micetools/miceboot/TrueCrypt.cmd b/src/micetools/miceboot/TrueCrypt.cmd new file mode 100644 index 0000000..db5929e --- /dev/null +++ b/src/micetools/miceboot/TrueCrypt.cmd @@ -0,0 +1,4 @@ +@echo off +@REM "C:\Program Files (x86)\TrueCrypt\TrueCrypt.exe" %* +echo %* +pause diff --git a/src/micetools/miceboot/ewfapi.h b/src/micetools/miceboot/ewfapi.h new file mode 100644 index 0000000..034ad8a --- /dev/null +++ b/src/micetools/miceboot/ewfapi.h @@ -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__ diff --git a/src/micetools/miceboot/meson.build b/src/micetools/miceboot/meson.build new file mode 100644 index 0000000..dd2fae0 --- /dev/null +++ b/src/micetools/miceboot/meson.build @@ -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', + ], +) diff --git a/src/micetools/miceboot/mice_ewfapi.h b/src/micetools/miceboot/mice_ewfapi.h new file mode 100644 index 0000000..eec7a64 --- /dev/null +++ b/src/micetools/miceboot/mice_ewfapi.h @@ -0,0 +1,105 @@ +#include + +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); diff --git a/src/micetools/miceboot/mxmaster.c b/src/micetools/miceboot/mxmaster.c new file mode 100644 index 0000000..bebe45b --- /dev/null +++ b/src/micetools/miceboot/mxmaster.c @@ -0,0 +1,8 @@ +#include +#include + +int main(int argc, char** argv) { + puts("mxmaster.exe dummy hit"); + + while (1) Sleep(1000); +} diff --git a/src/micetools/miceboot/mxprestartup.c b/src/micetools/miceboot/mxprestartup.c new file mode 100644 index 0000000..3cbaf50 --- /dev/null +++ b/src/micetools/miceboot/mxprestartup.c @@ -0,0 +1,216 @@ +/* +Currently unimplemented: +- Changing the screen resoltuion to something very small (lol) +- The UI that shows "NOW LOADING" +*/ +#include +#include +#include +#include +#include + +#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 \n", argv[0]); + printf(" %s \n", argv[0]); + printf(" %s \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; +} diff --git a/src/micetools/miceboot/mxstartup.c b/src/micetools/miceboot/mxstartup.c new file mode 100644 index 0000000..4877256 --- /dev/null +++ b/src/micetools/miceboot/mxstartup.c @@ -0,0 +1,410 @@ +#include +#include +#include +#include +#include +#include + +#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); } diff --git a/src/micetools/miceboot/truecrypt.c b/src/micetools/miceboot/truecrypt.c new file mode 100644 index 0000000..67051f6 --- /dev/null +++ b/src/micetools/miceboot/truecrypt.c @@ -0,0 +1,5 @@ +#include + +int main(int argc, char** argv) { + puts("TrueCrypt.exe dummy hit"); +} diff --git a/src/micetools/micekeychip/callbacks/appboot.c b/src/micetools/micekeychip/callbacks/appboot.c index 03f3622..572b1e6 100644 --- a/src/micetools/micekeychip/callbacks/appboot.c +++ b/src/micetools/micekeychip/callbacks/appboot.c @@ -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); +} diff --git a/src/micetools/micekeychip/callbacks/billing.c b/src/micetools/micekeychip/callbacks/billing.c index 3939f8e..3d8c849 100644 --- a/src/micetools/micekeychip/callbacks/billing.c +++ b/src/micetools/micekeychip/callbacks/billing.c @@ -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); +} diff --git a/src/micetools/micekeychip/callbacks/tracedata.c b/src/micetools/micekeychip/callbacks/tracedata.c index 7f081bb..a55a38e 100644 --- a/src/micetools/micekeychip/callbacks/tracedata.c +++ b/src/micetools/micekeychip/callbacks/tracedata.c @@ -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, ""); +} diff --git a/src/micetools/micekeychip/meson.build b/src/micetools/micekeychip/meson.build index a94510d..b0e7bf8 100644 --- a/src/micetools/micekeychip/meson.build +++ b/src/micetools/micekeychip/meson.build @@ -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, +) diff --git a/src/micetools/micekeychip/mxk.c b/src/micetools/micekeychip/mxk.c index 568c8fe..75ca34f 100644 --- a/src/micetools/micekeychip/mxk.c +++ b/src/micetools/micekeychip/mxk.c @@ -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; } \ No newline at end of file diff --git a/src/micetools/micepatch/main.c b/src/micetools/micepatch/main.c index d86f602..5204b86 100644 --- a/src/micetools/micepatch/main.c +++ b/src/micetools/micepatch/main.c @@ -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 \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 \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; +} diff --git a/src/micetools/micetest/main.c b/src/micetools/micetest/main.c deleted file mode 100644 index 3394a91..0000000 --- a/src/micetools/micetest/main.c +++ /dev/null @@ -1,6 +0,0 @@ -#include "stdio.h" - -int main() { - puts("Hello world"); - return 0; -} diff --git a/src/micetools/micetest/meson.build b/src/micetools/micetest/meson.build deleted file mode 100644 index 41058e3..0000000 --- a/src/micetools/micetest/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -executable( - 'micetest', - win_subsystem: subsystem, - sources: [ - 'main.c', - ], -) diff --git a/src/micetools/util/meson.build b/src/micetools/util/meson.build new file mode 100644 index 0000000..1fc139a --- /dev/null +++ b/src/micetools/util/meson.build @@ -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', + ], +) diff --git a/src/micetools/util/micedump.c b/src/micetools/util/micedump.c new file mode 100644 index 0000000..3fe88f7 --- /dev/null +++ b/src/micetools/util/micedump.c @@ -0,0 +1,271 @@ +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/src/micetools/util/micemonitor.c b/src/micetools/util/micemonitor.c new file mode 100644 index 0000000..0d21713 --- /dev/null +++ b/src/micetools/util/micemonitor.c @@ -0,0 +1,14 @@ +#include +#include + +#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; +} diff --git a/src/micetools/util/micetinker.c b/src/micetools/util/micetinker.c new file mode 100644 index 0000000..7a739c5 --- /dev/null +++ b/src/micetools/util/micetinker.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include +#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 \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; +} diff --git a/src/patches/mxgfetcher.patch.json b/src/patches/mxgfetcher.patch.json new file mode 100644 index 0000000..a4aaeac --- /dev/null +++ b/src/patches/mxgfetcher.patch.json @@ -0,0 +1,9 @@ +[ + { + "name": "LOG_EN_AMSRAM", + "at": "00465e54", + "from": "00000000", + "to": "01000000", + "count": 4 + } +] \ No newline at end of file diff --git a/src/patches/patches.json b/src/patches/patches.json index d1e37ed..498bc02 100644 --- a/src/patches/patches.json +++ b/src/patches/patches.json @@ -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" + } ] \ No newline at end of file