Implement CrackProof drivers

This commit is contained in:
Bottersnike 2023-04-22 21:28:10 +01:00
parent 701887940c
commit d3ff2e7c24
Signed by: Bottersnike
SSH Key Fingerprint: SHA256:3g0ghwd4dNX1k1RX8qazbiT+3RIYn/daeBevHZVCiU0
10 changed files with 389 additions and 1 deletions

View File

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

View File

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

View File

@ -6,4 +6,5 @@ drivers_files = files(
'mxsmbus.c',
'mxsram.c',
'mxsuperio.c',
'htsysmnt.c',
)

View File

@ -26,3 +26,6 @@ void setup_columba();
FnDeviceIoControl mxparallel_DeviceIoControl;
void setup_mxparallel();
FnDeviceIoControl htsysmnt_DeviceIoControl;
void setup_htsysmnt();

View File

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

View File

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

View File

@ -4,6 +4,7 @@
#include <winioctl.h>
#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)

View File

@ -39,3 +39,4 @@ _LF(Drivers, MxSuperio, "mxsuperio")
_LF(Drivers, MxSmbus, "mxsmbus")
_LF(Drivers, MxHwreset, "mxhwreset")
_LF(Drivers, Platform, "platform")
_LF(Drivers, Htsysmnt, "htsysmnt")

View File

@ -66,3 +66,14 @@ executable(
amiDebug,
],
)
executable(
'storagecraft',
win_subsystem: subsystem,
sources: [
'storagecraft.c',
],
link_with: [
amiCrc,
amiDebug,
],
)

View File

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