diff --git a/Makefile b/Makefile index 5ac5516..c9b8018 100644 --- a/Makefile +++ b/Makefile @@ -53,15 +53,8 @@ dist: @copy /Y "$(BUILD_DIR)/src/micetools/miceboot\TrueCrypt.exe" "$(DIST_DIR)/Execute/TrueCrypt.exe" @copy /Y "$(BUILD_DIR)/src/micetools/miceboot\mxmaster.exe" "$(DIST_DIR)/Execute/S/mxmaster.exe" -# @copy /Y "$(BUILD_DIR)/src/micetools/micepatch\micepatch.exe" "$(DIST_DIR)/util/micepatch.exe" - @copy /Y "$(BUILD_DIR)/src/micetools/util\micedump.exe" "$(DIST_DIR)/util/micedump.exe" - @copy /Y "$(BUILD_DIR)/src/micetools/util\micedump.pdb" "$(DIST_DIR)/util/micedump.pdb" - @copy /Y "$(BUILD_DIR)/src/micetools/util\micetinker.exe" "$(DIST_DIR)/util/micetinker.exe" - @copy /Y "$(BUILD_DIR)/src/micetools/util\micemonitor.exe" "$(DIST_DIR)/util/micemonitor.exe" - @copy /Y "$(BUILD_DIR)/src/micetools/util\exio_test.exe" "$(DIST_DIR)/util/exio_test.exe" - @copy /Y "$(BUILD_DIR)/src/micetools/util\dongleDecrypt.exe" "$(DIST_DIR)/util/dongleDecrypt.exe" - @copy /Y "$(BUILD_DIR)/src/micetools/util\testBin.exe" "$(DIST_DIR)/util/testBin.exe" - @copy /Y "$(BUILD_DIR)/src/micetools/util\micegbdisk.exe" "$(DIST_DIR)/util/micegbdisk.exe" + @copy /Y "$(BUILD_DIR)/src/micetools/util\*.exe" "$(DIST_DIR)/util/" + @copy /Y "$(BUILD_DIR)/src/micetools/util\*.pdb" "$(DIST_DIR)/util/" @copy /Y "$(BUILD_DIR)/src/micetools/system_dummy\dummymaster\dummymaster.exe" "$(DIST_DIR)/system_dummy/dummymaster.exe" @copy /Y "$(BUILD_DIR)/src/micetools/system_dummy\dummyinstaller\dummyinstaller.exe" "$(DIST_DIR)/system_dummy/dummyinstaller.exe" diff --git a/src/micetools/dll/devices/smb_n2.c b/src/micetools/dll/devices/smb_n2.c index 0eaf483..d750577 100644 --- a/src/micetools/dll/devices/smb_n2.c +++ b/src/micetools/dll/devices/smb_n2.c @@ -5,6 +5,7 @@ #include #include "../../lib/mxk/mxk.h" +#include "../../segastructs.h" #include "../../sysconf.h" #include "_devices.h" @@ -50,36 +51,24 @@ typedef struct { DWORD m_Crc; BYTE Rsv04[12]; char m_KeyId[16]; - struct { - DWORD m_Crc; - DWORD m_Format; - char m_GameId[4]; - BYTE m_Region; - BYTE m_ModelType; - BYTE m_SystemFlag; - BYTE Rsv0f; - // - char m_PlatformId[3]; - BYTE m_DvdFlag; - DWORD m_NetworkAddr; - BYTE Unk00[88]; - BYTE m_Seed[16]; - } m_Appboot; + AM_APPBOOT_128 m_Appboot; } N2_KEYCHIP_INFO, *PN2_KEYCHIP_INFO; #pragma pack(pop) N2_KEYCHIP_INFO n2_keychip_info = { .m_KeyId = KEY_ID, .m_Appboot = { - .m_Format = 1, - .m_GameId = GAME_ID, - .m_Region = 0xff, - .m_ModelType = 2, - .m_SystemFlag = 0x24, - .m_PlatformId = HW_ID, - .m_DvdFlag = 1, - .m_NetworkAddr = - (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24), + .m_Header = { + .m_Format = 1, + .m_GameId = GAME_ID, + .m_Region = 0xff, + .m_ModelType = 2, + .m_SystemFlag = 0x24, + .m_PlatformId = HW_ID, + .m_DvdFlag = 1, + .m_NetworkAddr = + (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24), + }, }, }; @@ -134,8 +123,8 @@ WORD n2_read_keychip_id(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nO *nOut = (nbytes & 0xff) + 2; - n2_keychip_info.m_Appboot.m_Crc = amiCrc32RCalc(sizeof n2_keychip_info.m_Appboot - 4, - (LPBYTE)&n2_keychip_info.m_Appboot + 4, 0); + n2_keychip_info.m_Appboot.m_Header.m_Crc = amiCrc32RCalc( + sizeof n2_keychip_info.m_Appboot - 4, (LPBYTE)&n2_keychip_info.m_Appboot + 4, 0); n2_keychip_info.m_Crc = amiCrc32RCalc(sizeof n2_keychip_info - 4, (LPBYTE)&n2_keychip_info + 4, 0); diff --git a/src/micetools/dll/dllmain.c b/src/micetools/dll/dllmain.c index d09a97b..02b8781 100644 --- a/src/micetools/dll/dllmain.c +++ b/src/micetools/dll/dllmain.c @@ -95,13 +95,6 @@ void apply_patches(HMODULE hModule) { void prebind_hooks() { hook_all(); install_devices(); - // TODO: Figure out why we're needing to call this manually (medium priority) - // if (wcscmp(exeName, L"ALLNetProc.exe") == 0) { - // log_warning(plfBoot, "Making explicit call to OPENSSL_add_all_algorithms_noconf"); - - // // OPENSSL_add_all_algorithms_noconf - // ((void (*)(void))(0x00459770))(); - // } } void init_injection(HMODULE hModule) { @@ -117,8 +110,45 @@ void init_injection(HMODULE hModule) { MiceSetLogBasename(exeNameC); log_info(plfBoot, "Handover complete. Now executing within %ls", exeName); + // Start Mice FS + BOOL success = TRUE; + success &= MiceFSInit(); + if (success) success &= MiceFSAddRingedgeLayers(FALSE); + if (!success) { + log_error(plfFile, "Failed to initialise Mice FS stack: %d", GetLastError()); + exit(1); + } + + if (MiceConfig.mice.original && MiceConfig.mice.original[0] == '\0') { + CHAR szCurrentDir[MAX_PATH + 1]; + GetCurrentDirectoryA(sizeof szCurrentDir, szCurrentDir); + MiceFSAddLayer(RING_MOUNT_ORIGINAL, szCurrentDir); + MiceFSAddLayer(RING_MOUNT_GAME, szCurrentDir); + } else { + MiceFSAddLayer(RING_MOUNT_ORIGINAL, MiceConfig.mice.original); + MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.original); + } + if (MiceConfig.mice.patch && MiceConfig.mice.patch[0] != '\0') { + MiceFSAddLayer(RING_MOUNT_PATCH, MiceConfig.mice.patch); + MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.patch); + } + if (MiceConfig.mice.extend && MiceConfig.mice.extend[0] != '\0') { + MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, MiceConfig.mice.extend); + MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.extend); + } + if (MiceConfig.mice.extend2 && MiceConfig.mice.extend2[0] != '\0') { + MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, MiceConfig.mice.extend2); + MiceFSAddLayer(RING_MOUNT_GAME, MiceConfig.mice.extend2); + } + + if (success) success &= MiceFSAddDevLayers(); + + MiceFSSetCwd(RING_MOUNT_GAME); + + // Setup default COM devices init_com_devices(); + // Apply any in-memory patches requested if (MiceConfig.mice.apply_patches) apply_patches(hModule); // Columba: Driver-level memory access, used to read the DMI tables @@ -144,6 +174,21 @@ void init_injection(HMODULE hModule) { // Must be the last thing called! prebind_hooks(); + + // TODO: Figure out why we're needing to call this manually (medium priority) + if (wcscmp(exeName, L"ALLNetProc.exe") == 0) { + log_warning(plfBoot, "Making explicit call to OPENSSL_add_all_algorithms_noconf"); + + DWORD imageBase = GetImageBase(); + imageOffset = (DWORD)hModule - imageBase; + + // OPENSSL_add_all_algorithms_noconf (old exe) + // ((void (*)(void))(0x00459770 + imageOffset))(); + + // OPENSSL_add_all_algorithms_noconf (new exe) + ((void (*)(void))(0x00463480 + imageOffset))(); + } + setup_hooks(); } diff --git a/src/micetools/dll/drivers/mxparallel.c b/src/micetools/dll/drivers/mxparallel.c index b969223..3041716 100644 --- a/src/micetools/dll/drivers/mxparallel.c +++ b/src/micetools/dll/drivers/mxparallel.c @@ -10,20 +10,22 @@ BYTE parallel_data = 0x00; BYTE KEYCHIP_ID[16] = KEY_ID; BYTE _MAIN_ID[16] = MAIN_ID; -appboot_t APPBOOT = { - .format = 1, - .game_id = GAME_ID, - .region = 8 | 4 | 2 | 1, - .model_type = 2, - // Bitfield - // 1 = use flash for appboot - .system_flag = 0x24, - ._ = 0, - .platform_id = HW_ID, - .dvd_flag = 1, - .network_addr = (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24), - .__ = 0, - .seed = 1, +AM_APPBOOT_256 APPBOOT = { + .m_Header = { + .m_Format = 1, + .m_GameId = GAME_ID, + .m_Region = 8 | 4 | 2 | 1, + .m_ModelType = 2, + // Bitfield + // 1 = use flash for appboot + .m_SystemFlag = 0x24, + .Rsv0f = 0, + .m_PlatformId = HW_ID, + .m_DvdFlag = 1, + .m_NetworkAddr = (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24), + }, + .Rsv18 = 0, + .m_Seed = 1, }; billing_t BILLING = { .playlimit = 21046, @@ -46,9 +48,10 @@ uint32_t BILLING_PLAYCOUNT = 69420; overlappedComplete(len); \ } while (0) -BOOL WINAPI mxparallel_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, - DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, - LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { +BOOL WINAPI mxparallel_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, + LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, + DWORD nOutBufferSize, LPDWORD lpBytesReturned, + LPOVERLAPPED lpOverlapped) { log_trace(plfMxParallel, "DeviceIoControl(, 0x%08x, 0x%p, 0x%x, -, 0x%x, -, -)", dwIoControlCode, lpInBuffer, nInBufferSize, nOutBufferSize); @@ -273,7 +276,8 @@ void mxparallel_process_packet(BYTE* request) { log_warning(plfMxParallel, "GetAppBootInfo[%d] unexpected!", request[1]); } - APPBOOT.crc = amiCrc32RCalc(sizeof APPBOOT - 4, (unsigned char*)&APPBOOT + 4, 0); + APPBOOT.m_Header.m_Crc = + amiCrc32RCalc(sizeof APPBOOT - 4, (unsigned char*)&APPBOOT + 4, 0); for (int i = 0; i < sizeof APPBOOT; i += 16) { micexkSendPacket((unsigned char*)(&APPBOOT) + i); } diff --git a/src/micetools/dll/drivers/mxparallel.h b/src/micetools/dll/drivers/mxparallel.h index 980e331..a68be30 100644 --- a/src/micetools/dll/drivers/mxparallel.h +++ b/src/micetools/dll/drivers/mxparallel.h @@ -23,7 +23,7 @@ void micexkSendPacket(unsigned char* send_data); void micexkTransportRecv(unsigned char* buffer, int nbytes); void micexkRecvPacket(unsigned char* packet); -static appboot_t APPBOOT; +static AM_APPBOOT_256 APPBOOT; static billing_t BILLING; static uint32_t BILLING_PLAYCOUNT; diff --git a/src/micetools/dll/games.c b/src/micetools/dll/games.c index 97c6955..73dacf1 100644 --- a/src/micetools/dll/games.c +++ b/src/micetools/dll/games.c @@ -102,7 +102,10 @@ void mice_got_game_id(char game_id[4]) { MiceConfig.devices.com7 = ""; MiceConfig.devices.com8 = ""; } else { - if (game_id[0] != '\0') return log_warning(plfBoot, "Unknown game ID: %.4s", game_id); + if (game_id[0] != '\0') { + log_warning(plfBoot, "Unknown game ID: %.4s", game_id); + return; + } return; } diff --git a/src/micetools/dll/hooks/drive/disks.c b/src/micetools/dll/hooks/drive/disks.c index a2b11e4..0b3b716 100644 --- a/src/micetools/dll/hooks/drive/disks.c +++ b/src/micetools/dll/hooks/drive/disks.c @@ -126,8 +126,8 @@ physical_disk_t APM_HDD = { physical_disk_t* PHYSICAL_DISKS[] = { &SSD, &UPDATE_USB, - &APM_HDD, + // &APM_HDD, - &LOG_USB, + // &LOG_USB, // &ALPHA_DVD, }; diff --git a/src/micetools/dll/hooks/drive/drive.c b/src/micetools/dll/hooks/drive/drive.c index 4abd950..0d6d69a 100644 --- a/src/micetools/dll/hooks/drive/drive.c +++ b/src/micetools/dll/hooks/drive/drive.c @@ -474,7 +474,7 @@ void init_volume(disk_volume_t* vol) { StringFromGUID2(&guid, volume_name + 10, MAX_PATH + 1 - 10); file_hook_t* volume_hook = new_file_hook(volume_name); - log_misc(plfDrive, "Creating fake volume: %ls", volume_name); + log_misc(plfDrive, "Creating fake volume: %ls (for %s)", volume_name, vol->m_Name); volume_hook->DeviceIoControl = &volume_DeviceIoControl; volume_hook->hook_data = (void*)vol; @@ -702,7 +702,7 @@ void hook_drives() { q_drive->DeviceIoControl = &q_drive_DeviceIoControl; q_drive->ReadFile = &q_drive_ReadFile; hook_file(q_drive); - // ewwwwwwwwwwwwwwwwww + // TODO: ewwwwwwwwwwwwwwwwww file_hook_t* q_drive_lower = new_file_hook(L"\\\\.\\q:"); q_drive_lower->DeviceIoControl = &q_drive_DeviceIoControl; q_drive_lower->ReadFile = &q_drive_ReadFile; diff --git a/src/micetools/dll/hooks/files.c b/src/micetools/dll/hooks/files.c index 5e877b1..d0e5ea6 100644 --- a/src/micetools/dll/hooks/files.c +++ b/src/micetools/dll/hooks/files.c @@ -1,7 +1,22 @@ #define _MICE_FILES #include "files.h" + #include "../util/_util.h" +// TODO: This should be part of MiceFS I think +file_hook_t* MiceFSLocateHookW(_In_ LPCWSTR lpFileName); +file_hook_t* MiceFSLocateHookW(LPCWSTR lpFileName) { + 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)) { + return file_hook; + } + file_hook = file_hook->next; + } + return NULL; +} + HANDLE open_hook(file_hook_t* file_hook) { open_hook_t* opened = (open_hook_t*)malloc(sizeof(open_hook_t)); ZeroMemory(opened, sizeof *opened); @@ -97,78 +112,11 @@ void hook_file_with_buffer(LPCWSTR filename, LPBYTE buffer, DWORD nBytes, DWORD hook_file(hook); } -drive_redirect_t DRIVE_REDIRECT_TABLE[] = { - // Note: Had to create last_shime.log - { .drive = "C:\\Documents and Settings\\AppUser\\temp\\", .path = ".\\dev\\temp\\" }, - // {.drive = "C:\\ProgramData/boost_interprocess/", .path = "\\\\.\\ipc\\"}, -}; - -char _redirected_path[MAX_PATH]; - -file_hook_t* find_hook(LPCWSTR lpFileName) { - 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)) { - return file_hook; - } - file_hook = file_hook->next; - } - return NULL; -}; - -BOOL redirect_path(LPCSTR path, LPCSTR* redirected) { - for (int i = 0; i < sizeof DRIVE_REDIRECT_TABLE / sizeof DRIVE_REDIRECT_TABLE[0]; i++) { - drive_redirect_t row = DRIVE_REDIRECT_TABLE[i]; - if (PathPrefix(path, row.drive)) { - log_trace(plfHooks, "Redirecting '%s' to '%s'", path, row.path); - - size_t new_len = strlen(path) - strlen(row.drive) + strlen(row.path); - strcpy_s(_redirected_path, new_len + 1, row.path); - - char* dst = _redirected_path + 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_trace(plfHooks, "New filename: '%s'", _redirected_path); - - make_dirs(_redirected_path); - *redirected = _redirected_path; - return TRUE; - } - } - - // Don't redirect local paths - if (IsGamedataLocalPath(path)) return FALSE; - - if ((('a' <= path[0] && path[0] <= 'z') || ('A' <= path[0] && path[0] <= 'Z')) && - path[1] == ':' && (path[2] == '/' || path[2] == '\\')) { - ZeroMemory(_redirected_path, sizeof _redirected_path); - snprintf(_redirected_path, sizeof _redirected_path, "dev\\%c\\%s", char_lower(path[0]), - path + 3); - - make_dirs(_redirected_path); - *redirected = _redirected_path; - return TRUE; - } - - return FALSE; -} - -BOOL redirect_path_w(LPCWSTR lpFileName, LPCSTR* redirected) { - char cFileName[MAX_PATH] = { 0 }; - WideCharToMultiByte(CP_ACP, 0, lpFileName, wcslen(lpFileName), cFileName, sizeof cFileName, - NULL, NULL); - return redirect_path(cFileName, redirected); -} - HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { - file_hook_t* found_fh = find_hook(lpFileName); + file_hook_t* found_fh = MiceFSLocateHookW(lpFileName); if (found_fh != NULL) { HANDLE handle = open_hook(found_fh); log_info(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle); @@ -177,16 +125,10 @@ HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD d HANDLE handle; - LPCSTR redirected; - if (redirect_path_w(lpFileName, &redirected)) { - handle = TrueCreateFileA(redirected, dwDesiredAccess, dwShareMode, lpSecurityAttributes, - dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - log_misc(plfHooks, "CreateFileW(%s) -> 0x%p", redirected, handle); - } else { - handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, - dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); - log_misc(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle); - } + MiceFSRedirectPathW(lpFileName, &lpFileName); + handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, + dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); + log_misc(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle); return handle; } @@ -197,14 +139,14 @@ HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw WCHAR wideFileName[MAX_PATH + 1]; MultiByteToWideChar(CP_ACP, 0, lpFileName, -1, (LPWSTR)&wideFileName, MAX_PATH + 1); - file_hook_t* found_fh = find_hook(wideFileName); + file_hook_t* found_fh = MiceFSLocateHookW(wideFileName); if (found_fh != NULL) { HANDLE handle = open_hook(found_fh); log_info(plfHooks, "CreateFileA(%s) -> 0x%p", lpFileName, handle); return handle; } - redirect_path(lpFileName, &lpFileName); + MiceFSRedirectPathA(lpFileName, &lpFileName); HANDLE handle = TrueCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); log_misc(plfHooks, "CreateFileA(%s) -> 0x%p", lpFileName, handle); @@ -212,32 +154,24 @@ HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw } BOOL WINAPI FakePathFileExistsA(LPCSTR pszPath) { - log_misc(plfHooks, "PathFileExists(%s)", pszPath); - redirect_path(pszPath, &pszPath); + MiceFSRedirectPathA(pszPath, &pszPath); BOOL ret = TruePathFileExistsA(pszPath); + log_misc(plfHooks, "PathFileExistsA(%s) = %d", pszPath, ret); return ret; } BOOL WINAPI FakePathFileExistsW(LPCWSTR pszPath) { - log_misc(plfHooks, "PathFileExists(%ls)", pszPath); - LPCSTR redirected; - if (redirect_path_w(pszPath, &redirected)) { - return TruePathFileExistsA(redirected); - } - return TruePathFileExistsW(pszPath); + MiceFSRedirectPathW(pszPath, &pszPath); + BOOL ret = TruePathFileExistsW(pszPath); + log_misc(plfHooks, "PathFileExistsW(%ls) = %d", pszPath, ret); + return ret; } BOOL WINAPI FakeDeleteFileA(LPCSTR pszPath) { - LPCSTR redirected; - if (redirect_path(pszPath, &redirected)) { - return TrueDeleteFileA(redirected); - } + MiceFSRedirectPathA(pszPath, &pszPath); return TrueDeleteFileA(pszPath); } BOOL WINAPI FakeDeleteFileW(LPCWSTR pszPath) { - LPCSTR redirected; - if (redirect_path_w(pszPath, &redirected)) { - return TrueDeleteFileA(redirected); - } + MiceFSRedirectPathW(pszPath, &pszPath); return TrueDeleteFileW(pszPath); } @@ -387,38 +321,35 @@ BOOL WINAPI FakeCloseHandle(HANDLE hObject) { } int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) { - redirect_path((char*)path, &path); + MiceFSRedirectPathA((char*)path, &path); return True_stat64i32(path, buffer); }; DWORD WINAPI FakeGetFileAttributesA(LPCSTR lpFileName) { // The game quits out if MiniDump is present! - if (PathEqual(lpFileName, "Y:\\MiniDump\\") == 0) { + if (PathEqual(lpFileName, "Y:\\MiniDump\\")) { return 0; } - return (DWORD)-1; - LPCSTR redirected; - if (redirect_path(lpFileName, &redirected)) { - return TrueGetFileAttributesA(redirected); - } + MiceFSRedirectPathA(lpFileName, &lpFileName); return TrueGetFileAttributesA(lpFileName); } DWORD WINAPI FakeGetFileAttributesW(LPCWSTR lpFileName) { - LPCSTR redirected; - if (redirect_path_w(lpFileName, &redirected)) { - return TrueGetFileAttributesA(redirected); - } + MiceFSRedirectPathW(lpFileName, &lpFileName); return TrueGetFileAttributesW(lpFileName); } HANDLE WINAPI FakeFindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData) { - LPCSTR redirected; - if (redirect_path(lpFileName, &redirected)) { - return TrueFindFirstFileA(redirected, lpFindFileData); - } + MiceFSRedirectPathA(lpFileName, &lpFileName); return TrueFindFirstFileA(lpFileName, lpFindFileData); } +DWORD WINAPI FakeGetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer) { + strcpy_s(lpBuffer, nBufferLength, MiceFSGetCwd()); +} +DWORD WINAPI FakeGetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer) { + MultiByteToWideChar(CP_ACP, 0, MiceFSGetCwd(), -1, lpBuffer, nBufferLength); +} + void hook_io() { hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl); @@ -436,6 +367,10 @@ void hook_io() { hook("Shlwapi.dll", "PathFileExistsW", FakePathFileExistsW, (void**)&TruePathFileExistsW); hook("Kernel32.dll", "DeleteFileA", FakeDeleteFileA, (void**)&TrueDeleteFileA); hook("Kernel32.dll", "DeleteFileW", FakeDeleteFileW, (void**)&TrueDeleteFileW); + hook("Kernel32.dll", "GetCurrentDirectoryA", FakeGetCurrentDirectoryA, + (void**)&TrueGetCurrentDirectoryA); + hook("Kernel32.dll", "GetCurrentDirectoryW", FakeGetCurrentDirectoryW, + (void**)&TrueGetCurrentDirectoryW); hook("Kernel32.dll", "FindFirstFileA", FakeFindFirstFileA, (void**)&TrueFindFirstFileA); diff --git a/src/micetools/dll/hooks/files.h b/src/micetools/dll/hooks/files.h index c85694e..0dc5d37 100644 --- a/src/micetools/dll/hooks/files.h +++ b/src/micetools/dll/hooks/files.h @@ -1,5 +1,4 @@ #pragma once -#include "../common.h" #include "com.h" #ifndef _MICE_FILES @@ -41,6 +40,8 @@ _MICE_FILES BOOL(WINAPI* TrueDeleteFileW)(LPCWSTR lpFileName); _MICE_FILES HANDLE(WINAPI* TrueFindFirstFileA)(LPCSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData); _MICE_FILES DWORD(WINAPI* TrueGetFileAttributesA)(LPCSTR lpFileName); _MICE_FILES DWORD(WINAPI* TrueGetFileAttributesW)(LPCWSTR lpFileName); +_MICE_FILES DWORD(WINAPI* TrueGetCurrentDirectoryA)(DWORD nBufferLength, LPSTR lpBuffer); +_MICE_FILES DWORD(WINAPI* TrueGetCurrentDirectoryW)(DWORD nBufferLength, LPWSTR lpBuffer); typedef struct { HANDLE m_Handle; @@ -75,6 +76,10 @@ static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer); #define _SetFilePointer (TrueSetFilePointer ? TrueSetFilePointer : SetFilePointer) #define _SetFilePointerEx (TrueSetFilePointerEx ? TrueSetFilePointerEx : SetFilePointerEx) #define _PathFileExistsA (TruePathFileExistsA ? TruePathFileExistsA : PathFileExistsA) +#define _GetCurrentDirectoryA \ + (TrueGetCurrentDirectoryA ? TrueGetCurrentDirectoryA : GetCurrentDirectoryA) +#define _GetCurrentDirectoryW \ + (TrueGetCurrentDirectoryW ? TrueGetCurrentDirectoryA : GetCurrentDirectoryA) typedef struct drive_redirect { const CHAR* drive; diff --git a/src/micetools/dll/hooks/gui.c b/src/micetools/dll/hooks/gui.c index 9bc17bb..95d82d5 100644 --- a/src/micetools/dll/hooks/gui.c +++ b/src/micetools/dll/hooks/gui.c @@ -258,6 +258,9 @@ static HRESULT(STDMETHODCALLTYPE* TrueCreateDevice)(IDirect3D9* this, UINT Adapt DWORD BehaviorFlags, D3DPRESENT_PARAMETERS* pPresentationParameters, IDirect3DDevice9** ppReturnedDeviceInterface); +static HRESULT(STDMETHODCALLTYPE* TrueEnumAdapterModes)(IDirect3D9* this, UINT Adapter, + D3DFORMAT Format, UINT Mode, + D3DDISPLAYMODE* pMode); extern RECT monitorRect; HRESULT STDMETHODCALLTYPE FakeCreateDevice(IDirect3D9* this, UINT Adapter, D3DDEVTYPE DeviceType, @@ -309,6 +312,23 @@ HRESULT STDMETHODCALLTYPE FakeCreateDevice(IDirect3D9* this, UINT Adapter, D3DDE break; } } + log_info(plfD3D9, "Device created: %d", res); + return res; +} + +HRESULT STDMETHODCALLTYPE FakeEnumAdapterModes(IDirect3D9* this, UINT Adapter, D3DFORMAT Format, + UINT Mode, D3DDISPLAYMODE* pMode) { + HRESULT res = TrueEnumAdapterModes(this, Adapter, Format, Mode, pMode); + if (res == S_OK) { + // printf("Found: %dx%d @ %d\n", pMode->Width, pMode->Height, pMode->RefreshRate); + // TODO: Is this going to ever cause issues? + pMode->Width = MiceConfig.window.w; + pMode->Height = MiceConfig.window.h; + pMode->RefreshRate = 60; + } + + // printf("Request format: %d/%d. Result: %d\n", Format, Mode, res); + // pMode->Format = Format; return res; } @@ -320,6 +340,10 @@ IDirect3D9* WINAPI FakeDirect3DCreate9(UINT SDKVersion) { DWORD patch = (DWORD)&FakeCreateDevice; patch_at(&pD3D->lpVtbl->CreateDevice, (char*)&patch, 4); + TrueEnumAdapterModes = pD3D->lpVtbl->EnumAdapterModes; + patch = (DWORD)&FakeEnumAdapterModes; + patch_at(&pD3D->lpVtbl->EnumAdapterModes, (char*)&patch, 4); + return pD3D; }; diff --git a/src/micetools/dll/hooks/network.c b/src/micetools/dll/hooks/network.c index a6723bb..d4213a0 100644 --- a/src/micetools/dll/hooks/network.c +++ b/src/micetools/dll/hooks/network.c @@ -5,7 +5,7 @@ int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) { USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port); // Poorly exclude nxauth and mxgcatcher. // TODO: better - if (port != 40190 && port != 40110) { + if (port != 40190 && port != 40110 && port != 40102 && port != 40103) { log_info(plfNetwork, "connect(%hhu.%hhu.%hhu.%hhu:%hu)", (addr >> 24) & 0xff, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff, port); } @@ -26,7 +26,7 @@ int WINAPI Fake_bind(SOCKET s, const SOCKADDR* name, int namelen) { #define MAC_PREFIX_1 0xBB #define MAC_PREFIX_2 0xC1 DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder) { - log_info(plfNetwork, "Injecting fake IfTable"); + log_misc(plfNetwork, "Injecting fake IfTable"); MIB_IFROW* row; uint32_t nbytes; diff --git a/src/micetools/dll/hooks/processes.c b/src/micetools/dll/hooks/processes.c index 187ceb8..8acf008 100644 --- a/src/micetools/dll/hooks/processes.c +++ b/src/micetools/dll/hooks/processes.c @@ -1,17 +1,13 @@ #include "processes.h" -const wchar_t* HOOK_BINARIES[] = { - L"app\\ALLNetProc.exe", - L"app\\CameraUploader.exe", - L"app\\GmSync.exe", -}; - BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes, BOOL bInheritHandles, DWORD dwCreationFlags, LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOW lpStartupInfo, LPPROCESS_INFORMATION lpProcessInformation) { + // Somewhat janky way to identify when this is a loopback from start_and_inject + // TODO: _CreateProcessA() if (dwCreationFlags & CREATE_SUSPENDED) { return TrueCreateProcessA(lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, @@ -19,10 +15,33 @@ BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, lpProcessInformation); } + if (strcmp(lpCommandLine, "s:\\mxkeychip.exe") == 0 || + strcmp(lpCommandLine, "C:\\WINDOWS\\system32\\regini.exe S:\\default_regset.txt") == 0) { + if (lpProcessInformation) { + lpProcessInformation->hProcess = CreateEventA(NULL, FALSE, TRUE, NULL); + lpProcessInformation->hThread = CreateEventA(NULL, FALSE, TRUE, NULL); + } + return TRUE; + } + + CHAR szApplicationName[MAX_PATH + 1]; + if (lpApplicationName == NULL) { + strcpy_s(szApplicationName, sizeof szApplicationName, lpCommandLine); + for (int i = 0; i < sizeof szApplicationName; i++) { + if (szApplicationName[i] == ' ') { + szApplicationName[i] = '\0'; + break; + } + } + + lpApplicationName = szApplicationName; + } + + MiceFSRedirectPathA(lpApplicationName, &lpApplicationName); log_info(plfProcesses, "CreateProcessA %s %s", lpApplicationName, lpCommandLine); - return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationName, lpCommandLine, - MICELIB, FALSE, 0, NULL, 0, lpProcessInformation); + return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationName, lpCommandLine, MICELIB, FALSE, + 0, NULL, 0, lpProcessInformation); } BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes, @@ -32,16 +51,40 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine, LPPROCESS_INFORMATION lpProcessInformation) { log_info(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine); - CHAR applicationName[MAX_PATH + 1]; - WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName, - NULL, NULL); + if (wcsncmp(lpCommandLine, L"chkdsk.exe", wcslen(L"chkdsk.exe")) == 0) { + if (lpProcessInformation) { + lpProcessInformation->hProcess = CreateEventA(NULL, FALSE, TRUE, NULL); + lpProcessInformation->hThread = CreateEventA(NULL, FALSE, TRUE, NULL); + } + return TRUE; + } int nMultiChars = WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, NULL, 0, NULL, NULL); LPSTR commandLine = malloc(nMultiChars); WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, nMultiChars, NULL, NULL); - return start_and_inject(INVALID_HANDLE_VALUE, applicationName, commandLine, MICELIB, - FALSE, 0, NULL, 0, lpProcessInformation); + CHAR szApplicationName[MAX_PATH + 1]; + LPCSTR lpApplicationNameA; + if (lpApplicationName == NULL) { + strcpy_s(szApplicationName, sizeof szApplicationName, commandLine); + for (int i = 0; i < sizeof szApplicationName; i++) { + if (szApplicationName[i] == ' ') { + szApplicationName[i] = '\0'; + break; + } + } + + lpApplicationNameA = szApplicationName; + } else { + WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, szApplicationName, + sizeof szApplicationName, NULL, NULL); + + lpApplicationNameA = szApplicationName; + } + + MiceFSRedirectPathA(lpApplicationNameA, &lpApplicationNameA); + return start_and_inject(INVALID_HANDLE_VALUE, lpApplicationNameA, commandLine, MICELIB, FALSE, + 0, NULL, 0, lpProcessInformation); } BOOL WINAPI FakeGetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) { @@ -52,5 +95,5 @@ BOOL WINAPI FakeGetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) { void hook_processes() { hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW); hook("Kernel32.dll", "CreateProcessA", FakeCreateProcessA, (void**)&TrueCreateProcessA); - // hook("Kernel32.dll", "GetExitCodeProcess", FakeGetExitCodeProcess, NULL); + hook("Kernel32.dll", "GetExitCodeProcess", FakeGetExitCodeProcess, NULL); } diff --git a/src/micetools/dll/hooks/registry.c b/src/micetools/dll/hooks/registry.c index 365031a..f8e591a 100644 --- a/src/micetools/dll/hooks/registry.c +++ b/src/micetools/dll/hooks/registry.c @@ -1,29 +1,34 @@ #include "registry.h" +// TODO: Do we want to make a proper registry emulation? + +static BOOL bHALDeleted = FALSE; + LSTATUS WINAPI FakeRegCloseKey(HKEY hKey) { - log_trace(plfRegistry, "RegCloseKey %08x", hKey); + log_misc(plfRegistry, "RegCloseKey %08x", hKey); return ERROR_SUCCESS; } LSTATUS WINAPI FakeRegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions, REGSAM samDesired, const LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition) { - log_trace(plfRegistry, "RegCreateKeyExA %08x %s", hKey, lpSubKey); + log_misc(plfRegistry, "RegCreateKeyExA %08x %s", hKey, lpSubKey); return ERROR_SUCCESS; } LSTATUS WINAPI FakeRegDeleteKeyA(HKEY hKey, LPCSTR lpSubKey) { - log_trace(plfRegistry, "RegDeleteKeyA %08x %s", hKey, lpSubKey); + log_misc(plfRegistry, "RegDeleteKeyA %08x %s", hKey, lpSubKey); + bHALDeleted = TRUE; return ERROR_SUCCESS; } LSTATUS WINAPI FakeRegDeleteKeyValueA(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpValueName) { - log_trace(plfRegistry, "RegDeleteKeyValueA %08x %s %s", hKey, lpSubKey, lpValueName); + log_misc(plfRegistry, "RegDeleteKeyValueA %08x %s %s", hKey, lpSubKey, lpValueName); return ERROR_SUCCESS; } LSTATUS WINAPI FakeRegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved, LPSTR lpClass, LPDWORD lpcchClass, PFILETIME lpftLastWriteTime) { - log_trace(plfRegistry, "RegEnumKeyExA %08x[%d]", hKey, dwIndex); - if (dwIndex == 0) { + log_misc(plfRegistry, "RegEnumKeyExA %08x[%d]", hKey, dwIndex); + if (dwIndex == 0 && !bHALDeleted) { strcpy(lpName, "Direct3D HAL"); return ERROR_SUCCESS; } @@ -32,7 +37,7 @@ LSTATUS WINAPI FakeRegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD LSTATUS WINAPI FakeRegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName, LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) { - log_trace(plfRegistry, "RegEnumValueA %08x %s", hKey, lpValueName); + log_misc(plfRegistry, "RegEnumValueA %08x %s", hKey, lpValueName); return ERROR_NO_MORE_ITEMS; } diff --git a/src/micetools/dll/hooks/time.c b/src/micetools/dll/hooks/time.c index 95e1713..798ac1a 100644 --- a/src/micetools/dll/hooks/time.c +++ b/src/micetools/dll/hooks/time.c @@ -49,7 +49,6 @@ BOOL WINAPI Fake_GetLocalTime(SYSTEMTIME* lpSystemTime) { return TrueGetLocalTime(lpSystemTime); } BOOL WINAPI Fake_GetSystemTime(SYSTEMTIME* lpSystemTime) { - log_trace(plfTime, "GetSystemTime"); if (stCache) { memcpy(lpSystemTime, &systemTime, sizeof systemTime); return TRUE; diff --git a/src/micetools/launcher/main.c b/src/micetools/launcher/main.c index e161e19..01f9514 100644 --- a/src/micetools/launcher/main.c +++ b/src/micetools/launcher/main.c @@ -129,7 +129,7 @@ static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) { } if (!inVt100) WriteFile(hLogFile, &(readBuffer[i]), 1, &nWrote, NULL); } - FlushFileBuffers(hLogFile); + // FlushFileBuffers(hLogFile); } } } diff --git a/src/micetools/launcher/spawn.c b/src/micetools/launcher/spawn.c index 4b79eac..5a659e1 100644 --- a/src/micetools/launcher/spawn.c +++ b/src/micetools/launcher/spawn.c @@ -4,9 +4,12 @@ #include "../lib/mice/mice.h" spawn_t mxspawns[3] = { - { "keychip", SPAWN_DUMMY, MdkThreadProc, MxkThreadProc }, - { "master", SPAWN_DUMMY, MdmThreadProc, NULL }, - { "installer", SPAWN_DUMMY, MdiThreadProc, NULL }, + // { "keychip", SPAWN_DUMMY, MdkThreadProc, MxkThreadProc }, + // { "master", SPAWN_DUMMY, MdmThreadProc, NULL }, + // { "installer", SPAWN_DUMMY, MdiThreadProc, NULL }, + { "keychip", SPAWN_NONE, MdkThreadProc, MxkThreadProc }, + { "master", SPAWN_NONE, MdmThreadProc, NULL }, + { "installer", SPAWN_NONE, MdiThreadProc, NULL }, }; int mxkMain(); diff --git a/src/micetools/lib/mice/config.def b/src/micetools/lib/mice/config.def index d988c3e..6776e28 100644 --- a/src/micetools/lib/mice/config.def +++ b/src/micetools/lib/mice/config.def @@ -18,6 +18,10 @@ CFG_bool(mice, log_to_file, true, "Also log out to log_file") CFG_str(mice, log_file, "log.txt", "The file to log to if log_to_file is enabled") CFG_bool(mice, apply_patches, true, "Load and apply patches from patches_file at runtime") CFG_str(mice, patches_file, "patches.index", "The file to read patches from") +CFG_str(mice, original, "", "Location of the 'original' partition. The current directory is used by default") +CFG_str(mice, patch, "", "Location of the 'patch' partition. No patch is configured by default") +CFG_str(mice, extend, "", "Location of the 'extend' partition. No extend is configured by default") +CFG_str(mice, extend2, "", "Location of the 'extend2' partition. No extend2 is configured by default") ENDSECTION(mice) SECTION(launcher, "These options are only used during initial bootstrapping") diff --git a/src/micetools/lib/mice/kcf.c b/src/micetools/lib/mice/kcf.c new file mode 100644 index 0000000..ea28ceb --- /dev/null +++ b/src/micetools/lib/mice/kcf.c @@ -0,0 +1,41 @@ +#include "kcf.h" + +#include +#include + +inline static void scramble(LPBYTE data, DWORD a, DWORD b, DWORD c, DWORD d) { + BYTE temp; + + temp = data[a]; + data[a] = data[b]; + data[b] = temp; + + temp = data[c]; + data[c] = data[d]; + data[d] = temp; +} + +BOOL MiceParseKcf(LPCSTR lpFileName, PAM_KCF pKcf) { + // Load in scrambled data + HANDLE hFile = + CreateFileA(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return FALSE; + } + DWORD nNumberOfBytesRead; + if (!ReadFile(hFile, pKcf, sizeof *pKcf, &nNumberOfBytesRead, NULL)) { + CloseHandle(hFile); + return FALSE; + } + CloseHandle(hFile); + if (nNumberOfBytesRead != sizeof *pKcf) { + return FALSE; + } + + // Unscramble + scramble(pKcf->m_Seed, 1, 8, 12, 15); + scramble(pKcf->m_Key, 0, 4, 2, 14); + scramble(pKcf->m_Iv, 0, 11, 5, 15); + + return TRUE; +} diff --git a/src/micetools/lib/mice/kcf.h b/src/micetools/lib/mice/kcf.h new file mode 100644 index 0000000..f9d4cbc --- /dev/null +++ b/src/micetools/lib/mice/kcf.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +#include "../../segastructs.h" + +#pragma pack(push, 1) +typedef struct _AM_KCF { + AM_APPBOOT m_Header; + BYTE m_AppData[216]; + BYTE m_Seed[16]; + BYTE m_Key[16]; + BYTE m_Iv[16]; + BYTE Unk[128]; +} AM_KCF, *PAM_KCF; +#pragma pack(pop) + +BOOL MiceParseKcf(LPCSTR lpFileName, PAM_KCF pKcf); diff --git a/src/micetools/lib/mice/meson.build b/src/micetools/lib/mice/meson.build index 7510a98..738da92 100644 --- a/src/micetools/lib/mice/meson.build +++ b/src/micetools/lib/mice/meson.build @@ -6,6 +6,8 @@ mice_lib = static_library( 'patch.c', 'ringbuf.c', 'config.c', + 'kcf.c', + 'micefs.c', ], link_with: [ inih.get_variable('lib_inih'), diff --git a/src/micetools/lib/mice/mice.h b/src/micetools/lib/mice/mice.h index a74d37d..32b6998 100644 --- a/src/micetools/lib/mice/mice.h +++ b/src/micetools/lib/mice/mice.h @@ -8,7 +8,9 @@ #include "config.h" #include "exe.h" #include "ioctl.h" +#include "kcf.h" #include "log.h" +#include "micefs.h" #include "patch.h" #include "ringbuf.h" #include "version_fallback.h" diff --git a/src/micetools/lib/mice/micefs.c b/src/micetools/lib/mice/micefs.c new file mode 100644 index 0000000..b1c6b76 --- /dev/null +++ b/src/micetools/lib/mice/micefs.c @@ -0,0 +1,323 @@ +#include "micefs.h" + +#pragma comment(lib, "Shlwapi.lib") +#include +#include +#include +#include + +// TODO: This is awful +extern BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath); +#define _PathFileExistsA (TruePathFileExistsA ? TruePathFileExistsA : PathFileExistsA) + +static char miceFSCwd[MAX_PATH + 1]; + +/* Filesystem layer storage. When locating files, the first found result will be used. New items are + * inserted at the start of the list. */ +static MICE_FS_LAYER miceFsRoot = { + .m_lpMountPoint = NULL, + .m_lpTargetPath = NULL, + .m_Next = NULL, +}; + +static volatile LONG miceFsLockCount = 0; +#define MiceTakeLockExclusive(lock) \ + do { \ + LONG __miceLockCount = (lock); \ + if (__miceLockCount == 0) { \ + if (InterlockedCompareExchange(&(lock), -1, 0) == 0) break; \ + } \ + SwitchToThread(); \ + } while (1) +#define MiceReleaseLockExclusive(lock) \ + do { \ + (lock) = 0; \ + } while (0) + +#define MiceTakeLockShared(lock) \ + do { \ + LONG __miceLockCount = (lock); \ + if (__miceLockCount != -1) { \ + if (InterlockedCompareExchange(&(lock), __miceLockCount + 1, __miceLockCount) == \ + __miceLockCount) \ + break; \ + } \ + SwitchToThread(); \ + } while (1) +#define MiceReleaseLockShared(lock) \ + do { \ + (lock)--; \ + } while (0) + +BOOL MiceFSInit(VOID) { + // By not using MiceFSSetCwd we can save a buffer allocation + GetCurrentDirectoryA(sizeof miceFSCwd, miceFSCwd); + return TRUE; +} + +LPCSTR MiceFSGetCwd(VOID) { return miceFSCwd; } +VOID MiceFSSetCwd(LPCSTR lpNewCwd) { strcpy_s(miceFSCwd, sizeof miceFSCwd, lpNewCwd); } + +BOOL MiceFSAddLayer(LPCSTR lpMountPoint, LPCSTR lpTargetPath) { + DWORD dwMountLength = strlen(lpMountPoint) + 1; + DWORD dwTargetlength = strlen(lpTargetPath) + 1; + if (dwMountLength <= 1 || dwTargetlength <= 1) { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + PMICE_FS_LAYER layer = malloc(sizeof *layer); + if (layer == NULL) return FALSE; + + LPSTR szMountPoint = malloc(MAX_PATH + 1); + if (szMountPoint == NULL) { + free(layer); + return FALSE; + } + LPSTR szTargetPath = malloc(MAX_PATH + 1); + if (szTargetPath == NULL) { + free(szMountPoint); + free(layer); + return FALSE; + } + + ZeroMemory(szMountPoint, MAX_PATH + 1); + if (!GetFullPathNameA(lpMountPoint, MAX_PATH + 1, szMountPoint, NULL)) { + free(szTargetPath); + free(szMountPoint); + free(layer); + return FALSE; + } + ZeroMemory(szTargetPath, MAX_PATH + 1); + if (!GetFullPathNameA(lpTargetPath, MAX_PATH + 1, szTargetPath, NULL)) { + free(szTargetPath); + free(szMountPoint); + free(layer); + return FALSE; + } + + // Mount and target are promoted to LPCSTR from LPSTR here + layer->m_lpMountPoint = szMountPoint; + layer->m_lpTargetPath = szTargetPath; + + // Commit ourselves to the FS + MiceTakeLockExclusive(miceFsLockCount); + layer->m_Next = miceFsRoot.m_Next; + miceFsRoot.m_Next = layer; + MiceReleaseLockExclusive(miceFsLockCount); + + SetLastError(ERROR_SUCCESS); + return TRUE; +} + +BOOL MiceFSAddDevLayers(VOID) { + CHAR szMountPoint[4]; + CHAR szTargetPath[MAX_PATH + 1]; + ZeroMemory(szTargetPath, sizeof szTargetPath); + strcpy_s(szTargetPath, sizeof szTargetPath, ".\\dev\\x\\"); + + BOOL success = TRUE; + for (int i = 0; i < 26; i++) { + szMountPoint[0] = 'A' + (char)i; + szMountPoint[1] = ':'; + szMountPoint[2] = '\\'; + szMountPoint[3] = '\0'; + + szTargetPath[6] = 'a' + (char)i; + + success &= MiceFSAddLayer(szMountPoint, szTargetPath); + } + return success; +} +BOOL MiceFSAddRingedgeLayers(BOOL bIsOsupdate) { + BOOL success = TRUE; + + // Windows file systems + success &= MiceFSAddLayer(RING_MOUNT_OS, "mount/os"); + success &= MiceFSAddLayer(RING_MOUNT_EXTEND, "mount/extend"); + success &= MiceFSAddLayer(RING_MOUNT_RECOVERY, "mount/os_recovery"); + + // TrueCrypt Volumes + success &= MiceFSAddLayer(RING_MOUNT_SYSTEM, "mount/system"); + success &= MiceFSAddLayer(RING_MOUNT_ORIGINAL, "mount/original"); + success &= MiceFSAddLayer(RING_MOUNT_PATCH, "mount/patch"); + if (bIsOsupdate) { + success &= MiceFSAddLayer(RING_MOUNT_OS_UPDATE, "mount/os_update"); + success &= MiceFSAddLayer(RING_MOUNT_OS_DEFAULT_DRVIERS, "mount/os_default_drivers"); + } else { + success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, "mount/extend/extend"); + success &= MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, "mount/extend/extend2"); + } + + // geminifs + success &= MiceFSAddLayer(RING_MOUNT_GAME, "mount/original"); + success &= MiceFSAddLayer(RING_MOUNT_GAME, "mount/patch"); + + // External media + success &= MiceFSAddLayer(RING_MOUNT_APM, "mount/apm"); + success &= MiceFSAddLayer(RING_MOUNT_AM_LOG, "mount/am_log"); + success &= MiceFSAddLayer(RING_MOUNT_DVD, "mount/dvd"); + success &= MiceFSAddLayer(RING_MOUNT_DEV, "mount/dev"); + + // TODO: Configurable! + MiceFSAddLayer("R:", "H:\\Arcades\\USBs\\FiNALE_DL\\usb"); + MiceFSAddLayer("S:", "C:\\Users\\Nathan\\Desktop\\ac_research\\sega\\S-Drive"); + MiceFSAddLayer("C:\\System\\Execute", "C:\\Users\\Nathan\\Desktop\\ac_research\\sega\\S-Drive"); + + return success; +} + +LPSTR MiceFSPathTokA(LPSTR lpPath, DWORD dwPath, PMICE_FS_PATH_TOK lpWork) { + DWORD dwWorkPtr = 0; + LPSTR lpPathStart; + + if (lpPath != NULL) { + // A zero-length string has no tokens (as oppoed to a single empty token) + if (lpPath[0] == '\0') { + SetLastError(ERROR_SUCCESS); + return NULL; + } + + lpWork->m_lpPath = lpPath; + lpPathStart = lpPath; + lpWork->m_dwWorkPtr = dwWorkPtr; + lpWork->m_dwPath = dwPath; + } else { + // We just finished processing the last token! + if (lpWork->m_cSave == '\0') { + SetLastError(ERROR_SUCCESS); + return NULL; + } + + dwWorkPtr = lpWork->m_dwWorkPtr; + lpPath = lpWork->m_lpPath; + lpPath[dwWorkPtr++] = lpWork->m_cSave; + lpPathStart = lpPath + dwWorkPtr; + } + DWORD dwComponentStart = dwWorkPtr; + + for (; dwWorkPtr < lpWork->m_dwPath; dwWorkPtr++) { + CHAR cWork = lpPath[dwWorkPtr]; + if (cWork == '\0' || cWork == '\\' || cWork == '/') { + // Omit 0-length components, with the exception of the very first position in the + // string, as that would indicate a double-backslash prefix, which is syntax for a path + // namespace and should not be treated the same as a single backslash there. + if (dwWorkPtr == dwComponentStart && dwWorkPtr != 0) { + // Special case: Trailing slashes + if (cWork == '\0') { + SetLastError(ERROR_SUCCESS); + return NULL; + } + dwComponentStart++; + continue; + } + + lpWork->m_dwComponentStart = dwComponentStart; + lpWork->m_dwWorkPtr = dwWorkPtr; + lpWork->m_cSave = cWork; + lpPath[dwWorkPtr] = '\0'; + + return lpPathStart; + } + } + // Will only occur if lpPath was not null terminated within dwPath bytes. lpPathStart at this + // point does not point to a null-terminated string, and therefore we cannot return it. + // This is technically an error condition, so allow diligent users to catch this + SetLastError(ERROR_BUFFER_OVERFLOW); + return NULL; +} + +VOID MiceFSPathTokRestA(PMICE_FS_PATH_TOK lpWork, LPSTR lpPath, DWORD dwPath) { + lpWork->m_lpPath[lpWork->m_dwWorkPtr] = lpWork->m_cSave; + memcpy_s(lpPath, dwPath, lpWork->m_lpPath + lpWork->m_dwComponentStart, + lpWork->m_dwPath - lpWork->m_dwComponentStart); +} + +BOOL MiceFSMatchPathA(LPCSTR lpPath, LPCSTR lpPrefix, LPSTR lpTail, DWORD dwTail) { + CHAR szPath[MAX_PATH + 1]; + CHAR szPrefix[MAX_PATH + 1]; + + strcpy_s(szPath, sizeof szPath, lpPath); + strcpy_s(szPrefix, sizeof szPrefix, lpPrefix); + + MICE_FS_PATH_TOK pathTok; + MICE_FS_PATH_TOK matchTok; + LPSTR pathComponent = MiceFSPathTokA(szPath, _countof(szPath), &pathTok); + LPSTR prefixComponent = MiceFSPathTokA(szPrefix, _countof(szPrefix), &matchTok); + + while (pathComponent && prefixComponent) { + if (lstrcmpiA(pathComponent, prefixComponent) != 0) return FALSE; + + pathComponent = MiceFSPathTokNextA(&pathTok); + prefixComponent = MiceFSPathTokNextA(&matchTok); + } + + // We still had parts of the prefic left! + if (prefixComponent) return FALSE; + + if (lpTail && dwTail) { + if (pathComponent) + MiceFSPathTokRestA(&pathTok, lpTail, dwTail); + else + lpTail[0] = '\0'; + } + + return TRUE; +} + +inline static DWORD MiceFSGetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, + LPSTR* lpFilePart) { + if (PathIsRelativeA(lpFileName)) { + CHAR newPath[MAX_PATH + 1]; + PathCombineA(newPath, miceFSCwd, lpFileName); + return GetFullPathNameA(newPath, nBufferLength, lpBuffer, lpFilePart); + } + return GetFullPathNameA(lpFileName, nBufferLength, lpBuffer, lpFilePart); +} + +// TODO: Ewwwwwwww why are these globals (it's a bodge to not need free) +static char _redirected_path[MAX_PATH + 1]; +static wchar_t _redirected_path_w[MAX_PATH + 1]; +BOOL MiceFSRedirectPathA(LPCSTR lpFilename, LPCSTR* pszRedirected) { + CHAR szExpanded[MAX_PATH + 1]; + if (!MiceFSGetFullPathNameA(lpFilename, sizeof szExpanded, szExpanded, NULL)) return FALSE; + + MiceTakeLockShared(miceFsLockCount); + + PMICE_FS_LAYER layer = miceFsRoot.m_Next; + CHAR szTail[MAX_PATH + 1]; + BOOL bFound = FALSE; + while (layer) { + if (MiceFSMatchPathA(szExpanded, layer->m_lpMountPoint, szTail, sizeof szTail)) { + _redirected_path[0] = '\0'; + PathCombineA(_redirected_path, layer->m_lpTargetPath, szTail); + *pszRedirected = _redirected_path; + + if (_PathFileExistsA(_redirected_path)) { + MiceReleaseLockShared(miceFsLockCount); + return TRUE; + } + bFound = TRUE; + } + + layer = layer->m_Next; + } + MiceReleaseLockShared(miceFsLockCount); + return bFound; +} + +// TODO: This is kinda awful, because we do two roundtrips through string conversion... +BOOL MiceFSRedirectPathW(LPCWSTR lpFileName, LPCWSTR* pszRedirected) { + char szFileName[MAX_PATH] = { 0 }; + WideCharToMultiByte(CP_ACP, 0, lpFileName, wcslen(lpFileName), szFileName, sizeof szFileName, + NULL, NULL); + + LPCSTR szRedirected; + BOOL bRedirected = MiceFSRedirectPathA(szFileName, &szRedirected); + + if (!bRedirected) return FALSE; + + MultiByteToWideChar(CP_ACP, 0, szRedirected, -1, _redirected_path_w, sizeof _redirected_path_w); + *pszRedirected = _redirected_path_w; + return bRedirected; +} diff --git a/src/micetools/lib/mice/micefs.h b/src/micetools/lib/mice/micefs.h new file mode 100644 index 0000000..4b7785b --- /dev/null +++ b/src/micetools/lib/mice/micefs.h @@ -0,0 +1,155 @@ +#pragma once + +#include + +#define RING_MOUNT_OS "C:" +#define RING_MOUNT_EXTEND "Y:" +#define RING_MOUNT_RECOVERY "Z:" +#define RING_MOUNT_SYSTEM "S:" +#define RING_MOUNT_ORIGINAL "O:" +#define RING_MOUNT_PATCH "P:" +#define RING_MOUNT_OS_UPDATE "W:" +#define RING_MOUNT_OS_DEFAULT_DRVIERS "V:" +#define RING_MOUNT_EXTEND_VOL "W:" +#define RING_MOUNT_EXTEND2_VOL "V:" +#define RING_MOUNT_GAME "X:" +#define RING_MOUNT_APM "I:" +#define RING_MOUNT_AM_LOG "L:" +#define RING_MOUNT_DVD "Q:" +#define RING_MOUNT_DEV "Z:" + +typedef enum { + MICE_FS_NS_WIN32, + MICE_FS_NS_DEVICE, +} MICE_FS_NAMESPACE; + +typedef struct MICE_FS_PATH MICE_FS_PATH, *PMICE_FS_PATH; +struct MICE_FS_PATH { + MICE_FS_NAMESPACE m_dwNamespace; + LPCSTR m_lpComponents; +}; + +typedef struct MICE_FS_LAYER MICE_FS_LAYER, *PMICE_FS_LAYER; +struct MICE_FS_LAYER { + LPCSTR m_lpMountPoint; + LPCSTR m_lpTargetPath; + PMICE_FS_LAYER m_Next; +}; + +typedef struct { + LPSTR m_lpPath; + DWORD m_dwPath; + DWORD m_dwComponentStart; + DWORD m_dwWorkPtr; + CHAR m_cSave; +} MICE_FS_PATH_TOK, *PMICE_FS_PATH_TOK; + +/** + * @brief Initialise the Mice filesystem emulation stack + */ +BOOL MiceFSInit(VOID); + +/** + * @brief Get the currently emulated CWD + */ +LPCSTR MiceFSGetCwd(VOID); +/** + * @brief Set the currently emulated CWD + * + * @param lpNewCwd New CWD + */ +VOID MiceFSSetCwd(LPCSTR lpNewCwd); + +/** + * @brief Add a new layer to the emulation stack + * Layers added later will be used preferentially. + * + * @param lpMountPoint Virtual path to mount this layer at + * @param lpTargetPath Real location that will serve files for this layer + * @return BOOL Success. Use GetLastError to identify the cause of failiure. + */ +BOOL MiceFSAddLayer(_In_z_ LPCSTR lpMountPoint, _In_z_ LPCSTR lpTargetPath); + +/** + * @brief Add layers for all drive letters backed by ".\dev\[letter]" + * If used, this should be the first set of layers added, to act as a fallback + * + * @return BOOL Success. As this function adds 26 layers, and failiure could occur at any time, + * failiure of this function should be considered a fatal failiure and MiceFS should be considered + * to be in an indeterminate state. + */ +BOOL MiceFSAddDevLayers(VOID); + +/** + * @brief Add layers for all RingEdge system partitions. + * + * @return BOOL Success. See MiceFSAddDevLayers rearding when this is FALSE. + */ +BOOL MiceFSAddRingedgeLayers(BOOL bIsOsupdate); + +/** + * @brief Tokenise a path, returning each individual token (think, strtok) + * + * The first call to this function should provide lpPath and dwPath to initialise the operation. + * Subsequence calls should provide NULL and 0 respectively. The "MiceFSPathTokNextA" macro aids in + * this. + * + * Empty strings are defined as having no components, and as such NULL will be returned on the first + * call. + * + * Multiple slashes in a row will be combined, rather than returning an empty component. + * + * Special handling is applied for paths starting with slashes. The first component returned will be + * a 0-length string. This is the only time this function returns 0-length strings. The second + * component will contain all but the first slash. + * That is, \\.\demo will return "", "\.", "demo", NULL. Tihis is done to allow handling of path + * namespaces. + * + * @param lpPath Path to split. This buffer will be modified! + * @param dwPath Length of lpPath including the null termination + * @param lpWork Pointer to a work structure to identify this path operation + * @return LPSTR The path component, or NULL when the operation is completed. + */ +LPSTR MiceFSPathTokA(_In_reads_opt_z_(dwPath) LPSTR lpPath, _In_ DWORD dwPath, + _In_ PMICE_FS_PATH_TOK lpWork); +#define MiceFSPathTokNextA(lpWork) MiceFSPathTokA(NULL, 0, lpWork) + +/** + * @brief Return the full path in a tokenising buffer, starting with the current component + * + * @param lpWork Work buffer + * @param lpPath Destination buffer + * @param dwPath Size of lpPath + */ +VOID MiceFSPathTokRestA(_In_ PMICE_FS_PATH_TOK lpWork, _Out_writes_z_(dwPath) LPSTR lpPath, + _In_ DWORD dwPath); + +/** + * @brief Attempt to a path against a prefix + * + * @param lpPath The path to test + * @param lpPrefix The prefix to match against + * @param lpTail (Optional) Received the tail of lpPath after lpPrefix + * @param dwTail Size of lptail + */ +BOOL MiceFSMatchPathA(_In_z_ LPCSTR lpPath, _In_z_ LPCSTR lpPrefix, + _Out_writes_z_(dwTail) LPSTR lpTail, _In_ DWORD dwTail); + +/** + * @brief Redirect a virtual path to a real path using Mice FS layers. + * + * The first layer to match with an existing file on disk will be selected. + * + * If redirection does not occur, the value of pszRedirected is unchanged. + * + * It is safe to (lpFilename, &lpFilename) as an argument pair. + * + * @param lpFileName Virtual filename + * @param pszRedirected Redirected real filename + * @return BOOL If redirection occured + */ +BOOL MiceFSRedirectPathA(_In_z_ LPCSTR lpFileName, _Out_ LPCSTR* pszRedirected); +/** + * @brief Wide variant of MiceFSRedirectPathA + */ +BOOL MiceFSRedirectPathW(_In_z_ LPCWSTR lpFileName, _Out_ LPCWSTR* pszRedirected); diff --git a/src/micetools/lib/mxk/mxk.c b/src/micetools/lib/mxk/mxk.c index e75dd00..fe5f064 100644 --- a/src/micetools/lib/mxk/mxk.c +++ b/src/micetools/lib/mxk/mxk.c @@ -199,7 +199,7 @@ MXK_STATUS mxkGetKeychipIdFromN2(void) { amiCrc32RInit(); uint32_t crcCalc = amiCrc32RCalc((sizeof kcId.m_AppBoot) - 4, (LPBYTE)&kcId.m_AppBoot + 4, 0); - if (crcCalc != kcId.m_AppBoot.m_Crc) { + if (crcCalc != kcId.m_AppBoot.m_Header.m_Crc) { amiDebugLog("Error AppBootInfo CRC!!!"); return MXK_STATUS_ERROR; } @@ -213,16 +213,16 @@ MXK_STATUS mxkGetKeychipIdFromN2(void) { // N2 keychip ID is a smaller, more compact, format than normal appboot. Restructure it to match // before committing it to memory! unsigned char keyId[16]; - appboot_t appboot; + AM_APPBOOT_256 appboot; memcpy_s(keyId, sizeof keyId, kcId.m_KeyId, sizeof kcId.m_KeyId); memcpy_s(&appboot, sizeof appboot, &kcId.m_AppBoot, sizeof kcId.m_AppBoot - sizeof kcId.m_AppBoot.m_Seed); - memcpy_s(appboot.seed, sizeof appboot.seed, kcId.m_AppBoot.m_Seed, + memcpy_s(appboot.m_Seed, sizeof appboot.m_Seed, kcId.m_AppBoot.m_Seed, sizeof kcId.m_AppBoot.m_Seed); printf("Got N2 key ID: %.16s\n", keyId); - printf("Got N2 game ID: %.4s\n", kcId.m_AppBoot.m_GameId); + printf("Got N2 game ID: %.4s\n", kcId.m_AppBoot.m_Header.m_GameId); // ...but we're not actually committing it to memory at the moment! // memcpy_s(&APPBOOT, 256, &appboot, sizeof appboot); diff --git a/src/micetools/lib/mxk/mxkAb.c b/src/micetools/lib/mxk/mxkAb.c index ba622c5..74de422 100644 --- a/src/micetools/lib/mxk/mxkAb.c +++ b/src/micetools/lib/mxk/mxkAb.c @@ -20,7 +20,7 @@ MXK_STATUS mxkGetAppBootInfo(void) { return status; } - appboot_t appBoot; + AM_APPBOOT_256 appBoot; for (int i = 0; i < sizeof appBoot; i += 16) { status = mxkRecvPacket((unsigned char*)(&appBoot) + i); if (status != MXK_STATUS_OK) { @@ -30,7 +30,8 @@ MXK_STATUS mxkGetAppBootInfo(void) { } amiCrc32RInit(); - if (amiCrc32RCalc(sizeof appBoot - 4, (unsigned char*)&appBoot + 4, 0) != appBoot.crc) { + if (amiCrc32RCalc(sizeof appBoot - 4, (unsigned char*)&appBoot + 4, 0) != + appBoot.m_Header.m_Crc) { amiDebugLog("Error CRC AppBootInfo"); return MXK_STATUS_ERROR; } @@ -75,11 +76,11 @@ MXK_STATUS mxkAbSystemFlag(MXK_CACHE cache, unsigned char* systemFlag, unsigned if (status == MXK_STATUS_OK) { LAB_00401d7b: - if (AppBoot.m_Cache.format != 1) { + if (AppBoot.m_Cache.m_Header.m_Format != 1) { *systemFlag = 0; return MXK_STATUS_OK; } - *systemFlag = AppBoot.m_Cache.system_flag; + *systemFlag = AppBoot.m_Cache.m_Header.m_SystemFlag; return MXK_STATUS_OK; } @@ -127,18 +128,18 @@ MXK_STATUS mxkAbGameId(MXK_CACHE cache, char* gameId, unsigned char* err) { if (status == MXK_STATUS_OK) { LAB_00401c7f: - if (AppBoot.m_Cache.format != 1) { + if (AppBoot.m_Cache.m_Header.m_Format != 1) { gameId[0] = '_'; gameId[1] = '_'; gameId[2] = '_'; gameId[3] = '_'; return MXK_STATUS_OK; } - if (!mxkValidString(AppBoot.m_Cache.game_id, 4)) { + if (!mxkValidString(AppBoot.m_Cache.m_Header.m_GameId, 4)) { *err = 55; return MXK_STATUS_ERROR; } - memcpy(gameId, AppBoot.m_Cache.game_id, 4); + memcpy(gameId, AppBoot.m_Cache.m_Header.m_GameId, 4); return MXK_STATUS_OK; } LAB_00401c6a: diff --git a/src/micetools/lib/mxk/mxkAb.h b/src/micetools/lib/mxk/mxkAb.h index b408a1e..e59846d 100644 --- a/src/micetools/lib/mxk/mxkAb.h +++ b/src/micetools/lib/mxk/mxkAb.h @@ -2,30 +2,14 @@ #include #include +#include "../../segastructs.h" #include "../ami/ami.h" #include "mxkDefs.h" -#pragma pack(push, 1) -typedef struct { - DWORD crc; - DWORD format; - char game_id[4]; - BYTE region; - BYTE model_type; - BYTE system_flag; - BYTE _; - char platform_id[3]; - BYTE dvd_flag; - DWORD network_addr; - BYTE __[216]; - BYTE seed[16]; -} appboot_t; -#pragma pack(pop) - typedef struct { bool m_useFlash; bool m_cacheDirty; - appboot_t m_Cache; + AM_APPBOOT_256 m_Cache; } APP_BOOT; extern APP_BOOT AppBoot; diff --git a/src/micetools/lib/mxk/mxkCrypt.c b/src/micetools/lib/mxk/mxkCrypt.c index 5b4e678..eee2c06 100644 --- a/src/micetools/lib/mxk/mxkCrypt.c +++ b/src/micetools/lib/mxk/mxkCrypt.c @@ -185,7 +185,7 @@ MXK_STATUS mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned cha int outl; EVP_DecryptUpdate(ctx, pt, &outl, ct, nbytes); unsigned char dump[16]; - EVP_EncryptFinal_ex(ctx, dump, &outl); + EVP_DecryptFinal_ex(ctx, dump, &outl); EVP_CIPHER_CTX_free(ctx); return MXK_STATUS_OK; diff --git a/src/micetools/lib/mxk/mxkN2.c b/src/micetools/lib/mxk/mxkN2.c index cf9fa47..e4d691d 100644 --- a/src/micetools/lib/mxk/mxkN2.c +++ b/src/micetools/lib/mxk/mxkN2.c @@ -53,6 +53,26 @@ typedef struct { } N2DeviceInfo_t; N2DeviceInfo_t N2DeviceInfo; +/** + * Device keys for: + * + * RingEdge: + * Key: 76ec42b6ae0cb048105171ad8cb2fb07 + * IV: 8e300ba42e154baf651532f570041f5b + * Auth: 96ed31b2287105a5a330540f25bed851a5c83621 + * + * ELEFUN: + * Key: 519aaa25b5ed20b53d28bb56731d7c8d + * IV: 40a1bfc5341340d3dfdbd1a12b855700 + * Auth: 998e952b6a4899ba42d1d0e8a4fdc87775e19c26 + * + * Nu: + * Key: c21c966cbd8b00b9cf4c51bab2c3dfa5 + * IV: 0b137aab20acc7eea0bbec594957dc6d + * Auth: 74935ef7e0181c0661f7bb7118c5512a130a5d19 + */ + +// Auth = 96ed31b2287105a5a330540f25bed851a5c83621 unsigned char N2_KEY_HMAC[2][20] = { { 0x2c, 0xf8, 0x3e, 0x5e, 0x51, 0xf0, 0x60, 0x1b, 0xf6, 0xb1, 0x49, 0x11, 0x3a, 0xaf, 0x36, 0xe1, 0x51, 0x1c, 0x16, 0x05 }, @@ -60,6 +80,8 @@ unsigned char N2_KEY_HMAC[2][20] = { 0x1d, 0x1e, 0x1f, 0x11, 0xee, 0xb0, 0xf4, 0xd4, 0x20, 0x24 } }; +// Key = 76ec42b6ae0cb048105171ad8cb2fb07 +// IV = 8e300ba42e154baf651532f570041f5b AESKey_t N2_KEY_AES[2] = { { { 0xd7, 0xf6, 0x86, 0xfb, 0x63, 0x44, 0xff, 0xa5, 0x60, 0x9d, 0x4e, 0xf0, 0x18, 0xe9, 0x45, 0xb4 }, diff --git a/src/micetools/lib/mxk/mxkN2.h b/src/micetools/lib/mxk/mxkN2.h index ce39026..fac1ae1 100644 --- a/src/micetools/lib/mxk/mxkN2.h +++ b/src/micetools/lib/mxk/mxkN2.h @@ -4,26 +4,14 @@ #include #include "mxkCrypt.h" +#include "../../segastructs.h" #pragma pack(push, 1) typedef struct { uint32_t m_Crc; uint8_t m_Unk04[12]; uint8_t m_KeyId[16]; - struct { - uint32_t m_Crc; - uint32_t m_FormatType; - uint8_t m_GameId[4]; - uint8_t m_Region; - uint8_t m_ModelType; - uint8_t m_SystemFlags; - uint8_t Rsv0f; - uint8_t m_PlatformId[3]; - uint8_t m_DvdFlag; - uint8_t m_NetworkAddr[4]; - uint8_t Unk10[88]; - uint8_t m_Seed[16]; - } m_AppBoot; + AM_APPBOOT_128 m_AppBoot; } N2KeychipId_t; #pragma pack(pop) diff --git a/src/micetools/micekeychip/callbacks/appboot.c b/src/micetools/micekeychip/callbacks/appboot.c index 2d267a7..9cbefba 100644 --- a/src/micetools/micekeychip/callbacks/appboot.c +++ b/src/micetools/micekeychip/callbacks/appboot.c @@ -1,77 +1,92 @@ -#include "../config.h" #include "../lib/libpcp/libpcp.h" #include "callbacks.h" -void mxkPcpAbGameId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, AB_GAMEID, Config.appboot_gameid); } +void mxkPcpAbGameId(pcpa_t* stream, void* data) { + char gameId[5]; + memcpy_s(gameId, 5, mxkKcfConfig.m_Header.m_GameId, 4); + gameId[4] = '\0'; + pcpaSetSendPacket(stream, AB_GAMEID, gameId); +} void mxkPcpAbSystemFlag(pcpa_t* stream, void* data) { char sf[3]; - snprintf(sf, 3, "%02X", Config.appboot_systemflag); + sprintf_s(sf, 3, "%02X", mxkKcfConfig.m_Header.m_SystemFlag); pcpaSetSendPacket(stream, AB_SYSTEMFLAG, sf); } void mxkPcpAbModelType(pcpa_t* stream, void* data) { char mt[3]; - snprintf(mt, 3, "%02X", Config.appboot_modeltype); + sprintf_s(mt, 3, "%02X", mxkKcfConfig.m_Header.m_ModelType); pcpaSetSendPacket(stream, AB_MODELTYPE, mt); } void mxkPcpAbFormatType(pcpa_t* stream, void* data) { char ft[3]; - snprintf(ft, 3, "%02X", Config.appboot_formattype); + sprintf_s(ft, 3, "%02X", mxkKcfConfig.m_Header.m_Format); pcpaSetSendPacket(stream, AB_FORMATTYPE, ft); } void mxkPcpAbRegion(pcpa_t* stream, void* data) { char rg[3]; - snprintf(rg, 3, "%02X", Config.appboot_region); + sprintf_s(rg, 3, "%02X", mxkKcfConfig.m_Header.m_Region); pcpaSetSendPacket(stream, AB_REGION, rg); } void mxkPcpAbPlatformId(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, AB_PLATFORMID, Config.appboot_platformid); + char platformId[4]; + memcpy_s(platformId, 4, mxkKcfConfig.m_Header.m_PlatformId, 3); + platformId[3] = '\0'; + pcpaSetSendPacket(stream, AB_PLATFORMID, platformId); } void mxkPcpAbNetworkAddress(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, AB_NETWORKADDRESS, Config.appboot_network); + char networkAddr[16]; + sprintf_s(networkAddr, sizeof networkAddr, "%d.%d.%d.%d", + (mxkKcfConfig.m_Header.m_NetworkAddr >> 0) & 0xff, + (mxkKcfConfig.m_Header.m_NetworkAddr >> 8) & 0xff, + (mxkKcfConfig.m_Header.m_NetworkAddr >> 16) & 0xff, + (mxkKcfConfig.m_Header.m_NetworkAddr >> 24) & 0xff); + + pcpaSetSendPacket(stream, AB_NETWORKADDRESS, networkAddr); } void mxkPcpAbDvd(pcpa_t* stream, void* data) { char dvd[3]; - snprintf(dvd, 3, "%02X", Config.appboot_dvdflag); + sprintf_s(dvd, 3, "%02X", mxkKcfConfig.m_Header.m_DvdFlag); pcpaSetSendPacket(stream, AB_DVD, dvd); } -#define SEED_BUF_MAX 1024 -byte SEED_BUF[SEED_BUF_MAX]; -int SEED_BUF_LEN = 0; +// #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); + // 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); - } - } + // 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; - } + // 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); + BINARY_DATA_LEN = sizeof mxkKcfConfig.m_Seed; + memcpy(BINARY_DATA, mxkKcfConfig.m_Seed, sizeof mxkKcfConfig.m_Seed); 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); + + char sSize[16]; + sprintf_s(sSize, sizeof sSize, "%d", sizeof mxkKcfConfig.m_Seed); pcpaAddSendPacket(stream, "size", sSize); } diff --git a/src/micetools/micekeychip/callbacks/billing.c b/src/micetools/micekeychip/callbacks/billing.c index 4ba3d3a..2270b4d 100644 --- a/src/micetools/micekeychip/callbacks/billing.c +++ b/src/micetools/micekeychip/callbacks/billing.c @@ -2,8 +2,12 @@ #include "../lib/libpcp/libpcp.h" #include "callbacks.h" -void mxkPcpPbKeyId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_KEYID, Config.billing_keyid); } -void mxkPcpPbMainId(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, BIL_MAINID, Config.billing_mainid); } +void mxkPcpPbKeyId(pcpa_t* stream, void* data) { + pcpaSetSendPacket(stream, BIL_KEYID, Config.billing_keyid); +} +void mxkPcpPbMainId(pcpa_t* stream, void* data) { + pcpaSetSendPacket(stream, BIL_MAINID, Config.billing_mainid); +} void mxkPcpPbPlayCount(pcpa_t* stream, void* data) { char pc[9]; snprintf(pc, sizeof pc, "%08X", Config.billing_playcount); diff --git a/src/micetools/micekeychip/callbacks/callbacks.h b/src/micetools/micekeychip/callbacks/callbacks.h index 31c62d7..692a156 100644 --- a/src/micetools/micekeychip/callbacks/callbacks.h +++ b/src/micetools/micekeychip/callbacks/callbacks.h @@ -1,4 +1,10 @@ #include "../lib/libpcp/libpcp.h" +#include "../lib/mice/kcf.h" + +#define N2_VERSION 0x0106 +#define PIC_VERSION 0x0104 + +extern AM_KCF mxkKcfConfig; pcpa_callback mxkBinaryCallback; extern byte BINARY_DATA[4096]; diff --git a/src/micetools/micekeychip/callbacks/crypto.c b/src/micetools/micekeychip/callbacks/crypto.c index 17ce534..37106eb 100644 --- a/src/micetools/micekeychip/callbacks/crypto.c +++ b/src/micetools/micekeychip/callbacks/crypto.c @@ -1,12 +1,73 @@ +#include +#include + +#include "../../lib/util/hex.h" #include "callbacks.h" void mxkPcpDsCompute(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, "code", "54"); } void mxkPcpSsdProof(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, "code", "54"); } void mxkPcpSsdHostProof(pcpa_t* stream, void* data) {} + +EVP_CIPHER_CTX* ctxEnc = NULL; +EVP_CIPHER_CTX* ctxDec = NULL; + void mxkPcpEncrypt(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, KC_ENCRYPT, "B6787E941C3956EAC70095D6A91E635C"); + char* ptHex = pcpaGetCommand(stream, KC_ENCRYPT); + unsigned char pt[16]; + memset(pt, 0, sizeof(pt)); + hex_to_bin(ptHex, pt, strlen(ptHex) > 32 ? 32 : strlen(ptHex)); + + if (ctxEnc == NULL) { + ctxEnc = EVP_CIPHER_CTX_new(); + EVP_CipherInit_ex(ctxEnc, EVP_aes_128_cbc(), NULL, mxkKcfConfig.m_Key, mxkKcfConfig.m_Iv, + 1); + } + + int outl; + unsigned char ct[16]; + memset(ct, 0, sizeof(ct)); + EVP_EncryptUpdate(ctxEnc, ct, &outl, pt, 16); + + char ctHex[33]; + bin_to_hex(ctHex, ct, 16); + + pcpaSetSendPacket(stream, KC_ENCRYPT, ctHex); } +unsigned char workingIv[16]; void mxkPcpDecrypt(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, KC_DECRYPT, "68271898FB92ABFB49321FAF72F04FF1"); + char* ctHex = pcpaGetCommand(stream, KC_DECRYPT); + unsigned char ct[16]; + memset(ct, 0, sizeof(ct)); + hex_to_bin(ctHex, ct, strlen(ctHex) > 32 ? 32 : strlen(ctHex)); + + if (ctxDec == NULL) { + ctxDec = EVP_CIPHER_CTX_new(); + memcpy(workingIv, mxkKcfConfig.m_Iv, 16); + } else { + EVP_CIPHER_CTX_cleanup(ctxDec); + } + EVP_CipherInit_ex(ctxDec, EVP_aes_128_cbc(), NULL, mxkKcfConfig.m_Key, workingIv, 0); + memcpy(workingIv, ct, 16); + + int outl = 0; + unsigned char pt[16]; + memset(pt, 0, sizeof(pt)); + EVP_DecryptUpdate(ctxDec, pt, &outl, ct, 16); + + char ptHex[33]; + bin_to_hex(ptHex, pt, 16); + + pcpaSetSendPacket(stream, KC_DECRYPT, ptHex); +} +void mxkPcpSetIv(pcpa_t* stream, void* data) { + if (ctxEnc != NULL) { + EVP_CIPHER_CTX_cleanup(ctxEnc); + } else { + ctxEnc = EVP_CIPHER_CTX_new(); + } + EVP_CipherInit_ex(ctxEnc, EVP_aes_128_cbc(), NULL, mxkKcfConfig.m_Key, mxkKcfConfig.m_Iv, 1); + + memcpy(workingIv, mxkKcfConfig.m_Iv, 16); + + pcpaSetSendPacket(stream, KC_SETIV, "1"); } -void mxkPcpSetIv(pcpa_t* stream, void* data) { pcpaSetSendPacket(stream, KC_SETIV, "1"); } diff --git a/src/micetools/micekeychip/callbacks/misc.c b/src/micetools/micekeychip/callbacks/misc.c index 2558daf..c93496a 100644 --- a/src/micetools/micekeychip/callbacks/misc.c +++ b/src/micetools/micekeychip/callbacks/misc.c @@ -1,4 +1,3 @@ -#include "../config.h" #include "callbacks.h" void mxkPcpVersion(pcpa_t* stream, void* data) { @@ -9,12 +8,12 @@ void mxkPcpVersion(pcpa_t* stream, void* data) { char version[5]; if (sDevice && strcmp(sDevice, "n2") == 0) - snprintf(version, 5, "%04X", Config.keychip_dongle_version); + snprintf(version, 5, "%04X", N2_VERSION); else - snprintf(version, 5, "%04X", Config.keychip_pic_version); + snprintf(version, 5, "%04X", PIC_VERSION); pcpaSetSendPacket(stream, KC_VERSION, version); } void mxkPcpStatus(pcpa_t* stream, void* data) { - pcpaSetSendPacket(stream, KC_STATUS, Config.keychip_status); + pcpaSetSendPacket(stream, KC_STATUS, "available"); } diff --git a/src/micetools/micekeychip/config.def b/src/micetools/micekeychip/config.def index 2c5bbef..fff17c8 100644 --- a/src/micetools/micekeychip/config.def +++ b/src/micetools/micekeychip/config.def @@ -7,27 +7,14 @@ HEADER("The main config file for micekeychip") +SECTION(config, "") +CFG_str(config, kcf_path, "", "Path to a KCF file for appboot config") + SECTION(pcp, "") CFG_int(pcp, control_port, 40106, "The port to bind for control") CFG_int(pcp, binary_port, 40107, "The port to bind for binary transfer") CFG_bool(pcp, bind_global, false, "Should we bind to 0.0.0.0 instead of 127.0.0.1") -SECTION(keychip, "") -CFG_hex(keychip, pic_version, 4, 0104, "The version to report for the pic") -CFG_hex(keychip, dongle_version, 4, 0104, "The version to report for the dongle") -CFG_str(keychip, status, "available", "Status to report") - -SECTION(appboot, "") -CFG_str(appboot, gameid, "SDEY", "4-letter game ID this keychip is for") -CFG_hex(appboot, systemflag, 2, 6C, "System flags") -CFG_int(appboot, modeltype, 2, "System model this keychip is for") -CFG_int(appboot, formattype, 1, "") -CFG_int(appboot, region, 1, "Region bitmask\n; 8 4 2 1\n; CN EX US JP") -CFG_str(appboot, platformid, "AAS", "The platform this keychip is for. AAM=AMD, AAS=Nvidia") -CFG_str(appboot, network, "192.168.103.0", "The subnet this keychip allows for networking. Must be 192.168.103.0 for network checks to pass") -CFG_int(appboot, dvdflag, 1, "") -CFG_str(appboot, seed, "C:\\system\\device\\seed.bin", "Path to constant appboot.seed (indev)") - SECTION(crypto, "") CFG_bool(crypto, ds_enable, false, "Process keychip.ds.compute?") CFG_bool(crypto, ssd_enable, false, "Process keychip.ssd.proof?") diff --git a/src/micetools/micekeychip/meson.build b/src/micetools/micekeychip/meson.build index 27eab29..977c564 100644 --- a/src/micetools/micekeychip/meson.build +++ b/src/micetools/micekeychip/meson.build @@ -1,5 +1,5 @@ -dependencies = [] -link_with = [inih.get_variable('lib_inih'), libpcp] +dependencies = [openssl_lib] +link_with = [inih.get_variable('lib_inih'), libpcp, mice_lib] rc = import('windows').compile_resources('micekeychip.rc', depend_files: micekeychip_ico) @@ -18,6 +18,10 @@ mxk = static_library( 'mxk', sources: sources, link_with: link_with, + dependencies: dependencies, + include_directories: [ + openssl_inc, + ], ) executable( 'micekeychip', @@ -25,4 +29,7 @@ executable( sources: sources + ['main.c'], link_with: link_with, dependencies: dependencies, + include_directories: [ + openssl_inc, + ], ) diff --git a/src/micetools/micekeychip/mxk.c b/src/micetools/micekeychip/mxk.c index d5a661c..3bd25a1 100644 --- a/src/micetools/micekeychip/mxk.c +++ b/src/micetools/micekeychip/mxk.c @@ -1,5 +1,7 @@ #include "mxk.h" +AM_KCF mxkKcfConfig; + byte SERVER_STATE = 0; pcpa_t PCP; pcpa_cb_table_t CALLBACK_FUNCTION_BUFFER[40]; @@ -162,6 +164,11 @@ e_pcpa_t mxkPcpServer() { return err; } +static LPCSTR kcfSearchPaths[] = { + "S:\\config.kcf", + "C:\\system\\device\\config.kcf", +}; + int mxkMain(void) { DWORD dwAttrib = GetFileAttributes(CONFIG_PATH); if (dwAttrib == INVALID_FILE_ATTRIBUTES || (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) @@ -169,6 +176,27 @@ int mxkMain(void) { mxkLoadConfig(); + ZeroMemory(&mxkKcfConfig, sizeof mxkKcfConfig); + BOOL kcfLoaded = false; + if (Config.config_kcf_path && Config.config_kcf_path[0]) { + kcfLoaded = MiceParseKcf(Config.config_kcf_path, &mxkKcfConfig); + } + if (!kcfLoaded) { + for (int i = 0; i < _countof(kcfSearchPaths); i++) { + kcfLoaded = MiceParseKcf(kcfSearchPaths[i], &mxkKcfConfig); + if (kcfLoaded) break; + } + } + + if (!kcfLoaded) { + amiDebugLog("Failed to parse kcf!"); + } else { + amiDebugLog("Loaded KCF for:"); + amiDebugLog("Game ID : %.4s", mxkKcfConfig.m_Header.m_GameId); + amiDebugLog("Platform : %.3s", mxkKcfConfig.m_Header.m_PlatformId); + amiDebugLog("System Fag : %02x", mxkKcfConfig.m_Header.m_SystemFlag); + } + int err = mxkInit(); if (err != 0) { amiDebugLog("Error mxkInit. Code %d", err); diff --git a/src/micetools/micekeychip/mxk.h b/src/micetools/micekeychip/mxk.h index 0cb0db4..a256c22 100644 --- a/src/micetools/micekeychip/mxk.h +++ b/src/micetools/micekeychip/mxk.h @@ -2,9 +2,12 @@ #include "../../../subprojects/inih_dep/ini.h" #include "../lib/libpcp/libpcp.h" +#include "../lib/mice/kcf.h" #include "callbacks/callbacks.h" #include "config.h" +extern AM_KCF mxkKcfConfig; + void mxkBinaryCallback(pcpa_t* stream, void* data); int mxkInit(); e_pcpa_t mxkPcpStreamInit(); diff --git a/src/micetools/segastructs.h b/src/micetools/segastructs.h new file mode 100644 index 0000000..1fde3d1 --- /dev/null +++ b/src/micetools/segastructs.h @@ -0,0 +1,30 @@ +#pragma once + +#include + +#pragma pack(push, 1) +typedef struct _AM_APPBOOT { + uint32_t m_Crc; + uint32_t m_Format; + char m_GameId[4]; + uint8_t m_Region; + uint8_t m_ModelType; + uint8_t m_SystemFlag; + uint8_t Rsv0f; + char m_PlatformId[3]; + uint8_t m_DvdFlag; + uint32_t m_NetworkAddr; +} AM_APPBOOT; + +typedef struct _AM_APPBOOT_128 { + AM_APPBOOT m_Header; + uint8_t Rsv18[88]; + uint8_t m_Seed[16]; +} AM_APPBOOT_128; + +typedef struct _AM_APPBOOT_256 { + AM_APPBOOT m_Header; + uint8_t Rsv18[216]; + uint8_t m_Seed[16]; +} AM_APPBOOT_256; +#pragma pack(pop) diff --git a/src/micetools/util/meson.build b/src/micetools/util/meson.build index 1190d0a..1c5821a 100644 --- a/src/micetools/util/meson.build +++ b/src/micetools/util/meson.build @@ -81,3 +81,14 @@ executable( amiDebug, ], ) + +executable( + 'micefs_test', + win_subsystem: subsystem, + sources: [ + 'micefs_test.c', + ], + link_with: [ + mice_lib, + ], +) diff --git a/src/micetools/util/micedump.c b/src/micetools/util/micedump.c index 8f05007..1d8e49c 100644 --- a/src/micetools/util/micedump.c +++ b/src/micetools/util/micedump.c @@ -289,7 +289,7 @@ BOOL dump_keychip() { printf("Keychip ID:\t%.16s\n", KEYCHIP_ID); } - appboot_t appboot; + AM_APPBOOT_256 appboot; if (!mxkGetAppBootInfo(mxparallel, &appboot)) { puts("Failed to request appboot info!"); } else { diff --git a/src/micetools/util/micefs_test.c b/src/micetools/util/micefs_test.c new file mode 100644 index 0000000..92736bc --- /dev/null +++ b/src/micetools/util/micefs_test.c @@ -0,0 +1,32 @@ +#include + +#include "../lib/mice/mice.h" + +// TODO: Ewww +BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath) = PathFileExistsA; + +int main() { + MiceFSInit(); + // MiceFSAddDevLayers(); + // MiceFSAddRingedgeLayers(FALSE); + + CHAR path[MAX_PATH + 1]; + strcpy_s(path, sizeof path, "X:\\Systemconfig.txt"); + + MICE_FS_PATH_TOK pathTok; + LPSTR pathComponent = MiceFSPathTokA(path, _countof(path), &pathTok); + + while (pathComponent) { + printf("Component : '%s'\n", pathComponent); + pathComponent = MiceFSPathTokNextA(&pathTok); + } + + + // CHAR tail[MAX_PATH + 1]; + // printf("Test 1: %d\n", MiceFSMatchPathA("C:\\windows\\system32\\etc\\help.exe", "C:\\WINDOWS", tail, sizeof(tail))); + // printf("Tail: %s\n", tail); + + // LPSTR redirected = NULL; + // MiceFSRedirectPathA("X:\\game.bat", &redirected); + // printf("Redirected path: %s\n", redirected); +}