diff --git a/src/micetools/dll/dllmain.c b/src/micetools/dll/dllmain.c index 02b8781..8695ae5 100644 --- a/src/micetools/dll/dllmain.c +++ b/src/micetools/dll/dllmain.c @@ -165,6 +165,8 @@ void init_injection(HMODULE hModule) { if (MiceConfig.drivers.mxsmbus) setup_mxsmbus(); // MX Parallel: The parallel port (i.e. keychip) if (MiceConfig.drivers.mxparallel) setup_mxparallel(); + // CrackProof + if (MiceConfig.drivers.htsysmnt) setup_htsysmnt(); if (MiceConfig.drivers.platform) { if (!add_fake_device(&PLATFORM_GUID, L"\\\\.\\platform")) { diff --git a/src/micetools/dll/drivers/htsysmnt.c b/src/micetools/dll/drivers/htsysmnt.c new file mode 100644 index 0000000..4195f75 --- /dev/null +++ b/src/micetools/dll/drivers/htsysmnt.c @@ -0,0 +1,113 @@ +#include "mx.h" + +#pragma pack(push, 1) +typedef struct { + LPBYTE dest; + LPBYTE src; + DWORD nBytes; +} HTSYSMNT_1x, *LPHTSYSMNT_1x; + +typedef struct { + DWORD offset; + LPBYTE data; + DWORD nBytes; +} HTSYSMNT_2x, *LPHTSYSMNT_2x; + +typedef struct { + void (*callback)(void); +} HTSYSMNT_3x, *LPHTSYSMNT_3x; +#pragma pack(pop) + +static BYTE HTSYS_BUFFER[256]; + +static BOOL htsysmntBufferTransact(DWORD offset, LPBYTE data, DWORD nbytes, BOOL doWrite) { + LPBYTE source; + LPBYTE destination; + + if (!(offset < 16 && nbytes < 16)) return FALSE; + + destination = HTSYS_BUFFER + offset * 16; + source = data; + if (!doWrite) { + source = destination; + destination = data; + } + memcpy(destination, source, nbytes); + return TRUE; +} + +static BOOL htsysmntExchangeBuffers(LPBYTE dest, LPBYTE src, DWORD nBytes, BOOL direction) { + if (dest == NULL || src == NULL || nBytes == 0) return FALSE; + + LPBYTE destination; + destination = dest; + if (!direction) { + destination = src; + src = dest; + } + + memcpy(src, destination, nBytes); + return TRUE; +} + +BOOL WINAPI htsysmnt_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer, + DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, + LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) { + DWORD expectedIn = 0; + DWORD expectedOut = /* 4 */ sizeof(BOOL); + + switch (dwIoControlCode) { + case IOCTL_CRACKPROOF_10: + case IOCTL_CRACKPROOF_11: + case IOCTL_CRACKPROOF_20: + case IOCTL_CRACKPROOF_21: + expectedIn = 12; + break; + case IOCTL_CRACKPROOF_30: + expectedIn = 4; + break; + default: + log_warning(plfHtsysmnt, "unhandled 0x%08x", dwIoControlCode); + return FALSE; + } + + if (nInBufferSize != expectedIn || nOutBufferSize != expectedOut) { + return FALSE; + } + + BOOL result = TRUE; + + switch (dwIoControlCode) { + case IOCTL_CRACKPROOF_10: + case IOCTL_CRACKPROOF_11: { + result = htsysmntExchangeBuffers( + ((LPHTSYSMNT_1x)lpInBuffer)->dest, ((LPHTSYSMNT_1x)lpInBuffer)->src, + ((LPHTSYSMNT_1x)lpInBuffer)->nBytes, dwIoControlCode == IOCTL_CRACKPROOF_11); + break; + } + + case IOCTL_CRACKPROOF_20: + case IOCTL_CRACKPROOF_21: { + result = htsysmntBufferTransact( + ((LPHTSYSMNT_2x)lpInBuffer)->offset, ((LPHTSYSMNT_2x)lpInBuffer)->data, + ((LPHTSYSMNT_2x)lpInBuffer)->nBytes, dwIoControlCode == IOCTL_CRACKPROOF_21); + break; + } + + case IOCTL_CRACKPROOF_30: + result = TRUE; + ((LPHTSYSMNT_3x)lpInBuffer)->callback(); + break; + } + + *(LPBOOL)lpOutBuffer = result; + *lpBytesReturned = expectedOut; + return TRUE; +} + +void setup_htsysmnt() { + file_hook_t* htsysmnt = new_file_hook(L"\\\\.\\Htsysm"); + htsysmnt->DeviceIoControl = &htsysmnt_DeviceIoControl; + + hook_file(htsysmnt); +} diff --git a/src/micetools/dll/drivers/meson.build b/src/micetools/dll/drivers/meson.build index 7ee8333..351d16f 100644 --- a/src/micetools/dll/drivers/meson.build +++ b/src/micetools/dll/drivers/meson.build @@ -6,4 +6,5 @@ drivers_files = files( 'mxsmbus.c', 'mxsram.c', 'mxsuperio.c', + 'htsysmnt.c', ) \ No newline at end of file diff --git a/src/micetools/dll/drivers/mx.h b/src/micetools/dll/drivers/mx.h index d74798b..9e74ad3 100644 --- a/src/micetools/dll/drivers/mx.h +++ b/src/micetools/dll/drivers/mx.h @@ -26,3 +26,6 @@ void setup_columba(); FnDeviceIoControl mxparallel_DeviceIoControl; void setup_mxparallel(); + +FnDeviceIoControl htsysmnt_DeviceIoControl; +void setup_htsysmnt(); diff --git a/src/micetools/dll/hooks/drive/disks.c b/src/micetools/dll/hooks/drive/disks.c index 0b3b716..fc1ee42 100644 --- a/src/micetools/dll/hooks/drive/disks.c +++ b/src/micetools/dll/hooks/drive/disks.c @@ -28,7 +28,6 @@ physical_disk_t SSD = { { 0x403947, MBR_FS_FAT16, SPD_Patch1, .m_ReadFunc = NULL }, // 2GB patch1 { 0x48ed459, MBR_FS_NTFS, SPD_AppData, .m_ReadFunc = NULL }, // 40GB something { - // mxinstaller.exe -cmdport 40102 -bindport 40103 // 16GB partition for the game // The real value here should be "0x20014aa," 0x20014aa, // 16GB, FiNALE diff --git a/src/micetools/lib/mice/config.def b/src/micetools/lib/mice/config.def index a219c5f..742afe3 100644 --- a/src/micetools/lib/mice/config.def +++ b/src/micetools/lib/mice/config.def @@ -78,6 +78,7 @@ CFG_bool(drivers, mxjvs, true, "") CFG_bool(drivers, mxhwreset, true, "") CFG_bool(drivers, mxsmbus, true, "") CFG_bool(drivers, mxparallel, true, "") +CFG_bool(drivers, htsysmnt, true, "") CFG_bool(drivers, platform, true, "") ENDSECTION(drivers) diff --git a/src/micetools/lib/mice/ioctl.h b/src/micetools/lib/mice/ioctl.h index 220a79c..c6830a9 100644 --- a/src/micetools/lib/mice/ioctl.h +++ b/src/micetools/lib/mice/ioctl.h @@ -4,6 +4,7 @@ #include #define FILE_DEVICE_SEGA 0x9c40 +#define FILE_DEVICE_HTSYS 0xaa00 // amSramInit #define IOCTL_MXSRAM_PING \ @@ -83,3 +84,10 @@ (DWORD) CTL_CODE(FILE_DEVICE_SEGA, 0x806, METHOD_BUFFERED, FILE_WRITE_ACCESS) #define IOCTL_MXPARALLEL_READ_FLAGS \ (DWORD) CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS) + +// CrackProof +#define IOCTL_CRACKPROOF_10 CTL_CODE(FILE_DEVICE_HTSYS, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_CRACKPROOF_11 CTL_CODE(FILE_DEVICE_HTSYS, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_CRACKPROOF_20 CTL_CODE(FILE_DEVICE_HTSYS, 0x820, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_CRACKPROOF_21 CTL_CODE(FILE_DEVICE_HTSYS, 0x821, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_CRACKPROOF_30 CTL_CODE(FILE_DEVICE_HTSYS, 0x830, METHOD_BUFFERED, FILE_ANY_ACCESS) diff --git a/src/micetools/lib/mice/log_facilities.def b/src/micetools/lib/mice/log_facilities.def index 58bb624..0fe129f 100644 --- a/src/micetools/lib/mice/log_facilities.def +++ b/src/micetools/lib/mice/log_facilities.def @@ -39,3 +39,4 @@ _LF(Drivers, MxSuperio, "mxsuperio") _LF(Drivers, MxSmbus, "mxsmbus") _LF(Drivers, MxHwreset, "mxhwreset") _LF(Drivers, Platform, "platform") +_LF(Drivers, Htsysmnt, "htsysmnt") diff --git a/src/micetools/util/meson.build b/src/micetools/util/meson.build index fadb75b..39db54a 100644 --- a/src/micetools/util/meson.build +++ b/src/micetools/util/meson.build @@ -66,3 +66,14 @@ executable( amiDebug, ], ) +executable( + 'storagecraft', + win_subsystem: subsystem, + sources: [ + 'storagecraft.c', + ], + link_with: [ + amiCrc, + amiDebug, + ], +) diff --git a/src/micetools/util/storagecraft.c b/src/micetools/util/storagecraft.c new file mode 100644 index 0000000..c8fb175 --- /dev/null +++ b/src/micetools/util/storagecraft.c @@ -0,0 +1,249 @@ +#include +#include + +#include "../dll/hooks/drive/drive.h" + +physical_disk_t newSSD = { + .m_SerialNumber = 0x00144DB0, + + .m_BusType = BusTypeAta, + .m_BootPartition = 1, + .m_HasSegaboot = TRUE, + .m_BlockSize = BLOCK_SIZE_HDD, + .m_TotalSize = 64 * 1024 * 1024 * (1024 / BLOCK_SIZE_HDD), + .m_DiskType = DiskType_HardDisk, + .m_IsFormatted = true, + .m_Partitions = { + // 1.5GB boot partition + { .m_Size = 0x300B85, .m_Filesystem = MBR_FS_NTFS }, + // 1.5GB OS recovery + { .m_Size = 0x300BC4, .m_Filesystem = MBR_FS_NTFS }, + }, + .m_Extended = { + { 0x102d83, MBR_FS_FAT16, SPD_OS }, // 512MB OS update + { 0x403947, MBR_FS_FAT16, SPD_Patch0 }, // 2GB patch0 + { 0x403947, MBR_FS_FAT16, SPD_Patch1 }, // 2GB patch1 + { 0x48ed459, MBR_FS_NTFS, SPD_AppData }, // 40GB appdata + { 0x20014aa, MBR_FS_FAT16, SPD_Original0 }, // 16GB original0 + { 0 }, // End of table + }, +}; + +sbr_t SegaBootRecord0; +sbr_t SegaBootRecord1; +sbr_slot_t* get_sbr_slot(spd_slot_t slot) { + switch (slot) { + case SPD_Original0: + return &SegaBootRecord0.slot_original0; + case SPD_Original1: + return NULL; + case SPD_Patch0: + return &SegaBootRecord0.slot_patch0; + case SPD_Patch1: + return &SegaBootRecord0.slot_patch1; + case SPD_OS: + return &SegaBootRecord0.slot_os; + case SPD_AppData: + return &SegaBootRecord0.slot_appdata; + default: + return NULL; + } +} +void init_pd(physical_disk_t* pConfig) { + // Apply default block sizes + if (!pConfig->m_BlockSize) { + switch (pConfig->m_DiskType) { + case DiskType_HardDisk: + pConfig->m_BlockSize = BLOCK_SIZE_HDD; + break; + case DiskType_Flash: + pConfig->m_BlockSize = BLOCK_SIZE_FLASH; + break; + case DiskType_CdRom: + pConfig->m_BlockSize = BLOCK_SIZE_CDROM; + break; + default: + printf("Unable to guess block size for drive %d", pConfig->m_DriveNumber); + break; + } + } + + // Non-SCSI devices don't have a SCSI type to report + if (pConfig->m_BusType != BusTypeScsi) pConfig->m_DeviceType = DeviceTypeUnknown; + + // If we need to initialise the partition tables, do so + if (pConfig->m_IsFormatted) { + DWORD partitionNumber = 1; + DWORD currentLBA = MBR_LBA_GAP; + + // Init MBR + for (int i = 0; i < 4; i++) { + if (pConfig->m_Partitions[i].m_Size == 0) break; + + pConfig->m_Partitions[i].m_PartitionNumber = partitionNumber++; + pConfig->m_Partitions[i].m_PhysicalLBA = currentLBA; + + pConfig->m_Partitions[i].m_Volume.m_pDrive = pConfig; + pConfig->m_Partitions[i].m_Volume.m_pPartition = &(pConfig->m_Partitions[i]); + + currentLBA += pConfig->m_Partitions[i].m_Size; + } + + // If we have any extended partitions + DWORD extendedPartNo = 0; + if (pConfig->m_Extended[0].m_Size) { + if (partitionNumber == 5) { + printf("Fatal: Too many paritions in drive %d!", pConfig->m_DriveNumber); + exit(1); + } + pConfig->m_Partitions[partitionNumber - 1].m_Filesystem = MBR_FS_EXT_LBA; + pConfig->m_Partitions[partitionNumber - 1].m_PhysicalLBA = currentLBA; + extendedPartNo = partitionNumber; + + // Note: We don't increment partitionNumber, to keep the presence of this partition + // transparent elsewhere. + } + DWORD extendedStart = currentLBA; + + // Init extended partitions + for (int i = 0;; i++) { + if (!pConfig->m_Extended[i].m_Size) break; + + pConfig->m_Extended[i].m_PartitionNumber = partitionNumber++; + + currentLBA += EXT_HEADER_GAP; + pConfig->m_Extended[i].m_PhysicalLBA = currentLBA; + pConfig->m_Extended[i].m_SlotLBA = currentLBA; + currentLBA += pConfig->m_Extended[i].m_Size; + + pConfig->m_Extended[i].m_Volume.m_pDrive = pConfig; + pConfig->m_Extended[i].m_Volume.m_pPartition = &(pConfig->m_Extended[i]); + + sbr_slot_t* pslot = get_sbr_slot(pConfig->m_Extended[i].m_SPDContent); + if (pslot != NULL) { + DWORD slot_size = ((LONGLONG)pslot->segcount * (LONGLONG)pslot->segsize) / + (long long)pConfig->m_BlockSize; + DWORD slot_offset = pConfig->m_Extended[i].m_Size - slot_size; + pConfig->m_Extended[i].m_SlotLBA += slot_offset; + } + } + + // Back-fill, if needed + if (extendedPartNo) { + pConfig->m_Partitions[extendedPartNo - 1].m_Size = currentLBA - extendedStart; + } + } else { + // Raw disks have just a single spanning volume + pConfig->m_Partitions[0].m_PartitionNumber = 1; + pConfig->m_Partitions[0].m_PhysicalLBA = 0; + pConfig->m_Partitions[0].m_Size = pConfig->m_TotalSize; + pConfig->m_Partitions[0].m_Volume.m_pDrive = pConfig; + pConfig->m_Partitions[0].m_Volume.m_pPartition = &(pConfig->m_Partitions[0]); + } +} + +BYTE writeBuffer[1024]; +void write_buffer(HANDLE hDisk, LONG nOffset, DWORD nBytes, physical_disk_t* pConfig) { + LARGE_INTEGER offset; + offset.QuadPart = nOffset * pConfig->m_BlockSize; + SetFilePointerEx(hDisk, offset, NULL, FILE_BEGIN); + DWORD nOut; + WriteFile(hDisk, writeBuffer, nBytes, &nOut, NULL); +} + +// TODO: Write start_chs lol +void write_mbr(HANDLE hDisk, LONG nOffset, physical_disk_t* pConfig) { + printf("Writing MBR at block %d\n", nOffset); + mbr_t* mbr = (mbr_t*)writeBuffer; + + memset(mbr, 0, sizeof *mbr); + mbr->sig[0] = 0x55; + mbr->sig[1] = 0xAA; + + for (size_t i = 0; i < 4; i++) { + if (pConfig->m_Partitions[i].m_Size == 0) break; + + mbr->partitions[i].status = + (pConfig->m_BootPartition == i + 1) ? MBR_FLAG_BOOTABLE : MBR_FLAG_NONE; + mbr->partitions[i].type = pConfig->m_Partitions[i].m_Filesystem; + mbr->partitions[i].lba = pConfig->m_Partitions[i].m_PhysicalLBA; + mbr->partitions[i].sectors = pConfig->m_Partitions[i].m_Size; + } + + write_buffer(hDisk, nOffset, sizeof *mbr, pConfig); +} +void write_ext_header(HANDLE hDisk, LONG nOffset, physical_disk_t* pConfig, DWORD nPartition) { + printf("Writing extended header at block %d\n", nOffset); + + mbr_t* mbr = (mbr_t*)writeBuffer; + + memset(mbr, 0, sizeof *mbr); + mbr->sig[0] = 0x55; + mbr->sig[1] = 0xAA; + + mbr->partitions[0].status = MBR_FLAG_NONE; + mbr->partitions[0].type = pConfig->m_Extended[nPartition].m_Filesystem; + mbr->partitions[0].lba = EXT_HEADER_GAP; + mbr->partitions[0].sectors = pConfig->m_Extended[nPartition].m_Size; + + if (pConfig->m_Extended[nPartition + 1].m_Size) { + mbr->partitions[1].status = MBR_FLAG_NONE; + // ! mxinstaller expects to see CHS here, then uses the LBA values + mbr->partitions[1].type = MBR_FS_EXT_CHS; + mbr->partitions[1].lba = pConfig->m_Extended[nPartition + 1].m_PhysicalLBA - + pConfig->m_Extended[0].m_PhysicalLBA; + mbr->partitions[1].sectors = pConfig->m_Extended[nPartition + 1].m_Size + EXT_HEADER_GAP; + } + + write_buffer(hDisk, nOffset, sizeof *mbr, pConfig); +} + +void write_pd(HANDLE hDisk, physical_disk_t* pConfig) { + puts("Force-allocating disk space"); + write_buffer(hDisk, pConfig->m_TotalSize - 1, pConfig->m_BlockSize, pConfig); + + // Write MBR headers + write_mbr(hDisk, 0, pConfig); + for (size_t i = 0; pConfig->m_Extended[i].m_Size; i++) { + DWORD headerLBA = pConfig->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP; + write_ext_header(hDisk, headerLBA, pConfig, i); + + if (i == 0 && pConfig->m_HasSegaboot) { + puts("Writing segaboot"); + + // SEGA Partition Description + spd_t* spd = (spd_t*)writeBuffer; + + spd->version = SPD_VERSION; + for (size_t j = 0; pConfig->m_Extended[j].m_Size; j++) { + spd->slots[j].block_size = pConfig->m_BlockSize & 0xFFFF; + spd->slots[j].block_count = pConfig->m_Extended[j].m_Size; + spd->slots[j].slot_content = pConfig->m_Extended[j].m_SPDContent; + spd->slots[j].uk1 = pConfig->m_Extended[j].m_Filesystem == MBR_FS_FAT16 ? 0 : 1; + } + + spd->crc = amiCrc32RCalc(sizeof *spd - 4, &(spd->version), 0); + write_buffer(hDisk, headerLBA + SPD_OFFSET, sizeof *spd, pConfig); + + // SEGA Boot Record 0 and 1. The two are a redundant copy of each other + memcpy(writeBuffer, &SegaBootRecord0, sizeof SegaBootRecord0); + write_buffer(hDisk, headerLBA + SBR0_OFFSET, sizeof SegaBootRecord0, pConfig); + + memcpy(writeBuffer, &SegaBootRecord1, sizeof SegaBootRecord1); + write_buffer(hDisk, headerLBA + SBR1_OFFSET, sizeof SegaBootRecord1, pConfig); + } + } +} + +int main(int argc, char* argv[]) { + init_pd(&newSSD); + + HANDLE hDisk = INVALID_HANDLE_VALUE; + + hDisk = CreateFileA("H:\\NewDiskImage.img", GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); + + write_pd(hDisk, &newSSD); + + return 0; +}