Micekeychip rework; MiceFS

This commit is contained in:
Bottersnike 2023-04-11 02:29:59 +09:00
parent 69cc1ce5b7
commit 358d1880dd
Signed by: Bottersnike
SSH Key Fingerprint: SHA256:3g0ghwd4dNX1k1RX8qazbiT+3RIYn/daeBevHZVCiU0
43 changed files with 1085 additions and 314 deletions

View File

@ -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"

View File

@ -5,6 +5,7 @@
#include <openssl/rand.h>
#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);

View File

@ -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();
}

View File

@ -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(<mxparallel>, 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);
}

View File

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

View File

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

View File

@ -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,
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -129,7 +129,7 @@ static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) {
}
if (!inVt100) WriteFile(hLogFile, &(readBuffer[i]), 1, &nWrote, NULL);
}
FlushFileBuffers(hLogFile);
// FlushFileBuffers(hLogFile);
}
}
}

View File

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

View File

@ -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")

View File

@ -0,0 +1,41 @@
#include "kcf.h"
#include <Windows.h>
#include <stdio.h>
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;
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <Windows.h>
#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);

View File

@ -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'),

View File

@ -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"

View File

@ -0,0 +1,323 @@
#include "micefs.h"
#pragma comment(lib, "Shlwapi.lib")
#include <shlwapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 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;
}

View File

@ -0,0 +1,155 @@
#pragma once
#include <Windows.h>
#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);

View File

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

View File

@ -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:

View File

@ -2,30 +2,14 @@
#include <Windows.h>
#include <stdbool.h>
#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;

View File

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

View File

@ -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 },

View File

@ -4,26 +4,14 @@
#include <varargs.h>
#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)

View File

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

View File

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

View File

@ -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];

View File

@ -1,12 +1,73 @@
#include <openssl/evp.h>
#include <openssl/pem.h>
#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"); }

View File

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

View File

@ -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?")

View File

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

View File

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

View File

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

View File

@ -0,0 +1,30 @@
#pragma once
#include <stdint.h>
#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)

View File

@ -81,3 +81,14 @@ executable(
amiDebug,
],
)
executable(
'micefs_test',
win_subsystem: subsystem,
sources: [
'micefs_test.c',
],
link_with: [
mice_lib,
],
)

View File

@ -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 {

View File

@ -0,0 +1,32 @@
#include <stdio.h>
#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);
}