Idk if this is even stable

This commit is contained in:
Bottersnike 2023-02-10 04:22:16 +00:00
parent 8bd3bb38cb
commit eb7bcb1a1b
99 changed files with 5794 additions and 1899 deletions

1
.gitignore vendored
View File

@ -3,4 +3,3 @@ build/
builddir/
srcdir/
.vscode/
openssl-1.0.1/

View File

@ -71,6 +71,9 @@ dist:
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micedump.exe" "$(DIST_DIR)/util/micedump.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micetinker.exe" "$(DIST_DIR)/util/micetinker.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\micemonitor.exe" "$(DIST_DIR)/util/micemonitor.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\exio_test.exe" "$(DIST_DIR)/util/exio_test.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\dongleDecrypt.exe" "$(DIST_DIR)/util/dongleDecrypt.exe"
@copy /Y "$(BUILD_DIR_32)/src/micetools/util\testBin.exe" "$(DIST_DIR)/util/testBin.exe"
@copy /Y "src/micetools/miceboot\TrueCrypt.cmd" "$(DIST_DIR)/Execute/TrueCrypt.cmd"

View File

@ -210,3 +210,11 @@ typedef struct {
* 0x0600 - 0x07ff, sram
* 0x1600 - 0x17ff, sram
*/
#define AM_SYSDATAwH_BACKUP_REG 0x0000
#define AM_SYSDATAwH_BACKUP_DUP 0x1000
#define AM_SYSDATAwH_HM_PEAK_REG 0x0200
#define AM_SYSDATAwH_HM_PEAK_DUP 0x1200
#define AM_SYSDATAwH_TIMEZONE_REG 0x0400
#define AM_SYSDATAwH_TIMEZONE_DUP 0x1400
#define AM_SYSDATAwH_ERROR_LOG_REG 0x0600
#define AM_SYSDATAwH_ERROR_LOG_DUP 0x1600

View File

@ -110,7 +110,7 @@ void comio_write(com_device_t* com, BYTE* data, BYTE len) {
comdev_write(com, &one_byte, 1);
}
}
void comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data) {
unsigned char comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data) {
BYTE one_byte;
do {
if (comdev_available(com) < (sizeof *head + 1)) {
@ -131,6 +131,7 @@ void comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data) {
comio_read(com, data, head->length);
unsigned char sum;
comio_read(com, &sum, 1);
return sum;
}
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len, BYTE* data) {
BYTE one_byte;

View File

@ -47,7 +47,7 @@ BYTE comdev_peek(com_device_t* com);
void comio_read(com_device_t* com, BYTE* data, BYTE len);
void comio_write(com_device_t* com, BYTE* data, BYTE len);
void comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data);
unsigned char comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* data);
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len, BYTE* data);
void com_device_thread(com_device_t* com, FnComDeviceThread* thread);

View File

@ -24,5 +24,5 @@
#include "../lib/mice/mice.h"
#include "./util/_util.h"
extern WCHAR exePath[MAX_PATH + 1];
extern WCHAR exeName[MAX_PATH + 1];
extern DWORD imageOffset;

View File

@ -1,11 +1,16 @@
#include "_devices.h"
#include "smb_pca9535.h"
#include "smb_at24c64an.h"
#include "smb_ds28cn01.h"
#include "smb_ds2460.h"
void install_devices() {
install_led_bd();
install_touch_bd();
install_aime_bd();
smbus_install(0x20, &smbus_PCA9535_write, &smbus_PCA9535_read);
smbus_install(/* 0x20 */ PCA9535_ADDRESS, &smbus_PCA9535_write, &smbus_PCA9535_read);
// mxkN2CmdWriteData(byte addr,byte *data,ushort nbytes,ushort *nbytesOut)
// -> smbusWriteByte(addr, command:0xcc, byte:data[i])
@ -13,10 +18,9 @@ void install_devices() {
smbus_install(0x30, &smbus_N2_write, &smbus_N2_read);
// mxkDsExioRequestComputeMac() -> smbusWriteByte(addr:0x54, command:0x5c, byte:0x94)
smbus_install(0x54, &smbus_EXIO_write, &smbus_EXIO_read);
smbus_install(/* 0x54 */ DS2460_ADDRESS, &smbus_ds2460_write, &smbus_ds2460_read);
// mxkDsKeychipComputeMac
smbus_install(0x55, &smbus_DS_write, &smbus_DS_read);
smbus_install(0x57, &smbus_AT24C64AN_write, &smbus_AT24C64AN_read);
smbus_install(/* 0x55 */ DS28CN01_ADDRESS, &smbus_ds28cn01_write, &smbus_ds28cn01_read);
smbus_install(/* 0x57 */ AT24C64AN_ADDRESS, &smbus_AT24C64AN_write, &smbus_AT24C64AN_read);
}

View File

@ -7,15 +7,7 @@ void install_led_bd();
void install_touch_bd();
void install_aime_bd();
smbus_callback_t smbus_PCA9535_write;
smbus_callback_t smbus_PCA9535_read;
smbus_callback_t smbus_DS_write;
smbus_callback_t smbus_DS_read;
smbus_callback_t smbus_N2_write;
smbus_callback_t smbus_N2_read;
smbus_callback_t smbus_AT24C64AN_write;
smbus_callback_t smbus_AT24C64AN_read;
smbus_callback_t smbus_EXIO_write;
smbus_callback_t smbus_EXIO_read;
void install_devices();

View File

@ -0,0 +1,45 @@
#include "_ds_sha.h"
#define KTN(n) ((n < 20) ? 0x5a827999 : (n < 40) ? 0x6ed9eba1 : (n < 60) ? 0x8f1bbcdc : 0xca62c1d6)
#define NLF(B, C, D, n) \
((n < 20) ? ((B & C) | ((~B) & D)) \
: (n < 40) ? (B ^ C ^ D) \
: (n < 60) ? ((B & C) | (B & D) | (C & D)) \
: (B ^ C ^ D))
/**
* @brief This is almost identical to a typical SHA1 implementation, except the final step involving
* the addition of constants is ommitted as per the datasheet.
*/
void ComputeDallasSha(unsigned char *MT, long *A, long *B, long *C, long *D, long *E) {
unsigned long MTword[80];
int i;
long ShftTmp;
long Temp;
for (i = 0; i < 16; i++)
MTword[i] =
(MT[i * 4] << 24) | (MT[i * 4 + 1] << 16) | (MT[i * 4 + 2] << 8) | MT[i * 4 + 3];
for (i = 16; i < 80; i++) {
ShftTmp = MTword[i - 3] ^ MTword[i - 8] ^ MTword[i - 14] ^ MTword[i - 16];
MTword[i] = ((ShftTmp << 1) & 0xfffffffe) | ((ShftTmp >> 31) & 0x00000001);
}
*A = 0x67452301;
*B = 0xefcdab89;
*C = 0x98badcfe;
*D = 0x10325476;
*E = 0xc3d2e1f0;
for (i = 0; i < 80; i++) {
ShftTmp = ((*A << 5) & 0xffffffe0) | ((*A >> 27) & 0x0000001f);
Temp = NLF(*B, *C, *D, i) + *E + KTN(i) + MTword[i] + ShftTmp;
*E = *D;
*D = *C;
*C = ((*B << 30) & 0xc0000000) | ((*B >> 2) & 0x3fffffff);
*B = *A;
*A = Temp;
}
}

View File

@ -0,0 +1 @@
void ComputeDallasSha(unsigned char *MT, long *A, long *B, long *C, long *D, long *E);

View File

@ -1,13 +1,14 @@
devices_files = files(
'_ds_sha.c',
'_devices.c',
# Serial devices
'ser_led_bd.c',
'ser_maitouch.c',
'ser_tn32msec.c',
# SMBus devices
'smb_exio.c',
'smb_pca9535.c',
'smb_ds.c',
'smb_ds2460.c',
'smb_ds28cn01.c',
'smb_n2.c',
'smb_at24c64a.c',
'smb_at24c64an.c',
)

View File

@ -15,30 +15,45 @@ BYTE extra[0xff];
* TODO: Validate against a real board
*/
enum TN32_Opcode {
TN32Op_Unknown20 = 0x20,
TN32Op_Unknown20 = 0x20, // where did this come from??
TN32Op_GetFWVersion = 0x30,
TN32Op_GetHWVersion = 0x32,
TN32Op_RadioOn = 0x40,
TN32Op_RadioOff = 0x41,
TN32Op_Poll = 0x42,
TN32Op_MifareSelectTag = 0x43,
TN32Op_Unknown44 = 0x44, // Present in code, not seen used
TN32Op_SetKeyBana = 0x50,
TN32Op_GetKeyBana = 0x51,
TN32Op_ReadBlock = 0x52,
TN32Op_Unknown53 = 0x53, // Present in code, not seen used
TN32Op_SetKeyAime = 0x54,
TN32Op_GetKeyAime = 0x55,
// Firmware update (I think)
TN32Op_Unknown60 = 0x60, // Present in code, not seen used
TN32Op_Unknown61 = 0x61, // Present in code, not seen used
TN32Op_Reset = 0x62,
TN32Op_Unknown63 = 0x63,
TN32Op_Unknown64 = 0x64,
TN32Op_Unknown70 = 0x70, // Present in code, not seen used
TN32Op_FelicaEncap = 0x71,
// No responses to either
LedUnknown80 = 0x80,
LedSetColour = 0x81,
LedGetInfo = 0xf0,
LedF2 = 0xf2,
LedF3 = 0xf3,
LedF4 = 0xf4,
LedReset = 0xf5,
};
#define LedReset 0xf5
#define LedGetInfo 0xf0
#define LedSetColour 0x81
char* OpcodeNames[256];
const char FWVer[] = "TN32MSEC003S F/W Ver1.2";
const char HWVer[] = "TN32MSEC003S H/W Ver3.0";
@ -84,7 +99,7 @@ typedef struct FelicaMemory {
MifareMemory_t mifareMemory;
FelicaMemory_t felicaMemory;
BYTE luid[10] = {0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89};
BYTE luid[10] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89 };
#define PMm_VALUE 0x00F1000000014300ULL
#define FelicaSystemBlock_RC 0x00
@ -135,8 +150,7 @@ void populate_felica(NFCFelica_t* card) {
0x00, 0x2a, 0x05, 0x73, 0x02, 0x01, 0x03, 0x00,
// ^DFC^ ^~~~~~ arbitary value
};
memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_ID].bytes, blockID,
16);
memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_ID].bytes, blockID, 16);
BYTE blockDID[16] = {
// IDd (=IDm)
0x01,
@ -157,8 +171,7 @@ void populate_felica(NFCFelica_t* card) {
0x43,
0x00,
};
memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_D_ID].bytes, blockDID,
16);
memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_D_ID].bytes, blockDID, 16);
}
void populate_mifare(NFCMifare_t* card) {
card->type = CardType_Mifare;
@ -202,14 +215,16 @@ BYTE AIME_KEY[6];
BYTE BANA_KEY[6];
DWORD WINAPI aime_bd_thread(com_device_t* dev) {
static int fwNumBytes = 0;
log_info("aime_bd", "%ls woke up", dev->com->wName);
bool radio = false;
while (1) {
comio_recv_head_t req;
comio_next_req(dev, &req, extra);
unsigned char sum = comio_next_req(dev, &req, extra);
log_info("aime_bd", "(%d) %02x", req.dst, req.op);
log_info("aime_bd", "(%d) %02x(%d) = %s", req.dst, req.op, req.length, OpcodeNames[req.op]);
if (req.dst == 0x00 || req.dst == 0x01) {
// Aime readers
@ -218,12 +233,14 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_GetFWVersion:
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof FWVer - 1,
(LPBYTE)FWVer);
// BYTE fver = 0x10;
// comio_reply(dev, &req, COMIO_STATUS_OK, 1, &fver);
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof FWVer - 1, (LPBYTE)FWVer);
break;
case TN32Op_GetHWVersion:
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof HWVer - 1,
(LPBYTE)HWVer);
// BYTE hver = 0x10;
// comio_reply(dev, &req, COMIO_STATUS_OK, 1, &hver);
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof HWVer - 1, (LPBYTE)HWVer);
break;
case TN32Op_SetKeyAime:
if (req.length != sizeof AIME_KEY) {
@ -232,10 +249,8 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
memcpy(AIME_KEY, extra, sizeof AIME_KEY);
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
log_info("aime_bd",
"Aime key: %02x %02x %02x %02x %02x %02x",
AIME_KEY[0], AIME_KEY[1], AIME_KEY[2],
AIME_KEY[3], AIME_KEY[4], AIME_KEY[5]);
log_info("aime_bd", "Aime key: %02x %02x %02x %02x %02x %02x", AIME_KEY[0],
AIME_KEY[1], AIME_KEY[2], AIME_KEY[3], AIME_KEY[4], AIME_KEY[5]);
}
break;
case TN32Op_SetKeyBana:
@ -245,10 +260,8 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
memcpy(BANA_KEY, extra, sizeof BANA_KEY);
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
log_info("aime_bd",
"Bana key: %02x %02x %02x %02x %02x %02x",
BANA_KEY[0], BANA_KEY[1], BANA_KEY[2],
BANA_KEY[3], BANA_KEY[4], BANA_KEY[5]);
log_info("aime_bd", "Bana key: %02x %02x %02x %02x %02x %02x", BANA_KEY[0],
BANA_KEY[1], BANA_KEY[2], BANA_KEY[3], BANA_KEY[4], BANA_KEY[5]);
}
break;
case TN32Op_RadioOn:
@ -274,6 +287,43 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_Unknown60:
// req.length == 0; start firmware update?
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_Unknown61:
// null-terminated line of the firmware hex!
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
log_info("aime_bd", "Recv firmware: %s", extra);
break;
case TN32Op_Unknown63:
// req.length == 0; start binary firmware update?
fwNumBytes = 0;
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
case TN32Op_Unknown64:
// Raw binary firmware data
// [req.length == 256 -> wraps to 00] [256 bytes]
if (req.length == 0) {
unsigned char update_buffer[256];
update_buffer[0] = sum;
comio_read(dev, update_buffer + 1, 255);
// We need to account for the actual checksum at the end of this lot
comio_read(dev, &sum, 1);
fwNumBytes += 256;
} else {
fwNumBytes += req.length;
}
// nxAuth is segfaulting past this. Rather than figure it out, let's just
// protect it from itself for now.
if (fwNumBytes >= 0x3000)
;
else
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
// TODO: These
case TN32Op_ReadBlock:
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
@ -291,12 +341,10 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
case LedGetInfo:
// TODO: I'm not sure what this actually means.
// 838-15084 is probably a part number
comio_reply(dev, &req, COMIO_STATUS_OK, 9,
(BYTE*)"15084\xff\x10\x00\x12");
comio_reply(dev, &req, COMIO_STATUS_OK, 9, (BYTE*)"15084\xff\x10\x00\x12");
break;
case LedSetColour:
log_misc("nfc", "Set LED: #%02x%02x%02x", extra[0],
extra[1], extra[2]);
log_misc("nfc", "Set LED: #%02x%02x%02x", extra[0], extra[1], extra[2]);
printf(
"\033[48;2;%d;%d;%dm "
" \033[0m",
@ -311,6 +359,31 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
}
void install_aime_bd() {
ZeroMemory(OpcodeNames, sizeof OpcodeNames);
OpcodeNames[TN32Op_Unknown20] = "Unknown20";
OpcodeNames[TN32Op_GetFWVersion] = "GetFWVersion";
OpcodeNames[TN32Op_GetHWVersion] = "GetHWVersion";
OpcodeNames[TN32Op_RadioOn] = "RadioOn";
OpcodeNames[TN32Op_RadioOff] = "RadioOff";
OpcodeNames[TN32Op_Poll] = "Poll";
OpcodeNames[TN32Op_MifareSelectTag] = "MifareSelectTag";
OpcodeNames[TN32Op_Unknown44] = "Unknown44";
OpcodeNames[TN32Op_SetKeyBana] = "SetKeyBana";
OpcodeNames[TN32Op_GetKeyBana] = "GetKeyBana";
OpcodeNames[TN32Op_ReadBlock] = "ReadBlock";
OpcodeNames[TN32Op_Unknown53] = "Unknown53";
OpcodeNames[TN32Op_SetKeyAime] = "SetKeyAime";
OpcodeNames[TN32Op_GetKeyAime] = "GetKeyAime";
OpcodeNames[TN32Op_Unknown60] = "Unknown60";
OpcodeNames[TN32Op_Unknown61] = "Unknown61";
OpcodeNames[TN32Op_Reset] = "Reset";
OpcodeNames[TN32Op_Unknown70] = "Unknown70";
OpcodeNames[TN32Op_FelicaEncap] = "FelicaEncap";
OpcodeNames[LedReset] = "LedReset";
OpcodeNames[LedGetInfo] = "LedGetInfo";
OpcodeNames[LedSetColour] = "LedSetColour";
char* text = MiceConfig.devices.aime_bd;
char* copy = (char*)malloc(strlen(text) + 1);
memcpy_s(copy, strlen(text) + 1, text, strlen(text) + 1);
@ -319,8 +392,7 @@ void install_aime_bd() {
char* token = strtok_s(copy, ",", &next_token);
while (token != NULL) {
BYTE com_port = atoi(token) & 0xFF;
if (com_port)
com_device_thread(new_com_device(com_port), aime_bd_thread);
if (com_port) com_device_thread(new_com_device(com_port), aime_bd_thread);
token = strtok_s(NULL, ",", &next_token);
}

View File

@ -4,6 +4,8 @@
#define EEPROM_DUMP L"dev/eeprom.bin"
#include "../../sysconf.h"
// 8192 x 8 (64kbit) of eeprom
BYTE EEPROM_DATA[0x2000];
@ -39,9 +41,9 @@ void eeprom_restore() {
*(uint32_t*)&val = (uint32_t)((a << 24) | (b << 16) | (c << 8) | d); \
} while (0)
#define fix_crc(block) \
do { \
(block).m_Crc = amCrc32RGet(sizeof(block) - 4, (BYTE*)(&(block)) + 4, 0); \
#define fix_crc(block) \
do { \
(block).m_Crc = amiCrc32RCalc(sizeof(block) - 4, (BYTE*)(&(block)) + 4, 0); \
} while (0)
void set_eeprom_network_config() {
@ -87,7 +89,14 @@ int build_eeprom() {
memcpy(&EEPROM_DATA[AM_SYSDATAwH_STATIC_REG], &Static, sizeof Static);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_STATIC_DUP], &Static, sizeof Static);
AM_SYSDATAwH_CREDIT Credit = { 0 };
AM_SYSDATAwH_CREDIT Credit = {
.m_Config = {
.ServiceType = 1,
.CreditRate = 1,
.CoinRate = { 1, 1 },
.Cost = { 1, 1, 1, 1, 1, 1, 1, 1 },
},
};
fix_crc(Credit);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_CREDIT_REG], &Credit, sizeof Credit);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_CREDIT_DUP], &Credit, sizeof Credit);
@ -96,10 +105,10 @@ int build_eeprom() {
AM_SYSDATAwH_HISTORY History = { 0 };
// TODO: Game ID here should be configurable.
History.m_GameId[0] = 'S';
History.m_GameId[1] = 'D';
History.m_GameId[2] = 'E';
History.m_GameId[3] = 'Y';
History.m_GameId[0] = GAME_ID_0;
History.m_GameId[1] = GAME_ID_1;
History.m_GameId[2] = GAME_ID_2;
History.m_GameId[3] = GAME_ID_3;
History.m_Region = MiceConfig.sysconf.region & (1 | 2 | 4 | 8);
fix_crc(History);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_REG], &History, sizeof History);

View File

@ -0,0 +1,15 @@
#include "smbus.h"
smbus_callback_t smbus_AT24C64AN_write;
smbus_callback_t smbus_AT24C64AN_read;
#define AT24C64AN_GND 0
#define AT24C64AN_VCC 1
// Ref: MS-9667 rev 0A sheet 10
#define AT24C64AN_PIN_A0 AT24C64AN_VCC
#define AT24C64AN_PIN_A1 AT24C64AN_VCC
#define AT24C64AN_PIN_A2 AT24C64AN_VCC
#define AT24C64AN_ADDRESS \
(0b1010'000 | (AT24C64AN_PIN_A2 << 2) | (AT24C64AN_PIN_A1 << 1) | AT24C64AN_PIN_A0)

View File

@ -1,85 +0,0 @@
#include "_devices.h"
/**
* TODO: This whole device, properly
*/
BOOL smbus_DS_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
static unsigned char challenge[7];
switch (cmd) {
case ICH9_CMD_BLOCK: {
switch (code) {
case 0xa9d0:
case 0xa9d1:
case 0xa9d2:
case 0xa9d3: {
if (dlen != 7) {
log_error("smb-ds", "Expected challenge length of 7 (saw %d)!", dlen);
return FALSE;
}
memcpy(challenge, &(data[2]), 7);
char* challenge_s = malloc(dlen * 3 + 1);
if (challenge_s == NULL) {
log_info("smb-ds", "Challenge: (buffer failed)");
return TRUE;
}
for (int i = 0; i < dlen; i++) {
sprintf_s(challenge_s + i * 3, 4, "%02x ", data[2 + i]);
}
challenge_s[dlen * 3 + 1] = '\0';
log_info("smb-ds", "Challenge: %s", challenge_s);
free(challenge_s);
return TRUE;
}
default:
log_error("smb-ds", "Unknown write command: %04x", code);
}
}
case ICH9_CMD_I2C_READ: {
switch (code) {
case DS_I2C_CHALLENGE_RESPONSE:
// This just has to match EXIO!
for (int i = 0; i < dlen; i++) data[i] = 0x69;
return TRUE;
default:
log_error("smb-ds", "Unknown I2C read command: %04x", code);
}
}
default:
log_error("smb-ds", "Unsupported write mode: %01x (%04x)", cmd, code);
return FALSE;
}
}
BOOL smbus_DS_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
static unsigned char DS_eeprom[3][0x20];
switch (cmd) {
case ICH9_CMD_BYTE_DATA:
if (code < 0x80) {
BYTE page = (code >> 5) & 0b11;
BYTE offset = code & 0x1f;
data[0] = DS_eeprom[page][offset];
return TRUE;
} else if (code >= DS_GET_UNIQUE_NUMBER && code < DS_GET_UNIQUE_NUMBER + 0xf) {
data[0] = 0x04; // chosen by fair dice roll.
return TRUE;
} else if (code == DS_GET_STATUS) {
// Polled until DS_STATUS_FLAG_BUSY low
data[0] = 0x00;
return TRUE;
} else {
log_error("smb-ds", "Unknown read command: %04x", code);
return FALSE;
}
default:
log_error("smb-ds", "Unsupported read mode: %01x (%04x)", cmd, code);
return FALSE;
}
}

View File

@ -0,0 +1,144 @@
/**
* This board is located on the mezzanine board in the Ring (IC7).
*
* Similar to the DS28CN01, this is a SHA-1 coprocessor with EEPROM
* storage.
*
* The pins are wired as:
*
* pin | name | connection
* 1 | AD0 | GND
* 2 | AD1 | Floating
* 3 | AD2 | Floating
* 4 | GND | GND
* 5 | NC |
* 6 | SDA | SMData
* 7 | SCL | SMClock
* 8 | Vcc | VCC3
*
* Pins 2 and 3 are floating, when they should be pulled to Vcc. It is
* therefore assumed that there's an internal pull-up on all three AD
* pins, as otherwise this device would be at address 0x40!
*
* In code it is referred to as the "ds exio" device, complemeting the
* "ds" device on the keychip.
*/
#include "smb_ds2460.h"
#include <openssl/evp.h>
#include "_ds_sha.h"
static BYTE USER_EEPROM[DS2460_EEPROM_SIZE];
static BYTE INPUT_BUFFER[DS2460_INPUT_BUFFER_SIZE];
static BYTE COMPUTED_MAC[DS2460_MAC_LEN];
static BYTE SECRETS[4][8] = {
// S-Secret
{ 0 },
// E-Secret 1
{ 0 },
// E-Secret 2 <-- The one that's used
{ 0 },
// E-Secret 3
{ 0 },
};
void ds2460_update_mac(bool gpSha, byte* secret) {
memcpy(&INPUT_BUFFER[0], &secret[0], 4);
memcpy(&INPUT_BUFFER[48], &secret[4], 4);
INPUT_BUFFER[55] = 0x80;
for (int i = 56; i < 62; i++) INPUT_BUFFER[i] = 0;
INPUT_BUFFER[62] = 0x01;
INPUT_BUFFER[63] = 0xB8;
puts("ds2460: SHA1 input buffer:");
for (int i = 0; i < DS2460_INPUT_BUFFER_SIZE; i++) {
printf("%02x", INPUT_BUFFER[i]);
}
puts("");
if (gpSha) {
EVP_MD_CTX* ctx = EVP_MD_CTX_create();
EVP_DigestInit(ctx, EVP_sha1());
EVP_DigestUpdate(ctx, INPUT_BUFFER, DS2460_INPUT_BUFFER_SIZE);
unsigned int outlen;
EVP_DigestFinal_ex(ctx, COMPUTED_MAC, &outlen);
EVP_MD_CTX_destroy(ctx);
} else {
ComputeDallasSha(INPUT_BUFFER, (long*)&COMPUTED_MAC[0], (long*)&COMPUTED_MAC[4],
(long*)&COMPUTED_MAC[8], (long*)&COMPUTED_MAC[12],
(long*)&COMPUTED_MAC[16]);
}
}
BOOL smbus_ds2460_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
switch (cmd) {
case ICH9_CMD_BYTE_DATA:
switch (code) {
case DS2460_MEM_CMD:
/**
* 0x94 =
* | 0x80 -> DS2460_CMD_COMPUTE
* | 0x10 -> (secret = ESecret2) << 3
* | 0x04 -> DS2460_CMD_COMPUTE_TO_MAC_BUFFER
*/
if (!(data[0] & DS2460_CMD_COMPUTE)) {
log_error("ds2460", "Unknown command: %02x", data[0]);
return FALSE;
}
BYTE numSecret = (data[0] >> 3) & 3;
BOOL toMacBuffer = !!(data[0] & DS2460_CMD_COMPUTE_TO_MAC_BUFFER);
BYTE gpSha = !!(data[0] & DS2460_CMD_COMPUTE_GP_SHA);
if (data[0] != DS2460_REQUEST_COMPUTE_MAC) {
}
ds2460_update_mac(gpSha, SECRETS[numSecret]);
return TRUE;
default:
log_error("ds2460", "Unknown write command: %02x", code);
return FALSE;
}
case ICH9_CMD_BLOCK: {
BYTE offset = code >> 8;
// One extra byte of data is stuffed into the command code
if (offset < DS2460_INPUT_BUFFER_SIZE) INPUT_BUFFER[offset] = code & 0xff;
if (offset + 1 < DS2460_INPUT_BUFFER_SIZE)
memcpy_s(&INPUT_BUFFER[offset + 1], DS2460_INPUT_BUFFER_SIZE - (offset + 1), data,
dlen);
log_info("ds2460", "Block write, %d @ %04x: ", dlen + 1, offset);
return TRUE;
}
default:
log_error("ds2460", "Unsupported write mode: %01x (%02x)", cmd, code);
return FALSE;
}
}
BOOL smbus_ds2460_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
switch (cmd) {
case ICH9_CMD_BYTE_DATA:
if (code == DS2460_MEM_SHA) {
// if we were busy processing something we'd:
// return FALSE;
return TRUE;
}
if (DS2460_MEM_MAC <= code < DS2460_MEM_MAC + DS2460_MAC_LEN) {
data[0] = COMPUTED_MAC[code - DS2460_MEM_MAC];
return TRUE;
}
log_error("smx-exio", "Unknown read command: %02x", code);
return FALSE;
default:
log_error("ds2460", "Unsupported read mode: %01x (%02x)", cmd, code);
return FALSE;
}
}

View File

@ -0,0 +1,42 @@
#include "smbus.h"
smbus_callback_t smbus_ds2460_write;
smbus_callback_t smbus_ds2460_read;
// Specification
#define DS2460_EEPROM_SIZE 112
#define DS2460_INPUT_BUFFER_SIZE 64
#define DS2460_MAC_LEN 20
// Registers
#define DS2460_MEM_SHA 0x00
#define DS2460_MEM_MAC 0x40
#define DS2460_MEM_SSECRET 0x54
#define DS2460_MEM_CMD 0x5C
#define DS2460_MEM_MATCHMAC 0x5E
#define DS2460_MEM_ESECRET1 0x60
#define DS2460_MEM_ESECRET2 0x68
#define DS2460_MEM_ESECRET3 0x70
#define DS2460_MEM_EEPROM 0x80
#define DS2460_MEM_SERIAL 0xF0
#define DS2460_CMD_COMPUTE 0x80
#define DS2460_CMD_COMPUTE_GP_SHA 0x20
#define DS2460_CMD_COMPUTE_TO_MAC_BUFFER 0x04
#define DS2460_CMD_TXSECRET 0x40
// Consts
#define DS2460_REQUEST_COMPUTE_MAC 0x94
// Wiring
#define DS2460_GND 0
#define DS2460_VCC 1
#define DS2460_PIN_AD0 DS2460_GND
#define DS2460_PIN_AD1 DS2460_VCC
#define DS2460_PIN_AD2 DS2460_VCC
#define DS2460_ADDRESS \
(0b10'0'0'0'0'0 | DS2460_PIN_AD0 | (DS2460_PIN_AD1 << 2) | (DS2460_PIN_AD2 << 4))

View File

@ -0,0 +1,200 @@
/**
* This is one of three uniquely accesible chips on the keychip, and one
* of two on the SMBus.
*
* The DS28CN01 is a 1Kbit EEPROM with hardware SHA-1 and a factory-
* unique random number.
*
* The pins are wired as:
*
* pin | name | connection
* -----------------------
* 1 | AD0 | VCC3
* 2 | AD1 | VCC3
* 3 | NC |
* 4 | GND | GND
* 5 | SDA | SMData
* 6 | SCL | SMClock
* 7 | NC |
* 8 | Vcc | VCC3
*/
#include "smb_ds28cn01.h"
#include <openssl/evp.h>
#include "_ds_sha.h"
// Keychip secrets!
static BYTE USER_EEPROM[DS28CN01_EEPROM_PAGES][DS28CN01_EEPROM_PAGE_SIZE] = {
{
0x09, 0xb7, 0xcc, 0xe7, 0x74, 0x5f, 0x5c, 0xd9, 0xf2, 0x29, 0x70,
0x86, 0x70, 0x61, 0xf4, 0xba, 0xdb, 0x4f, 0xde, 0x1e, 0x85, 0x0b,
0xb6, 0xaf, 0xcb, 0x93, 0x55, 0x6e, 0xf5, 0x1b, 0xed, 0x59,
},
{
0x5d, 0xa4, 0x49, 0x9b, 0xd4, 0xd0, 0x56, 0x00, 0x41, 0xf5, 0xe3,
0xab, 0x8b, 0x70, 0xa5, 0x0b, 0xb9, 0x3c, 0x7e, 0x0b, 0x58, 0xc3,
0xfe, 0x89, 0x1d, 0xf3, 0x2b, 0x0a, 0xcc, 0x95, 0x7d, 0xac,
},
{
0x58, 0xda, 0x2d, 0x5c, 0x4c, 0x37, 0xb0, 0x48, 0x69, 0x73, 0x7e,
0x97, 0x91, 0xff, 0x17, 0x58, 0xe4, 0x85, 0x48, 0xb9, 0x28, 0xc3,
0xaa, 0x7a, 0x6e, 0x9a, 0x6d, 0xa1, 0xf2, 0x62, 0x53, 0x6e,
},
{
0x44, 0x81, 0xff, 0x91, 0xa5, 0x3c, 0x70, 0x9b, 0xb4, 0xcd, 0xc9,
0xb3, 0x4a, 0xb5, 0x53, 0x8a, 0xa2, 0x53, 0xc4, 0x91, 0xbd, 0xb6,
0xc2, 0x69, 0x04, 0xb0, 0xa3, 0x9a, 0x30, 0x2b, 0x77, 0x89,
},
};
// TODO: Make this actually a valid ID (crc and whatnot)
// Unique per keychip
static const BYTE UNIQUE_NUMBER[DS28CN01_UNIQUE_NUMBER_SIZE] = {
'M', 'I', 'C', 'E', 'K', 'E', 'Y', '\0',
};
#define DS28CN01_INPUT_BUFFER_SIZE 64
static BYTE MAC_INPUT_BUFFER[DS28CN01_INPUT_BUFFER_SIZE];
static BYTE COMPUTED_MAC[DS28CN01_MAC_LEN];
static BYTE SECRET[8] = { 0 };
void ds28cn01_update_mac(void) {
puts("ds28cn01: SHA1 input buffer:");
for (int i = 0; i < DS28CN01_INPUT_BUFFER_SIZE; i++) {
printf("%02x", MAC_INPUT_BUFFER[i]);
}
puts("");
// EVP_MD_CTX* ctx = EVP_MD_CTX_create();
// EVP_DigestInit(ctx, EVP_sha1());
// EVP_DigestUpdate(ctx, MAC_INPUT_BUFFER, DS28CN01_INPUT_BUFFER_SIZE);
// unsigned int outlen;
// EVP_DigestFinal_ex(ctx, COMPUTED_MAC, &outlen);
// EVP_MD_CTX_destroy(ctx);
ComputeDallasSha(MAC_INPUT_BUFFER, (long*)&COMPUTED_MAC[0], (long*)&COMPUTED_MAC[4],
(long*)&COMPUTED_MAC[8], (long*)&COMPUTED_MAC[12],
(long*)&COMPUTED_MAC[16]);
puts("ds28cn01: SHA1 out buffer:");
for (int i = 0; i < 20; i++) {
printf("%02x", COMPUTED_MAC[i]);
}
puts("");
}
BOOL smbus_ds28cn01_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
static unsigned char challenge[8];
switch (cmd) {
case ICH9_CMD_BLOCK: {
if (code >> 8 == 0xa9) {
BYTE command = code & 0xff;
BYTE page = command & 3;
BYTE upper = command & 0xf0;
if (upper == 0xD0) {
log_warning("ds28cn01", "Computing for: authentication (flag = 1)");
} else if (upper == 0xE0) {
log_warning("ds28cn01", "Computing for: ds.compute (flag = 0)");
} else {
log_error("ds28cn01", "Unknown A9");
return FALSE;
}
if (dlen != 7) {
log_error("ds28cn01", "Expected challenge length of 7 (saw %d)!", dlen);
return FALSE;
}
memcpy(&MAC_INPUT_BUFFER[0], &SECRET[0], 4);
memcpy(&MAC_INPUT_BUFFER[4], USER_EEPROM[page], DS28CN01_EEPROM_PAGE_SIZE);
memcpy(&MAC_INPUT_BUFFER[36], &data[0], 4);
MAC_INPUT_BUFFER[40] = 0x40 | page;
memcpy(&MAC_INPUT_BUFFER[41], UNIQUE_NUMBER, 7);
memcpy(&MAC_INPUT_BUFFER[48], &SECRET[4], 4);
memcpy(&MAC_INPUT_BUFFER[52], &data[4], 3);
MAC_INPUT_BUFFER[55] = 0x80;
for (int i = 56; i < 62; i++) MAC_INPUT_BUFFER[i] = 0;
MAC_INPUT_BUFFER[62] = 0x01;
MAC_INPUT_BUFFER[63] = 0xB8;
//
// Stuffing into the command code, as ever
// challenge[0] = command & 0xff;
// memcpy(&(challenge[1]), data, dlen);
// dlen++;
// char* challenge_s = malloc(dlen * 3 + 1);
// if (challenge_s == NULL) {
// log_info("ds28cn01", "Challenge: (buffer failed)");
// return TRUE;
// }
// for (int i = 0; i < dlen; i++) {
// sprintf_s(challenge_s + i * 3, 4, "%02x ", data[i]);
// }
// challenge_s[dlen * 3 + 1] = '\0';
// log_info("ds28cn01", "Challenge: %s", challenge_s);
// free(challenge_s);
return TRUE;
}
log_error("ds28cn01", "Unknown write command: %04x", code);
}
case ICH9_CMD_I2C_READ: {
switch (code) {
case DS28CN01_REG_MAC:
// This just has to match EXIO!
if (dlen > DS28CN01_MAC_LEN) return FALSE;
ds28cn01_update_mac();
for (int i = 0; i < dlen; i++) data[i] = COMPUTED_MAC[i];
return TRUE;
default:
log_error("ds28cn01", "Unknown I2C read command: %04x", code);
}
}
default:
log_error("ds28cn01", "Unsupported write mode: %01x (%04x)", cmd, code);
return FALSE;
}
}
BOOL smbus_ds28cn01_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
switch (cmd) {
case ICH9_CMD_BYTE_DATA:
if (code < DS28CN01_EEPROM_SIZE) {
BYTE page = (code >> 5) & 0b11;
BYTE offset = code & 0x1f;
data[0] = USER_EEPROM[page][offset];
return TRUE;
}
if (code >= DS28CN01_REG_NUM && code <= DS28CN01_REG_NUM_END) {
data[0] = UNIQUE_NUMBER[code - DS28CN01_REG_NUM];
return TRUE;
}
if (code == DS28CN01_REG_STATUS) {
// Polled until DS_STATUS_FLAG_BUSY low
data[0] = 0x00;
return TRUE;
}
log_error("ds28cn01", "Unknown read command: %04x", code);
return FALSE;
default:
log_error("ds28cn01", "Unsupported read mode: %01x (%04x)", cmd, code);
return FALSE;
}
}

View File

@ -0,0 +1,43 @@
#include "smbus.h"
smbus_callback_t smbus_ds28cn01_write;
smbus_callback_t smbus_ds28cn01_read;
// Specification
#define DS28CN01_EEPROM_PAGES 4
#define DS28CN01_EEPROM_PAGE_SIZE 32
#define DS28CN01_EEPROM_SIZE (DS28CN01_EEPROM_PAGES * DS28CN01_EEPROM_PAGE_SIZE)
#define DS28CN01_UNIQUE_NUMBER_SIZE 8
#define DS28CN01_MAC_LEN 20
// Registers
#define DS28CN01_REG_NUM 0xA0
#define DS28CN01_REG_NUM_END (DS28CN01_REG_NUM + DS28CN01_UNIQUE_NUMBER_SIZE - 1)
#define DS28CN01_REG_STATUS 0xA8
#define DS28CN01_REG_MAC 0xB0
// Flags
#define DS28CN01_STATUS_FLAG_BUSY 2
// Wiring
#define DS28CN01_GND 0
#define DS28CN01_VCC 1
#define DS28CN01_SCL 2
#define DS28CN01_SDA 3
#define DS28CN01_PIN_AD1 DS28CN01_VCC
#define DS28CN01_PIN_AD0 DS28CN01_VCC
#define DS28CN01_ADDRESS \
(0b101'00'00 | \
(((DS28CN01_PIN_AD1 == DS28CN01_GND) ? 0b00 \
: (DS28CN01_PIN_AD1 == DS28CN01_VCC) ? 0b01 \
: (DS28CN01_PIN_AD1 == DS28CN01_SCL) ? 0b10 \
: 0b11) \
<< 2) | \
((DS28CN01_PIN_AD0 == DS28CN01_GND) ? 0b00 \
: (DS28CN01_PIN_AD0 == DS28CN01_VCC) ? 0b01 \
: (DS28CN01_PIN_AD0 == DS28CN01_SCL) ? 0b10 \
: 0b11))

View File

@ -1,53 +0,0 @@
#include "_devices.h"
BOOL smbus_EXIO_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
switch (cmd) {
case ICH9_CMD_BYTE_DATA:
switch (code) {
case 0x5c:
if (data[0] == 0x94) return TRUE;
default:
log_error("smb-exio", "Unknown write command: %02x", code);
return FALSE;
}
case ICH9_CMD_BLOCK: {
WORD reg = *(WORD*)(&data[-1]);
dlen = data[1];
// char* data_s = malloc(dlen * 3 + 1);
// for (int i = 0; i < dlen; i++) {
// sprintf_s(data_s + i * 3, 3, "%02x ", data[2 + i]);
// }
// data_s[dlen * 3 + 1] = '\0';
log_info("smb-exio", "Block write, %d @ %04x: ", dlen, reg);
// free(data_s);
return TRUE;
}
default:
log_error("smb-exio", "Unsupported write mode: %01x (%02x)", cmd, code);
return FALSE;
}
}
BOOL smbus_EXIO_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
switch (cmd) {
case ICH9_CMD_BYTE_DATA:
if (0x40 <= code < 0x40 + 0x14) {
// mxkDsExioReadMacOutputBuffer
// This just has to match N2_I2C_CHALLENGE_RESPONSE!
data[0] = 0x69;
return TRUE;
} else if (code == EXIO_GET_BUSY) {
data[0] = 0x00; // Anything non-zero = busy
return TRUE;
} else {
log_error("smx-exio", "Unknown read command: %02x", code);
return FALSE;
}
default:
log_error("smb-exio", "Unsupported read mode: %01x (%02x)", cmd, code);
return FALSE;
}
}

View File

@ -3,6 +3,7 @@
#include <openssl/rand.h>
#include "../../lib/mxk/mxk.h"
#include "../../sysconf.h"
#include "_devices.h"
#define N2_TAG_OFFSET 0
@ -111,19 +112,18 @@ typedef struct {
} N2_KEYCHIP_INFO, *PN2_KEYCHIP_INFO;
#pragma pack(pop)
N2_KEYCHIP_INFO n2_keychip_info = {
.m_KeyId = { 'A', '7', '2', 'E', '-', '0', '2', 'D', '1', '1', '2', '6', '1', '1', '1', '6' },
.m_Appboot = {
.m_Format = 1,
.m_GameId = { 'S' , 'D', 'E', 'Y' },
.m_Region = 0xff,
.m_ModelType = 2,
.m_SystemFlag = 0x24,
.m_PlatformId = {'A', 'A', 'S'},
.m_DvdFlag = 1,
.m_NetworkAddr = (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24),
}
};
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),
} };
WORD n2_enable_session(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) {
*nOut = 20;
@ -172,10 +172,13 @@ WORD n2_read_keychip_id(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nO
*nOut = (nbytes & 0xff) + 2;
n2_keychip_info.m_Appboot.m_Crc = amCrc32RGet(sizeof n2_keychip_info.m_Appboot - 4, (LPBYTE)&n2_keychip_info.m_Appboot + 4, 0);
n2_keychip_info.m_Crc = amCrc32RGet(sizeof n2_keychip_info - 4, (LPBYTE)&n2_keychip_info + 4, 0);
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_Crc =
amiCrc32RCalc(sizeof n2_keychip_info - 4, (LPBYTE)&n2_keychip_info + 4, 0);
mxkCryptEncryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataOut + 2, (LPBYTE)&n2_keychip_info, nbytes);
mxkCryptEncryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataOut + 2, (LPBYTE)&n2_keychip_info,
nbytes);
log_misc("smb-n2", "Read keychip ID: %08x", nbytes);
return N2_SUCCESS;
@ -192,9 +195,9 @@ WORD n2_encrypt_with_gkey(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD
BYTE temp[16];
mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn + 1, temp, sizeof temp);
for(size_t i=0;i<17;i++)printf(" %02x",dataIn[i]);
for (size_t i = 0; i < 17; i++) printf(" %02x", dataIn[i]);
puts("");
for(size_t i=0;i<17;i++)printf(" %02x",temp[i]);
for (size_t i = 0; i < 17; i++) printf(" %02x", temp[i]);
puts("");
// Do Gkey encryption
@ -246,7 +249,6 @@ WORD n2_decrypt_with_skey(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD
return N2_SUCCESS;
}
n2_command N2_COMMANDS[0xff];
#define N2_INSTALL_COMMAND(ord, tag_, paramSize_, handler_) \
do { \

View File

@ -74,7 +74,7 @@ BOOL smbus_PCA9535_read(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
// data[0] = 0b00001000;
// data[0] = 0b0'111'0'000;
data[0] = DIPSW_LANDSCAPE | DIPSW_RES_DEFAULT;
data[0] = DIPSW_LANDSCAPE | DIPSW_RES_1920x1080;
return TRUE;
case PCA9535_IN1: // SW1/2 + extras

View File

@ -0,0 +1,14 @@
#include "smbus.h"
smbus_callback_t smbus_PCA9535_write;
smbus_callback_t smbus_PCA9535_read;
#define PCA9535_GND 0
#define PCA9535_VCC 1
#define PCA9535_PIN_A0 PCA9535_GND
#define PCA9535_PIN_A1 PCA9535_GND
#define PCA9535_PIN_A2 PCA9535_GND
#define PCA9535_ADDRESS \
(0b0100'000 | (PCA9535_PIN_A2 << 2) | (PCA9535_PIN_A1 << 1) | PCA9535_PIN_A0)

View File

@ -3,15 +3,21 @@
#include "drivers/mx.h"
#include "hooks/_hooks.h"
WCHAR exePath[MAX_PATH + 1];
WCHAR exeName[MAX_PATH + 1];
DWORD imageOffset;
#define WIN32_EXE_BASE 0x00400000
DWORD GetImageBase(LPCWSTR sModulePath) {
DWORD GetImageBase(void) {
WCHAR sModulePath[MAX_PATH];
GetModuleFileNameW(NULL, sModulePath, MAX_PATH);
HANDLE hObject =
_CreateFileW(sModulePath, FILE_READ_DATA, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hObject == INVALID_HANDLE_VALUE) return 0;
if (hObject == INVALID_HANDLE_VALUE) {
log_error(BOOT_LOGGER, "Failed to open %ls %03x", sModulePath, GetLastError());
return 0;
}
IMAGE_DOS_HEADER dosHeader = { 0 };
DWORD nRead;
@ -45,17 +51,17 @@ DWORD GetImageBase(LPCWSTR sModulePath) {
void apply_patches(HMODULE hModule) {
void* baseAddress = (void*)hModule;
DWORD imageBase = GetImageBase(exePath);
DWORD imageBase = GetImageBase();
if (imageBase == 0) {
log_error(BOOT_LOGGER, "Failed to locate image base. Patches will not be applied.");
return;
}
imageOffset = (DWORD)hModule - imageBase;
char exePathC[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, exePath, -1, exePathC, sizeof exePathC, NULL, NULL);
char exeNameC[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, exeName, -1, exeNameC, sizeof exeNameC, NULL, NULL);
if (!load_patches(MiceConfig.mice.patches_file, exePathC)) {
if (!load_patches(MiceConfig.mice.patches_file, exeNameC)) {
log_error(BOOT_LOGGER, "Failed to load patches file %s", MiceConfig.mice.patches_file);
return;
}
@ -89,7 +95,7 @@ void prebind_hooks() {
hook_all();
install_devices();
// TODO: Figure out why we're needing to call this manually (medium priority)
if (wcscmp(exePath, L"ALLNetProc.exe") == 0) {
if (wcscmp(exeName, L"ALLNetProc.exe") == 0) {
log_warning(BOOT_LOGGER, "Making explicit call to OPENSSL_add_all_algorithms_noconf");
// OPENSSL_add_all_algorithms_noconf
@ -99,13 +105,13 @@ void prebind_hooks() {
void init_injection(HMODULE hModule) {
// Make sure our CRC32 tables are ready for anything that might want to use them
amCrc32RCreateTable();
amiCrc32RInit();
load_mice_config();
// We're in a new context now, so need to reconfigure
setup_logging();
log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exePath);
log_info(BOOT_LOGGER, "Handover complete. Now executing within %ls", exeName);
if (MiceConfig.mice.apply_patches) apply_patches(hModule);
@ -145,20 +151,20 @@ void tea_hook_test(char* fmt, ...) {
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
if (ul_reason_for_call != DLL_PROCESS_ATTACH) return TRUE;
GetModuleFileNameW(NULL, exePath, MAX_PATH);
wcscpy_s(exePath, MAX_PATH + 1, PathFindFileNameW(exePath));
GetModuleFileNameW(NULL, exeName, MAX_PATH);
wcscpy_s(exeName, MAX_PATH + 1, PathFindFileNameW(exeName));
HMODULE exeModule = GetModuleHandleA(NULL);
init_injection(exeModule);
if (wcscmp(exePath, L"InitialD8_GLW_RE_SBZZ_dumped_.exe") == 0) {
CreateHook((void*)(0x00407850), &tea_hook_test, 5);
if (wcscmp(exeName, L"InitialD8_GLW_RE_SBZZ_dumped_.exe") == 0) {
CreateHook32((void*)(0x00407850), &tea_hook_test);
// *((DWORD*)(0x00407850)) = (DWORD)(&logcb);
}
if (wcscmp(exePath, L"RingGame.exe") == 0) {
if (wcscmp(exeName, L"RingGame.exe") == 0) {
log_warning(BOOT_LOGGER, "Bodge hook goo!");
CreateHook((void*)(0x005f2580), &tea_hook_test, 5);
CreateHook32((void*)(0x005f2580), &tea_hook_test);
}
return TRUE;

View File

@ -10,8 +10,10 @@ BOOL test_btn = false;
#define PLAYER_COUNT 2
#define COIN_COUNTERS 2
#define SWITCH_BYTES 2
const char JVS_837_13551_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
// const char JVS_837_14572_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-14572 ;Ver1.00;98/10";
const char JVS_837_14572_ID[] = "SEGA ENTERPRISES,LTD.;I/O BD JVS;837-13551 ;Ver1.00;98/10";
typedef struct _jvs_board {
char test_keybind;
@ -26,6 +28,8 @@ typedef struct _jvs_board {
unsigned char* outData, unsigned char* outCount);
const char* id;
unsigned char last_sysbuttons;
unsigned short last_buttons[PLAYER_COUNT];
} jvs_board_t;
#define JVS_FLAG_NONE 0
#define JVS_FLAG_NC 1
@ -34,10 +38,6 @@ typedef struct _jvs_board {
jvs_board_t (*jvs_config)[];
size_t jvs_num_boards;
// unsigned short coin_data[COIN_COUNTERS];
// #define JVS_BUTTON_COIN_1 '1'
// #define JVS_BUTTON_COIN_2 '2'
short jvs_unpad(unsigned char* paddedData, short length, unsigned char* unpaddedData) {
short index = 0;
bool escape = false;
@ -69,6 +69,27 @@ short jvs_pad(unsigned char* unpaddedData, short length, unsigned char* paddedDa
return index;
}
void update_jvs_buttons(jvs_board_t* board) {
unsigned char sysButtons = 0x00;
if (GetAsyncKeyState(board->test_keybind) < 0) sysButtons |= 0x80;
board->last_sysbuttons = sysButtons;
for (int player = 0; player < PLAYER_COUNT; player++) {
unsigned short buttons = 0x0000;
for (int i = 0; i < SWITCH_BYTES * 8; i++) {
int scancode = board->keybinds[player][i];
unsigned char flags = board->flags[player][i];
if (flags & JVS_FLAG_NC) continue;
if (flags & JVS_FLAG_INVERT)
buttons |= (GetAsyncKeyState(scancode) >= 0) << i;
else
buttons |= (GetAsyncKeyState(scancode) < 0) << i;
}
board->last_buttons[player] = buttons;
}
}
unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCount,
unsigned char* response, unsigned char* outCount) {
short jvsIndex = 0;
@ -136,7 +157,7 @@ unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCo
jvs_write(JVS_FEATURE_PLAYERS);
jvs_write(PLAYER_COUNT);
jvs_write(13);
jvs_write(13); // bits per player
jvs_write(JVS_FEATURE_PAD);
jvs_write(JVS_FEATURE_COINS);
jvs_write(COIN_COUNTERS);
@ -169,31 +190,15 @@ unsigned char jvs_exchange(jvs_board_t* board, unsigned char* inData, short inCo
jvs_write(JVS_REPORT_PARAM_INVALID);
break;
}
update_jvs_buttons(board);
jvs_write(JVS_REPORT_OK);
unsigned char buttons = 0x00;
if (GetAsyncKeyState(board->test_keybind) < 0) buttons |= 0x80;
jvs_write(buttons);
jvs_write(board->last_sysbuttons);
for (int player = 0; player < players; player++) {
for (int j = 0; j < switch_bytes; j++) {
buttons = 0x00;
for (int bit = 0; bit < 8; bit++) {
int scancode =
board->keybinds[player][(switch_bytes - j - 1) * 8 + bit];
unsigned char flags =
board->flags[player][(switch_bytes - j - 1) * 8 + bit];
if (flags & JVS_FLAG_NC) continue;
if (flags & JVS_FLAG_INVERT)
buttons |= (GetAsyncKeyState(scancode) >= 0) << bit;
else
buttons |= (GetAsyncKeyState(scancode) < 0) << bit;
}
jvs_write(buttons);
for (int i = switch_bytes - 1; i >= 0; i--) {
jvs_write((board->last_buttons[player] >> (i * 8)) & 0xff);
}
}
break;
case JVS_CMD_READ_COIN:
@ -323,6 +328,7 @@ void mxjvs_handle(unsigned char* paddedIn, short inCount, unsigned char* outData
unsigned char* response = malloc(maxOut);
jvs_board_t* board = &(*jvs_config)[jvs_num_boards - destination];
// jvs_board_t* board = &(*jvs_config)[0];
unsigned char packetSize;
unsigned char status =
board->handler(board, inData + 3, inData[2] - 1, response + 4, &packetSize);
@ -475,10 +481,10 @@ jvs_board_t maimai_jvs_config[1] = { {
},
.coin_counts = {0, 0},
.handler = &jvs_exchange,
.id = JVS_837_13551_ID,
.id = JVS_837_14572_ID,
} };
jvs_board_t under_night_jvs_config[2] = {
jvs_board_t under_night_jvs_config[1] = {
{
.test_keybind = VK_OEM_4, // [{
.coin_keybinds = {'1', '2'},
@ -497,57 +503,7 @@ jvs_board_t under_night_jvs_config[2] = {
VK_RETURN, // Start
},
{
0
},
},
.flags = {
{
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
},
{
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
},
},
.coin_counts = {0, 0},
.handler = &jvs_exchange,
.id = JVS_837_13551_ID,
},
{
.test_keybind = VK_OEM_4, // [{
.coin_keybinds = {0, 0},
.keybinds = {
{
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
'J', // D (EXCs)
'P', // C (Heavy)
'O', // B (Middle)
@ -559,7 +515,6 @@ jvs_board_t under_night_jvs_config[2] = {
VK_BACK, // Service
VK_RETURN, // Start
},
{0},
},
.flags = {
{
@ -581,28 +536,105 @@ jvs_board_t under_night_jvs_config[2] = {
JVS_FLAG_NONE,
},
{
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NC,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
JVS_FLAG_NONE,
},
},
.coin_counts = {0, 0},
.handler = &jvs_exchange,
.id = JVS_837_13551_ID,
.id = JVS_837_14572_ID,
},
// {
// .test_keybind = VK_OEM_4, // [{
// .coin_keybinds = {0, 0},
// .keybinds = {
// {
// 0, 0, 0, 0, 0, 0,
// 'J', // D (EXCs)
// 'P', // C (Heavy)
// 'O', // B (Middle)
// 'I', // A (Light)
// VK_NUMPAD6, // Right
// VK_NUMPAD4, // Left
// VK_NUMPAD2, // Down
// VK_NUMPAD8, // Up
// VK_BACK, // Service
// VK_RETURN, // Start
// },
// {0},
// },
// .flags = {
// {
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// JVS_FLAG_NONE,
// },
// {
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// JVS_FLAG_NC,
// },
// },
// .coin_counts = {0, 0},
// .handler = &jvs_exchange,
// .id = JVS_837_14572_ID,
// },
};
// jvs_board_t (*jvs_config)[] = &maimai_jvs_config;

View File

@ -1,24 +1,25 @@
#include "mxparallel.h"
#include "../../sysconf.h"
BYTE parallel_flags = 0x00;
BYTE parallel_ctrl = 0x00;
BYTE parallel_status = 0x00;
BYTE parallel_data = 0x00;
BYTE KEYCHIP_ID[16] = { 'A', '7', '2', 'E', '-', '0', '2', 'D',
'1', '1', '2', '6', '1', '1', '1', '6' };
BYTE MAIN_ID[16] = { 'A', 'A', 'S', 'E', '-', '0', '1', 'A', '6', '5', '6', '4' };
BYTE KEYCHIP_ID[16] = KEY_ID;
BYTE _MAIN_ID[16] = MAIN_ID;
appboot_t APPBOOT = {
.format = 1,
.game_id = { 'S', 'D', 'E', 'Y' },
.game_id = GAME_ID,
.region = 8 | 4 | 2 | 1,
.model_type = 2,
// Bitfield
// 1 = use flash for appboot
.system_flag = 0x24,
._ = 0,
.platform_id = { 'A', 'A', 'S' },
.platform_id = HW_ID,
.dvd_flag = 1,
.network_addr = (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24),
.__ = 0,
@ -155,7 +156,7 @@ void init_nv_storage() {
billing_info.nearfull = 512;
mxkSignValue(billing_info.nearfull, billing_info.nearfull_sig);
mxkSignValue(billing_info.playlimit, billing_info.playlimit_sig);
billing_info.crc = amCrc32RGet(sizeof billing_info - 4, (unsigned char*)&billing_info + 4, 0);
billing_info.crc = amiCrc32RCalc(sizeof billing_info - 4, (unsigned char*)&billing_info + 4, 0);
memcpy(&flash[0x7a000], &billing_info, sizeof billing_info);
memcpy(&flash[0x7b000], &billing_info, sizeof billing_info);
@ -263,7 +264,7 @@ void mxparallel_process_packet(BYTE* request) {
log_warning("mxparallel", "GetAppBootInfo[%d] unexpected!", request[1]);
}
APPBOOT.crc = amCrc32RGet(sizeof APPBOOT - 4, (unsigned char*)&APPBOOT + 4, 0);
APPBOOT.crc = amiCrc32RCalc(sizeof APPBOOT - 4, (unsigned char*)&APPBOOT + 4, 0);
for (int i = 0; i < sizeof APPBOOT; i += 16) {
micexkSendPacket((unsigned char*)(&APPBOOT) + i);
}
@ -381,14 +382,14 @@ void mxparallel_process_packet(BYTE* request) {
case SetMainId:
log_info("mxparallel", "SetMainId");
// micexkRecvPacket(MAIN_ID);
// micexkRecvPacket(_MAIN_ID);
micexkRecvPacket(request);
response[0] = 0xff;
micexkSendPacket(response);
break;
case GetMainId:
log_info("mxparallel", "GetMainId");
micexkSendPacket(MAIN_ID);
micexkSendPacket(_MAIN_ID);
break;
case SetKeyId:
log_info("mxparallel", "SetKeyId");

View File

@ -69,9 +69,6 @@ BOOL handle_smbus(BYTE command, WORD v_addr, WORD command_code, BYTE nbytes, BYT
BOOL WINAPI mxsmbus_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
mxsmbus_i2c_packet* i2c_packet = (mxsmbus_i2c_packet*)lpInBuffer;
mxsmbus_i2c_packet* i2c_out = (mxsmbus_i2c_packet*)lpOutBuffer;
// Default value
if (lpBytesReturned) *lpBytesReturned = nOutBufferSize;

View File

@ -35,7 +35,7 @@ void sram_restore() {
#define fix_crc(block) \
do { \
(block).m_Crc = amCrc32RGet(sizeof(block) - 4, (BYTE*)(&(block)) + 4, 0); \
(block).m_Crc = amiCrc32RCalc(sizeof(block) - 4, (BYTE*)(&(block)) + 4, 0); \
} while (0)
int build_sram() {

View File

@ -1,15 +1,15 @@
#pragma once
#include "com.h"
#include "drive/drive.h"
#include "files.h"
#include "gui.h"
#include "logging.h"
#include "network.h"
#include "processes.h"
#include "setupapi_.h"
#include "time.h"
#include "registry.h"
#include "drive.h"
#include "setupapi_.h"
#include "system.h"
#include "time.h"
void hook_all();

View File

@ -159,14 +159,14 @@ BOOL WINAPI FakeClearCommError(HANDLE hFile, LPDWORD lpErrors, LPCOMSTAT lpStat)
}
void hook_commio() {
hook("Kernel32.dll", "GetCommState", FakeGetCommState, (void**)&TrueGetCommState, 6);
hook("Kernel32.dll", "SetCommState", FakeSetCommState, (void**)&TrueSetCommState, 6);
hook("Kernel32.dll", "GetCommTimeouts", FakeGetCommTimeouts, (void**)&TrueGetCommTimeouts, 6);
hook("Kernel32.dll", "SetCommTimeouts", FakeSetCommTimeouts, (void**)&TrueSetCommTimeouts, 6);
hook("Kernel32.dll", "SetupComm", FakeSetupComm, (void**)&TrueSetupComm, 6);
hook("Kernel32.dll", "PurgeComm", FakePurgeComm, (void**)&TruePurgeComm, 6);
hook("Kernel32.dll", "GetCommState", FakeGetCommState, (void**)&TrueGetCommState);
hook("Kernel32.dll", "SetCommState", FakeSetCommState, (void**)&TrueSetCommState);
hook("Kernel32.dll", "GetCommTimeouts", FakeGetCommTimeouts, (void**)&TrueGetCommTimeouts);
hook("Kernel32.dll", "SetCommTimeouts", FakeSetCommTimeouts, (void**)&TrueSetCommTimeouts);
hook("Kernel32.dll", "SetupComm", FakeSetupComm, (void**)&TrueSetupComm);
hook("Kernel32.dll", "PurgeComm", FakePurgeComm, (void**)&TruePurgeComm);
hook("Kernel32.dll", "GetCommModemStatus", FakeGetCommModemStatus,
(void**)&TrueGetCommModemStatus, 6);
hook("Kernel32.dll", "WaitCommEvent", FakeWaitCommEvent, (void**)&TrueWaitCommEvent, 6);
hook("Kernel32.dll", "ClearCommError", FakeClearCommError, (void**)&TrueClearCommError, 6);
(void**)&TrueGetCommModemStatus);
hook("Kernel32.dll", "WaitCommEvent", FakeWaitCommEvent, (void**)&TrueWaitCommEvent);
hook("Kernel32.dll", "ClearCommError", FakeClearCommError, (void**)&TrueClearCommError);
}

View File

@ -1,904 +0,0 @@
#include "drive.h"
#include <Ntddscsi.h>
#include <Objbase.h>
#include "./files.h"
typedef struct _physical_disk physical_disk_t;
typedef struct _disk_partition disk_partition_t;
typedef struct _disk_volume disk_volume_t;
struct _disk_volume {
wchar_t m_FilenameW[MAX_PATH + 1];
char m_FilenameA[MAX_PATH + 1];
LPSTR m_Name;
char m_MountPoint;
// Back-references
physical_disk_t* m_pDrive;
disk_partition_t* m_pPartition;
BOOL m_NameIsOnHeap;
};
struct _disk_partition {
DWORD m_Size;
UCHAR m_Filesystem;
spd_slot_t m_SPDContent;
UCHAR* m_Content;
LONGLONG m_ContentSize;
disk_volume_t m_Volume;
DWORD m_PhysicalLBA;
DWORD m_SlotLBA;
DWORD m_PartitionNumber;
};
struct _physical_disk {
DWORD m_DriveNumber;
STORAGE_BUS_TYPE m_BusType;
LPSTR m_VID;
LPSTR m_PID;
DWORD m_BootPartition;
BOOL m_HasSegaboot;
disk_partition_t m_Partitions[4];
disk_partition_t m_Extended[];
};
/*
First 512 bytes of SPD_Original0:
LOADER::LoadBootIDHeader
*/
BYTE Original0BootIDHeader[512] = {
0x4B, 0xDF, 0xB4, 0x43, 0x27, 0x3C, 0xFE, 0xD6, 0xA2, 0xA8, 0xF8, 0xFD, 0xB4, 0x55, 0xE6, 0xBA,
0x5A, 0x0F, 0xBF, 0x14, 0xA4, 0x37, 0xB6, 0x42, 0xB3, 0xAD, 0x11, 0x4A, 0xCA, 0x1A, 0x4C, 0xD9,
0x11, 0xF1, 0x60, 0x4B, 0x37, 0x58, 0x9C, 0x9A, 0x89, 0x8F, 0x07, 0x9C, 0xE7, 0xF2, 0x64, 0xCC,
0x6E, 0x84, 0x87, 0xAA, 0x20, 0xA0, 0xB8, 0x55, 0x9B, 0xE7, 0x79, 0x4F, 0x51, 0x25, 0xC3, 0x7E,
0xEF, 0xD9, 0x25, 0xA9, 0x94, 0xF1, 0x7F, 0xEF, 0xE1, 0xD9, 0xAE, 0x4F, 0xC2, 0xEE, 0xB6, 0xA8,
0xD9, 0x54, 0x0F, 0x33, 0xA8, 0xA9, 0x22, 0x72, 0x81, 0xD0, 0xA3, 0x04, 0x5C, 0x45, 0x3E, 0xBE,
0xF7, 0x2A, 0xED, 0x55, 0xAB, 0x16, 0xC1, 0xA8, 0x61, 0x70, 0xEE, 0x55, 0xCB, 0xE6, 0x68, 0xA5,
0xB4, 0xDC, 0x30, 0x6D, 0x32, 0xD6, 0x69, 0x8D, 0xFC, 0x90, 0x71, 0x7E, 0xDB, 0x6B, 0x17, 0xFA,
0xAB, 0xE0, 0x11, 0x14, 0xBA, 0xD9, 0x33, 0xB7, 0x7C, 0x54, 0x9E, 0x21, 0xA1, 0x43, 0xFD, 0x8F,
0x14, 0xF4, 0xBE, 0x5F, 0x0B, 0x02, 0x8E, 0x87, 0xCA, 0x85, 0xE9, 0xC1, 0x60, 0xF7, 0x7E, 0x44,
0x55, 0x3A, 0x5E, 0x94, 0x65, 0x95, 0xFD, 0x02, 0xF9, 0xFF, 0xBF, 0x07, 0x80, 0xC5, 0x26, 0x58,
0x6F, 0x37, 0xFA, 0x59, 0x2F, 0x02, 0xF3, 0x9D, 0x24, 0x7D, 0x42, 0x6B, 0xF3, 0x49, 0x63, 0xC9,
0x2A, 0xCB, 0xFC, 0x71, 0x69, 0x44, 0xB5, 0xAC, 0xD3, 0x37, 0xA0, 0x01, 0x65, 0x3D, 0x49, 0xC4,
0x7D, 0xE5, 0xF8, 0x6E, 0x09, 0xC7, 0x3E, 0xD1, 0x96, 0x09, 0x23, 0xA4, 0xE8, 0xA5, 0x6A, 0xA2,
0x5B, 0x5B, 0xA5, 0x9C, 0xF8, 0x8D, 0x84, 0x55, 0x3F, 0x19, 0x8F, 0xDC, 0xFA, 0x7B, 0xF1, 0xC9,
0xB6, 0xBF, 0xE8, 0x73, 0xB9, 0xC9, 0xC3, 0x17, 0x14, 0xAB, 0xA3, 0x60, 0x13, 0xED, 0x6D, 0xCC,
0x10, 0x7B, 0x1D, 0xC6, 0xBC, 0xEC, 0x56, 0xFA, 0x52, 0xC5, 0x4E, 0xAC, 0x8F, 0x36, 0x8B, 0x92,
0x6C, 0xB5, 0x9A, 0x57, 0x7D, 0xFA, 0x97, 0x72, 0xFC, 0xFA, 0xB8, 0xFE, 0x20, 0x71, 0xFB, 0x63,
0x00, 0x96, 0x29, 0xCE, 0xE2, 0x06, 0xFF, 0x64, 0x48, 0xB5, 0x1F, 0xD6, 0x88, 0x48, 0x7A, 0x62,
0x2B, 0xBE, 0xE6, 0xC4, 0xFD, 0xF6, 0x85, 0x45, 0x0A, 0x8C, 0x6C, 0x20, 0x64, 0x05, 0x81, 0x13,
0xB5, 0x59, 0xAE, 0x34, 0x41, 0x0B, 0xB5, 0x65, 0x57, 0x59, 0x9C, 0xE8, 0xD0, 0xAE, 0x81, 0xD8,
0x6D, 0xC9, 0xFD, 0xF8, 0xC9, 0x15, 0xB6, 0xDC, 0xC9, 0x13, 0xF2, 0x6E, 0xD9, 0xA5, 0x77, 0x62,
0xB7, 0x15, 0x61, 0x21, 0x73, 0xFE, 0x0A, 0x57, 0x3B, 0x2C, 0x2F, 0x23, 0xC3, 0x33, 0xB8, 0x77,
0xCE, 0xCE, 0x76, 0x98, 0xDB, 0xE5, 0x9A, 0x00, 0xE1, 0xC3, 0x6F, 0x7D, 0x42, 0xC4, 0xDE, 0xB7,
0x1D, 0xA0, 0xC1, 0x1C, 0xB9, 0x09, 0x28, 0xD9, 0x59, 0x9D, 0x3F, 0xEA, 0xF1, 0xB6, 0xA0, 0x1C,
0x5E, 0x4A, 0xE4, 0x1A, 0xE7, 0xA7, 0x1C, 0xAD, 0xF6, 0xF1, 0xCB, 0x9C, 0x06, 0xE6, 0x4C, 0xF4,
0xD6, 0xEE, 0x5F, 0x18, 0xF5, 0x00, 0x4A, 0x76, 0x5E, 0x7D, 0x96, 0x20, 0x57, 0x68, 0x23, 0x69,
0x8F, 0x60, 0x91, 0xBF, 0x00, 0x08, 0xFE, 0x4F, 0x36, 0x45, 0x86, 0x14, 0x48, 0xC5, 0x8B, 0xEA,
0xE3, 0x64, 0x27, 0x1E, 0x49, 0xDF, 0x98, 0xAD, 0xE2, 0x66, 0x09, 0x07, 0xDD, 0x24, 0xB0, 0x4D,
0x52, 0xA6, 0xD1, 0x3D, 0xB9, 0x52, 0x0B, 0x88, 0x97, 0x97, 0x0F, 0x83, 0x85, 0xD5, 0x3F, 0x0E,
0x1A, 0xF2, 0x26, 0xBA, 0x14, 0x53, 0xDD, 0xF4, 0x7D, 0xAF, 0xB6, 0xEE, 0x36, 0x3A, 0xB5, 0xDA,
0x2F, 0x99, 0xC8, 0x54, 0xD2, 0xDB, 0x52, 0x49, 0xD6, 0xB6, 0x07, 0x1A, 0xBA, 0x9A, 0x85, 0xBB,
};
physical_disk_t SSD = {
.m_DriveNumber = 0,
.m_BusType = BusTypeAta,
.m_BootPartition = 1,
.m_HasSegaboot = TRUE,
.m_Partitions = {
// 1.5GB boot partitions
{
.m_Size = 0x300B85,
.m_Filesystem = MBR_FS_NTFS,
},
// 1.5GB recovery partitions
{
.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 something
{
0x20014aa,
MBR_FS_FAT16,
SPD_Original0,
.m_Content = Original0BootIDHeader,
.m_ContentSize = sizeof Original0BootIDHeader,
}, // 16GB game
{ 0 },
},
};
physical_disk_t UPDATE_USB = {
.m_DriveNumber = 1,
.m_BusType = BusTypeUsb,
.m_VID = "13FE",
.m_PID = "4200",
.m_Partitions = {
// 59050 MB update partitions
{
.m_Size = 0x735a080,
.m_Filesystem = MBR_FS_NTFS,
.m_Volume = {
.m_Name = "SEGA_INS",
},
},
},
.m_Extended = {{0}},
};
physical_disk_t* PHYSICAL_DISKS[] = { &SSD, &UPDATE_USB };
BOOL WINAPI c_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
log_trace("C", "DeviceIOControl %08x", dwIoControlCode);
ZeroMemory(lpOutBuffer, nOutBufferSize);
switch (dwIoControlCode) {
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK;
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceNumber = 0;
return TRUE;
case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
((VOLUME_DISK_EXTENTS*)lpOutBuffer)->NumberOfDiskExtents = 1;
((VOLUME_DISK_EXTENTS*)lpOutBuffer)->Extents[0].DiskNumber = 0;
return TRUE;
default:
return FALSE;
}
}
BOOL WINAPI x_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
log_trace("X", "DeviceIOControl %08x", dwIoControlCode);
ZeroMemory(lpOutBuffer, nOutBufferSize);
switch (dwIoControlCode) {
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK;
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceNumber = 0;
return TRUE;
default:
log_warning("X", "Unhandled DeviceIOControl %08x", dwIoControlCode);
return FALSE;
}
}
BOOL WINAPI pd_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData;
if (pd == NULL) {
log_error("drive", "ioctl:ctx->m_HookData NULL; expected a physical drive!");
return FALSE;
}
log_trace("drive", "DeviceIOControl %08x", dwIoControlCode);
ZeroMemory(lpOutBuffer, nOutBufferSize);
switch (dwIoControlCode) {
case IOCTL_ATA_PASS_THROUGH:
if (pd->m_BusType != BusTypeAta) return FALSE;
PATA_PASS_THROUGH_EX ata = (PATA_PASS_THROUGH_EX)lpInBuffer;
BYTE command = ata->CurrentTaskFile[6];
if (command != 0xC1) {
log_error("pd0", "Unimplemented ATA command: %02x", command);
return FALSE;
}
BYTE data = ata->CurrentTaskFile[0];
switch (data) {
// These are used un UnlockSection1, 2, and 3 in mxstorage!
case 0x11: // mxkSsdHostProofSet (step == 0)
// Game -> ATA | 128 bytes: random from N2
case 0x12: // mxkSsdHostProofGet (step == 0)
// ATA -> GAME | 128 bytes: (guess) readback of 0x11
case 0x21: // mxkSsdHostProofSet (step == 1)
// Game -> ATA | 128 bytes: random from N2
case 0x22: // mxkSsdHostProofGet (step == 1)
// ATA -> GAME | 128 bytes: (guess) readback of 0x21
case 0x31: // mxkSsdHostProofSeed
// ATA -> Game | 80 bytes: seed
case 0x32: // mxkSsdHostProofChallenge
// Game -> ATA | 80 bytes: the seed, encrypted by N2 with S-Key
// It looks like mxkeychip never actually checks the response buffer,
// as long as the ioctl succeeds! Saves us a lot of work here!
return TRUE;
}
log_error("drive", "Unimeplemented ATA C1 command: %02x", data);
return FALSE;
}
log_error("drive", "Unimplemented ioctl: %08x", dwIoControlCode);
return FALSE;
}
sbr_t SegaBootRecord = {
.version = SBR_VERSION,
.bootslot = 0x02,
.slot_status = { Slot_Complete, Slot_Complete, Slot_Invalid, Slot_Check, Slot_Complete },
.slot_os = {
// Starts at 0xc5469400
// i.e. [partition 6] - (segcount * segsize)
// i.e. partition 5 = [dead space] [slot_os]
.id = {'A', 'A', 'S', '0'},
.time = { 0 },
.version = 0x450a01,
.segcount = 1745,
.segsize = 0x40000,
.hw = { 'A', 'A', 'S' },
.instant = 0,
.osver = 0x450a01,
.ossegcount = 0,
.orgtime = { 0 },
.orgversion = 0x450a01,
},
.slot_original0 = {
// Starts at 0xb065bae00
// i.e. [end of disk] - (segcount * segsize)
// i.e. partition 9 = [dead space] [slot_original0]
.id = {'S', 'D', 'E', 'Y'},
.time = { 2018, 10, 29, 15, 7, 36 },
.version = 0x10061,
.segcount = 65082,
.segsize = 0x40000,
.hw = { 'A', 'A', 'S' },
.instant = 0,
.osver = 0x450a01,
.ossegcount = 1745,
.orgtime = { 2018, 10, 29, 15, 7, 36 },
.orgversion = 0x10061,
},
.slot_appdata = { 0 },
.slot_patch0 = {
// Starts at 0x15e49a000
// i.e. [partition 7] - (segcount * segsize)
// i.e. partition 6 = [dead space] [something] [patch0]
.id = { 'S', 'D', 'D', 'Z' },
.time = { 2018, 6, 21, 13, 46, 24 },
.version = 0x10060,
.segcount = 173,
.segsize = 0x40000,
.hw = { 'A', 'A', 'S' },
.instant = 0,
.osver = 0,
.ossegcount = 0,
.orgtime = { 2018, 5, 16, 20, 7, 12 },
.orgversion = 0x01005f,
},
.slot_patch1 = {
// Starts at 0x1debcac00
// i.e. [partition 8] - (segcount * segsize)
// i.e. partition 7 = [dead space] [something] [patch0]
.id = { 'S', 'D', 'E', 'Y' },
.time = { 2018, 11, 16, 19, 4, 48},
.version = 0x10062,
.segcount = 173,
.segsize = 0x40000,
.hw = { 'A', 'A', 'S' },
.instant = 0,
.osver = 0,
.ossegcount = 0,
.orgtime = { 2018, 10, 29, 15, 7, 36 },
.orgversion = 0x10061,
},
};
// Partitions
#define BOOT_PARITION_SIZE 0x300B85 // 1.5GB
#define RECOVER_PARTITION_SIZE 0x300BC4 // 1.5GB
typedef struct {
uint32_t size;
uint8_t type;
spd_slot_t content;
uint32_t offset;
LONGLONG slot_offset;
} partition_t;
#define PARITION_OS 0
#define PARITION_PATCH0 1
#define PARITION_PATCH1 2
#define PARITION_APP_DATA 3
#define PARITION_ORIGINAL0 4
#define MBR_LBA_GAP 0x3f // 1 track worth of sectors is claimed for the MBR
#define EXT_HEADER_GAP 0x3f
#define BLOCKSIZE 512ll
#define SPD_OFFSET 1
#define SBR0_OFFSET 2
#define SBR1_OFFSET 3
// Drives
/**
* VID_0CA3 = SEGA CORPROATION
* VID_0928 = PLX / Oxford Semiconductor
* VID/PID pairs for B:
* 0CA3/000E
* 0928/0007
* 0CA3/000C
*
* Mountpoints based on drive name:
* Z: DEV
* L: SEGA_AM_LOG
*/
// Volumes
typedef struct {
size_t disk;
size_t partition;
} find_index_t;
sbr_slot_t* get_sbr_slot(spd_slot_t slot) {
switch (slot) {
case SPD_Original0:
return &SegaBootRecord.slot_original0;
case SPD_Original1:
return NULL;
case SPD_Patch0:
return &SegaBootRecord.slot_patch0;
case SPD_Patch1:
return &SegaBootRecord.slot_patch1;
case SPD_OS:
return &SegaBootRecord.slot_os;
case SPD_AppData:
return &SegaBootRecord.slot_appdata;
default:
return NULL;
}
}
BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData;
if (pd == NULL) {
log_error("drive", "read:ctx->m_HookData NULL; expected a physical drive!");
return FALSE;
}
log_info("drive", "PhysicalDrive%d: Read %d @ %llx", pd->m_DriveNumber, nNumberOfBytesToRead,
ctx->m_Pointer.QuadPart);
// ! WARNING: This ReadFile implementation is currently limited to aligned
// ! reads. Given the main purpose of this function is to allow reading
// ! the partition information, this doesn't currently pose an issue.
DWORD ptrLBA = (ctx->m_Pointer.QuadPart / BLOCKSIZE) & 0xffffffff;
// MBR header
if (ptrLBA == 0) {
mbr_t* mbr = (mbr_t*)lpBuffer;
if (nNumberOfBytesToRead < sizeof *mbr) {
log_error("drive", "Buffer too small for master boot record!");
return FALSE;
}
memset(mbr, 0, sizeof *mbr);
mbr->sig[0] = 0x55;
mbr->sig[1] = 0xAA;
for (size_t i = 0; i < 4; i++) {
if (pd->m_Partitions[i].m_Size == 0) break;
mbr->partitions[i].status =
(pd->m_BootPartition == i + 1) ? MBR_FLAG_BOOTABLE : MBR_FLAG_NONE;
mbr->partitions[i].type = pd->m_Partitions[i].m_Filesystem;
mbr->partitions[i].lba = pd->m_Partitions[i].m_PhysicalLBA;
mbr->partitions[i].sectors = pd->m_Partitions[i].m_Size;
}
*lpNumberOfBytesRead = sizeof *mbr;
return TRUE;
}
if (ptrLBA <= MBR_LBA_GAP) {
// Read within the 63 extra tracks
log_error("drive", "Read failed");
return FALSE;
}
// MBR partitions
for (size_t i = 0; i < 4; i++) {
if (pd->m_Partitions[i].m_PartitionNumber == 0) break;
if (ptrLBA >= pd->m_Partitions[i].m_PhysicalLBA &&
ptrLBA < pd->m_Partitions[i].m_PhysicalLBA + pd->m_Partitions[i].m_Size) {
DWORD readOffset = ptrLBA - pd->m_Partitions[i].m_PhysicalLBA;
int willRead = pd->m_Partitions[i].m_ContentSize - (readOffset * BLOCKSIZE);
if (willRead > nNumberOfBytesToRead) willRead = nNumberOfBytesToRead;
if (willRead < 0) {
log_error("disk", "Attempted read in %d/%d at block offset %08x; No data to read!",
pd->m_DriveNumber, pd->m_Partitions[i].m_PartitionNumber, readOffset);
return FALSE;
}
memcpy(lpBuffer, pd->m_Partitions[i].m_Content, willRead);
*lpNumberOfBytesRead = willRead;
log_info("drive", "Read at %d/%d+%d", pd->m_DriveNumber,
pd->m_Partitions[i].m_PartitionNumber, readOffset);
return TRUE;
}
}
// Extended partitions
for (size_t i = 0; pd->m_Extended[i].m_Size; i++) {
// Extended header
DWORD headerLBA = pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP;
if (ptrLBA == headerLBA) {
mbr_t* mbr = (mbr_t*)lpBuffer;
if (nNumberOfBytesToRead < sizeof *mbr) {
log_error("drive", "Buffer too small for an extended boot record!");
return FALSE;
}
memset(mbr, 0, sizeof *mbr);
mbr->sig[0] = 0x55;
mbr->sig[1] = 0xAA;
mbr->partitions[0].status = MBR_FLAG_NONE;
mbr->partitions[0].type = pd->m_Extended[i].m_Filesystem;
mbr->partitions[0].lba = EXT_HEADER_GAP;
mbr->partitions[0].sectors = pd->m_Extended[i].m_Size;
if (pd->m_Extended[i + 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 =
pd->m_Extended[i + 1].m_PhysicalLBA - pd->m_Extended[0].m_PhysicalLBA;
mbr->partitions[1].sectors = pd->m_Extended[i + 1].m_Size + EXT_HEADER_GAP;
}
*lpNumberOfBytesRead = sizeof *mbr;
return TRUE;
}
if (i == 0 && pd->m_HasSegaboot) {
// SEGA Partition Description
if (ptrLBA == headerLBA + SPD_OFFSET) {
spd_t* spd = (spd_t*)lpBuffer;
if (nNumberOfBytesToRead < sizeof *spd) {
log_error("drive", "Buffer too small for SPD!");
return FALSE;
}
spd->version = SPD_VERSION;
for (size_t j = 0; pd->m_Extended[j].m_Size; j++) {
spd->slots[j].block_size = BLOCKSIZE;
spd->slots[j].block_count = pd->m_Extended[j].m_Size;
spd->slots[j].slot_content = pd->m_Extended[j].m_SPDContent;
spd->slots[j].uk1 = pd->m_Extended[j].m_Filesystem == MBR_FS_FAT16 ? 0 : 1;
}
spd->crc = amCrc32RGet(sizeof *spd - 4, &(spd->version), 0);
*lpNumberOfBytesRead = sizeof *spd;
return TRUE;
}
// SEGA Boot Record 0 and 1. The two are a redundant copy of each other
if (ptrLBA == headerLBA + SBR0_OFFSET || ptrLBA == headerLBA + SBR1_OFFSET) {
SegaBootRecord.crc = amCrc32RGet(sizeof SegaBootRecord - 4, &SegaBootRecord.version, 0);
memcpy(lpBuffer, &SegaBootRecord, sizeof SegaBootRecord);
*lpNumberOfBytesRead = sizeof SegaBootRecord;
return TRUE;
}
}
if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP &&
ptrLBA < pd->m_Extended[i].m_PhysicalLBA) {
// Read within the 63 extra tracks
log_error("drive", "Read failed");
return FALSE;
}
if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA &&
ptrLBA < pd->m_Extended[i].m_PhysicalLBA + pd->m_Extended[i].m_Size) {
DWORD readOffset = ptrLBA - pd->m_Extended[i].m_PhysicalLBA;
int willRead = pd->m_Extended[i].m_ContentSize - (readOffset * BLOCKSIZE);
if (willRead > nNumberOfBytesToRead) willRead = nNumberOfBytesToRead;
if (willRead < 0) {
log_error("disk", "Attempted read in %d/%d at block offset %08x; No data to read!",
pd->m_DriveNumber, pd->m_Extended[i].m_PartitionNumber, readOffset);
return FALSE;
}
memcpy(lpBuffer, pd->m_Extended[i].m_Content, willRead);
*lpNumberOfBytesRead = willRead;
log_info("drive", "Read at %d/%d+%d", pd->m_DriveNumber,
pd->m_Partitions[i].m_PartitionNumber, readOffset);
return TRUE;
}
}
log_error("drive", "Read failed");
return FALSE;
}
BOOL pd_WriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData;
if (pd == NULL) {
log_error("drive", "write:ctx->m_HookData NULL; expected a physical drive!");
return FALSE;
}
log_warning("drive", "PhysicalDrive%d: Write %d @ %llx", pd->m_DriveNumber,
nNumberOfBytesToWrite, ctx->m_Pointer.QuadPart);
for (DWORD i = 0; i < nNumberOfBytesToWrite; i += 32) {
for (int j = 0; j < 32; j++) {
printf("%02x ", ((BYTE*)lpBuffer)[i + j]);
}
puts("");
}
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
return TRUE;
}
disk_volume_t* incrementFindIndex(HANDLE hFindVolume) {
find_index_t* find_index = GetDataForHandle(hFindVolume, HDATA_FIND_VOLUME);
if (find_index == NULL) return NULL;
while (1) {
if (find_index->disk >= sizeof PHYSICAL_DISKS / sizeof PHYSICAL_DISKS[0]) {
return NULL;
}
if (find_index->partition > 3) {
if (PHYSICAL_DISKS[find_index->disk]
->m_Extended[find_index->partition - 4]
.m_PartitionNumber == 0) {
find_index->disk++;
find_index->partition = 0;
continue;
}
return &(PHYSICAL_DISKS[find_index->disk]
->m_Extended[(find_index->partition++) - 4]
.m_Volume);
}
if (PHYSICAL_DISKS[find_index->disk]
->m_Partitions[find_index->partition]
.m_PartitionNumber == 0) {
find_index->partition = 4;
continue;
}
return &(PHYSICAL_DISKS[find_index->disk]->m_Partitions[find_index->partition++].m_Volume);
}
}
BOOL WINAPI FakeFindNextVolumeW(HANDLE hFindVolume, LPWSTR lpszVolumeName, DWORD cchBufferLength) {
disk_volume_t* volume = incrementFindIndex(hFindVolume);
if (volume == NULL) {
SetLastError(ERROR_NO_MORE_FILES);
return FALSE;
}
wcscpy_s(lpszVolumeName, cchBufferLength, volume->m_FilenameW);
wcscat_s(lpszVolumeName, cchBufferLength, L"\\");
return TRUE;
}
BOOL WINAPI FakeFindNextVolumeA(HANDLE hFindVolume, LPSTR lpszVolumeName, DWORD cchBufferLength) {
disk_volume_t* volume = incrementFindIndex(hFindVolume);
if (volume == NULL) {
SetLastError(ERROR_NO_MORE_FILES);
return FALSE;
}
strcpy_s(lpszVolumeName, cchBufferLength, volume->m_FilenameA);
strcat_s(lpszVolumeName, cchBufferLength, "\\");
return TRUE;
}
HANDLE WINAPI FakeFindFirstVolumeW(LPWSTR lpszVolumeName, DWORD cchBufferLength) {
find_index_t* find_index = malloc(sizeof(find_index_t));
find_index->disk = 0;
find_index->partition = 0;
HANDLE handle = GetDummyHandle();
SetDataForHandle(handle, HDATA_FIND_VOLUME, find_index, TRUE);
FakeFindNextVolumeW(handle, lpszVolumeName, cchBufferLength);
return handle;
}
HANDLE WINAPI FakeFindFirstVolumeA(LPSTR lpszVolumeName, DWORD cchBufferLength) {
find_index_t* find_index = malloc(sizeof(find_index_t));
find_index->disk = 0;
find_index->partition = 0;
HANDLE handle = GetDummyHandle();
SetDataForHandle(handle, HDATA_FIND_VOLUME, find_index, TRUE);
FakeFindNextVolumeA(handle, lpszVolumeName, cchBufferLength);
return handle;
}
BOOL WINAPI FakeFindVolumeClose(HANDLE hFindVolume) {
if (RemoveDataForHandle(hFindVolume, HDATA_FIND_VOLUME)) return _CloseHandle(hFindVolume);
return FALSE;
}
disk_volume_t* getVolumeByPath(LPCSTR lpRootPathName) {
// Unimplemented
if (lpRootPathName == NULL) return FALSE;
char filename[MAX_PATH + 1];
for (size_t disk = 0; disk < sizeof PHYSICAL_DISKS / sizeof PHYSICAL_DISKS[0]; disk++) {
for (size_t part = 0; part < 4; part++) {
strcpy_s(filename, sizeof filename,
PHYSICAL_DISKS[disk]->m_Partitions[part].m_Volume.m_FilenameA);
strcat_s(filename, sizeof filename, "\\");
if (strcmp(filename, lpRootPathName)) continue;
return &(PHYSICAL_DISKS[disk]->m_Partitions[part].m_Volume);
}
for (size_t part = 0; PHYSICAL_DISKS[disk]->m_Extended[part].m_PartitionNumber; part++) {
strcpy_s(filename, sizeof filename,
PHYSICAL_DISKS[disk]->m_Extended[part].m_Volume.m_FilenameA);
strcat_s(filename, sizeof filename, "\\");
if (strcmp(filename, lpRootPathName)) continue;
return &(PHYSICAL_DISKS[disk]->m_Extended[part].m_Volume);
}
}
return NULL;
}
BOOL WINAPI FakeGetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer,
DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber,
LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags,
LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize) {
if (nVolumeNameSize) lpVolumeNameBuffer[0] = '\0';
if (lpVolumeSerialNumber) lpVolumeSerialNumber[0] = 0;
if (lpMaximumComponentLength) *lpMaximumComponentLength = MAX_PATH;
if (lpFileSystemFlags) *lpFileSystemFlags = 0;
if (nFileSystemNameSize) lpFileSystemNameBuffer[0] = '\0';
disk_volume_t* volume = getVolumeByPath(lpRootPathName);
if (volume == NULL) return FALSE;
if (volume->m_Name && lpVolumeNameBuffer)
strcpy_s(lpVolumeNameBuffer, nVolumeNameSize, volume->m_Name);
return TRUE;
}
BOOL WINAPI FakeSetVolumeLabelA(LPCSTR lpRootPathName, LPCSTR lpVolumeName) {
disk_volume_t* volume = getVolumeByPath(lpRootPathName);
if (volume == NULL) return FALSE;
if (lpVolumeName) {
size_t len = strlen(lpVolumeName);
// By default volume names are pointers to constants!
if (volume->m_NameIsOnHeap)
realloc(volume->m_Name, len + 1);
else {
volume->m_Name = malloc(len + 1);
volume->m_NameIsOnHeap = TRUE;
}
memcpy(volume->m_Name, lpVolumeName, len);
} else {
volume->m_Name = NULL;
}
return TRUE;
};
BOOL WINAPI volume_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
disk_volume_t* volume = (disk_volume_t*)ctx->m_HookData;
if (volume == NULL) {
log_error("drive", "ctx->m_HookData NULL; expected a volume!");
return FALSE;
}
memset(lpOutBuffer, 0, nInBufferSize);
switch (dwIoControlCode) {
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK;
((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->DeviceNumber = volume->m_pDrive->m_DriveNumber;
((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->PartitionNumber =
volume->m_pPartition->m_PartitionNumber;
return TRUE;
case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
PVOLUME_DISK_EXTENTS vde = (PVOLUME_DISK_EXTENTS)lpOutBuffer;
vde->NumberOfDiskExtents = 1;
vde->Extents[0].DiskNumber = volume->m_pDrive->m_DriveNumber;
vde->Extents[0].StartingOffset.QuadPart =
volume->m_pPartition->m_PhysicalLBA * BLOCKSIZE;
vde->Extents[0].ExtentLength.QuadPart = volume->m_pPartition->m_Size * BLOCKSIZE;
return TRUE;
case IOCTL_STORAGE_QUERY_PROPERTY:
PSTORAGE_PROPERTY_QUERY queryIn = (PSTORAGE_PROPERTY_QUERY)lpInBuffer;
if (queryIn->PropertyId != StorageDeviceProperty ||
queryIn->QueryType != PropertyStandardQuery) {
log_error("drive", "Unimplemented storage query: %d/%d", queryIn->PropertyId,
queryIn->QueryType);
return FALSE;
}
PSTORAGE_DEVICE_DESCRIPTOR descriptor = (PSTORAGE_DEVICE_DESCRIPTOR)(lpOutBuffer);
descriptor->BusType = volume->m_pDrive->m_BusType;
size_t rdpOffset = offsetof(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties);
if (volume->m_pDrive->m_VID) {
descriptor->VendorIdOffset = rdpOffset;
rdpOffset += sprintf_s((char*)descriptor + rdpOffset, nOutBufferSize - rdpOffset,
"%s", volume->m_pDrive->m_VID) +
1;
}
if (volume->m_pDrive->m_PID) {
descriptor->ProductIdOffset = rdpOffset;
rdpOffset += sprintf_s((char*)descriptor + rdpOffset, nOutBufferSize - rdpOffset,
"%s", volume->m_pDrive->m_PID) +
1;
}
descriptor->RawPropertiesLength =
rdpOffset - offsetof(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties);
return TRUE;
case IOCTL_DISK_GET_LENGTH_INFO:
PGET_LENGTH_INFORMATION length = (PGET_LENGTH_INFORMATION)lpOutBuffer;
if (volume->m_pPartition) {
length->Length.QuadPart = volume->m_pPartition->m_Size;
}
return TRUE;
default:
log_error("drive", "Unimplemented IOCTL: %08x", dwIoControlCode);
return FALSE;
}
}
void init_volume(disk_volume_t* vol) {
wchar_t* volume_name = vol->m_FilenameW;
wcscpy_s(volume_name, MAX_PATH + 1, L"\\\\?\\Volume");
GUID guid;
CoCreateGuid(&guid);
StringFromGUID2(&guid, volume_name + 10, MAX_PATH + 1 - 10);
file_hook_t* volume_hook = new_file_hook(volume_name);
log_misc("disk", "Creating fake volume: %ls", volume_name);
volume_hook->DeviceIoControl = &volume_DeviceIoControl;
volume_hook->hook_data = (void*)vol;
hook_file(volume_hook);
// This is a pretty nasty way to convert from W to A, but all values
// are always going to be within ASCII range so it's.. okay.
for (size_t i = 0; i < sizeof vol->m_FilenameA; i++) {
vol->m_FilenameA[i] = vol->m_FilenameW[i] & 0xff;
}
}
void init_pd(physical_disk_t* pd) {
DWORD partitionNumber = 1;
DWORD currentLBA = MBR_LBA_GAP;
// Init MBR
for (int i = 0; i < 4; i++) {
if (pd->m_Partitions[i].m_Size == 0) break;
pd->m_Partitions[i].m_PartitionNumber = partitionNumber++;
pd->m_Partitions[i].m_PhysicalLBA = currentLBA;
init_volume(&(pd->m_Partitions[i].m_Volume));
pd->m_Partitions[i].m_Volume.m_pDrive = pd;
pd->m_Partitions[i].m_Volume.m_pPartition = &(pd->m_Partitions[i]);
currentLBA += pd->m_Partitions[i].m_Size;
}
// If we have any extended partitions
DWORD extendedPartNo = 0;
if (pd->m_Extended[0].m_Size) {
if (partitionNumber == 5) {
log_error("drive", "Fatal: Too many paritions in drive %d!", pd->m_DriveNumber);
exit(1);
}
pd->m_Partitions[partitionNumber - 1].m_Filesystem = MBR_FS_EXT_LBA;
pd->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; pd->m_Extended[i].m_Size; i++) {
pd->m_Extended[i].m_PartitionNumber = partitionNumber++;
currentLBA += EXT_HEADER_GAP;
pd->m_Extended[i].m_PhysicalLBA = currentLBA;
pd->m_Extended[i].m_SlotLBA = currentLBA;
currentLBA += pd->m_Extended[i].m_Size;
init_volume(&(pd->m_Extended[i].m_Volume));
pd->m_Extended[i].m_Volume.m_pDrive = pd;
pd->m_Extended[i].m_Volume.m_pPartition = &(pd->m_Extended[i]);
sbr_slot_t* pslot = get_sbr_slot(pd->m_Extended[i].m_SPDContent);
if (pslot != NULL) {
DWORD slot_size = ((LONGLONG)pslot->segcount * (LONGLONG)pslot->segsize) / BLOCKSIZE;
DWORD slot_offset = pd->m_Extended[i].m_Size - slot_size;
pd->m_Extended[i].m_SlotLBA += slot_offset;
}
}
// Back-fill, if needed
if (extendedPartNo) {
pd->m_Partitions[extendedPartNo - 1].m_Size = currentLBA - extendedStart;
}
// Install hooks
// strlen(\\.\PhysicalDrive255) = 20, then +1 for null
wchar_t* hookPath = malloc(21 * sizeof(wchar_t));
swprintf_s(hookPath, 21, L"\\\\.\\PhysicalDrive%d", pd->m_DriveNumber);
file_hook_t* hook = new_file_hook(hookPath);
hook->DeviceIoControl = pd_DeviceIoControl;
hook->ReadFile = pd_ReadFile;
hook->WriteFile = pd_WriteFile;
hook->hook_data = (void*)pd;
hook_file(hook);
}
void hook_drives() {
init_pd(&SSD);
init_pd(&UPDATE_USB);
file_hook_t* c_drive = new_file_hook(L"\\\\.\\C:");
c_drive->DeviceIoControl = &c_drive_DeviceIoControl;
hook_file(c_drive);
file_hook_t* x_drive = new_file_hook(L"X:");
x_drive->DeviceIoControl = &x_drive_DeviceIoControl;
hook_file(x_drive);
hook("Kernel32.dll", "FindFirstVolumeW", &FakeFindFirstVolumeW, NULL, 5);
hook("Kernel32.dll", "FindNextVolumeW", &FakeFindNextVolumeW, NULL, 5);
hook("Kernel32.dll", "FindFirstVolumeA", &FakeFindFirstVolumeA, NULL, 5);
hook("Kernel32.dll", "FindNextVolumeA", &FakeFindNextVolumeA, NULL, 5);
hook("Kernel32.dll", "FindVolumeClose", &FakeFindVolumeClose, NULL, 5);
hook("Kernel32.dll", "SetVolumeLabelA", &FakeSetVolumeLabelA, NULL, 5);
hook("Kernel32.dll", "GetVolumeInformationA", &FakeGetVolumeInformationA, NULL, 5);
/**
* mxinstaller iterates all volumes to find those that match the slot metadata.
* It uses:
* - FindFirstVolumeW
* - FindNextVolumeW
* - FindVolumeClose
* to iterate volumes.
* For each volume, it:
* - opens it with CreateFileW
* - calls IOCTL_STORAGE_GET_DEVICE_NUMBER
* - asserts that DeviceType == FILE_DEVICE_DISK
* - calls IOCTL_VOLUME_GET_VOLUME_DISK_EXTENT
* - checks that NumberOfDiskExtents < 128
* - this is not fatal, however an error will be shown and only the first 128 will be checked
* - for each extent (!! sizeof DISK_EXTENT == 24; it's 8-byte aligned):
* - asserts that [].DiskNumber == state_->DiskNumber
* - finds a slot that matches:
* - slot->offset == [].StartingOffset
* - slot->segments == ([].ExtentLength.LowPart >> 9) | ([].ExtentLength.HighPart << 23)
* == [].ExtentLength / 512
*/
}

View File

@ -0,0 +1,110 @@
#include "drive.h"
physical_disk_t SSD = {
.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 partitions
{
.m_Size = 0x300B85,
.m_Filesystem = MBR_FS_NTFS,
},
// 1.5GB recovery partitions
{
.m_Size = 0x300BC4,
.m_Filesystem = MBR_FS_NTFS,
},
},
.m_Extended = {
{ 0x102d83, MBR_FS_FAT16, SPD_OS, .m_ReadFunc = &ReadFunc_OSLogFiles }, // 512MB OS update
{ 0x403947, MBR_FS_FAT16, SPD_Patch0, .m_ReadFunc = NULL }, // 2GB patch0
{ 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
// Instead, we're going to just allocate ~8GB, the exact size of SDCQ
// 0xeafc00, // ~8GB. Lol. Lmao.
MBR_FS_FAT16,
SPD_Original0,
.m_ReadFunc = &ReadFunc_Original0,
.m_WriteFunc = &WriteFunc_Original0,
},
{ 0 },
},
};
physical_disk_t UPDATE_USB = {
.m_BusType = BusTypeUsb,
.m_VID = "13FE",
.m_PID = "4200",
.m_BlockSize = BLOCK_SIZE_FLASH,
.m_TotalSize = 64 * 1024 * ((1024 * 1024) / BLOCK_SIZE_FLASH),
.m_IsFormatted = true,
.m_DiskType = DiskType_Flash,
.m_Partitions = {
// 59050 MB update partitions
{
.m_Size = 0xe6b410,
.m_Filesystem = MBR_FS_NTFS,
.m_Volume = {
.m_Name = "SEGA_INS",
},
},
},
.m_Extended = {{ 0 }},
};
physical_disk_t LOG_USB = {
.m_BusType = BusTypeUsb,
.m_VID = "13FE",
.m_PID = "4200",
.m_BlockSize = BLOCK_SIZE_FLASH,
.m_TotalSize = 16 * 1024 * ((1024 * 1024) / BLOCK_SIZE_FLASH),
.m_IsFormatted = true,
.m_DiskType = DiskType_Flash,
.m_Partitions = {
// 16 GB partition to store logs
{
.m_Size = 0x400000,
.m_Filesystem = MBR_FS_NTFS,
.m_Volume = {
.m_Name = "SEGA_AM_LOG",
.m_MountPoint = 'L',
},
},
},
.m_Extended = {{ 0 }},
};
physical_disk_t ALPHA_DVD = {
.m_BusType = BusTypeScsi,
.m_DeviceType = DeviceTypeCdRom,
.m_VID = "",
.m_PID = "",
.m_BlockSize = BLOCK_SIZE_DVD,
.m_TotalSize = 0,
.m_IsFormatted = FALSE,
.m_DiskType = DiskType_CdRom,
.m_Partitions = { {
.m_ReadFunc = NULL,
.m_Volume = {
.m_Name = "DVR5048_1_60_00",
.m_MountPoint = 'Q',
},
} },
};
physical_disk_t* PHYSICAL_DISKS[] = {
&SSD,
&UPDATE_USB,
// &LOG_USB,
// &ALPHA_DVD,
};

View File

@ -0,0 +1,82 @@
#pragma once
#include <Windows.h>
#include "segastruct.h"
typedef struct _physical_disk physical_disk_t;
typedef struct _disk_partition disk_partition_t;
typedef struct _disk_volume disk_volume_t;
typedef struct _disk_raw disk_raw_t;
#define MAX_DISKS 32
extern physical_disk_t* PHYSICAL_DISKS[MAX_DISKS];
typedef BOOL(mice_partition_read_function_t)(DWORD nOffset, LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead);
typedef BOOL(mice_partition_write_function_t)(DWORD nOffset, LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten);
typedef enum {
DiskType_HardDisk,
DiskType_Flash,
DiskType_CdRom,
DiskType_Floppy,
} DiskType;
struct _disk_volume {
wchar_t m_FilenameW[MAX_PATH + 1];
char m_FilenameA[MAX_PATH + 1];
LPSTR m_Name;
char m_MountPoint;
// Used for: \\Device\\DeviceName (kernel mode)
wchar_t m_DeviceName[MAX_PATH];
// Used for: \\OsDevices\\DosDeviceName (kernel mode), \\\\.\\DosDeviceName (user mode)
wchar_t m_DosDeviceName[MAX_PATH];
// Back-references
physical_disk_t* m_pDrive;
disk_partition_t* m_pPartition;
BOOL m_NameIsOnHeap;
};
struct _disk_partition {
DWORD m_Size;
UCHAR m_Filesystem;
spd_slot_t m_SPDContent;
mice_partition_read_function_t* m_ReadFunc;
mice_partition_write_function_t* m_WriteFunc;
disk_volume_t m_Volume;
DWORD m_PhysicalLBA;
DWORD m_SlotLBA;
DWORD m_PartitionNumber;
};
struct _disk_raw {
mice_partition_read_function_t* m_ReadFunc;
mice_partition_write_function_t* m_WriteFunc;
};
struct _physical_disk {
DWORD m_SerialNumber;
DWORD m_DriveNumber;
STORAGE_BUS_TYPE m_BusType;
DEVICE_TYPE m_DeviceType;
LPSTR m_VID;
LPSTR m_PID;
DWORD m_BootPartition;
BOOL m_HasSegaboot;
DWORD m_BlockSize;
DWORD m_TotalSize;
DiskType m_DiskType;
// Used for: \\Device\\DeviceName (kernel mode)
wchar_t m_DeviceName[MAX_PATH];
// Used for: \\OsDevices\\DosDeviceName (kernel mode), \\\\.\\DosDeviceName (user mode)
wchar_t m_DosDeviceName[MAX_PATH];
BOOL m_IsFormatted;
disk_partition_t m_Partitions[4];
disk_partition_t m_Extended[];
};

View File

@ -0,0 +1,743 @@
#define _MICE_DRIVE
#include "drive.h"
#include "../../../lib/ami/amiMd5.h"
#include "../../../micemaster/mxmEventLog.h"
#include "../../../sysconf.h"
#include "../files.h"
/*
First 512 bytes of SPD_Original0:
LOADER::LoadBootIDHeader
*/
BYTE Original0BootIDHeader[512] = {
0x4B, 0xDF, 0xB4, 0x43, 0x27, 0x3C, 0xFE, 0xD6, 0xA2, 0xA8, 0xF8, 0xFD, 0xB4, 0x55, 0xE6, 0xBA,
0x5A, 0x0F, 0xBF, 0x14, 0xA4, 0x37, 0xB6, 0x42, 0xB3, 0xAD, 0x11, 0x4A, 0xCA, 0x1A, 0x4C, 0xD9,
0x11, 0xF1, 0x60, 0x4B, 0x37, 0x58, 0x9C, 0x9A, 0x89, 0x8F, 0x07, 0x9C, 0xE7, 0xF2, 0x64, 0xCC,
0x6E, 0x84, 0x87, 0xAA, 0x20, 0xA0, 0xB8, 0x55, 0x9B, 0xE7, 0x79, 0x4F, 0x51, 0x25, 0xC3, 0x7E,
0xEF, 0xD9, 0x25, 0xA9, 0x94, 0xF1, 0x7F, 0xEF, 0xE1, 0xD9, 0xAE, 0x4F, 0xC2, 0xEE, 0xB6, 0xA8,
0xD9, 0x54, 0x0F, 0x33, 0xA8, 0xA9, 0x22, 0x72, 0x81, 0xD0, 0xA3, 0x04, 0x5C, 0x45, 0x3E, 0xBE,
0xF7, 0x2A, 0xED, 0x55, 0xAB, 0x16, 0xC1, 0xA8, 0x61, 0x70, 0xEE, 0x55, 0xCB, 0xE6, 0x68, 0xA5,
0xB4, 0xDC, 0x30, 0x6D, 0x32, 0xD6, 0x69, 0x8D, 0xFC, 0x90, 0x71, 0x7E, 0xDB, 0x6B, 0x17, 0xFA,
0xAB, 0xE0, 0x11, 0x14, 0xBA, 0xD9, 0x33, 0xB7, 0x7C, 0x54, 0x9E, 0x21, 0xA1, 0x43, 0xFD, 0x8F,
0x14, 0xF4, 0xBE, 0x5F, 0x0B, 0x02, 0x8E, 0x87, 0xCA, 0x85, 0xE9, 0xC1, 0x60, 0xF7, 0x7E, 0x44,
0x55, 0x3A, 0x5E, 0x94, 0x65, 0x95, 0xFD, 0x02, 0xF9, 0xFF, 0xBF, 0x07, 0x80, 0xC5, 0x26, 0x58,
0x6F, 0x37, 0xFA, 0x59, 0x2F, 0x02, 0xF3, 0x9D, 0x24, 0x7D, 0x42, 0x6B, 0xF3, 0x49, 0x63, 0xC9,
0x2A, 0xCB, 0xFC, 0x71, 0x69, 0x44, 0xB5, 0xAC, 0xD3, 0x37, 0xA0, 0x01, 0x65, 0x3D, 0x49, 0xC4,
0x7D, 0xE5, 0xF8, 0x6E, 0x09, 0xC7, 0x3E, 0xD1, 0x96, 0x09, 0x23, 0xA4, 0xE8, 0xA5, 0x6A, 0xA2,
0x5B, 0x5B, 0xA5, 0x9C, 0xF8, 0x8D, 0x84, 0x55, 0x3F, 0x19, 0x8F, 0xDC, 0xFA, 0x7B, 0xF1, 0xC9,
0xB6, 0xBF, 0xE8, 0x73, 0xB9, 0xC9, 0xC3, 0x17, 0x14, 0xAB, 0xA3, 0x60, 0x13, 0xED, 0x6D, 0xCC,
0x10, 0x7B, 0x1D, 0xC6, 0xBC, 0xEC, 0x56, 0xFA, 0x52, 0xC5, 0x4E, 0xAC, 0x8F, 0x36, 0x8B, 0x92,
0x6C, 0xB5, 0x9A, 0x57, 0x7D, 0xFA, 0x97, 0x72, 0xFC, 0xFA, 0xB8, 0xFE, 0x20, 0x71, 0xFB, 0x63,
0x00, 0x96, 0x29, 0xCE, 0xE2, 0x06, 0xFF, 0x64, 0x48, 0xB5, 0x1F, 0xD6, 0x88, 0x48, 0x7A, 0x62,
0x2B, 0xBE, 0xE6, 0xC4, 0xFD, 0xF6, 0x85, 0x45, 0x0A, 0x8C, 0x6C, 0x20, 0x64, 0x05, 0x81, 0x13,
0xB5, 0x59, 0xAE, 0x34, 0x41, 0x0B, 0xB5, 0x65, 0x57, 0x59, 0x9C, 0xE8, 0xD0, 0xAE, 0x81, 0xD8,
0x6D, 0xC9, 0xFD, 0xF8, 0xC9, 0x15, 0xB6, 0xDC, 0xC9, 0x13, 0xF2, 0x6E, 0xD9, 0xA5, 0x77, 0x62,
0xB7, 0x15, 0x61, 0x21, 0x73, 0xFE, 0x0A, 0x57, 0x3B, 0x2C, 0x2F, 0x23, 0xC3, 0x33, 0xB8, 0x77,
0xCE, 0xCE, 0x76, 0x98, 0xDB, 0xE5, 0x9A, 0x00, 0xE1, 0xC3, 0x6F, 0x7D, 0x42, 0xC4, 0xDE, 0xB7,
0x1D, 0xA0, 0xC1, 0x1C, 0xB9, 0x09, 0x28, 0xD9, 0x59, 0x9D, 0x3F, 0xEA, 0xF1, 0xB6, 0xA0, 0x1C,
0x5E, 0x4A, 0xE4, 0x1A, 0xE7, 0xA7, 0x1C, 0xAD, 0xF6, 0xF1, 0xCB, 0x9C, 0x06, 0xE6, 0x4C, 0xF4,
0xD6, 0xEE, 0x5F, 0x18, 0xF5, 0x00, 0x4A, 0x76, 0x5E, 0x7D, 0x96, 0x20, 0x57, 0x68, 0x23, 0x69,
0x8F, 0x60, 0x91, 0xBF, 0x00, 0x08, 0xFE, 0x4F, 0x36, 0x45, 0x86, 0x14, 0x48, 0xC5, 0x8B, 0xEA,
0xE3, 0x64, 0x27, 0x1E, 0x49, 0xDF, 0x98, 0xAD, 0xE2, 0x66, 0x09, 0x07, 0xDD, 0x24, 0xB0, 0x4D,
0x52, 0xA6, 0xD1, 0x3D, 0xB9, 0x52, 0x0B, 0x88, 0x97, 0x97, 0x0F, 0x83, 0x85, 0xD5, 0x3F, 0x0E,
0x1A, 0xF2, 0x26, 0xBA, 0x14, 0x53, 0xDD, 0xF4, 0x7D, 0xAF, 0xB6, 0xEE, 0x36, 0x3A, 0xB5, 0xDA,
0x2F, 0x99, 0xC8, 0x54, 0xD2, 0xDB, 0x52, 0x49, 0xD6, 0xB6, 0x07, 0x1A, 0xBA, 0x9A, 0x85, 0xBB,
};
BOOL ReadFunc_Original0(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead) {
*lpNumberOfBytesRead = 0;
if (!_PathFileExistsA(ORIGINAL0_PATH)) {
log_error("drive", "Failed to open %s (does not exist)", ORIGINAL0_PATH);
return FALSE;
}
HANDLE hFile =
_CreateFileA(ORIGINAL0_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_error("drive", "Failed to open %s", ORIGINAL0_PATH);
return FALSE;
}
LARGE_INTEGER seekTo;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
BOOL ret = _ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, NULL);
if (!ret) log_error("drive", "Failed to read to %s: %03x", ORIGINAL0_PATH, GetLastError());
_CloseHandle(hFile);
return ret;
}
BOOL WriteFunc_Original0(DWORD nOffset, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten) {
*lpNumberOfBytesWritten = 0;
HANDLE hFile =
_CreateFileA(ORIGINAL0_PATH, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_error("drive", "Failed to open %s", ORIGINAL0_PATH);
return FALSE;
}
LARGE_INTEGER seekTo;
seekTo.QuadPart = (LONGLONG)nOffset * (LONGLONG)SSD.m_BlockSize;
_SetFilePointerEx(hFile, seekTo, NULL, FILE_BEGIN);
BOOL ret = _WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL);
if (!ret) log_error("drive", "Failed to write to %s: %03x", ORIGINAL0_PATH, GetLastError());
_CloseHandle(hFile);
return ret;
}
BOOL ReadFunc_OSLogFiles(DWORD nOffset, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead) {
if (nOffset == 2047 && nNumberOfBytesToRead == sizeof(AM_EVENT_LOG_HEADER)) {
AM_EVENT_LOG_HEADER header;
ZeroMemory(&header, sizeof header);
// BYTE nullBuffer[512];
// ZeroMemory(nullBuffer, sizeof nullBuffer);
// AmiMd5 md5;
// amiMd5Init(&md5);
// amiMd5Update(&md5, sizeof nullBuffer, nullBuffer);
// amiMd5Finalise(&md5);
AmiMd5 md5;
amiMd5Init(&md5);
amiMd5Update(&md5, 0, NULL);
amiMd5Finalise(&md5);
header.m_nBytes[0] = 0;
header.m_nBytes[1] = 0;
memcpy(header.m_md5[0], md5.m_digest, sizeof header.m_md5[0]);
memcpy(header.m_md5[1], md5.m_digest, sizeof header.m_md5[1]);
header.m_crc32 = amiCrc32RCalc(sizeof header - 4, ((unsigned char*)&header) + 4, 0);
memcpy(lpBuffer, &header, sizeof header);
*lpNumberOfBytesRead = sizeof header;
return TRUE;
}
if (nOffset == 2048) {
log_warning("drive", "Requsted %d bytes of application log file", nNumberOfBytesToRead);
ZeroMemory(lpBuffer, nNumberOfBytesToRead);
*lpNumberOfBytesRead = nNumberOfBytesToRead;
return TRUE;
}
if (nOffset == 2048 + 1024) {
log_warning("drive", "Requsted %d bytes of system log file", nNumberOfBytesToRead);
ZeroMemory(lpBuffer, nNumberOfBytesToRead);
*lpNumberOfBytesRead = nNumberOfBytesToRead;
return TRUE;
}
*lpNumberOfBytesRead = 0;
return FALSE;
}
BOOL WINAPI c_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
log_trace("C", "DeviceIOControl %08x", dwIoControlCode);
ZeroMemory(lpOutBuffer, nOutBufferSize);
switch (dwIoControlCode) {
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK;
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceNumber = 0;
return TRUE;
case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
((VOLUME_DISK_EXTENTS*)lpOutBuffer)->NumberOfDiskExtents = 1;
((VOLUME_DISK_EXTENTS*)lpOutBuffer)->Extents[0].DiskNumber = 0;
return TRUE;
default:
return FALSE;
}
}
BOOL WINAPI x_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
log_trace("X", "DeviceIOControl %08x", dwIoControlCode);
ZeroMemory(lpOutBuffer, nOutBufferSize);
switch (dwIoControlCode) {
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK;
((STORAGE_DEVICE_NUMBER*)lpOutBuffer)->DeviceNumber = 0;
return TRUE;
default:
log_warning("X", "Unhandled DeviceIOControl %08x", dwIoControlCode);
return FALSE;
}
}
BOOL WINAPI q_drive_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
log_trace("Q", "DeviceIOControl %08x", dwIoControlCode);
ZeroMemory(lpOutBuffer, nOutBufferSize);
switch (dwIoControlCode) {
case IOCTL_STORAGE_MEDIA_REMOVAL:
// The game wants to disable ejecting the disk during installing
return TRUE;
case IOCTL_CDROM_GET_DRIVE_GEOMETRY:
((PDISK_GEOMETRY)lpOutBuffer)->BytesPerSector = ALPHA_DVD.m_BlockSize;
return TRUE;
default:
log_warning("Q", "Unhandled DeviceIOControl %08x", dwIoControlCode);
return FALSE;
}
}
sbr_t SegaBootRecordDefault = {
.version = SBR_VERSION,
.bootslot = 0x02,
.slot_status = { Slot_Complete, Slot_Complete, Slot_Invalid, Slot_Check, Slot_Complete },
.slot_os = {
// Starts at 0xc5469400
// i.e. [partition 6] - (segcount * segsize)
// i.e. partition 5 = [dead space] [slot_os]
.id = {'A', 'A', 'S', '0'},
.time = { 0 },
.version = 0x450a01,
.segcount = 1745,
.segsize = 0x40000,
.hw = HW_ID,
.instant = 0,
.osver = 0x450a01,
.ossegcount = 0,
.orgtime = { 0 },
.orgversion = 0x450a01,
},
.slot_original0 = {
// Starts at 0xb065bae00
// i.e. [end of disk] - (segcount * segsize)
// i.e. partition 9 = [dead space] [slot_original0]
.id = GAME_ID,
.time = { 2018, 10, 29, 15, 7, 36 },
.version = 0x10061,
.segcount = 65082,
.segsize = 0x40000,
.hw = HW_ID,
.instant = 0,
.osver = 0x450a01,
.ossegcount = 1745,
.orgtime = { 2018, 10, 29, 15, 7, 36 },
.orgversion = 0x10061,
},
.slot_appdata = { 0 },
.slot_patch0 = {
// Starts at 0x15e49a000
// i.e. [partition 7] - (segcount * segsize)
// i.e. partition 6 = [dead space] [something] [patch0]
.id = GAME_ID,
.time = { 2018, 6, 21, 13, 46, 24 },
.version = 0x10060,
.segcount = 173,
.segsize = 0x40000,
.hw = HW_ID,
.instant = 0,
.osver = 0,
.ossegcount = 0,
.orgtime = { 2018, 5, 16, 20, 7, 12 },
.orgversion = 0x01005f,
},
.slot_patch1 = {
// Starts at 0x1debcac00
// i.e. [partition 8] - (segcount * segsize)
// i.e. partition 7 = [dead space] [something] [patch0]
.id = GAME_ID,
.time = { 2018, 11, 16, 19, 4, 48},
.version = 0x10062,
.segcount = 173,
.segsize = 0x40000,
.hw = HW_ID,
.instant = 0,
.osver = 0,
.ossegcount = 0,
.orgtime = { 2018, 10, 29, 15, 7, 36 },
.orgversion = 0x10061,
},
};
sbr_t SegaBootRecord0;
sbr_t SegaBootRecord1;
// Drives
/**
* VID_0CA3 = SEGA CORPROATION
* VID_0928 = PLX / Oxford Semiconductor
* VID/PID pairs for B:
* 0CA3/000E
* 0928/0007
* 0CA3/000C
*
* Mountpoints based on drive name:
* Z: DEV
* L: SEGA_AM_LOG
*/
// Volumes
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;
}
}
inline char char_lower(char value) {
if ('A' <= value && value <= 'Z') return value - 'A' + 'a';
return value;
}
inline char char_upper(char value) {
if ('a' <= value && value <= 'z') return value - 'a' + 'A';
return value;
}
char matchWorkFilename[MAX_PATH + 1];
inline static BOOL matchVolume(disk_volume_t* volume, LPCSTR lpRootPathName, DWORD match) {
if (match & VOL_MATCH_GUID) {
strcpy_s(matchWorkFilename, sizeof matchWorkFilename, volume->m_FilenameA);
strcat_s(matchWorkFilename, sizeof matchWorkFilename, "\\");
if (strcmp(matchWorkFilename, lpRootPathName) == 0) return TRUE;
}
if (match & VOL_MATCH_PATH && volume->m_MountPoint) {
sprintf_s(matchWorkFilename, sizeof matchWorkFilename,
"\\\\.\\%c:", char_lower(volume->m_MountPoint));
if (strstr(lpRootPathName, matchWorkFilename) == lpRootPathName) return TRUE;
sprintf_s(matchWorkFilename, sizeof matchWorkFilename,
"\\\\.\\%c:", char_upper(volume->m_MountPoint));
if (strstr(lpRootPathName, matchWorkFilename) == lpRootPathName) return TRUE;
}
if (match & VOL_MATCH_DOS_DEVICE && volume->m_MountPoint) {
if (char_lower(volume->m_MountPoint) == char_lower(lpRootPathName[0])) {
if (lpRootPathName[1] == ':' && lpRootPathName[2] == '\0') return TRUE;
}
}
return FALSE;
}
disk_volume_t* getVolumeByPath(LPCSTR lpRootPathName, DWORD match) {
if (lpRootPathName == NULL) {
log_error("file", "getVolumeByPath(NULL) unimplemented!");
return FALSE;
}
for (size_t disk = 0; disk < MAX_DISKS && PHYSICAL_DISKS[disk] != NULL; disk++) {
for (size_t part = 0; part < 4; part++) {
disk_volume_t* volume = &(PHYSICAL_DISKS[disk]->m_Partitions[part].m_Volume);
if (matchVolume(volume, lpRootPathName, match)) return volume;
}
for (size_t part = 0; PHYSICAL_DISKS[disk]->m_Extended[part].m_PartitionNumber; part++) {
disk_volume_t* volume = &(PHYSICAL_DISKS[disk]->m_Extended[part].m_Volume);
if (matchVolume(volume, lpRootPathName, match)) return volume;
}
}
return NULL;
}
BOOL WINAPI volume_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
disk_volume_t* volume = (disk_volume_t*)ctx->m_HookData;
if (volume == NULL) {
log_error("drive", "ctx->m_HookData NULL; expected a volume!");
return FALSE;
}
memset(lpOutBuffer, 0, nInBufferSize);
switch (dwIoControlCode) {
case IOCTL_STORAGE_GET_DEVICE_NUMBER:
if (volume->m_pDrive->m_DiskType == DiskType_CdRom)
((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->DeviceType = FILE_DEVICE_CD_ROM;
else
((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->DeviceType = FILE_DEVICE_DISK;
((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->DeviceNumber = volume->m_pDrive->m_DriveNumber;
((PSTORAGE_DEVICE_NUMBER)lpOutBuffer)->PartitionNumber =
volume->m_pPartition->m_PartitionNumber;
return TRUE;
case IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS:
PVOLUME_DISK_EXTENTS vde = (PVOLUME_DISK_EXTENTS)lpOutBuffer;
vde->NumberOfDiskExtents = 1;
vde->Extents[0].DiskNumber = volume->m_pDrive->m_DriveNumber;
vde->Extents[0].StartingOffset.QuadPart =
volume->m_pPartition->m_PhysicalLBA * (long long)volume->m_pDrive->m_BlockSize;
vde->Extents[0].ExtentLength.QuadPart =
volume->m_pPartition->m_Size * (long long)volume->m_pDrive->m_BlockSize;
return TRUE;
case IOCTL_STORAGE_QUERY_PROPERTY:
PSTORAGE_PROPERTY_QUERY queryIn = (PSTORAGE_PROPERTY_QUERY)lpInBuffer;
if (queryIn->PropertyId != StorageDeviceProperty ||
queryIn->QueryType != PropertyStandardQuery) {
log_error("drive", "Unimplemented storage query: %d/%d", queryIn->PropertyId,
queryIn->QueryType);
return FALSE;
}
PSTORAGE_DEVICE_DESCRIPTOR descriptor = (PSTORAGE_DEVICE_DESCRIPTOR)(lpOutBuffer);
descriptor->DeviceType = volume->m_pDrive->m_DeviceType & 0xff;
descriptor->BusType = volume->m_pDrive->m_BusType;
size_t rdpOffset = offsetof(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties);
if (volume->m_pDrive->m_VID) {
descriptor->VendorIdOffset = rdpOffset;
rdpOffset += sprintf_s((char*)descriptor + rdpOffset, nOutBufferSize - rdpOffset,
"%s", volume->m_pDrive->m_VID) +
1;
}
if (volume->m_pDrive->m_PID) {
descriptor->ProductIdOffset = rdpOffset;
rdpOffset += sprintf_s((char*)descriptor + rdpOffset, nOutBufferSize - rdpOffset,
"%s", volume->m_pDrive->m_PID) +
1;
}
descriptor->RawPropertiesLength =
rdpOffset - offsetof(STORAGE_DEVICE_DESCRIPTOR, RawDeviceProperties);
return TRUE;
case IOCTL_DISK_GET_LENGTH_INFO:
PGET_LENGTH_INFORMATION length = (PGET_LENGTH_INFORMATION)lpOutBuffer;
if (volume->m_pPartition) {
length->Length.QuadPart = volume->m_pPartition->m_Size;
}
return TRUE;
default:
log_error("drive", "Unimplemented IOCTL: %08x", dwIoControlCode);
return FALSE;
}
}
void init_volume(disk_volume_t* vol) {
wchar_t* volume_name = vol->m_FilenameW;
wcscpy_s(volume_name, MAX_PATH + 1, L"\\\\?\\Volume");
GUID guid;
CoCreateGuid(&guid);
StringFromGUID2(&guid, volume_name + 10, MAX_PATH + 1 - 10);
file_hook_t* volume_hook = new_file_hook(volume_name);
log_misc("disk", "Creating fake volume: %ls", volume_name);
volume_hook->DeviceIoControl = &volume_DeviceIoControl;
volume_hook->hook_data = (void*)vol;
hook_file(volume_hook);
// This is a pretty nasty way to convert from W to A, but all values
// are always going to be within ASCII range so it's.. okay.
for (size_t i = 0; i < sizeof vol->m_FilenameA; i++) {
vol->m_FilenameA[i] = vol->m_FilenameW[i] & 0xff;
}
// Construct default device names
if (vol->m_DeviceName[0] == '\0') {
swprintf_s(vol->m_DeviceName, (sizeof vol->m_DeviceName) / (sizeof vol->m_DeviceName[0]),
L"Volume%s", volume_name + 10);
}
if (vol->m_DosDeviceName[0] == '\0') {
swprintf_s(
vol->m_DosDeviceName, (sizeof vol->m_DosDeviceName) / (sizeof vol->m_DosDeviceName[0]),
L"%ls\\Volume%d", vol->m_pDrive->m_DosDeviceName, vol->m_pPartition->m_PartitionNumber);
}
}
void init_pd(physical_disk_t* pd) {
// Apply default block sizes
if (!pd->m_BlockSize) {
switch (pd->m_DiskType) {
case DiskType_HardDisk:
pd->m_BlockSize = BLOCK_SIZE_HDD;
break;
case DiskType_Flash:
pd->m_BlockSize = BLOCK_SIZE_FLASH;
break;
case DiskType_CdRom:
pd->m_BlockSize = BLOCK_SIZE_CDROM;
break;
default:
log_error("disk", "Unable to guess block size for drive %d", pd->m_DriveNumber);
break;
}
}
// Construct default device paths
if (pd->m_DeviceName[0] == '\0') {
switch (pd->m_DiskType) {
case DiskType_HardDisk:
case DiskType_Flash: // TODO: Figure out what flash is meant to be called
swprintf_s(pd->m_DeviceName,
(sizeof pd->m_DeviceName) / (sizeof pd->m_DeviceName[0]), L"Harddisk%d",
pd->m_DriveNumber);
break;
case DiskType_CdRom:
swprintf_s(pd->m_DeviceName,
(sizeof pd->m_DeviceName) / (sizeof pd->m_DeviceName[0]), L"CdRom%d",
pd->m_DriveNumber);
break;
case DiskType_Floppy:
swprintf_s(pd->m_DeviceName,
(sizeof pd->m_DeviceName) / (sizeof pd->m_DosDeviceName[0]), L"Floppy%d",
pd->m_DriveNumber);
break;
default:
log_error("disk", "Unable to set DeviceName for drive %d (type: %d)",
pd->m_DriveNumber, pd->m_DiskType);
break;
}
}
if (pd->m_DosDeviceName[0] == '\0')
swprintf_s(pd->m_DosDeviceName,
(sizeof pd->m_DosDeviceName) / (sizeof pd->m_DosDeviceName[0]),
L"PhysicalDrive%d", pd->m_DriveNumber);
// Non-SCSI devices don't have a SCSI type to report
if (pd->m_BusType != BusTypeScsi) pd->m_DeviceType = DeviceTypeUnknown;
// If we need to initialise the partition tables, do so
if (pd->m_IsFormatted) {
DWORD partitionNumber = 1;
DWORD currentLBA = MBR_LBA_GAP;
// Init MBR
for (int i = 0; i < 4; i++) {
if (pd->m_Partitions[i].m_Size == 0) break;
pd->m_Partitions[i].m_PartitionNumber = partitionNumber++;
pd->m_Partitions[i].m_PhysicalLBA = currentLBA;
pd->m_Partitions[i].m_Volume.m_pDrive = pd;
pd->m_Partitions[i].m_Volume.m_pPartition = &(pd->m_Partitions[i]);
init_volume(&(pd->m_Partitions[i].m_Volume));
currentLBA += pd->m_Partitions[i].m_Size;
}
// If we have any extended partitions
DWORD extendedPartNo = 0;
if (pd->m_Extended[0].m_Size) {
if (partitionNumber == 5) {
log_error("drive", "Fatal: Too many paritions in drive %d!", pd->m_DriveNumber);
exit(1);
}
pd->m_Partitions[partitionNumber - 1].m_Filesystem = MBR_FS_EXT_LBA;
pd->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 (!pd->m_Extended[i].m_Size) break;
pd->m_Extended[i].m_PartitionNumber = partitionNumber++;
currentLBA += EXT_HEADER_GAP;
pd->m_Extended[i].m_PhysicalLBA = currentLBA;
pd->m_Extended[i].m_SlotLBA = currentLBA;
currentLBA += pd->m_Extended[i].m_Size;
pd->m_Extended[i].m_Volume.m_pDrive = pd;
pd->m_Extended[i].m_Volume.m_pPartition = &(pd->m_Extended[i]);
init_volume(&(pd->m_Extended[i].m_Volume));
sbr_slot_t* pslot = get_sbr_slot(pd->m_Extended[i].m_SPDContent);
if (pslot != NULL) {
DWORD slot_size = ((LONGLONG)pslot->segcount * (LONGLONG)pslot->segsize) /
(long long)pd->m_BlockSize;
DWORD slot_offset = pd->m_Extended[i].m_Size - slot_size;
pd->m_Extended[i].m_SlotLBA += slot_offset;
}
}
// Back-fill, if needed
if (extendedPartNo) {
pd->m_Partitions[extendedPartNo - 1].m_Size = currentLBA - extendedStart;
}
} else {
// Raw disks have just a single spanning volume
pd->m_Partitions[0].m_PartitionNumber = 1;
pd->m_Partitions[0].m_PhysicalLBA = 0;
pd->m_Partitions[0].m_Size = pd->m_TotalSize;
pd->m_Partitions[0].m_Volume.m_pDrive = pd;
pd->m_Partitions[0].m_Volume.m_pPartition = &(pd->m_Partitions[0]);
init_volume(&(pd->m_Partitions[0].m_Volume));
wcscpy_s(pd->m_Partitions[0].m_Volume.m_DeviceName,
sizeof pd->m_Partitions[0].m_Volume.m_DeviceName /
sizeof pd->m_Partitions[0].m_Volume.m_DeviceName[0],
pd->m_DeviceName);
wcscpy_s(pd->m_Partitions[0].m_Volume.m_DosDeviceName,
sizeof pd->m_Partitions[0].m_Volume.m_DosDeviceName /
sizeof pd->m_Partitions[0].m_Volume.m_DosDeviceName[0],
pd->m_DosDeviceName);
}
// Install hooks
// strlen(\\.\PhysicalDrive255) = 20, then +1 for null
wchar_t* hookPath = malloc(21 * sizeof(wchar_t));
swprintf_s(hookPath, 21, L"\\\\.\\%ls", pd->m_DosDeviceName);
file_hook_t* hook = new_file_hook(hookPath);
hook->DeviceIoControl = pd_DeviceIoControl;
hook->ReadFile = pd_ReadFile;
hook->WriteFile = pd_WriteFile;
hook->hook_data = (void*)pd;
hook_file(hook);
}
void init_all_pd() {
for (int i = 0; i < MAX_DISKS && PHYSICAL_DISKS[i] != NULL; i++) {
PHYSICAL_DISKS[i]->m_DriveNumber = i;
init_pd(PHYSICAL_DISKS[i]);
}
}
BOOL q_drive_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
log_misc("q", "CDROM read 0x%04x bytes at 0x%08x", nNumberOfBytesToRead,
ctx->m_Pointer.QuadPart);
/**
* [ Drive format ]
*
* - AlphaDVD authentication is prefixed onto the drive.
* - The real start can be extracted from the header
* - offset = 1264 (for my SDCQ)
*
* +511: Disk header (1 sector)
* 000800004574A1180002000053444351
* +512: Boot ID (128 sectors) [keychip.decrypt]
*/
HANDLE hFile = _CreateFileA("\\\\.\\E:", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_error("q", "READ FAILED. FILE FALLBACK FAILED. %d", GetLastError());
return FALSE;
}
_SetFilePointerEx(hFile, ctx->m_Pointer, NULL, FILE_BEGIN);
_ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
_CloseHandle(hFile);
log_warning("q", "READ FAILED. FILE FALLBACK (Read %d bytes).", *lpNumberOfBytesRead);
return TRUE;
}
void hook_drives() {
init_all_pd();
file_hook_t* c_drive = new_file_hook(L"\\\\.\\C:");
c_drive->DeviceIoControl = &c_drive_DeviceIoControl;
hook_file(c_drive);
file_hook_t* x_drive = new_file_hook(L"X:");
x_drive->DeviceIoControl = &x_drive_DeviceIoControl;
hook_file(x_drive);
file_hook_t* q_drive = new_file_hook(L"\\\\.\\Q:");
q_drive->DeviceIoControl = &q_drive_DeviceIoControl;
q_drive->ReadFile = &q_drive_ReadFile;
hook_file(q_drive);
// 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;
hook_file(q_drive_lower);
hook("Kernel32.dll", "FindFirstVolumeW", &FakeFindFirstVolumeW, NULL);
hook("Kernel32.dll", "FindNextVolumeW", &FakeFindNextVolumeW, NULL);
hook("Kernel32.dll", "FindFirstVolumeA", &FakeFindFirstVolumeA, NULL);
hook("Kernel32.dll", "FindNextVolumeA", &FakeFindNextVolumeA, NULL);
hook("Kernel32.dll", "FindVolumeClose", &FakeFindVolumeClose, NULL);
hook("Kernel32.dll", "SetVolumeLabelA", &FakeSetVolumeLabelA, NULL);
hook("Kernel32.dll", "GetVolumeInformationA", &FakeGetVolumeInformationA, NULL);
hook("Kernel32.dll", "QueryDosDeviceA", &FakeQueryDosDeviceA, NULL);
hook("Kernel32.dll", "GetVolumeNameForVolumeMountPointA",
&FakeGetVolumeNameForVolumeMountPointA, NULL);
hook("Kernel32.dll", "GetVolumePathNamesForVolumeNameA", &FakeGetVolumePathNamesForVolumeNameA,
NULL);
hook("Kernel32.dll", "DeleteVolumeMountPointA", &FakeDeleteVolumeMountPointA, NULL);
hook("Kernel32.dll", "SetVolumeMountPointA", &FakeSetVolumeMountPointA, NULL);
hook("Kernel32.dll", "GetDriveTypeA", &FakeGetDriveTypeA, NULL);
hook("Kernel32.dll", "GetDiskFreeSpaceExA", &FakeGetDiskFreeSpaceExA, (void**)&TrueGetDiskFreeSpaceExA);
hook("Winmm.dll", "mciSendStringA", &Fake_mciSendStringA, NULL);
make_dirs(DISK_PATH);
SegaBootRecordDefault.crc =
amiCrc32RCalc(sizeof SegaBootRecordDefault - 4, &SegaBootRecordDefault.version, 0);
HANDLE hFile;
DWORD numberOfBytesRead;
if (_PathFileExistsA(SBR0_PATH)) {
hFile =
_CreateFileA(SBR0_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_error("drive", "Failed to open %s", SBR0_PATH);
} else {
_ReadFile(hFile, &SegaBootRecord0, sizeof SegaBootRecord0, &numberOfBytesRead, NULL);
_CloseHandle(hFile);
log_info("drive", "Restored SBR0 from %s", SBR0_PATH);
}
} else {
// memcpy(&SegaBootRecord0, &SegaBootRecordDefault, sizeof SegaBootRecord0);
}
if (_PathFileExistsA(SBR1_PATH)) {
hFile =
_CreateFileA(SBR1_PATH, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_error("drive", "Failed to open %s", SBR1_PATH);
} else {
_ReadFile(hFile, &SegaBootRecord1, sizeof SegaBootRecord1, &numberOfBytesRead, NULL);
_CloseHandle(hFile);
log_info("drive", "Restored SBR1 from %s", SBR0_PATH);
}
} else {
memcpy(&SegaBootRecord1, &SegaBootRecord0, sizeof SegaBootRecord0);
}
/**
* mxinstaller iterates all volumes to find those that match the slot metadata.
* It uses:
* - FindFirstVolumeW
* - FindNextVolumeW
* - FindVolumeClose
* to iterate volumes.
* For each volume, it:
* - opens it with CreateFileW
* - calls IOCTL_STORAGE_GET_DEVICE_NUMBER
* - asserts that DeviceType == FILE_DEVICE_DISK
* - calls IOCTL_VOLUME_GET_VOLUME_DISK_EXTENT
* - checks that NumberOfDiskExtents < 128
* - this is not fatal, however an error will be shown and only the first 128 will be checked
* - for each extent (!! sizeof DISK_EXTENT == 24; it's 8-byte aligned):
* - asserts that [].DiskNumber == state_->DiskNumber
* - finds a slot that matches:
* - slot->offset == [].StartingOffset
* - slot->segments == ([].ExtentLength.LowPart >> 9) | ([].ExtentLength.HighPart << 23)
* == [].ExtentLength / 512
*/
}

View File

@ -0,0 +1,149 @@
#pragma once
#ifndef _MICE_DRIVE
#define _MICE_DRIVE extern
#endif
#include <Windows.h>
// (clang-format moves Windows.h if this isn't here!)
#include <Mmsystem.h>
#include <Ntddscsi.h>
#include <Objbase.h>
#include "../../common.h"
#include "../files.h"
#include "disks.h"
#include "irb.h"
#define DISK_PATH "dev/disk/"
#define SPD_PATH (DISK_PATH "spd.bin")
#define SBR0_PATH (DISK_PATH "sbr0.bin")
#define SBR1_PATH (DISK_PATH "sbr1.bin")
#define ORIGINAL0_PATH (DISK_PATH "original0.bin")
extern physical_disk_t SSD;
extern physical_disk_t UPDATE_USB;
extern physical_disk_t LOG_USB;
extern physical_disk_t ALPHA_DVD;
extern sbr_t SegaBootRecordDefault;
extern sbr_t SegaBootRecord0;
extern sbr_t SegaBootRecord1;
// Functions
void init_volume(disk_volume_t* vol);
void init_pd(physical_disk_t* pd);
void init_all_pd();
mice_partition_read_function_t ReadFunc_Original0;
mice_partition_write_function_t WriteFunc_Original0;
mice_partition_read_function_t ReadFunc_OSLogFiles;
FnDeviceIoControl c_drive_DeviceIoControl;
FnDeviceIoControl x_drive_DeviceIoControl;
FnDeviceIoControl q_drive_DeviceIoControl;
FnDeviceIoControl pd_DeviceIoControl;
FnDeviceIoControl volume_DeviceIoControl;
FnReadFile pd_ReadFile;
FnWriteFile pd_WriteFile;
FnReadFile q_drive_ReadFile;
sbr_slot_t* get_sbr_slot(spd_slot_t slot);
disk_volume_t* incrementFindIndex(HANDLE hFindVolume);
#define VOL_MATCH_PATH 1
#define VOL_MATCH_GUID 2
#define VOL_MATCH_DOS_DEVICE 4
#define VOL_MATCH_ALL (VOL_MATCH_PATH | VOL_MATCH_GUID | VOL_MATCH_DOS_DEVICE)
inline static BOOL matchVolume(disk_volume_t* volume, LPCSTR lpRootPathName, DWORD match);
disk_volume_t* getVolumeByPath(LPCSTR lpRootPathName, DWORD match);
// Hooks
BOOL WINAPI FakeFindNextVolumeW(HANDLE hFindVolume, LPWSTR lpszVolumeName, DWORD cchBufferLength);
BOOL WINAPI FakeFindNextVolumeA(HANDLE hFindVolume, LPSTR lpszVolumeName, DWORD cchBufferLength);
HANDLE WINAPI FakeFindFirstVolumeW(LPWSTR lpszVolumeName, DWORD cchBufferLength);
HANDLE WINAPI FakeFindFirstVolumeA(LPSTR lpszVolumeName, DWORD cchBufferLength);
BOOL WINAPI FakeFindVolumeClose(HANDLE hFindVolume);
BOOL WINAPI FakeGetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer,
DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber,
LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags,
LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize);
BOOL WINAPI FakeSetVolumeLabelA(LPCSTR lpRootPathName, LPCSTR lpVolumeName);
BOOL WINAPI FakeGetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint, LPSTR lpszVolumeName,
DWORD cchBufferLength);
BOOL WINAPI FakeGetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName, LPCH lpszVolumePathNames,
DWORD cchBufferLength, PDWORD lpcchReturnLength);
BOOL WINAPI FakeDeleteVolumeMountPointA(LPCSTR lpszVolumeMountPoint);
BOOL WINAPI FakeSetVolumeMountPointA(LPCSTR lpszVolumeMountPoint, LPCSTR lpszVolumeName);
DWORD WINAPI FakeQueryDosDeviceA(LPCSTR lpDeviceName, LPSTR lpTargetPath, DWORD ucchMax);
MCIERROR WINAPI Fake_mciSendStringA(LPCTSTR lpszCommand, LPTSTR lpszReturnString, UINT cchReturn,
HANDLE hwndCallback);
UINT WINAPI FakeGetDriveTypeA(LPCSTR lpRootPathName);
BOOL WINAPI FakeGetDiskFreeSpaceExA(LPCSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes);
_MICE_DRIVE BOOL(WINAPI* TrueGetDiskFreeSpaceExA)(LPCSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes);
void hook_drives();
// MBR
#define MBR_LBA_GAP 0x3f // 1 track worth of sectors is claimed for the MBR
#define EXT_HEADER_GAP 0x3f
#define MBR_FLAG_NONE 0x00
#define MBR_FLAG_BOOTABLE 0x80
#define MBR_FS_NONE 0x00
#define MBR_FS_EXT_CHS 0x05
#define MBR_FS_FAT16 0x06
#define MBR_FS_NTFS 0x07
#define MBR_FS_EXT_LBA 0x0F
#pragma pack(push, 1)
typedef struct mbr {
BYTE bootstrap_code[446];
struct {
BYTE status;
BYTE start_chs[3];
BYTE type;
BYTE end_chs[3];
DWORD lba;
DWORD sectors;
} partitions[4];
BYTE sig[2];
} mbr_t;
#pragma pack(pop)
#define IOCTL_CDROM_GET_DRIVE_GEOMETRY 0x2404c // #include <Ntddcdrm.h> causes errors
#define BLOCK_SIZE_FLASH 4096
#define BLOCK_SIZE_HDD 512
#define BLOCK_SIZE_CDROM 2048
#define BLOCK_SIZE_DVD BLOCK_SIZE_CDROM
// SCSI Peripheral Device Type
typedef enum {
DeviceTypeDAB = 0,
DeviceTypeSAB,
DeviceTypePrinter,
DeviceTypeProcessor,
DeviceTypeWriteOnce,
DeviceTypeCdRom,
DeviceTypeScanner,
DeviceTypeOpticalMemory,
DeviceTypeMediumChanger,
DeviceTypeCommunications,
DeviceTypeSAC = 12,
DeviceTypeEnclosure,
DeviceTypeOpticalCard,
DeviceTypeAutomationInterface,
DeviceTypeSecurityManager,
DeviceTypeHMBlock,
DeviceTypeUnknown = 31,
} DEVICE_TYPE;

View File

@ -0,0 +1,279 @@
#include "drive.h"
typedef struct {
size_t disk;
size_t partition;
} find_index_t;
disk_volume_t* incrementFindIndex(HANDLE hFindVolume) {
find_index_t* find_index = GetDataForHandle(hFindVolume, HDATA_FIND_VOLUME);
if (find_index == NULL) return NULL;
while (1) {
if (find_index->disk >= MAX_DISKS || PHYSICAL_DISKS[find_index->disk] == NULL) {
return NULL;
}
if (find_index->partition > 3) {
if (PHYSICAL_DISKS[find_index->disk]
->m_Extended[find_index->partition - 4]
.m_PartitionNumber == 0) {
find_index->disk++;
find_index->partition = 0;
continue;
}
return &(PHYSICAL_DISKS[find_index->disk]
->m_Extended[(find_index->partition++) - 4]
.m_Volume);
}
if (PHYSICAL_DISKS[find_index->disk]
->m_Partitions[find_index->partition]
.m_PartitionNumber == 0) {
find_index->partition = 4;
continue;
}
return &(PHYSICAL_DISKS[find_index->disk]->m_Partitions[find_index->partition++].m_Volume);
}
}
BOOL WINAPI FakeFindNextVolumeW(HANDLE hFindVolume, LPWSTR lpszVolumeName, DWORD cchBufferLength) {
disk_volume_t* volume = incrementFindIndex(hFindVolume);
if (volume == NULL) {
SetLastError(ERROR_NO_MORE_FILES);
return FALSE;
}
wcscpy_s(lpszVolumeName, cchBufferLength, volume->m_FilenameW);
wcscat_s(lpszVolumeName, cchBufferLength, L"\\");
return TRUE;
}
BOOL WINAPI FakeFindNextVolumeA(HANDLE hFindVolume, LPSTR lpszVolumeName, DWORD cchBufferLength) {
disk_volume_t* volume = incrementFindIndex(hFindVolume);
if (volume == NULL) {
SetLastError(ERROR_NO_MORE_FILES);
return FALSE;
}
strcpy_s(lpszVolumeName, cchBufferLength, volume->m_FilenameA);
strcat_s(lpszVolumeName, cchBufferLength, "\\");
return TRUE;
}
HANDLE WINAPI FakeFindFirstVolumeW(LPWSTR lpszVolumeName, DWORD cchBufferLength) {
find_index_t* find_index = malloc(sizeof(find_index_t));
find_index->disk = 0;
find_index->partition = 0;
HANDLE handle = GetDummyHandle();
SetDataForHandle(handle, HDATA_FIND_VOLUME, find_index, TRUE);
FakeFindNextVolumeW(handle, lpszVolumeName, cchBufferLength);
return handle;
}
HANDLE WINAPI FakeFindFirstVolumeA(LPSTR lpszVolumeName, DWORD cchBufferLength) {
find_index_t* find_index = malloc(sizeof(find_index_t));
find_index->disk = 0;
find_index->partition = 0;
HANDLE handle = GetDummyHandle();
SetDataForHandle(handle, HDATA_FIND_VOLUME, find_index, TRUE);
FakeFindNextVolumeA(handle, lpszVolumeName, cchBufferLength);
return handle;
}
BOOL WINAPI FakeFindVolumeClose(HANDLE hFindVolume) {
if (RemoveDataForHandle(hFindVolume, HDATA_FIND_VOLUME)) return _CloseHandle(hFindVolume);
return FALSE;
}
BOOL WINAPI FakeGetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameBuffer,
DWORD nVolumeNameSize, LPDWORD lpVolumeSerialNumber,
LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags,
LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize) {
disk_volume_t* volume = getVolumeByPath(lpRootPathName, VOL_MATCH_ALL);
if (volume == NULL) return FALSE;
if (lpVolumeSerialNumber) *lpVolumeSerialNumber = volume->m_pDrive->m_SerialNumber;
// TODO: Ripped from a RingEdge. Make these part of our emulation.
if (lpFileSystemFlags) *lpFileSystemFlags = 0x700ff;
if (lpMaximumComponentLength) *lpMaximumComponentLength = 255;
// TODO: This isn't even true for non-NTFS partitions
if (lpFileSystemNameBuffer) strncpy_s(lpFileSystemNameBuffer, nFileSystemNameSize, "NTFS", 5);
if (lpVolumeNameBuffer && nVolumeNameSize) {
if (volume->m_Name)
strcpy_s(lpVolumeNameBuffer, nVolumeNameSize, volume->m_Name);
else
lpVolumeNameBuffer[0] = '\0';
}
return TRUE;
}
BOOL WINAPI FakeSetVolumeLabelA(LPCSTR lpRootPathName, LPCSTR lpVolumeName) {
disk_volume_t* volume = getVolumeByPath(lpRootPathName, VOL_MATCH_ALL);
if (volume == NULL) return FALSE;
if (lpVolumeName) {
size_t len = strlen(lpVolumeName);
// By default volume names are pointers to constants!
if (volume->m_NameIsOnHeap)
realloc(volume->m_Name, len + 1);
else {
volume->m_Name = malloc(len + 1);
volume->m_NameIsOnHeap = TRUE;
}
memcpy(volume->m_Name, lpVolumeName, len);
} else {
volume->m_Name = NULL;
}
return TRUE;
}
BOOL WINAPI FakeGetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint, LPSTR lpszVolumeName,
DWORD cchBufferLength) {
log_trace("drive", "GetVolumeNameForVolumeMountPointA(%s)", lpszVolumeMountPoint);
disk_volume_t* volume = getVolumeByPath(lpszVolumeMountPoint, VOL_MATCH_PATH);
if (volume == NULL) {
SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
}
strcpy_s(lpszVolumeName, cchBufferLength, volume->m_FilenameA);
return TRUE;
}
BOOL WINAPI FakeGetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName, LPCH lpszVolumePathNames,
DWORD cchBufferLength, PDWORD lpcchReturnLength) {
log_trace("drive", "GetVolumeNameForVolumeMountPointA(%s)", lpszVolumeName);
disk_volume_t* volume = getVolumeByPath(lpszVolumeName, VOL_MATCH_GUID);
if (volume == NULL) {
SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
}
if (volume->m_MountPoint) {
// TODO: Handle the situation where the buffer is too small
*lpcchReturnLength =
sprintf_s(lpszVolumePathNames, cchBufferLength, "\\\\.\\%c:", volume->m_MountPoint);
if (*lpcchReturnLength != cchBufferLength) {
lpszVolumePathNames[*lpcchReturnLength] = '\0';
*lpcchReturnLength++;
}
} else {
*lpcchReturnLength = 0;
}
return TRUE;
}
BOOL WINAPI FakeDeleteVolumeMountPointA(LPCSTR lpszVolumeMountPoint) {
log_trace("drive", "DeleteVolumeMountPointA(%s)", lpszVolumeMountPoint);
disk_volume_t* volume = getVolumeByPath(lpszVolumeMountPoint, VOL_MATCH_PATH);
if (volume == NULL) {
SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
}
volume->m_MountPoint = '\0';
return TRUE;
}
BOOL WINAPI FakeSetVolumeMountPointA(LPCSTR lpszVolumeMountPoint, LPCSTR lpszVolumeName) {
log_trace("drive", "SetVolumeMountPointA(%s)", lpszVolumeMountPoint);
disk_volume_t* volume = getVolumeByPath(lpszVolumeName, VOL_MATCH_GUID);
if (volume == NULL) {
SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
}
char cMountPoint;
DWORD nScan;
if (sscanf_s(lpszVolumeMountPoint, "\\\\.\\%c:%n", &cMountPoint, 1, &nScan) == 1 &&
nScan == 6) {
log_info("drive", "Mounting %s at %c:\\", volume->m_Name, cMountPoint);
volume->m_MountPoint = cMountPoint;
return TRUE;
}
if (sscanf_s(lpszVolumeMountPoint, "%c:\\%n", &cMountPoint, 1, &nScan) == 1 && nScan == 3) {
log_info("drive", "Mounting %s at %c:\\", volume->m_Name, cMountPoint);
volume->m_MountPoint = cMountPoint;
return TRUE;
}
return FALSE;
}
DWORD WINAPI FakeQueryDosDeviceA(LPCSTR lpDeviceName, LPSTR lpTargetPath, DWORD ucchMax) {
if (lpDeviceName != NULL) {
disk_volume_t* volume = getVolumeByPath(lpDeviceName, VOL_MATCH_DOS_DEVICE);
if (volume == NULL) {
SetLastError(ERROR_FILE_NOT_FOUND);
return 0;
}
size_t mountLen = wcslen(volume->m_DeviceName);
if (ucchMax < mountLen + 1) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return 0;
}
sprintf_s(lpTargetPath, ucchMax, "\\Device\\%ls", volume->m_DeviceName);
return ucchMax;
}
return 0;
}
MCIERROR WINAPI Fake_mciSendStringA(LPCTSTR lpszCommand, LPTSTR lpszReturnString, UINT cchReturn,
HANDLE hwndCallback) {
if (strcmp(lpszCommand, "open cdaudio") == 0) {
return 0;
}
if (strcmp(lpszCommand, "set cdaudio door open") == 0) {
log_game("mci", "Cupholder opened!");
return 0;
}
if (strcmp(lpszCommand, "status cdaudio media present") == 0) {
if (lpszReturnString) {
if (TRUE)
strcpy_s(lpszReturnString, cchReturn, "true");
else
strcpy_s(lpszReturnString, cchReturn, "false");
}
return 0;
}
if (strcmp(lpszCommand, "close cdaudio") == 0) {
return 0;
}
return MCIERR_UNRECOGNIZED_COMMAND;
}
UINT WINAPI FakeGetDriveTypeA(LPCSTR lpRootPathName) {
disk_volume_t* volume = getVolumeByPath(lpRootPathName, VOL_MATCH_PATH | VOL_MATCH_DOS_DEVICE);
if (volume == NULL) {
SetLastError(ERROR_FILE_NOT_FOUND);
return DRIVE_NO_ROOT_DIR;
}
switch (volume->m_pDrive->m_DiskType) {
case DiskType_CdRom:
return DRIVE_CDROM;
case DiskType_HardDisk:
return DRIVE_FIXED;
case DiskType_Flash:
case DiskType_Floppy:
return DRIVE_REMOVABLE;
default:
return DRIVE_UNKNOWN;
}
}
BOOL WINAPI FakeGetDiskFreeSpaceExA(LPCSTR lpDirectoryName,
PULARGE_INTEGER lpFreeBytesAvailableToCaller,
PULARGE_INTEGER lpTotalNumberOfBytes,
PULARGE_INTEGER lpTotalNumberOfFreeBytes) {
// disk_volume_t* volume = getVolumeByPath(lpDirectoryName, VOL_MATCH_ALL);
// if (volume == NULL) {
// SetLastError(ERROR_FILE_NOT_FOUND);
// return FALSE;
// }
// We're going to be remapping the drive to ./dev/, so the free bytes are whatever the current
// real drive has free. No point claiming we have more than we do!
return TrueGetDiskFreeSpaceExA(NULL, lpFreeBytesAvailableToCaller, lpTotalNumberOfBytes,
lpTotalNumberOfFreeBytes);
}

View File

@ -0,0 +1,375 @@
#pragma once
#include <Windows.h>
// Lifted from Irb.h
typedef struct _IDENTIFY_DEVICE_DATA {
struct {
USHORT Reserved1 : 1;
USHORT Retired3 : 1;
USHORT ResponseIncomplete : 1;
USHORT Retired2 : 3;
USHORT FixedDevice : 1;
USHORT RemovableMedia : 1;
USHORT Retired1 : 7;
USHORT DeviceType : 1;
} GeneralConfiguration;
USHORT NumCylinders;
USHORT SpecificConfiguration;
USHORT NumHeads;
USHORT Retired1[2];
USHORT NumSectorsPerTrack;
USHORT VendorUnique1[3];
UCHAR SerialNumber[20];
USHORT Retired2[2];
USHORT Obsolete1;
UCHAR FirmwareRevision[8];
UCHAR ModelNumber[40];
UCHAR MaximumBlockTransfer;
UCHAR VendorUnique2;
struct {
USHORT FeatureSupported : 1;
USHORT Reserved : 15;
} TrustedComputing;
struct {
UCHAR CurrentLongPhysicalSectorAlignment : 2;
UCHAR ReservedByte49 : 6;
UCHAR DmaSupported : 1;
UCHAR LbaSupported : 1;
UCHAR IordyDisable : 1;
UCHAR IordySupported : 1;
UCHAR Reserved1 : 1;
UCHAR StandybyTimerSupport : 1;
UCHAR Reserved2 : 2;
USHORT ReservedWord50;
} Capabilities;
USHORT ObsoleteWords51[2];
USHORT TranslationFieldsValid : 3;
USHORT Reserved3 : 5;
USHORT FreeFallControlSensitivity : 8;
USHORT NumberOfCurrentCylinders;
USHORT NumberOfCurrentHeads;
USHORT CurrentSectorsPerTrack;
ULONG CurrentSectorCapacity;
UCHAR CurrentMultiSectorSetting;
UCHAR MultiSectorSettingValid : 1;
UCHAR ReservedByte59 : 3;
UCHAR SanitizeFeatureSupported : 1;
UCHAR CryptoScrambleExtCommandSupported : 1;
UCHAR OverwriteExtCommandSupported : 1;
UCHAR BlockEraseExtCommandSupported : 1;
ULONG UserAddressableSectors;
USHORT ObsoleteWord62;
USHORT MultiWordDMASupport : 8;
USHORT MultiWordDMAActive : 8;
USHORT AdvancedPIOModes : 8;
USHORT ReservedByte64 : 8;
USHORT MinimumMWXferCycleTime;
USHORT RecommendedMWXferCycleTime;
USHORT MinimumPIOCycleTime;
USHORT MinimumPIOCycleTimeIORDY;
struct {
USHORT ZonedCapabilities : 2;
USHORT NonVolatileWriteCache : 1;
USHORT ExtendedUserAddressableSectorsSupported : 1;
USHORT DeviceEncryptsAllUserData : 1;
USHORT ReadZeroAfterTrimSupported : 1;
USHORT Optional28BitCommandsSupported : 1;
USHORT IEEE1667 : 1;
USHORT DownloadMicrocodeDmaSupported : 1;
USHORT SetMaxSetPasswordUnlockDmaSupported : 1;
USHORT WriteBufferDmaSupported : 1;
USHORT ReadBufferDmaSupported : 1;
USHORT DeviceConfigIdentifySetDmaSupported : 1;
USHORT LPSAERCSupported : 1;
USHORT DeterministicReadAfterTrimSupported : 1;
USHORT CFastSpecSupported : 1;
} AdditionalSupported;
USHORT ReservedWords70[5];
USHORT QueueDepth : 5;
USHORT ReservedWord75 : 11;
struct {
USHORT Reserved0 : 1;
USHORT SataGen1 : 1;
USHORT SataGen2 : 1;
USHORT SataGen3 : 1;
USHORT Reserved1 : 4;
USHORT NCQ : 1;
USHORT HIPM : 1;
USHORT PhyEvents : 1;
USHORT NcqUnload : 1;
USHORT NcqPriority : 1;
USHORT HostAutoPS : 1;
USHORT DeviceAutoPS : 1;
USHORT ReadLogDMA : 1;
USHORT Reserved2 : 1;
USHORT CurrentSpeed : 3;
USHORT NcqStreaming : 1;
USHORT NcqQueueMgmt : 1;
USHORT NcqReceiveSend : 1;
USHORT DEVSLPtoReducedPwrState : 1;
USHORT Reserved3 : 8;
} SerialAtaCapabilities;
struct {
USHORT Reserved0 : 1;
USHORT NonZeroOffsets : 1;
USHORT DmaSetupAutoActivate : 1;
USHORT DIPM : 1;
USHORT InOrderData : 1;
USHORT HardwareFeatureControl : 1;
USHORT SoftwareSettingsPreservation : 1;
USHORT NCQAutosense : 1;
USHORT DEVSLP : 1;
USHORT HybridInformation : 1;
USHORT Reserved1 : 6;
} SerialAtaFeaturesSupported;
struct {
USHORT Reserved0 : 1;
USHORT NonZeroOffsets : 1;
USHORT DmaSetupAutoActivate : 1;
USHORT DIPM : 1;
USHORT InOrderData : 1;
USHORT HardwareFeatureControl : 1;
USHORT SoftwareSettingsPreservation : 1;
USHORT DeviceAutoPS : 1;
USHORT DEVSLP : 1;
USHORT HybridInformation : 1;
USHORT Reserved1 : 6;
} SerialAtaFeaturesEnabled;
USHORT MajorRevision;
USHORT MinorRevision;
struct {
USHORT SmartCommands : 1;
USHORT SecurityMode : 1;
USHORT RemovableMediaFeature : 1;
USHORT PowerManagement : 1;
USHORT Reserved1 : 1;
USHORT WriteCache : 1;
USHORT LookAhead : 1;
USHORT ReleaseInterrupt : 1;
USHORT ServiceInterrupt : 1;
USHORT DeviceReset : 1;
USHORT HostProtectedArea : 1;
USHORT Obsolete1 : 1;
USHORT WriteBuffer : 1;
USHORT ReadBuffer : 1;
USHORT Nop : 1;
USHORT Obsolete2 : 1;
USHORT DownloadMicrocode : 1;
USHORT DmaQueued : 1;
USHORT Cfa : 1;
USHORT AdvancedPm : 1;
USHORT Msn : 1;
USHORT PowerUpInStandby : 1;
USHORT ManualPowerUp : 1;
USHORT Reserved2 : 1;
USHORT SetMax : 1;
USHORT Acoustics : 1;
USHORT BigLba : 1;
USHORT DeviceConfigOverlay : 1;
USHORT FlushCache : 1;
USHORT FlushCacheExt : 1;
USHORT WordValid83 : 2;
USHORT SmartErrorLog : 1;
USHORT SmartSelfTest : 1;
USHORT MediaSerialNumber : 1;
USHORT MediaCardPassThrough : 1;
USHORT StreamingFeature : 1;
USHORT GpLogging : 1;
USHORT WriteFua : 1;
USHORT WriteQueuedFua : 1;
USHORT WWN64Bit : 1;
USHORT URGReadStream : 1;
USHORT URGWriteStream : 1;
USHORT ReservedForTechReport : 2;
USHORT IdleWithUnloadFeature : 1;
USHORT WordValid : 2;
} CommandSetSupport;
struct {
USHORT SmartCommands : 1;
USHORT SecurityMode : 1;
USHORT RemovableMediaFeature : 1;
USHORT PowerManagement : 1;
USHORT Reserved1 : 1;
USHORT WriteCache : 1;
USHORT LookAhead : 1;
USHORT ReleaseInterrupt : 1;
USHORT ServiceInterrupt : 1;
USHORT DeviceReset : 1;
USHORT HostProtectedArea : 1;
USHORT Obsolete1 : 1;
USHORT WriteBuffer : 1;
USHORT ReadBuffer : 1;
USHORT Nop : 1;
USHORT Obsolete2 : 1;
USHORT DownloadMicrocode : 1;
USHORT DmaQueued : 1;
USHORT Cfa : 1;
USHORT AdvancedPm : 1;
USHORT Msn : 1;
USHORT PowerUpInStandby : 1;
USHORT ManualPowerUp : 1;
USHORT Reserved2 : 1;
USHORT SetMax : 1;
USHORT Acoustics : 1;
USHORT BigLba : 1;
USHORT DeviceConfigOverlay : 1;
USHORT FlushCache : 1;
USHORT FlushCacheExt : 1;
USHORT Resrved3 : 1;
USHORT Words119_120Valid : 1;
USHORT SmartErrorLog : 1;
USHORT SmartSelfTest : 1;
USHORT MediaSerialNumber : 1;
USHORT MediaCardPassThrough : 1;
USHORT StreamingFeature : 1;
USHORT GpLogging : 1;
USHORT WriteFua : 1;
USHORT WriteQueuedFua : 1;
USHORT WWN64Bit : 1;
USHORT URGReadStream : 1;
USHORT URGWriteStream : 1;
USHORT ReservedForTechReport : 2;
USHORT IdleWithUnloadFeature : 1;
USHORT Reserved4 : 2;
} CommandSetActive;
USHORT UltraDMASupport : 8;
USHORT UltraDMAActive : 8;
struct {
USHORT TimeRequired : 15;
USHORT ExtendedTimeReported : 1;
} NormalSecurityEraseUnit;
struct {
USHORT TimeRequired : 15;
USHORT ExtendedTimeReported : 1;
} EnhancedSecurityEraseUnit;
USHORT CurrentAPMLevel : 8;
USHORT ReservedWord91 : 8;
USHORT MasterPasswordID;
USHORT HardwareResetResult;
USHORT CurrentAcousticValue : 8;
USHORT RecommendedAcousticValue : 8;
USHORT StreamMinRequestSize;
USHORT StreamingTransferTimeDMA;
USHORT StreamingAccessLatencyDMAPIO;
ULONG StreamingPerfGranularity;
ULONG Max48BitLBA[2];
USHORT StreamingTransferTime;
USHORT DsmCap;
struct {
USHORT LogicalSectorsPerPhysicalSector : 4;
USHORT Reserved0 : 8;
USHORT LogicalSectorLongerThan256Words : 1;
USHORT MultipleLogicalSectorsPerPhysicalSector : 1;
USHORT Reserved1 : 2;
} PhysicalLogicalSectorSize;
USHORT InterSeekDelay;
USHORT WorldWideName[4];
USHORT ReservedForWorldWideName128[4];
USHORT ReservedForTlcTechnicalReport;
USHORT WordsPerLogicalSector[2];
struct {
USHORT ReservedForDrqTechnicalReport : 1;
USHORT WriteReadVerify : 1;
USHORT WriteUncorrectableExt : 1;
USHORT ReadWriteLogDmaExt : 1;
USHORT DownloadMicrocodeMode3 : 1;
USHORT FreefallControl : 1;
USHORT SenseDataReporting : 1;
USHORT ExtendedPowerConditions : 1;
USHORT Reserved0 : 6;
USHORT WordValid : 2;
} CommandSetSupportExt;
struct {
USHORT ReservedForDrqTechnicalReport : 1;
USHORT WriteReadVerify : 1;
USHORT WriteUncorrectableExt : 1;
USHORT ReadWriteLogDmaExt : 1;
USHORT DownloadMicrocodeMode3 : 1;
USHORT FreefallControl : 1;
USHORT SenseDataReporting : 1;
USHORT ExtendedPowerConditions : 1;
USHORT Reserved0 : 6;
USHORT Reserved1 : 2;
} CommandSetActiveExt;
USHORT ReservedForExpandedSupportandActive[6];
USHORT MsnSupport : 2;
USHORT ReservedWord127 : 14;
struct {
USHORT SecuritySupported : 1;
USHORT SecurityEnabled : 1;
USHORT SecurityLocked : 1;
USHORT SecurityFrozen : 1;
USHORT SecurityCountExpired : 1;
USHORT EnhancedSecurityEraseSupported : 1;
USHORT Reserved0 : 2;
USHORT SecurityLevel : 1;
USHORT Reserved1 : 7;
} SecurityStatus;
USHORT ReservedWord129[31];
struct {
USHORT MaximumCurrentInMA : 12;
USHORT CfaPowerMode1Disabled : 1;
USHORT CfaPowerMode1Required : 1;
USHORT Reserved0 : 1;
USHORT Word160Supported : 1;
} CfaPowerMode1;
USHORT ReservedForCfaWord161[7];
USHORT NominalFormFactor : 4;
USHORT ReservedWord168 : 12;
struct {
USHORT SupportsTrim : 1;
USHORT Reserved0 : 15;
} DataSetManagementFeature;
USHORT AdditionalProductID[4];
USHORT ReservedForCfaWord174[2];
USHORT CurrentMediaSerialNumber[30];
struct {
USHORT Supported : 1;
USHORT Reserved0 : 1;
USHORT WriteSameSuported : 1;
USHORT ErrorRecoveryControlSupported : 1;
USHORT FeatureControlSuported : 1;
USHORT DataTablesSuported : 1;
USHORT Reserved1 : 6;
USHORT VendorSpecific : 4;
} SCTCommandTransport;
USHORT ReservedWord207[2];
struct {
USHORT AlignmentOfLogicalWithinPhysical : 14;
USHORT Word209Supported : 1;
USHORT Reserved0 : 1;
} BlockAlignment;
USHORT WriteReadVerifySectorCountMode3Only[2];
USHORT WriteReadVerifySectorCountMode2Only[2];
struct {
USHORT NVCachePowerModeEnabled : 1;
USHORT Reserved0 : 3;
USHORT NVCacheFeatureSetEnabled : 1;
USHORT Reserved1 : 3;
USHORT NVCachePowerModeVersion : 4;
USHORT NVCacheFeatureSetVersion : 4;
} NVCacheCapabilities;
USHORT NVCacheSizeLSW;
USHORT NVCacheSizeMSW;
USHORT NominalMediaRotationRate;
USHORT ReservedWord218;
struct {
UCHAR NVCacheEstimatedTimeToSpinUpInSeconds;
UCHAR Reserved;
} NVCacheOptions;
USHORT WriteReadVerifySectorCountMode : 8;
USHORT ReservedWord220 : 8;
USHORT ReservedWord221;
struct {
USHORT MajorVersion : 12;
USHORT TransportType : 4;
} TransportMajorVersion;
USHORT TransportMinorVersion;
USHORT ReservedWord224[6];
ULONG ExtendedNumberOfUserAddressableSectors[2];
USHORT MinBlocksPerDownloadMicrocodeMode03;
USHORT MaxBlocksPerDownloadMicrocodeMode03;
USHORT ReservedWord236[19];
USHORT Signature : 8;
USHORT CheckSum : 8;
} IDENTIFY_DEVICE_DATA, *PIDENTIFY_DEVICE_DATA;

View File

@ -0,0 +1,417 @@
#include "drive.h"
BOOL WINAPI pd_DeviceIoControl(file_context_t* ctx, DWORD dwIoControlCode, LPVOID lpInBuffer,
DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize,
LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped) {
physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData;
if (pd == NULL) {
log_error("drive", "ioctl:ctx->m_HookData NULL; expected a physical drive!");
return FALSE;
}
log_trace("drive", "DeviceIOControl %08x", dwIoControlCode);
ZeroMemory(lpOutBuffer, nOutBufferSize);
switch (dwIoControlCode) {
case IOCTL_ATA_PASS_THROUGH:
if (pd->m_BusType != BusTypeAta) return FALSE;
PATA_PASS_THROUGH_EX ata = (PATA_PASS_THROUGH_EX)lpInBuffer;
BYTE command = ata->CurrentTaskFile[6];
if (command == 0xEC) {
// TODO: One day re-visit this if amPlatformGetStorageInfo is used elsewhere
// PIDENTIFY_DEVICE_DATA identifyData =
// (PIDENTIFY_DEVICE_DATA)((LPBYTE)lpOutBuffer + sizeof *ata +
// ata->DataBufferOffset - 5);
// // ZeroMemory(identifyData, sizeof *identifyData);
// // TODO: Is there any point worth spoofing anything else?
// strcpy_s((char*)identifyData->ModelNumber, sizeof identifyData->ModelNumber,
// "VDrive");
// strcpy_s((char*)identifyData->SerialNumber, sizeof identifyData->SerialNumber,
// "AAAAAAAAAAA");
// identifyData->NumSectorsPerTrack = 0x4243;
*lpBytesReturned = nOutBufferSize;
return TRUE;
}
if (command != 0xC1) {
log_error("pd0", "Unimplemented ATA command: %02x", command);
return FALSE;
}
BYTE data = ata->CurrentTaskFile[0];
switch (data) {
// These are used un UnlockSection1, 2, and 3 in mxstorage!
case 0x11: // mxkSsdHostProofSet (step == 0)
// Game -> ATA | 128 bytes: random from N2
case 0x12: // mxkSsdHostProofGet (step == 0)
// ATA -> GAME | 128 bytes: (guess) readback of 0x11
case 0x21: // mxkSsdHostProofSet (step == 1)
// Game -> ATA | 128 bytes: random from N2
case 0x22: // mxkSsdHostProofGet (step == 1)
// ATA -> GAME | 128 bytes: (guess) readback of 0x21
case 0x31: // mxkSsdHostProofSeed
// ATA -> Game | 80 bytes: seed
case 0x32: // mxkSsdHostProofChallenge
// Game -> ATA | 80 bytes: the seed, encrypted by N2 with S-Key
// It looks like mxkeychip never actually checks the response buffer,
// as long as the ioctl succeeds! Saves us a lot of work here!
return TRUE;
}
log_error("drive", "Unimeplemented ATA C1 command: %02x", data);
return FALSE;
case IOCTL_DISK_GET_LENGTH_INFO:
PGET_LENGTH_INFORMATION pLi = (PGET_LENGTH_INFORMATION)lpOutBuffer;
pLi->Length.QuadPart = SSD.m_TotalSize * (long long)SSD.m_BlockSize;
*lpBytesReturned = sizeof *pLi;
return TRUE;
}
log_error("drive", "Unimplemented ioctl: %08x", dwIoControlCode);
return FALSE;
}
BOOL pd_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData;
if (pd == NULL) {
log_error("drive", "read:ctx->m_HookData NULL; expected a physical drive!");
return FALSE;
}
log_misc("drive", "PhysicalDrive%d: Read %d @ %llx", pd->m_DriveNumber, nNumberOfBytesToRead,
ctx->m_Pointer.QuadPart);
// ! WARNING: This ReadFile implementation is currently limited to aligned
// ! reads. Given the main purpose of this function is to allow reading
// ! the partition information, this doesn't currently pose an issue.
DWORD ptrLBA = (ctx->m_Pointer.QuadPart / (long long)pd->m_BlockSize) & 0xffffffff;
// MBR header
if (ptrLBA == 0) {
mbr_t* mbr = (mbr_t*)lpBuffer;
if (nNumberOfBytesToRead < sizeof *mbr) {
log_error("drive", "Buffer too small for master boot record!");
return FALSE;
}
memset(mbr, 0, sizeof *mbr);
mbr->sig[0] = 0x55;
mbr->sig[1] = 0xAA;
for (size_t i = 0; i < 4; i++) {
if (pd->m_Partitions[i].m_Size == 0) break;
mbr->partitions[i].status =
(pd->m_BootPartition == i + 1) ? MBR_FLAG_BOOTABLE : MBR_FLAG_NONE;
mbr->partitions[i].type = pd->m_Partitions[i].m_Filesystem;
mbr->partitions[i].lba = pd->m_Partitions[i].m_PhysicalLBA;
mbr->partitions[i].sectors = pd->m_Partitions[i].m_Size;
}
*lpNumberOfBytesRead = sizeof *mbr;
return TRUE;
}
if (ptrLBA <= MBR_LBA_GAP) {
// Read within the 63 extra tracks
log_error("drive", "Read failed");
return FALSE;
}
// MBR partitions
for (size_t i = 0; i < 4; i++) {
if (pd->m_Partitions[i].m_PartitionNumber == 0) break;
if (ptrLBA >= pd->m_Partitions[i].m_PhysicalLBA &&
ptrLBA < pd->m_Partitions[i].m_PhysicalLBA + pd->m_Partitions[i].m_Size) {
DWORD readOffset = ptrLBA - pd->m_Partitions[i].m_PhysicalLBA;
if (pd->m_Partitions[i].m_ReadFunc == NULL) {
log_error("disk", "Attempted read in %d/%d at block offset %08x; No read function",
pd->m_DriveNumber, pd->m_Partitions[i].m_PartitionNumber, readOffset);
return FALSE;
}
BOOL ret = pd->m_Partitions[i].m_ReadFunc(readOffset, lpBuffer, nNumberOfBytesToRead,
lpNumberOfBytesRead);
if (!ret) {
log_error("disk", "Attempted read in %d/%d at block offset %08x; Read rejected",
pd->m_DriveNumber, pd->m_Partitions[i].m_PartitionNumber, readOffset);
return FALSE;
}
log_misc("drive", "Read at %d/%d+%d", pd->m_DriveNumber,
pd->m_Partitions[i].m_PartitionNumber, readOffset);
return TRUE;
}
}
// Extended partitions
for (size_t i = 0; pd->m_Extended[i].m_Size; i++) {
// Extended header
DWORD headerLBA = pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP;
if (ptrLBA == headerLBA) {
mbr_t* mbr = (mbr_t*)lpBuffer;
if (nNumberOfBytesToRead < sizeof *mbr) {
log_error("drive", "Buffer too small for an extended boot record!");
return FALSE;
}
memset(mbr, 0, sizeof *mbr);
mbr->sig[0] = 0x55;
mbr->sig[1] = 0xAA;
mbr->partitions[0].status = MBR_FLAG_NONE;
mbr->partitions[0].type = pd->m_Extended[i].m_Filesystem;
mbr->partitions[0].lba = EXT_HEADER_GAP;
mbr->partitions[0].sectors = pd->m_Extended[i].m_Size;
if (pd->m_Extended[i + 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 =
pd->m_Extended[i + 1].m_PhysicalLBA - pd->m_Extended[0].m_PhysicalLBA;
mbr->partitions[1].sectors = pd->m_Extended[i + 1].m_Size + EXT_HEADER_GAP;
}
*lpNumberOfBytesRead = sizeof *mbr;
return TRUE;
}
if (i == 0 && pd->m_HasSegaboot) {
// SEGA Partition Description
if (ptrLBA == headerLBA + SPD_OFFSET) {
spd_t* spd = (spd_t*)lpBuffer;
if (nNumberOfBytesToRead < sizeof *spd) {
log_error("drive", "Buffer too small for SPD!");
return FALSE;
}
spd->version = SPD_VERSION;
for (size_t j = 0; pd->m_Extended[j].m_Size; j++) {
spd->slots[j].block_size = pd->m_BlockSize & 0xFFFF;
spd->slots[j].block_count = pd->m_Extended[j].m_Size;
spd->slots[j].slot_content = pd->m_Extended[j].m_SPDContent;
spd->slots[j].uk1 = pd->m_Extended[j].m_Filesystem == MBR_FS_FAT16 ? 0 : 1;
}
spd->crc = amiCrc32RCalc(sizeof *spd - 4, &(spd->version), 0);
*lpNumberOfBytesRead = sizeof *spd;
return TRUE;
}
// SEGA Boot Record 0 and 1. The two are a redundant copy of each other
if (ptrLBA == headerLBA + SBR0_OFFSET) {
if (nNumberOfBytesToRead < sizeof SegaBootRecord0) {
log_error("drive", "Buffer too small for SBR0!");
return FALSE;
}
memcpy(lpBuffer, &SegaBootRecord0, sizeof SegaBootRecord0);
*lpNumberOfBytesRead = sizeof SegaBootRecord0;
return TRUE;
}
if (ptrLBA == headerLBA + SBR1_OFFSET) {
if (nNumberOfBytesToRead < sizeof SegaBootRecord1) {
log_error("drive", "Buffer too small for SBR1!");
return FALSE;
}
memcpy(lpBuffer, &SegaBootRecord1, sizeof SegaBootRecord1);
*lpNumberOfBytesRead = sizeof SegaBootRecord1;
return TRUE;
}
}
if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP &&
ptrLBA < pd->m_Extended[i].m_PhysicalLBA) {
// Read within the 63 extra tracks
log_error("drive", "Read failed");
return FALSE;
}
if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA &&
ptrLBA < pd->m_Extended[i].m_PhysicalLBA + pd->m_Extended[i].m_Size) {
DWORD readOffset = ptrLBA - pd->m_Extended[i].m_PhysicalLBA;
if (pd->m_Extended[i].m_ReadFunc == NULL) {
log_error("disk", "Attempted read in %d/%d at block offset %08x; No read function",
pd->m_DriveNumber, pd->m_Extended[i].m_PartitionNumber, readOffset);
return FALSE;
}
BOOL ret = pd->m_Extended[i].m_ReadFunc(readOffset, lpBuffer, nNumberOfBytesToRead,
lpNumberOfBytesRead);
if (!ret) {
log_error("disk", "Attempted read in %d/%d at block offset %08x; Read rejected",
pd->m_DriveNumber, pd->m_Extended[i].m_PartitionNumber, readOffset);
return FALSE;
}
log_misc("drive", "Read at %d/%d+%d", pd->m_DriveNumber,
pd->m_Extended[i].m_PartitionNumber, readOffset);
return TRUE;
}
}
log_error("drive", "Read failed");
return FALSE;
}
BOOL pd_WriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
*lpNumberOfBytesWritten = 0;
physical_disk_t* pd = (physical_disk_t*)ctx->m_HookData;
if (pd == NULL) {
log_error("drive", "write:ctx->m_HookData NULL; expected a physical drive!");
return FALSE;
}
log_misc("drive", "PhysicalDrive%d: Write %d @ %llx", pd->m_DriveNumber, nNumberOfBytesToWrite,
ctx->m_Pointer.QuadPart);
// for (DWORD i = 0; i < nNumberOfBytesToWrite; i += 32) {
// for (int j = 0; j < 32; j++) {
// printf("%02x ", ((BYTE*)lpBuffer)[i + j]);
// }
// puts("");
// }
// *lpNumberOfBytesWritten = nNumberOfBytesToWrite;
// return TRUE;
// ! WARNING: This WriteFile implementation is currently limited to aligned
// ! reads. Given the main purpose of this function is to allow reading
// ! the partition information, this doesn't currently pose an issue.
DWORD ptrLBA = (ctx->m_Pointer.QuadPart / (long long)pd->m_BlockSize) & 0xffffffff;
// Writes to the MBR header or slack are blocked
if (ptrLBA <= MBR_LBA_GAP) {
log_error("drive", "Write rejected");
return FALSE;
}
// MBR partitions
for (size_t i = 0; i < 4; i++) {
if (pd->m_Partitions[i].m_PartitionNumber == 0) break;
if (ptrLBA >= pd->m_Partitions[i].m_PhysicalLBA &&
ptrLBA < pd->m_Partitions[i].m_PhysicalLBA + pd->m_Partitions[i].m_Size) {
DWORD writeOffset = ptrLBA - pd->m_Partitions[i].m_PhysicalLBA;
if (pd->m_Partitions[i].m_WriteFunc == NULL) {
log_error("disk",
"Attempted write in %d/%d at block offset %08x; No write function",
pd->m_DriveNumber, pd->m_Partitions[i].m_PartitionNumber, writeOffset);
return FALSE;
}
BOOL ret = pd->m_Partitions[i].m_WriteFunc(writeOffset, lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten);
if (!ret) {
log_error("disk", "Attempted write in %d/%d at block offset %08x; Write rejected",
pd->m_DriveNumber, pd->m_Partitions[i].m_PartitionNumber, writeOffset);
return FALSE;
}
log_misc("drive", "Write at %d/%d+%d", pd->m_DriveNumber,
pd->m_Partitions[i].m_PartitionNumber, writeOffset);
return TRUE;
}
}
// Extended partitions
for (size_t i = 0; pd->m_Extended[i].m_Size; i++) {
// Extended header
DWORD headerLBA = pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP;
if (ptrLBA == headerLBA) {
log_error("drive", "Write to extended header rejected");
return FALSE;
}
if (i == 0 && pd->m_HasSegaboot) {
// SEGA Partition Description
if (ptrLBA == headerLBA + SPD_OFFSET) {
if (nNumberOfBytesToWrite < sizeof(spd_t)) {
log_error("drive", "Buffer too small for SPD!");
return FALSE;
}
HANDLE hFile = _CreateFileA(SPD_PATH, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_error("drive", "Failed to open %s", SPD_PATH);
return FALSE;
}
BOOL ret = _WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten, lpOverlapped);
_CloseHandle(hFile);
return ret;
}
// SEGA Boot Records
if (ptrLBA == headerLBA + SBR0_OFFSET) {
if (nNumberOfBytesToWrite < sizeof(sbr_t)) {
log_error("drive", "Buffer too small for SBR!");
return FALSE;
}
HANDLE hFile = _CreateFileA(SBR0_PATH, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_error("drive", "Failed to open %s", SBR0_PATH);
return FALSE;
}
BOOL ret = _WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten, lpOverlapped);
_CloseHandle(hFile);
return ret;
}
if (ptrLBA == headerLBA + SBR1_OFFSET) {
if (nNumberOfBytesToWrite < sizeof(sbr_t)) {
log_error("drive", "Buffer too small for SBR!");
return FALSE;
}
HANDLE hFile = _CreateFileA(SBR1_PATH, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
OPEN_ALWAYS, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_error("drive", "Failed to open %s", SBR1_PATH);
return FALSE;
}
BOOL ret = _WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten, lpOverlapped);
_CloseHandle(hFile);
return ret;
}
}
if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA - EXT_HEADER_GAP &&
ptrLBA < pd->m_Extended[i].m_PhysicalLBA) {
// Write within the 63 extra tracks
log_error("drive", "Write failed");
return FALSE;
}
if (ptrLBA >= pd->m_Extended[i].m_PhysicalLBA &&
ptrLBA < pd->m_Extended[i].m_PhysicalLBA + pd->m_Extended[i].m_Size) {
DWORD writeOffset = ptrLBA - pd->m_Extended[i].m_PhysicalLBA;
if (pd->m_Extended[i].m_WriteFunc == NULL) {
log_error("disk",
"Attempted write in %d/%d at block offset %08x; No write function",
pd->m_DriveNumber, pd->m_Extended[i].m_PartitionNumber, writeOffset);
return FALSE;
}
BOOL ret = pd->m_Extended[i].m_WriteFunc(writeOffset, lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten);
if (!ret) {
log_error("disk", "Attempted write in %d/%d at block offset %08x; Write rejected",
pd->m_DriveNumber, pd->m_Extended[i].m_PartitionNumber, writeOffset);
return FALSE;
}
log_misc("drive", "Write at %d/%d+%d", pd->m_DriveNumber,
pd->m_Extended[i].m_PartitionNumber, writeOffset);
return TRUE;
}
}
}

View File

@ -1,125 +1,104 @@
#pragma once
#include "../common.h"
void hook_drives();
// MBR
#define MBR_FLAG_NONE 0x00
#define MBR_FLAG_BOOTABLE 0x80
#define MBR_FS_NONE 0x00
#define MBR_FS_EXT_CHS 0x05
#define MBR_FS_FAT16 0x06
#define MBR_FS_NTFS 0x07
#define MBR_FS_EXT_LBA 0x0F
#pragma pack(push, 1)
typedef struct mbr {
BYTE bootstrap_code[446];
struct {
BYTE status;
BYTE start_chs[3];
BYTE type;
BYTE end_chs[3];
DWORD lba;
DWORD sectors;
} partitions[4];
BYTE sig[2];
} mbr_t;
// SEGA
#define SPD_VERSION 1
#define SBR_VERSION 1
// Sega Partition Descriptor
enum spd_slot {
SPD_Original0 = 0x10,
SPD_Original1 = 0x11,
SPD_Patch0 = 0x20,
SPD_Patch1 = 0x21,
SPD_OS = 0x30,
SPD_AppData = 0x40,
};
typedef uint8_t spd_slot_t;
typedef struct spd {
uint32_t crc;
uint8_t version;
uint8_t _[11];
struct {
/*
(BCD)
1.0 = original0
1.1 = original1
2.0 = patch0
2.1 = patch1
3.0 = os
4.0 = app_data
*/
spd_slot_t slot_content;
/*
Guess: Filesystem type
0: Encrypted FAT16
1: Decrypted NTFS
*/
uint8_t uk1;
uint16_t block_size;
uint32_t block_count;
uint8_t __[8];
} slots[31];
} spd_t;
// Sega Boot Record
typedef struct {
uint16_t year;
uint8_t mon;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint8_t _;
} slot_time_t;
typedef struct {
char id[4];
slot_time_t time;
uint32_t version;
uint32_t _[2];
uint32_t segcount;
uint32_t segsize;
char hw[3];
uint8_t instant;
slot_time_t orgtime;
uint32_t orgversion;
uint32_t osver;
uint32_t ossegcount;
uint8_t __[8];
} sbr_slot_t;
enum {
Slot_Check = 0x00, // status=error
Slot_Install = 0x01, // status=install -> FAILED TO READ PREMADE BLOCK!!
Slot_Complete = 0x02, // status=complete
Slot_Empty = 0x03, // status=error
Slot_Error = 0x04, // status=error
Slot_Invalid = 0xff,
};
typedef uint8_t slot_status_t;
typedef struct {
uint32_t crc;
uint8_t version;
uint8_t _[11 + 16 + 32];
uint8_t bootslot;
uint8_t __[2];
slot_status_t slot_status[5];
uint8_t ___[8 + 16 + 32 + 64];
sbr_slot_t slot_os;
sbr_slot_t slot_original0;
sbr_slot_t slot_appdata;
sbr_slot_t slot_patch0;
sbr_slot_t slot_patch1;
} sbr_t;
#pragma pack(pop)
#pragma once
#include <stdint.h>
#define SPD_VERSION 1
#define SBR_VERSION 1
// Block count offsets from the extended partition header
#define SPD_OFFSET 1
#define SBR0_OFFSET 2
#define SBR1_OFFSET 3
// Sega Partition Descriptor
#pragma pack(push, 1)
enum spd_slot {
SPD_Original0 = 0x10,
SPD_Original1 = 0x11,
SPD_Patch0 = 0x20,
SPD_Patch1 = 0x21,
SPD_OS = 0x30,
SPD_AppData = 0x40,
};
typedef uint8_t spd_slot_t;
typedef struct spd {
uint32_t crc;
uint8_t version;
uint8_t _[11];
struct {
/*
(BCD)
1.0 = original0
1.1 = original1
2.0 = patch0
2.1 = patch1
3.0 = os
4.0 = app_data
*/
spd_slot_t slot_content;
/*
Guess: Filesystem type
0: Encrypted FAT16
1: Decrypted NTFS
*/
uint8_t uk1;
uint16_t block_size;
uint32_t block_count;
uint8_t __[8];
} slots[31];
} spd_t;
// Sega Boot Record
typedef struct {
uint16_t year;
uint8_t mon;
uint8_t day;
uint8_t hour;
uint8_t min;
uint8_t sec;
uint8_t _;
} slot_time_t;
typedef struct {
char id[4];
slot_time_t time;
uint32_t version;
uint32_t _[2];
uint32_t segcount;
uint32_t segsize;
char hw[3];
uint8_t instant;
slot_time_t orgtime;
uint32_t orgversion;
uint32_t osver;
uint32_t ossegcount;
uint8_t __[8];
} sbr_slot_t;
enum {
Slot_Check = 0x00, // status=error
Slot_Install = 0x01, // status=install -> FAILED TO READ PREMADE BLOCK!!
Slot_Complete = 0x02, // status=complete
Slot_Empty = 0x03, // status=error
Slot_Error = 0x04, // status=error
Slot_Invalid = 0xff,
};
typedef uint8_t slot_status_t;
typedef struct {
uint32_t crc;
uint8_t version;
uint8_t _[11 + 16 + 32];
uint8_t bootslot;
uint8_t __[2];
slot_status_t slot_status[5];
uint8_t ___[8 + 16 + 32 + 64];
sbr_slot_t slot_os;
sbr_slot_t slot_original0;
sbr_slot_t slot_appdata;
sbr_slot_t slot_patch0;
sbr_slot_t slot_patch1;
} sbr_t;
#pragma pack(pop)

View File

@ -0,0 +1,133 @@
#include "framework.h"
#include <stdlib.h>
typedef struct _LIST {
UINT Num;
UINT MaxNum;
PVOID *Entries;
} LIST, *PLIST;
typedef struct {
PDRIVER_OBJECT DriverObject;
ULONG DeviceExtensionSize;
PUNICODE_STRING DeviceName;
ULONG DeviceType;
ULONG DeviceCharacteristics;
BOOLEAN Exclusive;
PDEVICE_OBJECT *DeviceObject;
} DRIVER, *PDRIVER;
static LIST DriversList;
typedef struct {
UNICODE_STRING SymbolicLinkName;
UNICODE_STRING DeviceName;
} SYMBOLIC_LINK, *PSYMBOLIC_LINK;
static LIST SymbolicLinkList;
PVOID MT_ListAppend(PLIST List, UINT Size) {
if (List->Num == List->MaxNum) {
UINT newMaxNum = (List->MaxNum + 1) * 2;
PVOID newEntries = malloc(newMaxNum * sizeof List->Entries[0]);
memcpy(newEntries, List->Entries, List->Num * sizeof List->Entries[0]);
List->Entries = newEntries;
List->MaxNum = newMaxNum;
}
PVOID entry = malloc(Size);
return (List->Entries[List->Num++] = entry);
}
VOID MT_ListRemove(PLIST List, UINT Index) {
if (Index >= List->Num || List->Num == 0) return;
free(List->Entries[Index]);
for (UINT i = Index; i < List->Num - 1; i++) {
List->Entries[i] = List->Entries[i + 1];
}
List->Num--;
}
NTSTATUS MT_IoCreateDevice(PDRIVER_OBJECT DriverObject, ULONG DeviceExtensionSize,
PUNICODE_STRING DeviceName, ULONG DeviceType,
ULONG DeviceCharacteristics, BOOLEAN Exclusive,
PDEVICE_OBJECT *DeviceObject) {
PDRIVER Driver = MT_ListAppend(&DriversList, sizeof *Driver);
Driver->DriverObject = DriverObject;
Driver->DeviceExtensionSize = DeviceExtensionSize;
Driver->DeviceName = DeviceName;
Driver->DeviceType = DeviceType;
Driver->DeviceCharacteristics = DeviceCharacteristics;
Driver->Exclusive = Exclusive;
Driver->DeviceObject = DeviceObject;
return STATUS_SUCCESS;
}
NTSTATUS MT_RtlInitUnicodeStringEx(PUNICODE_STRING DestinationString, PCWSTR SourceString) {
if (SourceString) {
USHORT length = wcslen(SourceString) & 0xffff;
DestinationString->Length = length;
DestinationString->MaximumLength = length + 1;
DestinationString->Buffer = malloc(length + 1);
memcpy(DestinationString->Buffer, SourceString, length);
DestinationString->Buffer[length] = L'\0';
return STATUS_SUCCESS;
}
DestinationString->Buffer = NULL;
DestinationString->Length = 0;
DestinationString->MaximumLength = 0;
return STATUS_SUCCESS;
}
void MT_RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString) {
MT_RtlInitUnicodeStringEx(DestinationString, SourceString);
}
void MT_RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString) {
if (DestinationString->Buffer) {
if (DestinationString->MaximumLength < SourceString->Length + 1) {
realloc(DestinationString->Buffer, SourceString->MaximumLength);
DestinationString->MaximumLength = SourceString->MaximumLength;
}
} else {
DestinationString->Buffer = malloc(SourceString->MaximumLength);
DestinationString->MaximumLength = SourceString->MaximumLength;
}
DestinationString->Length = SourceString->Length;
memcpy(DestinationString->Buffer, SourceString->Buffer, SourceString->Length + 1);
}
LONG RtlCompareUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2,
BOOLEAN CaseInSensitive) {
if (CaseInSensitive) return _wcsicmp(String1->Buffer, String2->Buffer);
return wcscmp(String1->Buffer, String2->Buffer);
}
PIO_STACK_LOCATION MT_IoGetCurrentIrpStackLocation(PIRP Irp) {
return Irp->Tail.Overlay.CurrentStackLocation;
}
NTSTATUS MT_IoCreateSymbolicLink(PUNICODE_STRING SymbolicLinkName, PUNICODE_STRING DeviceName) {
PSYMBOLIC_LINK SymbolicLink = MT_ListAppend(&SymbolicLinkList, sizeof *SymbolicLink);
MT_RtlCopyUnicodeString(&SymbolicLink->DeviceName, DeviceName);
MT_RtlCopyUnicodeString(&SymbolicLink->SymbolicLinkName, SymbolicLinkName);
return STATUS_SUCCESS;
}
NTSTATUS MT_IoDeleteSymbolicLink(PUNICODE_STRING SymbolicLinkName) {
for (UINT i = 0; i < SymbolicLinkList.Num; i++) {
if (RtlCompareUnicodeString(
SymbolicLinkName, &((PSYMBOLIC_LINK)SymbolicLinkList.Entries[i])->SymbolicLinkName,
TRUE) == 0) {
MT_ListRemove(&SymbolicLinkList, i--);
}
}
return STATUS_SUCCESS;
}
NTSTATUS MT_IoDeleteDevice(PDEVICE_OBJECT DeviceObject) {
for (UINT i = 0; i < DriversList.Num; i++) {
if (*((PDRIVER)DriversList.Entries[i])->DeviceObject == DeviceObject) {
MT_ListRemove(&DriversList, i--);
}
}
return STATUS_SUCCESS;
}
void MT_IofCompleteRequest(PIRP Irp, CCHAR PriorityBoost) {
// TODO: This
}

View File

@ -0,0 +1,483 @@
#include <Windows.h>
typedef short CSHORT;
typedef struct {
USHORT Length;
USHORT MaximumLength;
PWCH Buffer;
} UNICODE_STRING, *PUNICODE_STRING;
#ifdef NTSTATUS
#undef NTSTATUS
#endif
#define NTSTATUS LONG
#define EVENT_INCREMENT 1
#define EVENT_PAIR_INCREMENT 1
#define LPC_RELEASE_WAIT_INCREMENT 1
#define IO_NO_INCREMENT 0
#define IO_CD_ROM_INCREMENT 1
#define IO_DISK_INCREMENT 1
#define IO_KEYBOARD_INCREMENT 6
#define IO_MAILSLOT_INCREMENT 2
#define IO_MOUSE_INCREMENT 6
#define IO_NAMED_PIPE_INCREMENT 2
#define IO_NETWORK_INCREMENT 2
#define IO_PARALLEL_INCREMENT 1
#define IO_SERIAL_INCREMENT 2
#define IO_SOUND_INCREMENT 8
#define IO_VIDEO_INCREMENT 1
#define MUTANT_INCREMENT 1
#define SEMAPHORE_INCREMENT 1
#define TIMER_APC_INCREMENT 0
#define ERESOURCE_INCREMENT 4
// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-erref/596a1078-e883-4972-9bbc-49e60bebca55
#define STATUS_SUCCESS 0
#define STATUS_INVALID_DEVICE_REQUEST 0xC0000010
#define STATUS_NOT_SUPPORTED 0xC00000BB
#define IRP_MJ_CREATE 0
#define IRP_MJ_CREATE_NAMED_PIPE 1
#define IRP_MJ_CLOSE 2
#define IRP_MJ_READ 3
#define IRP_MJ_WRITE 4
#define IRP_MJ_QUERY_INFORMATION 5
#define IRP_MJ_SET_INFORMATION 6
#define IRP_MJ_QUERY_EA 7
#define IRP_MJ_SET_EA 8
#define IRP_MJ_FLUSH_BUFFERS 9
#define IRP_MJ_QUERY_VOLUME_INFORMATION 10
#define IRP_MJ_SET_VOLUME_INFORMATION 11
#define IRP_MJ_DIRECTORY_CONTROL 12
#define IRP_MJ_FILE_SYSTEM_CONTROL 13
#define IRP_MJ_DEVICE_CONTROL 14
#define IRP_MJ_INTERNAL_DEVICE_CONTROL 15
#define IRP_MJ_SHUTDOWN 16
#define IRP_MJ_LOCK_CONTROL 17
#define IRP_MJ_CLEANUP 18
#define IRP_MJ_CREATE_MAILSLOT 19
#define IRP_MJ_QUERY_SECURITY 20
#define IRP_MJ_SET_SECURITY 21
#define IRP_MJ_POWER 22
#define IRP_MJ_SYSTEM_CONTROL 23
#define IRP_MJ_DEVICE_CHANGE 24
#define IRP_MJ_QUERY_QUOTA 25
#define IRP_MJ_SET_QUOTA 26
#define IRP_MJ_PNP 27
#define IRP_MJ_MAXIMUM_FUNCTION 27
typedef struct _DEVICE_OBJECT DEVICE_OBJECT, *PDEVICE_OBJECT;
typedef struct _DRIVER_OBJECT DRIVER_OBJECT, *PDRIVER_OBJECT;
typedef struct _IRP IRP, *PIRP;
typedef struct _IO_STACK_LOCATION IO_STACK_LOCATION, *PIO_STACK_LOCATION;
typedef struct _FILE_OBJECT FILE_OBJECT, *PFILE_OBJECT;
typedef struct _IO_STATUS_BLOCK IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef struct _KDEVICE_QUEUE_ENTRY KDEVICE_QUEUE_ENTRY, *PKDEVICE_QUEUE_ENTRY;
typedef NTSTATUS(__stdcall *PDRIVER_DISPATCH)(PDEVICE_OBJECT DeviceObject, PIRP Irp);
typedef void(__stdcall *PDRIVER_UNLOAD)(PDRIVER_OBJECT DriverObject);
typedef NTSTATUS(__stdcall *PDRIVER_ADD_DEVICE)(PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT PhysicalDeviceObject);
struct _KDEVICE_QUEUE_ENTRY {
LIST_ENTRY DeviceListEntry;
ULONG SortKey;
UCHAR Inserted;
};
typedef PVOID PETHREAD; // TODO: This
struct _FILE_OBJECT {
SHORT Type;
SHORT Size;
PDEVICE_OBJECT DeviceObject;
// PVPB Vpb;
PVOID FsContext;
PVOID FsContext2;
// PSECTION_OBJECT_POINTERS SectionObjectPointer;
PVOID PrivateCacheMap;
LONG FinalStatus;
PFILE_OBJECT RelatedFileObject;
UCHAR LockOperation;
UCHAR DeletePending;
UCHAR ReadAccess;
UCHAR WriteAccess;
UCHAR DeleteAccess;
UCHAR SharedRead;
UCHAR SharedWrite;
UCHAR SharedDelete;
ULONG Flags;
UNICODE_STRING FileName;
LARGE_INTEGER CurrentByteOffset;
ULONG Waiters;
ULONG Busy;
PVOID LastLock;
// KEVENT Lock;
// KEVENT Event;
// PIO_COMPLETION_CONTEXT CompletionContext;
ULONG IrpListLock;
LIST_ENTRY IrpList;
PVOID FileObjectExtension;
};
struct _DEVICE_OBJECT {
CSHORT Type;
USHORT Size;
LONG ReferenceCount;
struct _DRIVER_OBJECT *DriverObject;
struct _DEVICE_OBJECT *NextDevice;
struct _DEVICE_OBJECT *AttachedDevice;
struct _IRP *CurrentIrp;
// PIO_TIMER Timer;
ULONG Flags;
ULONG Characteristics;
// __volatile PVPB Vpb;
PVOID DeviceExtension;
// DEVICE_TYPE DeviceType;
CCHAR StackSize;
// union {
// LIST_ENTRY ListEntry;
// WAIT_CONTEXT_BLOCK Wcb;
// } Queue;
ULONG AlignmentRequirement;
// KDEVICE_QUEUE DeviceQueue;
// KDPC Dpc;
ULONG ActiveThreadCount;
PSECURITY_DESCRIPTOR SecurityDescriptor;
// KEVENT DeviceLock;
USHORT SectorSize;
USHORT Spare1;
struct _DEVOBJ_EXTENSION *DeviceObjectExtension;
PVOID Reserved;
};
struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
};
struct _IO_STACK_LOCATION {
UCHAR MajorFunction;
UCHAR MinorFunction;
UCHAR Flags;
UCHAR Control;
union {
// struct {
// PIO_SECURITY_CONTEXT SecurityContext;
// ULONG Options;
// USHORT FileAttributes;
// USHORT ShareAccess;
// ULONG EaLength;
// } Create;
// struct {
// PIO_SECURITY_CONTEXT SecurityContext;
// ULONG Options;
// USHORT Reserved;
// USHORT ShareAccess;
// PNAMED_PIPE_CREATE_PARAMETERS Parameters;
// } CreatePipe;
// struct {
// PIO_SECURITY_CONTEXT SecurityContext;
// ULONG Options;
// USHORT Reserved;
// USHORT ShareAccess;
// PMAILSLOT_CREATE_PARAMETERS Parameters;
// } CreateMailslot;
// struct {
// ULONG Length;
// ULONG Key;
// ULONG Flags;
// LARGE_INTEGER ByteOffset;
// } Read;
// struct {
// ULONG Length;
// ULONG Key;
// ULONG Flags;
// LARGE_INTEGER ByteOffset;
// } Write;
// struct {
// ULONG Length;
// PUNICODE_STRING FileName;
// FILE_INFORMATION_CLASS FileInformationClass;
// ULONG FileIndex;
// } QueryDirectory;
// struct {
// ULONG Length;
// ULONG CompletionFilter;
// } NotifyDirectory;
// struct {
// ULONG Length;
// ULONG CompletionFilter;
// DIRECTORY_NOTIFY_INFORMATION_CLASS DirectoryNotifyInformationClass;
// } NotifyDirectoryEx;
// struct {
// ULONG Length;
// FILE_INFORMATION_CLASS FileInformationClass;
// } QueryFile;
// struct {
// ULONG Length;
// FILE_INFORMATION_CLASS FileInformationClass;
// PFILE_OBJECT FileObject;
// union {
// struct {
// BOOLEAN ReplaceIfExists;
// BOOLEAN AdvanceOnly;
// };
// ULONG ClusterCount;
// HANDLE DeleteHandle;
// };
// } SetFile;
// struct {
// ULONG Length;
// PVOID EaList;
// ULONG EaListLength;
// ULONG EaIndex;
// } QueryEa;
// struct {
// ULONG Length;
// } SetEa;
// struct {
// ULONG Length;
// FS_INFORMATION_CLASS FsInformationClass;
// } QueryVolume;
// struct {
// ULONG Length;
// FS_INFORMATION_CLASS FsInformationClass;
// } SetVolume;
// struct {
// ULONG OutputBufferLength;
// ULONG InputBufferLength;
// ULONG FsControlCode;
// PVOID Type3InputBuffer;
// } FileSystemControl;
// struct {
// PLARGE_INTEGER Length;
// ULONG Key;
// LARGE_INTEGER ByteOffset;
// } LockControl;
struct {
ULONG OutputBufferLength;
ULONG InputBufferLength;
ULONG IoControlCode;
PVOID Type3InputBuffer;
} DeviceIoControl;
// struct {
// SECURITY_INFORMATION SecurityInformation;
// ULONG Length;
// } QuerySecurity;
// struct {
// SECURITY_INFORMATION SecurityInformation;
// PSECURITY_DESCRIPTOR SecurityDescriptor;
// } SetSecurity;
// struct {
// PVPB Vpb;
// PDEVICE_OBJECT DeviceObject;
// } MountVolume;
// struct {
// PVPB Vpb;
// PDEVICE_OBJECT DeviceObject;
// } VerifyVolume;
// struct {
// struct _SCSI_REQUEST_BLOCK *Srb;
// } Scsi;
// struct {
// ULONG Length;
// PSID StartSid;
// PFILE_GET_QUOTA_INFORMATION SidList;
// ULONG SidListLength;
// } QueryQuota;
// struct {
// ULONG Length;
// } SetQuota;
// struct {
// DEVICE_RELATION_TYPE Type;
// } QueryDeviceRelations;
// struct {
// const GUID *InterfaceType;
// USHORT Size;
// USHORT Version;
// PINTERFACE Interface;
// PVOID InterfaceSpecificData;
// } QueryInterface;
// struct {
// PDEVICE_CAPABILITIES Capabilities;
// } DeviceCapabilities;
// struct {
// PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList;
// } FilterResourceRequirements;
// struct {
// ULONG WhichSpace;
// PVOID Buffer;
// ULONG Offset;
// ULONG Length;
// } ReadWriteConfig;
// struct {
// BOOLEAN Lock;
// } SetLock;
// struct {
// BUS_QUERY_ID_TYPE IdType;
// } QueryId;
// struct {
// DEVICE_TEXT_TYPE DeviceTextType;
// LCID LocaleId;
// } QueryDeviceText;
// struct {
// BOOLEAN InPath;
// BOOLEAN Reserved[3];
// DEVICE_USAGE_NOTIFICATION_TYPE Type;
// } UsageNotification;
// struct {
// SYSTEM_POWER_STATE PowerState;
// } WaitWake;
// struct {
// PPOWER_SEQUENCE PowerSequence;
// } PowerSequence;
// #if...
// struct {
// union {
// ULONG SystemContext;
// SYSTEM_POWER_STATE_CONTEXT SystemPowerStateContext;
// };
// POWER_STATE_TYPE Type;
// POWER_STATE State;
// POWER_ACTION ShutdownType;
// } Power;
// #else
// struct {
// ULONG SystemContext;
// POWER_STATE_TYPE Type;
// POWER_STATE State;
// POWER_ACTION ShutdownType;
// } Power;
// #endif
// struct {
// PCM_RESOURCE_LIST AllocatedResources;
// PCM_RESOURCE_LIST AllocatedResourcesTranslated;
// } StartDevice;
// struct {
// ULONG_PTR ProviderId;
// PVOID DataPath;
// ULONG BufferSize;
// PVOID Buffer;
// } WMI;
// struct {
// PVOID Argument1;
// PVOID Argument2;
// PVOID Argument3;
// PVOID Argument4;
// } Others;
} Parameters;
PDEVICE_OBJECT DeviceObject;
// PFILE_OBJECT FileObject;
// PIO_COMPLETION_ROUTINE CompletionRoutine;
PVOID Context;
};
struct _IRP {
// CSHORT Type;
// USHORT Size;
// PMDL MdlAddress;
// ULONG Flags;
// union {
// struct _IRP *MasterIrp;
// __volatile LONG IrpCount;
// PVOID SystemBuffer;
// } AssociatedIrp;
// LIST_ENTRY ThreadListEntry;
IO_STATUS_BLOCK IoStatus;
// KPROCESSOR_MODE RequestorMode;
// BOOLEAN PendingReturned;
// CHAR StackCount;
// CHAR CurrentLocation;
// BOOLEAN Cancel;
// KIRQL CancelIrql;
// CCHAR ApcEnvironment;
// UCHAR AllocationFlags;
// union {
// PIO_STATUS_BLOCK UserIosb;
// PVOID IoRingContext;
// };
// PKEVENT UserEvent;
// union {
// struct {
// union {
// PIO_APC_ROUTINE UserApcRoutine;
// PVOID IssuingProcess;
// };
// union {
// PVOID UserApcContext;
// // #if...
// // _IORING_OBJECT *IoRing;
// // #else
// struct _IORING_OBJECT *IoRing;
// // #endif
// };
// } AsynchronousParameters;
// LARGE_INTEGER AllocationSize;
// } Overlay;
// __volatile PDRIVER_CANCEL CancelRoutine;
PVOID UserBuffer;
union {
struct {
union {
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
struct {
PVOID DriverContext[4];
};
};
PETHREAD Thread;
PCHAR AuxiliaryBuffer;
struct {
LIST_ENTRY ListEntry;
union {
struct _IO_STACK_LOCATION *CurrentStackLocation;
ULONG PacketType;
};
};
PFILE_OBJECT OriginalFileObject;
} Overlay;
// KAPC Apc;
PVOID CompletionKey;
} Tail;
};
struct _DRIVER_OBJECT {
CSHORT Type;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
// ULONG Flags;
// PVOID DriverStart;
// ULONG DriverSize;
// PVOID DriverSection;
// PDRIVER_EXTENSION DriverExtension;
// UNICODE_STRING DriverName;
// PUNICODE_STRING HardwareDatabase;
// PFAST_IO_DISPATCH FastIoDispatch;
// PDRIVER_INITIALIZE DriverInit;
// PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
};
NTSTATUS MT_IoCreateDevice(PDRIVER_OBJECT DriverObject, ULONG DeviceExtensionSize,
PUNICODE_STRING DeviceName, ULONG DeviceType,
ULONG DeviceCharacteristics, BOOLEAN Exclusive,
PDEVICE_OBJECT *DeviceObject);
NTSTATUS MT_IoDeleteDevice(PDEVICE_OBJECT DeviceObject);
NTSTATUS MT_RtlInitUnicodeStringEx(PUNICODE_STRING DestinationString, PCWSTR SourceString);
void MT_RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString);
void MT_RtlCopyUnicodeString(PUNICODE_STRING DestinationString, PUNICODE_STRING SourceString);
LONG RtlCompareUnicodeString(PUNICODE_STRING String1, PUNICODE_STRING String2,
BOOLEAN CaseInSensitive);
NTSTATUS MT_IoCreateSymbolicLink(PUNICODE_STRING SymbolicLinkName, PUNICODE_STRING DeviceName);
NTSTATUS MT_IoDeleteSymbolicLink(PUNICODE_STRING SymbolicLinkName);
void MT_IofCompleteRequest(PIRP Irp, CCHAR PriorityBoost);
PIO_STACK_LOCATION MT_IoGetCurrentIrpStackLocation(PIRP Irp);

View File

@ -0,0 +1,59 @@
#include "../../../lib/mice/ioctl.h"
#include "framework.h"
#define NTDEVICE_NAME_STRING L"\\Device\\mxhwreset"
#define SYMBOLIC_NAME_STRING L"\\DosDevices\\mxhwreset"
static NTSTATUS IrpComplete(PIRP Irp, NTSTATUS Status, PVOID Information) {
(Irp->IoStatus).Status = Status;
(Irp->IoStatus).Information = (ULONG_PTR)Information;
MT_IofCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
static NTSTATUS __stdcall EventNotSupported(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
return IrpComplete(Irp, STATUS_NOT_SUPPORTED, NULL);
}
static NTSTATUS __stdcall EventCreateClose(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
return IrpComplete(Irp, STATUS_SUCCESS, NULL);
}
static NTSTATUS __stdcall EventDispatchIoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
IrpComplete(Irp, STATUS_NOT_SUPPORTED, NULL);
PIO_STACK_LOCATION irpStack = MT_IoGetCurrentIrpStackLocation(Irp);
if (irpStack->Parameters.DeviceIoControl.IoControlCode != IOCTL_MXHWRESET_RESET) {
return IrpComplete(Irp, STATUS_INVALID_DEVICE_REQUEST, NULL);
}
return IrpComplete(Irp, STATUS_SUCCESS, NULL);
}
static void __stdcall EventUnload(PDRIVER_OBJECT DriverObject) {
UNICODE_STRING dosDevice;
MT_RtlInitUnicodeString(&dosDevice, SYMBOLIC_NAME_STRING);
MT_IoDeleteSymbolicLink(&dosDevice);
MT_IoDeleteDevice(DriverObject->DeviceObject);
}
NTSTATUS entry_mxHwReset(PDRIVER_OBJECT driver) {
UNICODE_STRING deviceName;
UNICODE_STRING dosDeviceName;
PDEVICE_OBJECT device = NULL;
MT_RtlInitUnicodeString(&deviceName, NTDEVICE_NAME_STRING);
MT_RtlInitUnicodeString(&dosDeviceName, SYMBOLIC_NAME_STRING);
NTSTATUS ret = MT_IoCreateDevice(driver, 0, &deviceName, 34, 0, '\0', &device);
if (ret != STATUS_SUCCESS) return ret;
for (int i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) {
driver->MajorFunction[i] = &EventNotSupported;
}
driver->MajorFunction[IRP_MJ_CREATE] = EventCreateClose;
driver->MajorFunction[IRP_MJ_CLOSE] = EventCreateClose;
driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = EventDispatchIoControl;
driver->DriverUnload = EventUnload;
MT_IoCreateSymbolicLink(&dosDeviceName, &deviceName);
return STATUS_SUCCESS;
}

View File

@ -37,9 +37,69 @@ void hook_file(file_hook_t* hook) {
hl->next = hook;
};
struct buffer_file {
LPBYTE buffer;
DWORD nBytes;
DWORD access;
};
BOOL bf_ReadFile(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped) {
struct buffer_file* pBF = (struct buffer_file*)ctx->m_HookData;
if (!(pBF->access & GENERIC_READ)) {
SetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
if (ctx->m_Pointer.QuadPart > pBF->nBytes) {
*lpNumberOfBytesRead = 0;
return TRUE;
}
if (ctx->m_Pointer.QuadPart + nNumberOfBytesToRead > pBF->nBytes) {
nNumberOfBytesToRead = (pBF->nBytes - ctx->m_Pointer.QuadPart) & 0xffffffff;
}
*lpNumberOfBytesRead = nNumberOfBytesToRead;
memcpy(lpBuffer, pBF->buffer + ctx->m_Pointer.QuadPart, nNumberOfBytesToRead);
return TRUE;
}
BOOL bf_WriteFile(file_context_t* ctx, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped) {
struct buffer_file* pBF = (struct buffer_file*)ctx->m_HookData;
if (!(pBF->access & GENERIC_WRITE)) {
SetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
if (ctx->m_Pointer.QuadPart > pBF->nBytes) {
*lpNumberOfBytesWritten = 0;
return TRUE;
}
if (ctx->m_Pointer.QuadPart + nNumberOfBytesToWrite > pBF->nBytes) {
nNumberOfBytesToWrite = (pBF->nBytes - ctx->m_Pointer.QuadPart) & 0xffffffff;
}
*lpNumberOfBytesWritten = nNumberOfBytesToWrite;
memcpy(pBF->buffer + ctx->m_Pointer.QuadPart, lpBuffer, nNumberOfBytesToWrite);
return TRUE;
}
void hook_file_with_buffer(LPCWSTR filename, LPBYTE buffer, DWORD nBytes, DWORD access) {
file_hook_t* hook = new_file_hook(filename);
struct buffer_file** ppBF = &((struct buffer_file*)hook->hook_data);
*ppBF = malloc(sizeof **ppBF);
(*ppBF)->buffer = buffer;
(*ppBF)->nBytes = nBytes;
(*ppBF)->access = access;
hook->ReadFile = bf_ReadFile;
hook->WriteFile = bf_WriteFile;
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 = "E:\\", .path = "\\\\.\\E:" },
// {.drive = "C:\\ProgramData/boost_interprocess/", .path = "\\\\.\\ipc\\"},
};
@ -57,27 +117,6 @@ file_hook_t* find_hook(LPCWSTR lpFileName) {
return NULL;
};
void make_dirs(char* path) {
int count = 0;
size_t i;
size_t len = strlen(path);
while (1) {
int n = 0;
for (i = 0; i < len; i++) {
if (path[i] == '\\' || path[i] == '/' || path[i] == '\0') {
if (n++ == count) {
path[i] = '\0';
count++;
break;
}
path[i] = '\\';
}
}
if (i == len) return;
CreateDirectory(path, NULL);
}
}
char WORKING_DIR[MAX_PATH + 1] = { 0 };
char get_gamedata_drive() {
if (WORKING_DIR[0] == 0x00) {
@ -87,7 +126,7 @@ char get_gamedata_drive() {
}
inline char char_lower(char value) {
if ('A' <= value <= 'Z') return value - 'A' + 'a';
if ('A' <= value && value <= 'Z') return value - 'A' + 'a';
return value;
}
@ -114,13 +153,15 @@ BOOL redirect_path(LPCSTR path, LPCSTR* redirected) {
}
}
// Don't redirect local paths
GetCurrentDirectoryA(sizeof WORKING_DIR, WORKING_DIR);
if (strstr(path, WORKING_DIR) == path) {
puts("SKIP");
return FALSE;
}
if ((('a' <= path[0] && path[0] <= 'z') || ('A' <= path[0] && path[0] <= 'Z')) &&
path[1] == ':' && (path[2] == '/' || path[2] == '\\')) {
// TODO: Ca
if (char_lower(path[0]) == char_lower(get_gamedata_drive())) {
return FALSE;
}
ZeroMemory(_redirected_path, sizeof _redirected_path);
snprintf(_redirected_path, sizeof _redirected_path, "dev\\%c\\%s", char_lower(path[0]),
path + 3);
@ -188,10 +229,13 @@ HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw
}
BOOL WINAPI FakePathFileExistsA(LPCSTR pszPath) {
log_misc(HOOKS_LOGGER, "PathFileExists(%s)", pszPath);
redirect_path(pszPath, &pszPath);
return TruePathFileExistsA(pszPath);
BOOL ret = TruePathFileExistsA(pszPath);
return ret;
}
BOOL WINAPI FakePathFileExistsW(LPCWSTR pszPath) {
log_misc(HOOKS_LOGGER, "PathFileExists(%ls)", pszPath);
LPCSTR redirected;
if (redirect_path_w(pszPath, &redirected)) {
return TruePathFileExistsA(redirected);
@ -318,8 +362,10 @@ DWORD WINAPI FakeWriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesT
log_error(HOOKS_LOGGER, "WriteFile(%ls) unimplemented", file_hook->filename);
return FALSE;
}
return file_hook->WriteFile(&(pHData->ctx), lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten, lpOverlapped);
BOOL ret = file_hook->WriteFile(&(pHData->ctx), lpBuffer, nNumberOfBytesToWrite,
lpNumberOfBytesWritten, lpOverlapped);
if (ret) pHData->ctx.m_Pointer.QuadPart += *lpNumberOfBytesWritten;
return ret;
}
BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
@ -328,6 +374,7 @@ BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRe
return TrueReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
lpOverlapped);
}
// log_misc(HOOKS_LOGGER, "ReadFile(%d) %d", hFile, nNumberOfBytesToRead);
open_hook_t* pHData = GetDataForHandle(hFile, HDATA_FILE);
if (pHData == NULL) {
@ -341,8 +388,10 @@ BOOL WINAPI FakeReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRe
log_error(HOOKS_LOGGER, "ReadFile(%ls) unimplemented", file_hook->filename);
return FALSE;
}
return file_hook->ReadFile(&(pHData->ctx), lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead,
lpOverlapped);
BOOL ret = file_hook->ReadFile(&(pHData->ctx), lpBuffer, nNumberOfBytesToRead,
lpNumberOfBytesRead, lpOverlapped);
if (ret) pHData->ctx.m_Pointer.QuadPart += *lpNumberOfBytesRead;
return ret;
}
BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
@ -355,24 +404,48 @@ int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) {
return True_stat64i32(path, buffer);
};
void hook_io() {
hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl, 5);
DWORD WINAPI FakeGetFileAttributesA(LPCSTR lpFileName) {
// The game quits out if MiniDump is present!
if (strcmp(lpFileName, "Y:\\MiniDump\\") == 0) {
return 0;
}
hook("Kernel32.dll", "CreateFileA", FakeCreateFileA, (void**)&TrueCreateFileA, 6);
hook("Kernel32.dll", "CreateFileW", FakeCreateFileW, (void**)&TrueCreateFileW, 6);
hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle, 6);
hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer, 6);
hook("Kernel32.dll", "SetFilePointerEx", FakeSetFilePointerEx, (void**)&TrueSetFilePointerEx,
6);
hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile, 6);
hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile, 6);
hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx, 6);
hook("Shlwapi.dll", "PathFileExistsA", FakePathFileExistsA, (void**)&TruePathFileExistsA, 5);
hook("Shlwapi.dll", "PathFileExistsW", FakePathFileExistsW, (void**)&TruePathFileExistsW, 5);
hook("Kernel32.dll", "DeleteFileA", FakeDeleteFileA, (void**)&TrueDeleteFileA, 7);
hook("Kernel32.dll", "DeleteFileW", FakeDeleteFileW, (void**)&TrueDeleteFileW, 7);
hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32, 5);
LPCSTR redirected;
if (redirect_path(lpFileName, &redirected)) {
return TrueGetFileAttributesA(redirected);
}
return TrueGetFileAttributesA(lpFileName);
}
DWORD WINAPI FakeGetFileAttributesW(LPCWSTR lpFileName) {
LPCSTR redirected;
if (redirect_path_w(lpFileName, &redirected)) {
return TrueGetFileAttributesA(redirected);
}
return TrueGetFileAttributesW(lpFileName);
}
void hook_io() {
hook("Kernel32.dll", "DeviceIoControl", FakeDeviceIoControl, (void**)&TrueDeviceIoControl);
hook("Kernel32.dll", "CreateFileA", FakeCreateFileA, (void**)&TrueCreateFileA);
hook("Kernel32.dll", "CreateFileW", FakeCreateFileW, (void**)&TrueCreateFileW);
hook("Kernel32.dll", "CloseHandle", FakeCloseHandle, (void**)&TrueCloseHandle);
hook("Kernel32.dll", "SetFilePointer", FakeSetFilePointer, (void**)&TrueSetFilePointer);
hook("Kernel32.dll", "SetFilePointerEx", FakeSetFilePointerEx, (void**)&TrueSetFilePointerEx);
hook("Kernel32.dll", "WriteFile", FakeWriteFile, (void**)&TrueWriteFile);
hook("Kernel32.dll", "ReadFile", FakeReadFile, (void**)&TrueReadFile);
hook("Kernel32.dll", "GetFileSizeEx", FakeGetFileSizeEx, (void**)&TrueGetFileSizeEx);
hook("Shlwapi.dll", "PathFileExistsA", FakePathFileExistsA, (void**)&TruePathFileExistsA);
hook("Shlwapi.dll", "PathFileExistsW", FakePathFileExistsW, (void**)&TruePathFileExistsW);
hook("Kernel32.dll", "DeleteFileA", FakeDeleteFileA, (void**)&TrueDeleteFileA);
hook("Kernel32.dll", "DeleteFileW", FakeDeleteFileW, (void**)&TrueDeleteFileW);
hook("Kernel32.dll", "GetFileAttributesA", FakeGetFileAttributesA,
(void**)&TrueGetFileAttributesA);
hook("Kernel32.dll", "GetFileAttributesW", FakeGetFileAttributesW,
(void**)&TrueGetFileAttributesW);
hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32);
}

View File

@ -38,6 +38,8 @@ _MICE_FILES BOOL(WINAPI* TruePathFileExistsA)(LPCSTR pszPath);
_MICE_FILES BOOL(WINAPI* TruePathFileExistsW)(LPCWSTR pszPath);
_MICE_FILES BOOL(WINAPI* TrueDeleteFileA)(LPCSTR lpFileName);
_MICE_FILES BOOL(WINAPI* TrueDeleteFileW)(LPCWSTR lpFileName);
_MICE_FILES DWORD(WINAPI* TrueGetFileAttributesA)(LPCSTR lpFileName);
_MICE_FILES DWORD(WINAPI* TrueGetFileAttributesW)(LPCWSTR lpFileName);
typedef struct {
HANDLE m_Handle;
@ -70,6 +72,8 @@ static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer);
#define _CreateFileW (TrueCreateFileW ? TrueCreateFileW : CreateFileW)
#define _CreateFileA (TrueCreateFileA ? TrueCreateFileA : CreateFileA)
#define _SetFilePointer (TrueSetFilePointer ? TrueSetFilePointer : SetFilePointer)
#define _SetFilePointerEx (TrueSetFilePointerEx ? TrueSetFilePointerEx : SetFilePointerEx)
#define _PathFileExistsA (TruePathFileExistsA ? TruePathFileExistsA : PathFileExistsA)
typedef struct drive_redirect {
const CHAR* drive;
@ -108,3 +112,4 @@ extern file_hook_t* file_hook_list;
file_hook_t* new_file_hook(LPCWSTR filename);
void hook_file(file_hook_t* hook);
void hook_io();
void hook_file_with_buffer(LPCWSTR filename, LPBYTE buffer, DWORD nBytes, DWORD access);

View File

@ -2,6 +2,8 @@
extern LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
HWND mainWindow;
static HWND window;
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam) {
DWORD wndProcId;
@ -134,9 +136,11 @@ void post_win_create(HWND hWnd) {
// Don't double-hook!
if (TrueEndScene != NULL) return;
mainWindow = hWnd;
void* d3d9Device[119];
if (GetD3D9Device(d3d9Device, sizeof(d3d9Device))) {
*((PVOID*)&TrueEndScene) = CreateHook((PVOID)d3d9Device[42], (PVOID)hkEndScene, 7);
*((PVOID*)&TrueEndScene) = CreateHook32((PVOID)d3d9Device[42], (PVOID)hkEndScene);
}
if (hWnd && !SetWindowSubclass(hWnd, WndProc, (int)&WndProc, (DWORD_PTR)NULL)) {
@ -270,8 +274,8 @@ int WINAPI FakeGetSystemMetrics(int nIndex) {
}
void hook_gui() {
hook("User32.dll", "CreateWindowExA", FakeCreateWindowExA, (void**)&TrueCreateWindowExA, 7);
hook("User32.dll", "CreateWindowExW", FakeCreateWindowExW, (void**)&TrueCreateWindowExW, 7);
hook("User32.dll", "GetSystemMetrics", FakeGetSystemMetrics, (void**)&TrueGetSystemMetrics, 7);
hook("D3d9.dll", "Direct3DCreate9", FakeDirect3DCreate9, (void**)&TrueDirect3DCreate9, 5);
hook("User32.dll", "CreateWindowExA", FakeCreateWindowExA, (void**)&TrueCreateWindowExA);
hook("User32.dll", "CreateWindowExW", FakeCreateWindowExW, (void**)&TrueCreateWindowExW);
hook("User32.dll", "GetSystemMetrics", FakeGetSystemMetrics, (void**)&TrueGetSystemMetrics);
hook("D3d9.dll", "Direct3DCreate9", FakeDirect3DCreate9, (void**)&TrueDirect3DCreate9);
}

View File

@ -29,3 +29,5 @@ end_scene_hook_t* end_scene_hook_list;
void register_gui_hook(FnEndScene* end_scene);
void hook_gui();
void setup_hud_gui();
extern HWND mainWindow;

View File

@ -101,14 +101,14 @@ BOOL WINAPI FakeDeregisterEventSource(HANDLE hEventLog) { return TRUE; }
// lpOutputString); }
void hook_logging() {
hook("MSVCR90.DLL", "printf", Fakeprintf, (void**)&Trueprintf, 6);
hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf, 6);
hook("MSVCR90.DLL", "fprintf_s", Fakefprintf_s, (void**)&Truefprintf_s, 6);
hook("MSVCR90.DLL", "vfprintf_s", Fakevfprintf_s, (void**)&Truevfprintf_s, 6);
hook("MSVCR90.DLL", "printf", Fakeprintf, (void**)&Trueprintf);
hook("MSVCR90.DLL", "fprintf", Fakefprintf, (void**)&Truefprintf);
hook("MSVCR90.DLL", "fprintf_s", Fakefprintf_s, (void**)&Truefprintf_s);
hook("MSVCR90.DLL", "vfprintf_s", Fakevfprintf_s, (void**)&Truevfprintf_s);
hook("Advapi32.dll", "RegisterEventSourceA", FakeRegisterEventSourceA,
(void**)&TrueRegisterEventSourceA, 6);
hook("Advapi32.dll", "ReportEventA", FakeReportEventA, (void**)&TrueReportEventA, 6);
(void**)&TrueRegisterEventSourceA);
hook("Advapi32.dll", "ReportEventA", FakeReportEventA, (void**)&TrueReportEventA);
hook("Advapi32.dll", "DeregisterEventSource", FakeDeregisterEventSource,
(void**)&TrueDeregisterEventSource, 6);
(void**)&TrueDeregisterEventSource);
}

View File

@ -9,6 +9,13 @@ hooks_files = files(
'setupapi.c',
'time.c',
'registry.c',
'drive.c',
'system.c',
)
'drive/drive.c',
'drive/disks.c',
'drive/hooks.c',
'drive/physicalDrive.c',
'drivers/framework.c',
'drivers/mxhwreset.c',
)

View File

@ -4,14 +4,15 @@ int WINAPI Fake_connect(SOCKET s, const SOCKADDR* name, int namelen) {
ULONG addr = _byteswap_ulong(((SOCKADDR_IN*)name)->sin_addr.S_un.S_addr);
USHORT port = _byteswap_ushort(((SOCKADDR_IN*)name)->sin_port);
// Poorly exclude pcps. TODO: better
if (port < 40100 || port > 40120) {
log_info("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
(addr >> 8) & 0xff, addr & 0xff, port);
}
// if (port < 40100 || port > 40120) {
log_misc("connect", "%hhu.%hhu.%hhu.%hhu:%hu", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
(addr >> 8) & 0xff, addr & 0xff, port);
// }
return True_connect(s, name, namelen);
}
#define IF_INDEX 1
// Sega prefix
#define MAC_PREFIX_0 0xD8
#define MAC_PREFIX_1 0xBB
#define MAC_PREFIX_2 0xC1
@ -89,6 +90,8 @@ DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID
if (ppQueryResults) {
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(pszName, INTERCEPT_DNS[i].name) == 0) {
printf("%08x\n", MiceConfig.network.naominet_jp);
log_info("dns", "Replacing %s with %08x", pszName, *INTERCEPT_DNS[i].address);
// We only support replacing at most one address, but that's all we'll ever need to!
@ -111,10 +114,14 @@ INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily,
log_misc("dns", "(WSA)DNS lookup for %s", AddressString);
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(AddressString, INTERCEPT_DNS[i].name) == 0) {
log_info("dns", "(WSA)Replacing %s with %08x", AddressString, INTERCEPT_DNS[i].address);
log_info("dns", "(WSA)Replacing %s with %08x", AddressString,
*INTERCEPT_DNS[i].address);
lpAddress->sa_family = AF_INET;
memcpy(&lpAddress->sa_data, INTERCEPT_DNS[i].address, 4);
PULONG addr = &(((SOCKADDR_IN*)lpAddress)->sin_addr.S_un.S_addr);
*addr = _byteswap_ulong(
*INTERCEPT_DNS[i]
.address); //(192UL) | (168UL << 8) | (103UL << 16) | (200UL << 24);
return ERROR_SUCCESS;
}
}
@ -124,9 +131,9 @@ INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily,
}
void hook_network() {
hook("Ws2_32.dll", "connect", Fake_connect, (void**)&True_connect, 5);
hook("Ws2_32.dll", "connect", Fake_connect, (void**)&True_connect);
hook("Ws2_32.dll", "WSAStringToAddressA", FakeWSAStringToAddressA,
(void**)&TrueWSAStringToAddressA, 7);
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable, 5);
hook("Dnsapi.dll", "DnsQuery_A", FakeDnsQuery_A, (void**)&TrueDnsQuery_A, 5);
(void**)&TrueWSAStringToAddressA);
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable);
hook("Dnsapi.dll", "DnsQuery_A", FakeDnsQuery_A, (void**)&TrueDnsQuery_A);
}

View File

@ -34,31 +34,66 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
// log_error("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
// return FALSE;
// #else
// log_info("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
log_info("spawn", "CreateProcessW %ls", lpApplicationName);
log_info("spawn", "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
lpProcessInformation->hThread = GetDummyHandle();
return TRUE;
// log_info("spawn", "CreateProcessW %ls", lpApplicationName);
// lpProcessInformation->hThread = GetDummyHandle();
// return TRUE;
CHAR applicationName[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1, applicationName, sizeof applicationName,
NULL, NULL);
HANDLE child;
CHAR commandLine[MAX_PATH + 1];
WCHAR commandLineW[MAX_PATH + 1];
WCHAR micePathW[MAX_PATH + 1];
GetModuleFileNameW(NULL, micePathW, MAX_PATH);
HANDLE fake_evt = CreateEvent(NULL, TRUE, FALSE, NULL);
SetEvent(fake_evt);
if (lpProcessInformation) {
lpProcessInformation->hProcess = fake_evt;
lpProcessInformation->hThread = GetDummyHandle();
}
return TRUE;
if (lpCommandLine != NULL) {
CHAR commandLine[MAX_PATH + 1];
WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL,
NULL);
child = start_and_inject(applicationName, commandLine, MICELIB, false, 0, NULL);
log_error("process", "!!");
return FALSE;
// WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1, commandLine, sizeof commandLine, NULL,
// NULL);
// child = start_and_inject(applicationName, commandLine, MICELIB, false, 0, NULL,
// CREATE_NEW_CONSOLE);
} else {
child = start_and_inject(applicationName, NULL, MICELIB, false, 0, NULL);
dwCreationFlags |= CREATE_NEW_CONSOLE;
wsprintfW(commandLineW, L"mice86 -b %ls", lpApplicationName);
printf("%ls %ls\n", micePathW, commandLineW);
BOOL ret =
TrueCreateProcessW(L"mice86.cmd", commandLineW, lpProcessAttributes, lpThreadAttributes,
bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory,
lpStartupInfo, lpProcessInformation);
printf("%d\n", ret);
return ret;
// CHAR commandLine[]
// child =
// start_and_inject(applicationName, NULL, MICELIB, false, 0, NULL, CREATE_NEW_CONSOLE);
}
return !FAILED(child);
// #endif
}
void hook_processes() {
hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW, 6);
hook("Kernel32.dll", "CreateProcessA", FakeCreateProcessA, (void**)&TrueCreateProcessA, 6);
BOOL WINAPI FakeGetExitCodeProcess(HANDLE hProcess, LPDWORD lpExitCode) {
*lpExitCode = 0;
return TRUE;
}
void hook_processes() {
hook("Kernel32.dll", "CreateProcessW", FakeCreateProcessW, (void**)&TrueCreateProcessW);
hook("Kernel32.dll", "CreateProcessA", FakeCreateProcessA, (void**)&TrueCreateProcessA);
hook("Kernel32.dll", "GetExitCodeProcess", FakeGetExitCodeProcess, NULL);
}

View File

@ -33,12 +33,12 @@ LSTATUS WINAPI FakeRegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName,
}
void hook_registry() {
hook("Advapi32.dll", "RegCloseKey", FakeRegCloseKey, (void**)&TrueRegCloseKey, 4);
hook("Advapi32.dll", "RegCreateKeyExA", FakeRegCreateKeyExA, (void**)&TrueRegCreateKeyExA, 6);
hook("Advapi32.dll", "RegDeleteKeyA", FakeRegDeleteKeyA, (void**)&TrueRegDeleteKeyA, 4);
hook("Advapi32.dll", "RegCloseKey", FakeRegCloseKey, (void**)&TrueRegCloseKey);
hook("Advapi32.dll", "RegCreateKeyExA", FakeRegCreateKeyExA, (void**)&TrueRegCreateKeyExA);
hook("Advapi32.dll", "RegDeleteKeyA", FakeRegDeleteKeyA, (void**)&TrueRegDeleteKeyA);
hook("Advapi32.dll", "RegDeleteKeyValueA", FakeRegDeleteKeyValueA,
(void**)&TrueRegDeleteKeyValueA, 5);
hook("Advapi32.dll", "RegEnumKeyExA", FakeRegEnumKeyExA, (void**)&TrueRegEnumKeyExA, 5);
(void**)&TrueRegDeleteKeyValueA);
hook("Advapi32.dll", "RegEnumKeyExA", FakeRegEnumKeyExA, (void**)&TrueRegEnumKeyExA);
// TODO: Passthrough
// hook("Advapi32.dll", "RegEnumValueA", FakeRegEnumValueA, (void**)&TrueRegEnumValueA, 5);
// hook("Advapi32.dll", "RegEnumValueA", FakeRegEnumValueA, (void**)&TrueRegEnumValueA);
}

View File

@ -109,11 +109,11 @@ BOOL WINAPI FakeSetupDiDestroyDeviceInfoList(HDEVINFO DevicesInfoSet) {
}
void hook_setupapi() {
hook("Setupapi.DLL", "SetupDiGetClassDevsA", FakeSetupDiGetClassDevsA, (void**)&TrueSetupDiGetClassDevsA, 6);
hook("Setupapi.DLL", "SetupDiGetClassDevsA", FakeSetupDiGetClassDevsA, (void**)&TrueSetupDiGetClassDevsA);
hook("Setupapi.DLL", "SetupDiEnumDeviceInterfaces", FakeSetupDiEnumDeviceInterfaces,
(void**)&TrueSetupDiEnumDeviceInterfaces, 7);
(void**)&TrueSetupDiEnumDeviceInterfaces);
hook("Setupapi.DLL", "SetupDiGetDeviceInterfaceDetailA", FakeSetupDiGetDeviceInterfaceDetailA,
(void**)&TrueSetupDiGetDeviceInterfaceDetailA, 6);
(void**)&TrueSetupDiGetDeviceInterfaceDetailA);
hook("Setupapi.DLL", "SetupDiDestroyDeviceInfoList", FakeSetupDiDestroyDeviceInfoList,
(void**)&TrueSetupDiDestroyDeviceInfoList, 7);
(void**)&TrueSetupDiDestroyDeviceInfoList);
}

View File

@ -1,5 +1,7 @@
#include "system.h"
#include "./files.h"
// const char OS_VERSION[] = "Service Pack 3";
OSVERSIONINFOA OS_VERSION = {
@ -22,14 +24,18 @@ BOOL WINAPI FakeGetVolumeInformationW(LPCWSTR lpRootPathName, LPWSTR lpVolumeNam
LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags,
LPWSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize) {
log_trace("system", "GetVolumeInformationW");
*lpVolumeSerialNumber = 0x1c0fd22b;
if (lpVolumeNameBuffer && nVolumeNameSize) lpVolumeNameBuffer[0] = '\0';
if (lpVolumeSerialNumber) *lpVolumeSerialNumber = 0x00144db0;
if (lpMaximumComponentLength) *lpMaximumComponentLength = 0xff;
if (lpFileSystemFlags) *lpFileSystemFlags = 0x700ff;
if (lpFileSystemNameBuffer) wcsncpy_s(lpFileSystemNameBuffer, nFileSystemNameSize, L"NTFS", 5);
return TRUE;
};
}
DWORD WINAPI FakeGetTempPathW(DWORD nBufferLength, LPWSTR lpBuffer) {
memcpy(lpBuffer, TEMP_PATH, sizeof TEMP_PATH);
return wcslen(TEMP_PATH);
};
}
HCURSOR WINAPI FakeLoadCursorFromFileA(LPCSTR lpFileName) { return (HANDLE)1; }
BOOL FakeSetSystemCursor(HCURSOR hcur, DWORD id) { return TRUE; }
@ -42,14 +48,33 @@ LONG WINAPI FakeChangeDisplaySettingsExA(LPCSTR lpszDeviceName, DEVMODEA* lpDevM
}
void hook_system() {
hook("Kernel32.dll", "GetVolumeInformationW", FakeGetVolumeInformationW, NULL, 5);
hook("Kernel32.dll", "GetTempPathW", FakeGetTempPathW, NULL, 5);
hook("Kernel32.dll", "GetVersionExA", FakeGetVersionExA, NULL, 5);
// TODO: This should be part of drives/hooks.c
hook("Kernel32.dll", "GetVolumeInformationW", FakeGetVolumeInformationW, NULL);
hook("Kernel32.dll", "GetTempPathW", FakeGetTempPathW, NULL);
hook("Kernel32.dll", "GetVersionExA", FakeGetVersionExA, NULL);
hook("User32.dll", "ChangeDisplaySettingsA", FakeChangeDisplaySettingsA, NULL, 4);
hook("User32.dll", "ChangeDisplaySettingsExA", FakeChangeDisplaySettingsExA, NULL, 6);
hook("User32.dll", "ChangeDisplaySettingsA", FakeChangeDisplaySettingsA, NULL);
hook("User32.dll", "ChangeDisplaySettingsExA", FakeChangeDisplaySettingsExA, NULL);
// hook("User32.dll", "LoadCursorFromFileA", FakeLoadCursorFromFileA, NULL, 5);
// hook("User32.dll", "SetSystemCursor", FakeSetSystemCursor, NULL, 5);
// hook("User32.dll", "DeleteObject", FakeDeleteObject, NULL, 5);
// hook("User32.dll", "LoadCursorFromFileA", FakeLoadCursorFromFileA, NULL);
// hook("User32.dll", "SetSystemCursor", FakeSetSystemCursor, NULL);
// hook("User32.dll", "DeleteObject", FakeDeleteObject, NULL);
const char* SystemVersion = "00691001\r\n";
const char* UpdateVersion = "0000\r\n";
const char* RingmasterPub =
("-----BEGIN PUBLIC KEY-----\r\n"
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDH/y0LFuiVonnU+7fKLEOhfQoi\r\n"
"uElB6f9+MVc+VwLzCNV/xU05TWJgm82m/lsmtYwArrA9gHHCB7ExgkaH3kDmd4l6\r\n"
"FumWIRCO/7Z4pbIFSb9xvPYWn7GJJvtJKn2OU/t7zt4nP3MiR0J4lqtT88x6F4Ui\r\n"
"UeI3d2jT+Fw1dgRn7wIDAQAB\r\n"
"-----END PUBLIC KEY-----\r\n");
hook_file_with_buffer(L"C:\\System\\SystemVersion.txt", SystemVersion,
strlen(SystemVersion) + 1, GENERIC_READ);
hook_file_with_buffer(L"C:\\System\\UpdateVersion.txt", UpdateVersion,
strlen(UpdateVersion) + 1, GENERIC_READ);
hook_file_with_buffer(L"c:\\System\\Execute\\ringmaster_pub.pem", RingmasterPub,
strlen(RingmasterPub) + 1, GENERIC_READ);
}

View File

@ -9,18 +9,23 @@ BOOL WINAPI Fake_SetLocalTime(const SYSTEMTIME* lpSystemTime) {
memcpy(&localTime, lpSystemTime, sizeof localTime);
ltCache = TRUE;
log_info("time", "Not setting local time to: %04d-%02d-%02d %02d:%02d:%02d.%04d", lpSystemTime->wYear,
lpSystemTime->wMonth, lpSystemTime->wDay, lpSystemTime->wHour, lpSystemTime->wMinute,
lpSystemTime->wSecond, lpSystemTime->wMilliseconds);
log_info("time", "Not setting local time to: %04d-%02d-%02d %02d:%02d:%02d.%04d",
lpSystemTime->wYear, lpSystemTime->wMonth, lpSystemTime->wDay, lpSystemTime->wHour,
lpSystemTime->wMinute, lpSystemTime->wSecond, lpSystemTime->wMilliseconds);
return TRUE;
}
BOOL WINAPI Fake_SetSystemTime(const SYSTEMTIME* lpSystemTime) {
memcpy(&systemTime, lpSystemTime, sizeof systemTime);
stCache = TRUE;
log_info("time", "Not setting system time to: %04d-%02d-%02d %02d:%02d:%02d.%04d", lpSystemTime->wYear,
lpSystemTime->wMonth, lpSystemTime->wDay, lpSystemTime->wHour, lpSystemTime->wMinute,
lpSystemTime->wSecond, lpSystemTime->wMilliseconds);
log_info("time", "Not setting system time to: %04d-%02d-%02d %02d:%02d:%02d.%04d",
lpSystemTime->wYear, lpSystemTime->wMonth, lpSystemTime->wDay, lpSystemTime->wHour,
lpSystemTime->wMinute, lpSystemTime->wSecond, lpSystemTime->wMilliseconds);
return TRUE;
}
BOOL WINAPI Fake_SetTimeZoneInformation(const TIME_ZONE_INFORMATION* lpTimeZoneInformation) {
log_info("time", "Not setting timezone to: %d", lpTimeZoneInformation->Bias);
return TRUE;
}
@ -41,8 +46,9 @@ BOOL WINAPI Fake_GetSystemTime(SYSTEMTIME* lpSystemTime) {
}
void hook_time() {
hook("Kernel32.dll", "SetLocalTime", Fake_SetLocalTime, (void**)&TrueSetLocalTime, 6);
hook("Kernel32.dll", "SetSystemTime", Fake_SetSystemTime, (void**)&TrueSetSystemTime, 6);
hook("Kernel32.dll", "GetLocalTime", Fake_GetLocalTime, (void**)&TrueGetLocalTime, 6);
hook("Kernel32.dll", "GetSystemTime", Fake_GetSystemTime, (void**)&TrueGetSystemTime, 6);
hook("Kernel32.dll", "SetLocalTime", Fake_SetLocalTime, NULL);
hook("Kernel32.dll", "SetSystemTime", Fake_SetSystemTime, NULL);
hook("Kernel32.dll", "SetTimeZoneInformation", Fake_SetTimeZoneInformation, NULL);
hook("Kernel32.dll", "GetLocalTime", Fake_GetLocalTime, (void**)&TrueGetLocalTime);
hook("Kernel32.dll", "GetSystemTime", Fake_GetSystemTime, (void**)&TrueGetSystemTime);
}

View File

@ -1,9 +1,7 @@
#pragma once
#include "../common.h"
static BOOL(WINAPI* TrueSetLocalTime)(const SYSTEMTIME* lpSystemTime);
static BOOL(WINAPI* TrueGetLocalTime)(SYSTEMTIME* lpSystemTime);
static BOOL(WINAPI* TrueSetSystemTime)(const SYSTEMTIME* lpSystemTime);
static BOOL(WINAPI* TrueGetSystemTime)(SYSTEMTIME* lpSystemTime);
void hook_time();

View File

@ -25,6 +25,7 @@ shared_library(
dmi_lib,
mice_lib,
amiTimer,
amiMd5,
mxklib,
],
include_directories: [

View File

@ -111,43 +111,15 @@ IOCTL_MXSUPERIO_READ:
- W83627UHC (schematics, sheet 16)
*/
// SMBUS Devices (+1 is implied for read addresses)
#define SMBUS_PCA9535 0x40
#define SMBUS_DIMM_A1 0xA0
#define SMBUS_DIMM_B1 0xA4
#define SMBUS_EXIO 0xA8
#define SMBUS_N2 0xAA
#define SMBUS_EEPROM 0xAE
// Keychip
#define DS_GET_EEPROM 0x40
#define DS_GET_UNIQUE_NUMBER 0xA0
#define DS_GET_STATUS 0xA8
#define DS_STATUS_FLAG_BUSY 2
#define DS_I2C_CHALLENGE_RESPONSE 0xB0
// #define DS_REG_ID 0xA0
// #define DS_REG_ID_END 0xA7
// #define DS_REG_STATUS 0xA8
#define EXIO_GET_BUSY 0x00
// #define DS_STATUS_FLAG_BUSY 2
// #define DS_I2C_CHALLENGE_RESPONSE 0xB0
// Old
// TODO: Check for uses, then delete
#pragma pack(push, 1)
typedef struct mxsmbus_request_packet_ {
BYTE status;
BYTE prt;
BYTE addr;
BYTE reg;
BYTE dlen;
BYTE data[32];
} mxsmbus_request_packet;
typedef struct mxsmbus_i2c_packet_ {
BYTE status;
BYTE prt;
WORD addr;
WORD reg;
BYTE dlen;
BYTE data[32];
} mxsmbus_i2c_packet;
typedef struct _MXSMBUS_REQUEST_PACKET {
BYTE status;
BYTE command;

View File

@ -13,3 +13,6 @@ void SetDataForHandle(HANDLE hObject, DWORD type, PVOID pData, BOOL isHeap);
BOOL RemoveDataForHandle(HANDLE hObject, DWORD type);
HANDLE GetDummyHandle();
void BytesToHex(char* hex_buffer, BYTE* bytes, DWORD nbytes);
void PrintStack(void);
void make_dirs(const char* path);

View File

@ -19,13 +19,12 @@ void append_hook(function_hook_t* hook) {
while (hl->next != NULL) hl = hl->next;
hl->next = hook;
}
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store, UINT length) {
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store) {
function_hook_t* hook = (function_hook_t*)malloc(sizeof(struct function_hook));
hook->dll = dll;
hook->name = name;
hook->patch = patch;
hook->store = store;
hook->length = length;
append_hook(hook);
}
@ -55,11 +54,68 @@ BOOL Detour(PVOID src, PVOID dst, const intptr_t len) {
return TRUE;
}
void* CreateHook(PVOID src, PVOID dst, const intptr_t len) {
if (len < 5) return NULL;
void* Win32HotpatchHook(PVOID src, PVOID dst) {
LPBYTE bSrc = (LPBYTE)src;
DWORD oldProt;
VirtualProtect(bSrc - 5, 7, PAGE_EXECUTE_READWRITE, &oldProt);
// relative JMP to dst
bSrc[-5] = 0xE9;
DWORD relJump = (DWORD)dst - (DWORD)src;
bSrc[-1] = (relJump >> 24) & 0xff;
bSrc[-2] = (relJump >> 16) & 0xff;
bSrc[-3] = (relJump >> 8) & 0xff;
bSrc[-4] = relJump & 0xff;
// JMP $-5
bSrc[0] = 0xEB;
bSrc[1] = 0xF9;
VirtualProtect(bSrc - 5, 7, oldProt, &oldProt);
// We don't need a gateway; we can just jump right in
return bSrc + 2;
}
void* CreateHook32(PVOID src, PVOID dst) {
LPBYTE bSrc = (LPBYTE)src;
// If this DLL is hotpatchable, sieze the opportunity
if (bSrc[0] == 0x8b && bSrc[1] == 0xff && bSrc[-1] == 0xCC && bSrc[-2] == 0xCC &&
bSrc[-3] == 0xCC && bSrc[-4] == 0xCC && bSrc[-5] == 0xCC) {
return Win32HotpatchHook(src, dst);
}
intptr_t len = 5;
// This is a very crude way to identify common instruction patterns
// to select or patch length.
if (bSrc[0] == 0xff && bSrc[1] == 0x25) {
// jmp DWORD PTR ds:0x........
len = 6;
} else if (bSrc[0] == 0x6a && bSrc[2] == 0x68) {
// push 0x... (byte)
// push 0x... (dword)
len = 7;
} else if (bSrc[0] == 0x6a && bSrc[2] == 0xb8) {
// push 0x... (byte)
// mov eax,0x... (dword)
len = 7;
} else if (bSrc[0] == 0x68) {
// push 0x... (dword)
len = 5;
} else {
log_error(HOOKS_LOGGER, "Unable to identify gateway length! Function peek:");
for (int i = 0; i < 16; i++) {
printf("%02x ", ((LPBYTE)src)[i]);
}
puts("");
log_error(HOOKS_LOGGER, "Unsafely defaulting to 5!");
len = 5;
}
PVOID gateway = VirtualAlloc(0, len + 5, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (!gateway) return NULL;
memcpy(gateway, src, len);
*(PCHAR)((int)gateway + len) = '\xE9';
@ -91,9 +147,10 @@ void setup_hooks() {
void* original = GetProcAddress(dll, hook->name);
if (original == NULL) {
log_warning(HOOKS_LOGGER, "failed to get original %s", hook->name);
log_warning(HOOKS_LOGGER, "failed to get original %s (%03x)", hook->name,
GetLastError());
} else {
void* gateway = CreateHook(original, hook->patch, hook->length);
void* gateway = CreateHook32(original, hook->patch);
if (hook->store != NULL) *hook->store = gateway;
log_misc(HOOKS_LOGGER, "hooked %s", hook->name);
}

View File

@ -7,7 +7,6 @@ typedef struct function_hook {
LPCSTR name;
PVOID patch;
PVOID* store;
UINT length;
struct function_hook* next;
} function_hook_t;
@ -15,9 +14,9 @@ static BOOL Detour(PVOID src, PVOID dst, const intptr_t len);
void patch_at(PVOID addr, const char* patch, DWORD length);
void clear_at(PVOID addr, BYTE clearVal, DWORD length);
void* CreateHook(PVOID src, PVOID dst, const intptr_t len);
void* CreateHook32(PVOID src, PVOID dst);
static void append_hook(function_hook_t* hook);
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store, UINT length);
void hook(LPCSTR dll, LPCSTR name, void* patch, void** store);
void setup_hooks();

View File

@ -10,7 +10,7 @@
#include "../../lib/mice/config.h"
#include "../hooks/logging.h"
extern WCHAR exePath[MAX_PATH + 1];
extern WCHAR exeName[MAX_PATH + 1];
extern DWORD imageOffset;
extern BOOL(WINAPI* TrueWriteFile)(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite,
@ -79,11 +79,11 @@ DWORD* ppLogcb;
int _do_log(BYTE log_level, const char* caller, const char* format, va_list args) {
// TODO: These are all horrible bodges
if (wcscmp(exePath, L"mxnetwork.exe") == 0) {
if (wcscmp(exeName, L"mxnetwork.exe") == 0) {
// *((DWORD*)(imageOffset + 0x004438e8)) = (DWORD)(&logcb);
*((DWORD*)(imageOffset + 0x004438e8)) = 0x00000000;
}
if (wcscmp(exePath, L"maimai_dump_.exe") == 0) {
if (wcscmp(exeName, L"maimai_dump_.exe") == 0) {
*((DWORD*)(imageOffset + 0x00c820ec)) = 0x00000001;
pLogcb = (DWORD)(&amLogCallback);
ppLogcb = &pLogcb;
@ -134,7 +134,7 @@ int _do_log(BYTE log_level, const char* caller, const char* format, va_list args
int vlog_trace(const char* caller, const char* format, va_list args) {
return _do_log(LOG_TRACE, caller, format, args);
}
int log_trace(const char* caller, const char* format, ...) {
int _log_trace(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_trace(caller, format, args);
@ -144,7 +144,7 @@ int log_trace(const char* caller, const char* format, ...) {
int vlog_misc(const char* caller, const char* format, va_list args) {
return _do_log(LOG_MISC, caller, format, args);
}
int log_misc(const char* caller, const char* format, ...) {
int _log_misc(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_misc(caller, format, args);
@ -154,7 +154,7 @@ int log_misc(const char* caller, const char* format, ...) {
int vlog_info(const char* caller, const char* format, va_list args) {
return _do_log(LOG_INFO, caller, format, args);
}
int log_info(const char* caller, const char* format, ...) {
int _log_info(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_info(caller, format, args);
@ -164,7 +164,7 @@ int log_info(const char* caller, const char* format, ...) {
int vlog_warning(const char* caller, const char* format, va_list args) {
return _do_log(LOG_WARNING, caller, format, args);
}
int log_warning(const char* caller, const char* format, ...) {
int _log_warning(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_warning(caller, format, args);
@ -174,7 +174,7 @@ int log_warning(const char* caller, const char* format, ...) {
int vlog_error(const char* caller, const char* format, va_list args) {
return _do_log(LOG_ERROR, caller, format, args);
}
int log_error(const char* caller, const char* format, ...) {
int _log_error(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_error(caller, format, args);
@ -184,7 +184,7 @@ int log_error(const char* caller, const char* format, ...) {
int vlog_game(const char* caller, const char* format, va_list args) {
return _do_log(LOG_GAME, caller, format, args);
}
int log_game(const char* caller, const char* format, ...) {
int _log_game(const char* caller, const char* format, ...) {
va_list args;
va_start(args, format);
int ret = vlog_game(caller, format, args);

View File

@ -16,12 +16,12 @@
extern CRITICAL_SECTION logger_lock;
int log_trace(const char* caller, const char* format, ...);
int log_misc(const char* caller, const char* format, ...);
int log_info(const char* caller, const char* format, ...);
int log_warning(const char* caller, const char* format, ...);
int log_error(const char* caller, const char* format, ...);
int log_game(const char* caller, const char* format, ...);
int _log_trace(const char* caller, const char* format, ...);
int _log_misc(const char* caller, const char* format, ...);
int _log_info(const char* caller, const char* format, ...);
int _log_warning(const char* caller, const char* format, ...);
int _log_error(const char* caller, const char* format, ...);
int _log_game(const char* caller, const char* format, ...);
int vlog_trace(const char* caller, const char* format, va_list args);
int vlog_misc(const char* caller, const char* format, va_list args);
@ -33,3 +33,42 @@ int vlog_game(const char* caller, const char* format, va_list args);
void log_stack(const char* caller);
void setup_logging();
// Disable some logging entirely at build time for speed
#define COMPILE_LOG_LEVEL 6
#if COMPILE_LOG_LEVEL >= 6
#define log_trace _log_trace
#else
#define log_trace(...)
#endif
#if COMPILE_LOG_LEVEL >= 5
#define log_misc _log_misc
#else
#define log_misc(...)
#endif
#if COMPILE_LOG_LEVEL >= 4
#define log_info _log_info
#else
#define log_info(...)
#endif
#if COMPILE_LOG_LEVEL >= 3
#define log_warning _log_warning
#else
#define log_warning(...)
#endif
#if COMPILE_LOG_LEVEL >= 2
#define log_error _log_error
#else
#define log_error(...)
#endif
#if COMPILE_LOG_LEVEL >= 1
#define log_game _log_game
#else
#define log_game(...)
#endif

View File

@ -1,7 +1,33 @@
#define _WIN32_WINNT 0x0600
#include <Windows.h>
#include <dbghelp.h>
#include "../hooks/files.h"
void PrintStack(void) {
unsigned int i;
void* stack[100];
unsigned short frames;
SYMBOL_INFO* symbol;
HANDLE process;
process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
frames = CaptureStackBackTrace(0, 100, stack, NULL);
symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
for (i = 0; i < frames; i++) {
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
printf("%i: %s - 0x%0X\n", frames - i - 1, symbol->Name, symbol->Address);
}
free(symbol);
}
BOOL FileExists(wchar_t* szPath) {
DWORD dwAttrib = GetFileAttributesW(szPath);
return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
@ -96,3 +122,29 @@ void BytesToHex(char* hex_buffer, BYTE* bytes, DWORD nbytes) {
}
hex_buffer[nbytes * 3] = '\0';
}
void make_dirs(const char* path) {
int count = 0;
size_t i;
size_t len = strlen(path);
char* temp = malloc(len + 1);
memcpy(temp, path, len + 1);
for (i = 0; i < len; i++) {
if (temp[i] == '/' || temp[i] == '\\') count++;
}
if (count == 0) {
free(temp);
return;
}
for (i = 0; i < len && count; i++) {
if (temp[i] == '/' || temp[i] == '\\') {
temp[i] = '\0';
CreateDirectory(temp, NULL);
temp[i] = '\\';
count--;
}
}
free(temp);
}

View File

@ -55,6 +55,11 @@ void parse_cmdline(int argc, char* argv[]) {
int main(int argc, char* argv[]) {
load_mice_config();
fprintf(stderr, "Argc: %d\n", argc);
CHAR workDir[MAX_PATH + 1];
GetCurrentDirectory(MAX_PATH, workDir);
fprintf(stderr, "Work dir: %s\n", workDir);
fprintf(stderr, "Micetools version: %s\n", MICE_VERSION);
parse_cmdline(argc, argv);
@ -98,7 +103,7 @@ int main(int argc, char* argv[]) {
char* extra_injections = MiceConfig.launcher.inject;
HANDLE game_proc =
start_and_inject(exe_name, cmdline, micepath, debug_wait, boot_delay, extra_injections);
start_and_inject(exe_name, cmdline, micepath, debug_wait, boot_delay, extra_injections, 0);
if (!game_proc) return -1;
if (FAILED(WaitForSingleObject(game_proc, INFINITE))) {

View File

@ -670,9 +670,9 @@ AM_DONGLE_STATUS amDongleRecvBinary(void) {
uint bufferLength;
switch (amDongle.requestCode) {
case AM_DONGLE_WTF_80:
case AM_DONGLE_APPBOOT_SEED:
buffer = amDongle.valueBuffer;
bufferLength = 0x10;
bufferLength = 16;
break;
case AM_DONGLE_WTF_81:
case AM_DONGLE_REQUEST_BILLING_GET_CA_CERT:
@ -999,7 +999,7 @@ AM_DONGLE_STATUS amDongleEncrypt(unsigned char *pt, unsigned char *ct,
if (pt == NULL || ct == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM;
char ptHex[32];
char ptHex[33];
bin_to_hex(ptHex, pt, 16);
pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.encrypt", ptHex);
if (packet == NULL && amDongleDebugLevel > 0)
@ -1020,7 +1020,8 @@ AM_DONGLE_STATUS amDongleDecrypt(unsigned char *ct, unsigned char *pt,
if (ct == NULL || pt == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM;
char ctHex[32];
char ctHex[33];
ZeroMemory(ctHex, 33);
bin_to_hex(ctHex, ct, 16);
pcp_send_data_t *packet = pcpaSetSendPacket(&amDongle.pcpa, "keychip.decrypt", ctHex);
if (packet == NULL && amDongleDebugLevel > 0)
@ -1119,7 +1120,51 @@ AM_DONGLE_STATUS amDongleBillingAddPlayCount(void *playCount, AM_DONGLE_BLOCKING
amiDebugLog("Error: pcpaAddSendPacket return NULL");
}
amDongle.valueBuffer = playCount;
amDongle.requestCode = 0xf;
amDongle.requestCode = AM_DONGLE_REQUEST_BILLING_ADD_PLAYCOUNT;
if (blocking == AM_DONGLE_BLOCK) {
return amDongleSendAndReceiveEx();
}
return amDongleOpen();
}
AM_DONGLE_STATUS amDongleSetIv(AM_DONGLE_BLOCKING blocking) {
if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT;
if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY;
if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG;
if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY;
pcp_send_data_t *send_data =
pcpaSetSendPacket(&amDongle.pcpa, "keychip.setiv", "?");
if (send_data == NULL && amDongleDebugLevel > 0) {
amiDebugLog("Error: pcpaSetSendPacket return NULL");
}
amDongle.requestCode = AM_DONGLE_REQUEST_SET_IV;
if (blocking == AM_DONGLE_BLOCK) {
return amDongleSendAndReceiveEx();
}
return amDongleOpen();
}
AM_DONGLE_STATUS amDongleGetSeed(unsigned char* seed, AM_DONGLE_BLOCKING blocking) {
if (!amDongle.m_init) return AM_DONGLE_STATUS_ERR_NO_INIT;
if (!amDongle.auth_ready) return AM_DONGLE_STATUS_ERR_AUTH_READY;
if (!amDongle.done_init || !amDongle.available) return AM_DONGLE_STATUS_NG;
if (amDongle.seq != AM_DONGLE_SEQ_NONE) return AM_DONGLE_STATUS_BUSY;
if (seed == NULL) return AM_DONGLE_STATUS_ERR_INVALID_PARAM;
pcp_send_data_t *send_data =
pcpaSetSendPacket(&amDongle.pcpa, "keychip.appboot.seed", "?");
if (send_data == NULL && amDongleDebugLevel > 0) {
amiDebugLog("Error: pcpaSetSendPacket return NULL");
}
send_data = pcpaAddSendPacket(&amDongle.pcpa, "cache", "1");
if (send_data == NULL && amDongleDebugLevel > 0) {
amiDebugLog("Error: pcpaAddSendPacket return NULL");
}
amDongle.requestCode = AM_DONGLE_APPBOOT_SEED;
amDongle.valueBuffer = seed;
if (blocking == AM_DONGLE_BLOCK) {
return amDongleSendAndReceiveEx();
}

View File

@ -122,7 +122,7 @@ typedef enum {
// 29
AM_DONGLE_REQUEST_GET_FORMAT_TYPE = 30,
AM_DONGLE_WTF_80 = 0x80 | 0,
AM_DONGLE_APPBOOT_SEED = 0x80 | 0,
AM_DONGLE_WTF_81 = 0x80 | 1,
AM_DONGLE_REQUEST_BILLING_GET_TRACEDATA = 0x80 | 2,
AM_DONGLE_REQUEST_BILLING_GET_SIGNATURE_PK = 0x80 | 3,
@ -179,6 +179,8 @@ AM_DONGLE_STATUS amDongleBillingAddPlayCount(void *playCount, AM_DONGLE_BLOCKING
AM_DONGLE_STATUS amDongleBillingGetNearfull(unsigned int *nearfull, AM_DONGLE_BLOCKING blocking);
AM_DONGLE_STATUS amDongleEncrypt(unsigned char *pt, unsigned char *ct, AM_DONGLE_BLOCKING blocking);
AM_DONGLE_STATUS amDongleDecrypt(unsigned char *ct, unsigned char *pt, AM_DONGLE_BLOCKING blocking);
AM_DONGLE_STATUS amDongleSetIv(AM_DONGLE_BLOCKING blocking);
AM_DONGLE_STATUS amDongleGetSeed(unsigned char* seed, AM_DONGLE_BLOCKING blocking);
void amDongleBillingGetCaCertification(void);
void amDongleBillingGetMainId(void);
@ -203,9 +205,7 @@ void amDongleGetDsMac(void);
void amDongleGetDvdFlag(void);
void amDongleGetFormatType(void);
void amDongleGetResult(void);
void amDongleGetSeed(void);
void amDongleGetSsdResponse(void);
void amDongleRequestSsdHostProof(void);
void amDongleSetAuthCondition(void);
void amDongleSetIv(void);
void amDongleUpdate(void);

View File

@ -99,7 +99,6 @@ void amPlatformGetGpuPstate(void);
void amPlatformGetGraphicInfo(void);
void amPlatformGetMemorySize(void);
void amPlatformGetOsVersion(void);
void amPlatformGetOsVersion(void);
void amPlatformGetPartitionInfo(void);
void amPlatformGetPlatformIdEx(void);
void amPlatformGetPortName(void);
@ -109,4 +108,4 @@ void amPlatformGetStorageInfo(void);
void amPlatformNvapiInit(void);
void amPlatformSetDisplayMode(void);
void amPlatformSetDisplayResolution(void);
void amPlatformSetDisplayResolutionAndMode(void);
void amPlatformSetDisplayResolutionAndMode(void);

View File

@ -15,9 +15,7 @@ BOOL amSerialIdIsValid(char *id_string) {
if (chr != '-') return FALSE;
} else if (i < 8 || i > 15) {
if (!isdigit(chr) && !isupper(chr)) return FALSE;
if (chr == 'I') return FALSE;
if (chr == 'O') return FALSE;
} else {
if (!isdigit(chr)) return FALSE;
@ -34,4 +32,4 @@ BOOL amSerialIdConvert(char *id_string, char *serial_id) {
memcpy_s(serial_id, 17, id_string, 4);
memcpy_s(serial_id + 4, 13, id_string + 5, 7);
return TRUE;
}
}

View File

@ -13,12 +13,12 @@ void amiCrc32RCreateTable(unsigned int *table);
unsigned int amiCrc32RGet(unsigned int *table, int length, unsigned char *data,
unsigned int initial);
#define amCrc32RCreateTable() \
#define amiCrc32RInit() \
do { \
if (!amiCrc.m_init) { \
amiCrc32RCreateTable(amiCrc.m_table); \
amiCrc.m_init = 1; \
} \
} while (0)
#define amCrc32RGet(length, data, initial) \
#define amiCrc32RCalc(length, data, initial) \
amiCrc32RGet(amiCrc.m_table, (length), (data), (initial))

View File

@ -0,0 +1,129 @@
#include "amiMd5.h"
#include <Windows.h>
static unsigned char rtable[4][4] = {
{ 7, 12, 17, 22 },
{ 5, 9, 14, 20 },
{ 4, 11, 16, 23 },
{ 6, 10, 15, 21 },
};
static unsigned int md5_init[4] = {
0x67452301,
0xefcdab89,
0x98badcfe,
0x10325476,
};
static unsigned int sines[] = {
0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391,
};
#define ROT_LEFT(x, n) (((x) << (n)) | ((x >> (32 - (n)))))
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | (~z)))
void amiMd5Init(AmiMd5 *md5) {
ZeroMemory(md5, sizeof *md5);
md5->m_state[0] = md5_init[0];
md5->m_state[1] = md5_init[1];
md5->m_state[2] = md5_init[2];
md5->m_state[3] = md5_init[3];
}
void amiMd5Transform(AmiMd5 *md5, unsigned char *buffer) {
unsigned int a = md5->m_state[0];
unsigned int b = md5->m_state[1];
unsigned int c = md5->m_state[2];
unsigned int d = md5->m_state[3];
unsigned int *uBuffer = (unsigned int *)buffer;
unsigned int tmp, i, j;
for (i = 0; i < 16; i++) {
tmp = a + F(b, c, d) + uBuffer[i] + sines[i];
tmp = ROT_LEFT(tmp, rtable[0][i & 3]) + b;
a = d;
d = c;
c = b;
b = tmp;
}
for (i = 0, j = 1; i < 16; i++, j += 5) {
tmp = a + G(b, c, d) + uBuffer[j & 15] + sines[i + 16];
tmp = ROT_LEFT(tmp, rtable[1][i & 3]) + b;
a = d;
d = c;
c = b;
b = tmp;
}
for (i = 0, j = 5; i < 16; i++, j += 3) {
tmp = a + H(b, c, d) + uBuffer[j & 15] + sines[i + 32];
tmp = ROT_LEFT(tmp, rtable[2][i & 3]) + b;
a = d;
d = c;
c = b;
b = tmp;
}
for (i = 0, j = 0; i < 16; i++, j += 7) {
tmp = a + I(b, c, d) + uBuffer[j & 15] + sines[i + 48];
tmp = ROT_LEFT(tmp, rtable[3][i & 3]) + b;
a = d;
d = c;
c = b;
b = tmp;
}
md5->m_state[0] += a;
md5->m_state[1] += b;
md5->m_state[2] += c;
md5->m_state[3] += d;
}
void amiMd5Update(AmiMd5 *md5, unsigned int nBytes, unsigned char *buffer) {
int buflen = md5->m_length & 63;
md5->m_length += nBytes;
if (buflen + nBytes < 64) {
memcpy(md5->m_buffer + buflen, buffer, nBytes);
buflen += nBytes;
return;
}
memcpy(md5->m_buffer + buflen, buffer, 64 - buflen);
amiMd5Transform(md5, md5->m_buffer);
buffer += 64 - buflen;
nBytes -= 64 - buflen;
while (nBytes >= 64) {
amiMd5Transform(md5, buffer);
buffer += 64;
nBytes -= 64;
}
memcpy(md5->m_buffer, buffer, nBytes);
}
void amiMd5Finalise(AmiMd5 *md5) {
int buflen = md5->m_length & 63;
md5->m_buffer[buflen++] = 0x80;
memset(md5->m_buffer + buflen, 0, 64 - buflen);
if (buflen > 56) {
amiMd5Transform(md5, md5->m_buffer);
memset(md5->m_buffer, 0, 64);
buflen = 0;
}
*(unsigned int *)(md5->m_buffer + 56) = 8 * md5->m_length;
*(unsigned int *)(md5->m_buffer + 60) = 0;
amiMd5Transform(md5, md5->m_buffer);
for (int i = 0; i < 4; i++) ((unsigned int *)md5->m_digest)[i] = md5->m_state[i];
}

View File

@ -0,0 +1,15 @@
typedef struct {
unsigned int m_state[4];
unsigned int m_offset;
unsigned int m_block;
unsigned int m_blockOffset;
unsigned int m_length;
unsigned char m_buffer[256];
unsigned char m_digest[16];
} AmiMd5;
void amiMd5Init(AmiMd5 *md5);
void amiMd5Update(AmiMd5 *md5, unsigned int nBytes, unsigned char *buffer);
void amiMd5Finalise(AmiMd5 *md5);

View File

@ -23,7 +23,7 @@ amtime_t* amiTimerGet(amtime_t* time) {
int amiTimerDiffSec(amtime_t* start, amtime_t* now) {
if (start == NULL || now == NULL) return -1;
return (now->seconds - (now->microseconds < start->microseconds)) - start->seconds;
return (start->seconds - (start->microseconds < now->microseconds)) - now->seconds;
}
int amiTimerDiffMsec(amtime_t* start, amtime_t* now) {

View File

@ -18,3 +18,10 @@ amiDebug = static_library(
'amiDebug.c',
],
)
amiMd5 = static_library(
'amiMd5',
sources: [
'amiMd5.c',
],
)

View File

@ -6,7 +6,7 @@ LPBYTE dmi_table = NULL;
WORD dmi_size = 0;
WORD _dmi_max = 0;
DMI_BIOS deafult_dmi_bios = {
DMI_BIOS default_dmi_bios = {
.Head.Type = DmiTypeBios,
.Head.Length = 0x12,
.Head.Handle = 0x0000,
@ -32,7 +32,7 @@ DMI_SYSTEM default_dmi_system = {
.Serial = 0x04, // "To Be Filled By O.E.M."
};
DMI_STRING deafult_dmi_string = {
DMI_STRING default_dmi_string = {
.Head.Type = DmiTypeString,
.Head.Length = 0x05,
.Head.Handle = 0x0002,
@ -80,7 +80,7 @@ static void dmi_append_with_strings(void* data, WORD size, int num_strings, ...)
void dmi_build_default() {
dmi_init();
dmi_append_with_strings(&deafult_dmi_bios, sizeof deafult_dmi_bios, 3,
dmi_append_with_strings(&default_dmi_bios, sizeof default_dmi_bios, 3,
"American Megatrends Inc.", "080015 ", "07/28/2011");
// Platform AAM: Board type one of "Supermicro"(=1) or "Advantech"(=2)
@ -89,9 +89,9 @@ void dmi_build_default() {
"To Be Filled By O.E.M.", "To Be Filled By O.E.M.",
"To Be Filled By O.E.M.");
deafult_dmi_string.NoStrings = 5;
default_dmi_string.NoStrings = 5;
dmi_append_with_strings(&deafult_dmi_string, sizeof deafult_dmi_string,
dmi_append_with_strings(&default_dmi_string, sizeof default_dmi_string,
// OEM strings:
// 0: ??
// 1: ??

View File

@ -1025,7 +1025,6 @@ e_pcpp_t pcppSendRequestMain(pcpp_t* stream, undefined4 param_2, timeout_t timeo
e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len, uint param_4) {
size_t* psVar1;
char** send_buf;
int iVar2;
e_pcpt_t eVar3;
e_pcpp_t eVar4;
@ -1097,14 +1096,14 @@ e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len,
stream->last_active = _amTimeMs(local_10);
if (stream->recv_binary_buf_len < stream->field_0x1fc ||
stream->recv_binary_buf_len == stream->field_0x1fc) {
send_buf = (char**)&stream->send_buf;
unsigned char* send_buf = (unsigned char*)stream->send_buf;
psVar1 = &stream->send_buf_len;
stream->state = pcpp_state_send_binary_ack;
*send_buf[0] = PCP_CHAR_BINACK;
send_buf[0] = PCP_CHAR_BINACK;
*psVar1 = 1;
iVar2 = pcppGetBlockingTime(stream->field_0x20c, param_4, stream, _amTimeMs(now),
&recvb_local);
eVar3 = pcptSend(&stream->sock, (unsigned char*)*send_buf, psVar1, stream->field_0x208,
eVar3 = pcptSend(&stream->sock, send_buf, psVar1, stream->field_0x208,
recvb_local);
eVar4 = _errT2P(eVar3);
stream->err = eVar4;
@ -1126,7 +1125,7 @@ e_pcpp_t pcppRecvBinary(pcpp_t* stream, unsigned char* recv_buf, size_t buf_len,
*psVar1 = PCP_SEND_BUF_MAX;
ZERO(stream->send_buf);
eVar3 =
pcptRecv(&stream->data_sock, (unsigned char*)*send_buf, psVar1, recvb_local);
pcptRecv(&stream->data_sock, send_buf, psVar1, recvb_local);
eVar4 = _errT2P(eVar3);
stream->err = eVar4;
if ((iVar2 != 0) && (eVar4 == e_pcpp_to)) {

View File

@ -93,6 +93,7 @@ int handler(void *user, const char *section, const char *name, const char *value
#define CFG_int(s, n, default, comment) \
else if (_stricmp(section, #s) == 0 && _stricmp(name, #n) == 0) { \
cfg->s.n = strtol(value, &end, 10); \
printf("%s.%s:%d\n", #s, #n, cfg->s.n);\
if (end == value || *end != '\0' || errno == ERANGE) cfg->s.n = default; \
}
#define CFG_hex(s, n, precision, default, comment) \

View File

@ -34,8 +34,8 @@ CFG_str(sysconf, serial, "AASE-01A65646203", "")
ENDSECTION(sysconf)
SECTION(window, "Game window positioning settings")
CFG_bool(window, windowed, false, "Force games into windowed mode")
CFG_bool(window, borderless, true, "Should windowed games run borderless")
CFG_bool(window, windowed, true, "Force games into windowed mode")
CFG_bool(window, borderless, false, "Should windowed games run borderless")
CFG_int(window, adaptor, 0, "Display adaptor to use")
CFG_bool(window, centre, true, "Centre the window. X and Y are used otherwise")
CFG_int(window, x, 0, "Window position X")

View File

@ -72,7 +72,7 @@ bool inject_dll(HANDLE process, LPCSTR inject) {
}
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait, DWORD delay,
LPCSTR extra_injections) {
LPCSTR extra_injections, DWORD flags) {
STARTUPINFOA startupInfo;
PROCESS_INFORMATION processInformation = { 0 };
@ -98,7 +98,8 @@ HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wa
}
// Start the binary
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL,
flags |= CREATE_SUSPENDED;
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, flags, NULL, NULL,
&startupInfo, &processInformation)) {
fprintf(stderr, "Fatal: CreateProcessA failed: %03x\n", GetLastError());
goto abort;

View File

@ -3,7 +3,7 @@
#include <stdio.h>
HANDLE start_and_inject(LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait, DWORD delay,
LPCSTR extra_injections);
LPCSTR extra_injections, DWORD flags);
#ifndef MICELIB
#ifdef MICE_WIN32

View File

@ -78,20 +78,18 @@ int hex_to_bin(char *hex, unsigned char *bin, int hex_len) {
return 1;
}
void bin_to_hex(char *hex, unsigned char *bin, int nbytes) {
int hex_len = nbytes * 2;
while (nbytes--) {
if (bin[0] & 0x0f > 0x09)
hex[--hex_len] = (bin[0] & 0x0f) + 'a';
for (int i = 0; i < nbytes; i++) {
if ((bin[i] & 0xf0) > 0x90)
hex[i * 2] = ((bin[i] & 0xf0) >> 4) - 0x0a + 'a';
else
hex[--hex_len] = (bin[0] & 0x0f) + '0';
hex[i * 2] = ((bin[i] & 0xf0) >> 4) + '0';
if (bin[0] & 0xf0 > 0x90)
hex[--hex_len] = ((bin[0] & 0xf0) >> 4) + 'a';
if ((bin[i] & 0x0f) > 0x09)
hex[i * 2 + 1] = (bin[i] & 0x0f) - 0x0a + 'a';
else
hex[--hex_len] = ((bin[0] & 0xf0) >> 4) + '0';
bin++;
hex[i * 2 + 1] = (bin[i] & 0x0f) + '0';
}
hex[nbytes * 2] = '\0';
}
int hex_to_int(unsigned int *value, char *hex) {

View File

@ -165,8 +165,8 @@ void mxmPcpActiveFgprocess(pcpa_t* stream, MX_MASTER* mxMaster) {
pcpaSetSendPacket(stream, MXM_FG_ACTIVE, "1");
mxMaster->m_current = mxMaster->m_next;
mxMaster->m_next = 0;
mxMaster->m_field5_0x14 = 1;
mxMaster->m_field4_0x10 = 1;
mxMaster->m_changeIsSpawn = 1;
mxMaster->m_processStateChange = true;
return;
}
@ -179,19 +179,19 @@ void mxmPcpActiveFgprocess(pcpa_t* stream, MX_MASTER* mxMaster) {
if (mxMaster->m_next != 0) {
mxMaster->m_current = mxMaster->m_next;
mxMaster->m_next = 0;
mxMaster->m_field4_0x10 = 1;
mxMaster->m_processStateChange = true;
return;
}
mxMaster->m_fault = 1;
mxMaster->m_current = 1;
mxMaster->m_field4_0x10 = 1;
mxMaster->m_processStateChange = true;
return;
}
mxMaster->m_next = 0;
mxMaster->m_current = 0;
mxMaster->m_field4_0x10 = 1;
mxMaster->m_processStateChange = true;
return;
} else {
pcpaSetSendPacket(stream, MXM_FG_ACTIVE, mxMaster->m_current == 0 ? "0" : "1");

View File

@ -1,145 +1,13 @@
#include <Windows.h>
#include <winioctl.h>
#include "../../lib/am/amInstall.h"
#include "../mxm.h"
#include "mxmEventLog.h"
bool mxmEventLogAccessGetMainStorageDeviceNum(int* devNum) {
if (devNum == NULL) {
amiDebugLog("Error : Invalid Argument");
return false;
}
char windir[256];
if (!GetSystemWindowsDirectoryA(windir, sizeof windir)) {
amiDebugLog("Error : GetSystemWindowsDirectoryA error");
*devNum = -1;
return false;
}
char windirDos[256];
sprintf_s(windirDos, sizeof windirDos, "\\\\.\\%c:", windir[0]);
HANDLE hDevice =
CreateFileA(windirDos, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_SUPPORTS_REPARSE_POINTS, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
amiDebugLog("Error : CreateFile error ErrorNum = %d", GetLastError());
*devNum = -1;
return false;
}
STORAGE_DEVICE_NUMBER ioctlBuf;
DWORD bytesReturned;
if (!DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &ioctlBuf,
sizeof ioctlBuf, &bytesReturned, NULL)) {
amiDebugLog("Error : DeviceIoControl error ErrorNum = %d", GetLastError());
CloseHandle(hDevice);
*devNum = -1;
return false;
}
CloseHandle(hDevice);
*devNum = ioctlBuf.DeviceNumber;
return true;
}
#define LOG_OFFSET (2047 * 512)
bool mxmEventLogAccessEraseEventLogData(int deviceNum, unsigned long long address) {
char drivePath[MAX_PATH];
ZeroMemory(drivePath, sizeof drivePath);
sprintf_s(drivePath, sizeof drivePath, "\\\\.\\PhysicalDrive%d", deviceNum);
HANDLE hFile =
CreateFileA(drivePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_SUPPORTS_REPARSE_POINTS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
amiDebugLog("Error : CreateFile error");
return false;
}
char logBuffer[512];
ZeroMemory(logBuffer, sizeof logBuffer);
LARGE_INTEGER writeAddress;
writeAddress.QuadPart = address + LOG_OFFSET;
if (!SetFilePointerEx(hFile, writeAddress, NULL, 0)) {
CloseHandle(hFile);
amiDebugLog("SetFilePointerEx error");
return false;
}
DWORD bytesWritten;
if (!WriteFile(hFile, logBuffer, sizeof logBuffer, &bytesWritten, NULL)) {
CloseHandle(hFile);
amiDebugLog("WriteFile error %d", GetLastError());
return false;
}
if (bytesWritten != sizeof logBuffer) {
CloseHandle(hFile);
amiDebugLog("Wriete Size Error");
return false;
}
CloseHandle(hFile);
return true;
}
bool mxmEventLogAccessLoadEpbr(AM_INSTALL_BOOT_RECORD* bootRecord) {
amtime_t start, now;
if (amInstallInit() != AM_INSTALL_STATUS_OK) {
amiDebugLog("Error : amInstallInit.");
return false;
}
amiTimerGet(&start);
while (1) {
AM_INSTALL_STATUS err = amInstallGetBr(bootRecord, 0);
if (!((err == AM_INSTALL_STATUS_ERR_REQUEST) ||
(err == AM_INSTALL_STATUS_ERR_UPDATE_STATUS) ||
(err == AM_INSTALL_STATUS_ERR_GET_SEMAPHORE) ||
(err == AM_INSTALL_STATUS_ERR_FORMAT) || (err == AM_INSTALL_STATUS_OK) ||
(err == AM_INSTALL_STATUS_BUSY))) {
amiDebugLog("Error : amInstallGetBr error.");
amInstallExit();
return false;
}
amiTimerGet(&now);
if (amiTimerDiffSec(&start, &now) > 30) {
amiDebugLog("Error : amInstallGetBr time out error.");
amInstallExit();
return false;
}
if (err == AM_INSTALL_STATUS_OK) {
if (amInstallExit() == AM_INSTALL_STATUS_OK) return true;
amiDebugLog("Error : amInstallExit.");
return false;
}
}
}
bool mxmEventLogEraseLog() {
AM_INSTALL_BOOT_RECORD br;
ZeroMemory(&br, sizeof br);
int devNum = 0;
if (!mxmEventLogAccessGetMainStorageDeviceNum(&devNum)) return false;
if (!mxmEventLogAccessLoadEpbr(&br)) return false;
if (!mxmEventLogAccessEraseEventLogData(devNum, br.os)) return false;
return true;
}
void mxmPcpLogAvailable(pcpa_t* stream, MX_MASTER* mxMaster) {
pcpaSetSendPacket(stream, MXM_LOG_AVAILALBE, mxMaster->m_loggingAvailable ? "1" : "0");
char* command = pcpaGetCommand(stream, MXM_LOG_AVAILALBE);
void mxmPcpLogAvailable(pcpa_t *stream, MX_MASTER *mxMaster) {
char *command = pcpaGetCommand(stream, MXM_LOG_AVAILALBE);
if (command == NULL) {
amiDebugLog("Error : Command is not set up.");
pcpaSetSendPacket(stream, MXM_LOG_AVAILALBE, "?");
return;
}
bool metadataChanged = false;
if (strcmp(command, "?") != 0) {
if (strcmp(command, "1") == 0) {
@ -176,7 +44,7 @@ void mxmPcpLogAvailable(pcpa_t* stream, MX_MASTER* mxMaster) {
}
char buffer[256];
pcpaSetSendPacket(stream, MXM_LOG_AVAILALBE, mxMaster->m_loggingAvailable ? "1" : 0);
pcpaSetSendPacket(stream, MXM_LOG_AVAILALBE, mxMaster->m_loggingAvailable ? "1" : "0");
_itoa_s(mxMaster->m_backupCount, buffer, sizeof buffer, 10);
pcpaAddSendPacket(stream, "backup_count", buffer);
@ -186,14 +54,99 @@ void mxmPcpLogAvailable(pcpa_t* stream, MX_MASTER* mxMaster) {
pcpaAddSendPacket(stream, "interval", buffer);
}
void mxmPcpOutputLog(pcpa_t* stream, MX_MASTER* mxMaster) {
// Only allowed: 0, 1, 2
pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "0");
pcpaAddSendPacket(stream, "path", "");
void mxmPcpOutputLog(pcpa_t *stream, MX_MASTER *mxMaster) {
char logName[12];
char path[260];
ZeroMemory(path, sizeof path);
ZeroMemory(logName, sizeof logName);
if (stream == NULL || mxMaster == NULL) {
amiDebugLog("Error : CallbackFuncOutputLog Invalid error");
return;
}
char *command = pcpaGetCommand(stream, pcpaGetKeyword(stream, 0));
char *sType = pcpaGetCommand(stream, "type");
if (command == NULL || sType == NULL) {
amiDebugLog("Error : Command error");
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "?") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL");
if (pcpaAddSendPacket(stream, "code", "1") == NULL)
amiDebugLog("Error : pcpaAddSendPacket return NULL");
return;
}
if (strlen(sType) == 0) {
amiDebugLog("Error : Command length error");
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "?") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL");
if (pcpaAddSendPacket(stream, "code", "1") == NULL)
amiDebugLog("Error : pcpaAddSendPacket return NULL");
return;
}
if (strcmp(command, "0") != 0) {
amiDebugLog("Error : Command type error");
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "?") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL\n");
if (pcpaAddSendPacket(stream, "code", "1") == NULL)
amiDebugLog("Error : pcpaAddSendPacket return NULL");
return;
}
if (strcmp(sType, "0") != 0 && strcmp(sType, "1") != 0) {
amiDebugLog("Error : Type error");
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "?") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL\n");
if (pcpaAddSendPacket(stream, "code", "1") == NULL)
amiDebugLog("Error : pcpaAddSendPacket return NULL");
return;
}
char *endPtr;
int nType = strtoul(sType, &endPtr, 10);
bool logValid = false;
if (!mxmEventLogCheckLog(&logValid)) {
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "1") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL");
return;
}
if (!logValid) {
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "2") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL");
return;
}
if (strcmp(sType, "0") == 0) {
strcpy_s(logName, sizeof logName, "application");
} else if (strcmp(sType, "1") == 0) {
strcpy_s(logName, sizeof logName, "system");
}
if (!mxmEventLogGetTempPath(logName, path)) {
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "1") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL");
return;
}
if (!mxmEventLogAccessBackup(path, nType)) {
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "1") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL");
return;
}
if (pcpaSetSendPacket(stream, MXM_OUTPUT_LOG, "0") == NULL)
amiDebugLog("Error : pcpaSetSendPacket return NULL");
if (pcpaAddSendPacket(stream, "path", path) == NULL)
amiDebugLog("Error : pcpaAddSendPacket return NULL");
}
void mxmPcpEraseLog(pcpa_t* stream, MX_MASTER* mxMaster) {
char* command = pcpaGetCommand(stream, MXM_ERASE_LOG);
void mxmPcpEraseLog(pcpa_t *stream, MX_MASTER *mxMaster) {
char *command = pcpaGetCommand(stream, MXM_ERASE_LOG);
if (command == NULL) {
amiDebugLog("Error : Command error");
pcpaSetSendPacket(stream, MXM_ERASE_LOG, "1");

View File

@ -1,22 +1,9 @@
#include <shlwapi.h>
#include "../lib/am/amInstall.h"
#include "../lib/ami/amiMd5.h"
#include "mxm.h"
void mxMasterMakeCopy(char* filename) {
char dest[256];
char src[256];
sprintf_s(src, sizeof src, "%s%s", Config.dir.system, filename);
sprintf_s(dest, sizeof dest, "%s%s", Config.dir.execute, filename);
if (!PathFileExistsA(src)) {
amiDebugLog("Error copy %s not exist", src);
return;
}
if (!PathFileExistsA(dest)) CopyFileA(src, dest, 0);
}
bool mxMasterInitPcp(MX_MASTER* mxMaster) {
if (mxMaster->m_pcpaHasInit) return true;
@ -55,27 +42,13 @@ bool mxMasterInitPcp(MX_MASTER* mxMaster) {
return true;
}
bool mxMasterOpen(MX_MASTER* mxMaster) {
e_pcpa_t err = pcpaOpenServerWithBinary(&mxMaster->m_pcp, mxMaster->m_openMode,
mxMaster->m_controlPort, mxMaster->m_dataPort, 60000);
if (err != e_pcpa_ok && err != e_pcpa_to) {
amiDebugLog("pcpaOpenServerWithBinary Error. Code %d", err);
return false;
}
amiDebugLog("Listening on %s:%d (:%d)",
mxMaster->m_openMode == OPEN_MODE_GLOBAL ? "0.0.0.0" : "127.0.0.1",
mxMaster->m_controlPort, mxMaster->m_dataPort);
return true;
}
bool mxMasterInit(MX_MASTER* mxMaster) {
mxMaster->m_develop = 0;
mxMaster->m_fault = 0;
mxMaster->m_current = 0;
mxMaster->m_next = 0;
mxMaster->m_field5_0x14 = 0;
mxMaster->m_field4_0x10 = 0;
mxMaster->m_changeIsSpawn = false;
mxMaster->m_processStateChange = false;
mxMaster->m_backupMetadataChanged = false;
mxMaster->m_loggingAvailable = false;
mxMaster->m_backupCount = 0;
@ -88,14 +61,14 @@ bool mxMasterInit(MX_MASTER* mxMaster) {
mxMaster->m_binaryMessageLen = 0;
ZeroMemory(mxMaster->m_binaryMessage, sizeof mxMaster->m_binaryMessage);
mxMasterMakeCopy("mxsegaboot.exe");
mxMasterMakeCopy("mxauthdisc.exe");
mxMasterMakeCopy("mxshellexecute.exe");
mxMasterMakeCopy("ringmaster_pub.pem");
mxMasterMakeCopy("develop_regset.txt");
mxMasterMakeCopy("lockid.txt");
mxMasterMakeCopy("d3dref9.dll");
mxMasterMakeCopy("mxsegaboot_2052.dll");
mxmCopySystemFile("mxsegaboot.exe");
mxmCopySystemFile("mxauthdisc.exe");
mxmCopySystemFile("mxshellexecute.exe");
mxmCopySystemFile("ringmaster_pub.pem");
mxmCopySystemFile("develop_regset.txt");
mxmCopySystemFile("lockid.txt");
mxmCopySystemFile("d3dref9.dll");
mxmCopySystemFile("mxsegaboot_2052.dll");
return mxMasterInitPcp(mxMaster);
}
@ -246,10 +219,10 @@ void mxMasterSysProcessesStart(MX_MASTER* mxMaster) {
Sleep(2000);
if (mxMasterLoadKeychipInfo(mxMaster)) {
mxMaster->m_current = 1;
mxMaster->m_kcReady = 0;
mxMaster->m_kcReady = true;
} else {
mxMaster->m_kcReady = 1;
mxMaster->m_current = 1;
mxMaster->m_kcReady = false;
}
char mxinstaller[128];
@ -275,7 +248,7 @@ void mxMasterFdcProcessesStart(MX_MASTER* mxMaster) {
strcpy_s(startup[1], sizeof startup[1], Config.binary.mxgfetcher);
strcpy_s(startup[2], sizeof startup[2], Config.binary.mxgdeliver);
if (mxMaster->m_kcReady != 0) {
if (mxMaster->m_kcReady) {
char* format;
char* networkAddr = inet_ntoa(mxMaster->m_networkAddr);
@ -353,19 +326,18 @@ void mxMasterMainLoop(MX_MASTER* mxMaster) {
mxMaster->m_backupCount = 1;
mxMaster->m_clearCount = 100;
mxMaster->m_interval = 60;
// if (mxEventLog_0044e5d8.init == 0) {
// mxEventLog_0044e5d8.backup_count = 1;
// mxEventLog_0044e5d8.clear_count = 100;
// mxEventLog_0044e5d8.interval = 60;
// mxEventLog_0044e5d8.field1_0x4 = 0;
// mxEventLog_0044e5d8.field2_0x8 = 0;
// _memset(mxEventLog_0044e5d8.field6_0x18, 0, 0x330);
// mxEventLog_0044e5d8.init = 1;
// uVar5 = extraout_ECX;
// param_2 = extraout_EDX;
// }
e_pcpa_t err;
if (!MxmEventLog.m_init) {
MxmEventLog.m_backupCount = 1;
MxmEventLog.m_clearCount = 100;
MxmEventLog.m_interval = 60;
MxmEventLog.m_logDriveFound = false;
MxmEventLog.m_filenamesSet = false;
ZeroMemory(MxmEventLog.m_desinations, sizeof MxmEventLog.m_desinations);
MxmEventLog.m_init = true;
}
e_pcpa_t err;
do {
err = pcpaOpenServerWithBinary(&mxMaster->m_pcp, mxMaster->m_openMode,
mxMaster->m_controlPort, mxMaster->m_dataPort, 60000);
@ -378,13 +350,12 @@ void mxMasterMainLoop(MX_MASTER* mxMaster) {
amiDebugLog("Error : Not Open Server. Code %d", err);
}
} while (err != e_pcpa_ok);
mxMaster->m_field23_0x3f4 = 1;
mxMaster->m_serverOpen = true;
appLauncherAppInfo_t appInfo[3];
while (1) {
err = pcpaServer(&mxMaster->m_pcp, 16);
if (err != e_pcpa_ok && err != e_pcpa_to && err != e_pcpa_closed) {
if (mxMaster->m_pcpaHasInit) {
pcpaClose(&mxMaster->m_pcp);
@ -407,22 +378,19 @@ void mxMasterMainLoop(MX_MASTER* mxMaster) {
}
appLauncher_t* appLauncher;
if (mxMaster->m_field4_0x10 != 0) {
if (mxMaster->m_processStateChange) {
appLauncher = mxMaster->m_appLauncher;
if (appLauncher->m_createdThread) goto code_r0x004056a9;
goto LAB_004056db;
}
if (appLauncher->m_createdThread) {
if (WaitForSingleObject(appLauncher->m_hThread, 0) != WAIT_TIMEOUT) {
CloseHandle(appLauncher->m_hThread);
appLauncher->m_hThread = NULL;
appLauncher->m_createdThread = false;
}
}
goto LAB_0040574e;
code_r0x004056a9:
if (WaitForSingleObject(appLauncher->m_hThread, 0) != WAIT_TIMEOUT) {
CloseHandle(appLauncher->m_hThread);
appLauncher->m_hThread = NULL;
appLauncher->m_createdThread = false;
LAB_004056db:
if (!mxMaster->m_develop || mxMaster->m_field5_0x14) {
if (!mxMaster->m_develop || mxMaster->m_changeIsSpawn) {
appInfo[0].m_mode = mxMaster->m_current;
mxMaster->m_field5_0x14 = 0;
mxMaster->m_changeIsSpawn = 0;
if (appInfo[0].m_mode == 2) {
sprintf_s(appInfo[0].m_path, sizeof appInfo[0].m_path, "%s",
mxMaster->m_nextPath);
@ -444,36 +412,24 @@ void mxMasterMainLoop(MX_MASTER* mxMaster) {
}
appLauncherCreateThread(appInfo, mxMaster->m_appLauncher);
}
mxMaster->m_field4_0x10 = 0;
LAB_0040574e:
if (mxMaster->m_backupMetadataChanged) {
// dVar3 = mxMaster->m_clearCount;
// dVar4 = mxMaster->m_interval;
// if (mxEventLog_0044e5d8.init != 0) {
// mxEventLog_0044e5d8.backup_count = mxMaster->backup_count;
// mxEventLog_0044e5d8.clear_count = dVar3;
// mxEventLog_0044e5d8.interval = dVar4;
// }
mxMaster->m_backupMetadataChanged = false;
mxMaster->m_processStateChange = false;
}
if (mxMaster->m_backupMetadataChanged) {
if (MxmEventLog.m_init) {
MxmEventLog.m_backupCount = mxMaster->m_backupCount;
MxmEventLog.m_clearCount = mxMaster->m_clearCount;
MxmEventLog.m_interval = mxMaster->m_interval;
}
mxMaster->m_backupMetadataChanged = false;
}
if (MxmEventLog.m_init && MxmEventLog.m_filenamesSet) {
for (int i = 0; i < NUM_LOGS; i++) {
if (mxmBackupEventlog(i) != 0) break;
}
// if ((mxEventLog_0044e5d8.init != 0) && (mxEventLog_0044e5d8.field2_0x8 != 0)) {
// iVar5 = 0;
// do {
// uVar6 = mxmBackupEventlog(dVar3, dVar4, iVar5);
// dVar4 = (dword)((ulonglong)uVar6 >> 0x20);
// if ((int)uVar6 != 0) break;
// iVar5 += 1;
// dVar3 = extraout_ECX_03;
// } while (iVar5 < 3);
// }
}
}
// mxMaster->m_serverState = 2;
// while (1) {
// err = mxmPcpServer(mxMaster);
// if (err != e_pcpp_ok) amiDebugLog("Server tick: %d", err);
// }
}
int main() {
@ -485,10 +441,12 @@ int main() {
if (GetConsoleMode(hConsole, &dwMode))
SetConsoleMode(hConsole, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
// Start WSA
WSADATA wsaData;
int err = WSAStartup(2, &wsaData);
if (err) return -1;
// Initialise mxm structures
MX_MASTER* mxMaster = malloc(sizeof *mxMaster);
if (mxMaster == NULL) {
amiDebugLog("Unable to allocate MX_MASTER");
@ -497,10 +455,10 @@ int main() {
ZeroMemory(mxMaster, sizeof *mxMaster);
appLauncher_t appLauncher;
ZeroMemory(&appLauncher, sizeof appLauncher);
pcpaInitStream(&appLauncher.m_pcp);
appLauncher.m_appInfo.m_appLauncher = &appLauncher;
mxMaster->m_appLauncher = &appLauncher;
// Startup
if (!mxMasterInit(mxMaster)) {
amiDebugLog("Error mxMasterInit");
return -1;
@ -509,11 +467,6 @@ int main() {
mxMaster->m_dataPort = 40101;
mxMaster->m_openMode = OPEN_MODE_LOCAL;
// if (!mxMasterOpen(mxMaster)) {
// amiDebugLog("Error mxMasterOpen");
// return -1;
// }
mxMasterSysProcessesStart(mxMaster);
mxMasterFdcProcessesStart(mxMaster);
mxMasterFirstFgProcessesStart(mxMaster);

View File

@ -19,6 +19,8 @@ executable(
amiDebug,
amDongle,
amInstall,
amiMd5,
amiCrc,
],
include_directories: incdir,
dependencies: [],

View File

@ -1,42 +1,105 @@
#include "mxm.h"
#include <shlwapi.h>
#define TICK_MS 16
void mxmBeforeBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster) {
void mxmBeforeBinaryCallback(pcpa_t *stream, MX_MASTER *mxMaster) {
pcpaSetSendBinaryBuffer(stream, mxMaster->m_binaryMessage, mxMaster->m_binaryMessageLen);
}
void mxmAfterBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster) {
void mxmAfterBinaryCallback(pcpa_t *stream, MX_MASTER *mxMaster) {
mxMaster->m_binaryMessage[0] = '\0';
mxMaster->m_binaryMessageLen = 0;
}
int mxmInit(MX_MASTER* mxMaster) {
void mxmCopySystemFile(char *filename) {
char dest[256];
char src[256];
sprintf_s(src, sizeof src, "%s%s", Config.dir.system, filename);
sprintf_s(dest, sizeof dest, "%s%s", Config.dir.execute, filename);
if (!PathFileExistsA(src)) {
amiDebugLog("Error copy %s not exist", src);
return;
}
if (!PathFileExistsA(dest)) CopyFileA(src, dest, 0);
}
e_pcpa_t mxmPcpStreamInit(MX_MASTER* mxMaster) { return 0; }
int mxmBackupEventlog(int destination) {
if (!MxmEventLog.m_logDriveFound) return 0;
e_pcpa_t mxmPcpServer(MX_MASTER* mxMaster) {
int err;
if (mxMaster->m_serverState == 1) {
err = mxmPcpStreamInit(mxMaster);
if (err == 0) {
mxMaster->m_serverState = 2;
return err;
}
char *logs[3] = {
"Application",
"Security",
"System",
};
HANDLE hEventLog = OpenEventLogA(NULL, logs[destination]);
if (hEventLog == INVALID_HANDLE_VALUE || hEventLog == NULL) {
amiDebugLog("Error OpenEventLog(%d). Code %d", destination, GetLastError());
return -2;
}
DWORD numberOfRecords = 0;
if (!GetNumberOfEventLogRecords(hEventLog, &numberOfRecords)) {
printf("%d\n", hEventLog);
amiDebugLog("Error GetNumberOf-EventLogRecords(%d). Code %d", destination, GetLastError());
CloseEventLog(hEventLog);
return -3;
}
bool clearLog = false;
if (MxmEventLog.m_clearCount < numberOfRecords) {
clearLog = true;
} else {
if (mxMaster->m_serverState != 2) {
return (mxMaster->m_serverState == 0) ? e_pcpa_cannot_open : e_pcpa_not_open;
}
err = pcpaServer(&mxMaster->m_pcp, TICK_MS);
if (err == e_pcpa_to || err == e_pcpa_closed) err = e_pcpa_ok;
if (err) {
amiDebugLog("Error pcpaServer. Code %d", err);
pcpaClose(&mxMaster->m_pcp);
mxMaster->m_serverState = 1;
amtime_t now;
amiTimerGet(&now);
unsigned int deltaT =
amiTimerDiffSec(&(MxmEventLog.m_desinations[destination].m_last), &now);
if (deltaT < MxmEventLog.m_interval) {
printf("Waiting: %d/%d\n", deltaT, MxmEventLog.m_interval);
CloseEventLog(hEventLog);
return 0;
}
}
return err;
}
if (MxmEventLog.m_backupCount <=
(numberOfRecords - MxmEventLog.m_desinations[destination].m_numRecords)) {
char *lpFileName = MxmEventLog.m_desinations[destination].m_filename;
HANDLE hFile = CreateFileA(lpFileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_SUPPORTS_REPARSE_POINTS, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
if (!DeleteFileA(lpFileName)) {
amiDebugLog("Error DeleteFileA() : %d", GetLastError());
CloseEventLog(hEventLog);
return -4;
}
}
if (!clearLog) {
if (!BackupEventLogA(hEventLog, lpFileName)) {
amiDebugLog("Error BackupEventLogA() : %d", GetLastError());
CloseEventLog(hEventLog);
return -3;
}
MxmEventLog.m_desinations[destination].m_numRecords = numberOfRecords;
} else {
if (!ClearEventLogA(hEventLog, lpFileName)) {
amiDebugLog("Error ClearEventLog() : %d", GetLastError());
CloseEventLog(hEventLog);
return -3;
}
MxmEventLog.m_desinations[destination].m_numRecords = 0;
char name[8];
strncpy_s(name, sizeof name, lpFileName, 3);
mxmEventLogSetDestination(name, destination);
}
amiTimerGet(&(MxmEventLog.m_desinations[destination].m_last));
}
CloseEventLog(hEventLog);
return 0;
}

View File

@ -5,6 +5,7 @@
#include "config.h"
#include "lib/am/amDongle.h"
#include "lib/libpcp/libpcp.h"
#include "mxmEventLog.h"
typedef enum {
mxMasterStartType_0 = 0,
@ -25,9 +26,8 @@ typedef struct MX_MASTER_ {
ushort m_dataPort;
int m_openMode;
// TODO: What are these?
unsigned int m_field4_0x10;
unsigned int m_field5_0x14;
bool m_processStateChange;
bool m_changeIsSpawn;
bool m_backupMetadataChanged;
unsigned int m_current;
@ -36,9 +36,9 @@ typedef struct MX_MASTER_ {
bool m_fault;
bool m_loggingAvailable;
bool m_backupCount;
bool m_clearCount;
bool m_interval;
unsigned int m_backupCount;
unsigned int m_clearCount;
unsigned int m_interval;
char m_nextPath[128];
char m_gameId[8];
char m_platformId[8];
@ -51,13 +51,8 @@ typedef struct MX_MASTER_ {
int m_countGameTest;
unsigned char m_binaryMessage[512];
size_t m_binaryMessageLen;
// TODO: What is this?
unsigned int m_field23_0x3f4;
int m_serverState; // TODO: Remove once unneeded
unsigned int m_kcReady;
bool m_serverOpen;
bool m_kcReady;
bool m_pcpaHasInit;
appLauncher_t* m_appLauncher;
pcpa_cb_table_t m_pcpCallbacks[11];
@ -67,8 +62,5 @@ typedef struct MX_MASTER_ {
void mxmBeforeBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster);
void mxmAfterBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster);
// void mxmBinaryCallback(pcpa_t* stream, MX_MASTER* mxMaster);
int mxmInit(MX_MASTER* mxMaster);
e_pcpa_t mxmPcpStreamInit(MX_MASTER* mxMaster);
e_pcpa_t mxmPcpServer(MX_MASTER* mxMaster);
void mxmCopySystemFile(char* filename);
int mxmBackupEventlog(int destination);

View File

@ -1,12 +1,26 @@
#include "mxmEventLog.h"
#include <Windows.h>
#include <stdio.h>
#include <winioctl.h>
#include "../lib/ami/amiMd5.h"
mxmEventLog_t MxmEventLog;
#define LOG_DRIVE "L:\\"
#define LOG_VOLUME "\\\\.\\L:\\"
#define LOG_DRIVE_NAME "SEGA_AM_LOG"
#define TEMP_PATH "C:\\WINDOWS\\TEMP\\"
bool mxmEventLogGetTempPath(char *name, char *buffer) {
SYSTEMTIME now;
GetLocalTime(&now);
_snprintf_s(buffer, 0x104, 0xffffffff, "%s%s%04d%02d%02d%02d%02d%02d.evt", TEMP_PATH, name,
now.wYear, now.wMonth, now.wDay, now.wHour, now.wMinute, now.wSecond);
return true;
}
bool mxmEventLogGetLogDrive(char *logPath) {
char volumeName[264];
@ -20,14 +34,14 @@ bool mxmEventLogGetLogDrive(char *logPath) {
}
int mxmEventLogSetDestination(char *name, unsigned int which) {
char *type_names[3];
char *type_names[NUM_LOGS];
SYSTEMTIME now;
type_names[0] = "application";
type_names[1] = "security";
type_names[2] = "system";
if (name == NULL || which >= 3) return -1;
if (name == NULL || which >= NUM_LOGS) return -1;
GetLocalTime(&now);
_snprintf_s(MxmEventLog.m_desinations[which].m_filename, MAX_PATH, _TRUNCATE,
@ -43,7 +57,377 @@ void mxmEventLogInit(void) {
name[0] = '\0';
MxmEventLog.m_logDriveFound = mxmEventLogGetLogDrive(name);
if (MxmEventLog.m_logDriveFound) {
for (int i = 0; i < 3; i++) mxmEventLogSetDestination(name, i);
for (int i = 0; i < NUM_LOGS; i++) mxmEventLogSetDestination(name, i);
MxmEventLog.m_filenamesSet = true;
}
}
bool mxmEventLogEraseLog(void) {
AM_INSTALL_BOOT_RECORD br;
ZeroMemory(&br, sizeof br);
int devNum = 0;
if (!mxmEventLogAccessGetMainStorageDeviceNum(&devNum)) return false;
if (!mxmEventLogAccessLoadEpbr(&br)) return false;
if (!mxmEventLogAccessEraseEventLogData(devNum, br.os)) return false;
return true;
}
bool mxmEventLogCheckLog(bool *valid) {
if (valid == NULL) return false;
AM_INSTALL_BOOT_RECORD br;
ZeroMemory(&br, sizeof br);
int devNum = 0;
if (!mxmEventLogAccessGetMainStorageDeviceNum(&devNum)) return false;
if (!mxmEventLogAccessLoadEpbr(&br)) return false;
if (!mxmEventLogAccessCheckEventLogData(devNum, br.os, valid)) return false;
return true;
}
bool mxmEventLogAccessGetMainStorageDeviceNum(int *devNum) {
if (devNum == NULL) {
amiDebugLog("Error : Invalid Argument");
return false;
}
char windir[256];
if (!GetSystemWindowsDirectoryA(windir, sizeof windir)) {
amiDebugLog("Error : GetSystemWindowsDirectoryA error");
*devNum = -1;
return false;
}
char windirDos[256];
sprintf_s(windirDos, sizeof windirDos, "\\\\.\\%c:", windir[0]);
HANDLE hDevice =
CreateFileA(windirDos, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_SUPPORTS_REPARSE_POINTS, NULL);
if (hDevice == INVALID_HANDLE_VALUE) {
amiDebugLog("Error : CreateFile error ErrorNum = %d", GetLastError());
*devNum = -1;
return false;
}
STORAGE_DEVICE_NUMBER ioctlBuf;
DWORD bytesReturned;
if (!DeviceIoControl(hDevice, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &ioctlBuf,
sizeof ioctlBuf, &bytesReturned, NULL)) {
amiDebugLog("Error : DeviceIoControl error ErrorNum = %d", GetLastError());
CloseHandle(hDevice);
*devNum = -1;
return false;
}
CloseHandle(hDevice);
*devNum = ioctlBuf.DeviceNumber;
return true;
}
bool mxmEventLogAccessEraseEventLogData(int deviceNum, unsigned long long address) {
char drivePath[MAX_PATH];
ZeroMemory(drivePath, sizeof drivePath);
sprintf_s(drivePath, sizeof drivePath, "\\\\.\\PhysicalDrive%d", deviceNum);
HANDLE hFile =
CreateFileA(drivePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_SUPPORTS_REPARSE_POINTS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
amiDebugLog("Error : CreateFile error");
return false;
}
char logBuffer[512];
ZeroMemory(logBuffer, sizeof logBuffer);
LARGE_INTEGER writeAddress;
writeAddress.QuadPart = address + LOG_OFFSET;
if (!SetFilePointerEx(hFile, writeAddress, NULL, FILE_BEGIN)) {
CloseHandle(hFile);
amiDebugLog("SetFilePointerEx error");
return false;
}
DWORD bytesWritten;
if (!WriteFile(hFile, logBuffer, sizeof logBuffer, &bytesWritten, NULL)) {
CloseHandle(hFile);
amiDebugLog("WriteFile error %d", GetLastError());
return false;
}
if (bytesWritten != sizeof logBuffer) {
CloseHandle(hFile);
amiDebugLog("Wriete Size Error");
return false;
}
CloseHandle(hFile);
return true;
}
bool mxmEventLogAccessCheckEventLogData(int deviceNum, unsigned long long address, bool *valid) {
AM_EVENT_LOG_HEADER logHeader;
char drivePath[MAX_PATH];
ZeroMemory(&logHeader, sizeof logHeader);
ZeroMemory(drivePath, sizeof drivePath);
sprintf_s(drivePath, sizeof drivePath, "\\\\.\\PhysicalDrive%d", deviceNum);
HANDLE hFile =
CreateFileA(drivePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_SUPPORTS_REPARSE_POINTS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
amiDebugLog("Error : CreateFile error");
return false;
}
LARGE_INTEGER writeAddress;
writeAddress.QuadPart = address + LOG_OFFSET;
if (!SetFilePointerEx(hFile, writeAddress, NULL, FILE_BEGIN)) {
CloseHandle(hFile);
amiDebugLog("SetFilePointerEx error");
return false;
}
DWORD bytesRead;
if (!ReadFile(hFile, &logHeader, sizeof logHeader, &bytesRead, NULL)) {
CloseHandle(hFile);
amiDebugLog("ReadFile Header error");
return false;
}
if (bytesRead != sizeof logHeader) {
CloseHandle(hFile);
amiDebugLog("Read Size Error");
return false;
}
amiCrc32RInit();
unsigned int calcCrc =
amiCrc32RCalc(sizeof logHeader - 4, (unsigned char *)(&logHeader) + 4, 0);
*valid = logHeader.m_crc32 == calcCrc;
CloseHandle(hFile);
return true;
}
bool mxmEventLogAccessLoadEpbr(AM_INSTALL_BOOT_RECORD *bootRecord) {
amtime_t start, now;
AM_INSTALL_STATUS err = amInstallInit();
if (err != AM_INSTALL_STATUS_OK && err != AM_INSTALL_STATUS_ERR_ALREADY_INIT) {
amiDebugLog("Error : amInstallInit. Code %d", err);
return false;
}
amiTimerGet(&start);
while (1) {
err = amInstallGetBr(bootRecord, 0);
if (!((err == AM_INSTALL_STATUS_ERR_REQUEST) ||
(err == AM_INSTALL_STATUS_ERR_UPDATE_STATUS) ||
(err == AM_INSTALL_STATUS_ERR_GET_SEMAPHORE) ||
(err == AM_INSTALL_STATUS_ERR_FORMAT) || (err == AM_INSTALL_STATUS_OK) ||
(err == AM_INSTALL_STATUS_BUSY))) {
amiDebugLog("Error : amInstallGetBr error.");
amInstallExit();
return false;
}
amiTimerGet(&now);
if (amiTimerDiffSec(&start, &now) > 30) {
amiDebugLog("Error : amInstallGetBr time out error.");
amInstallExit();
return false;
}
if (err == AM_INSTALL_STATUS_OK) {
if (amInstallExit() == AM_INSTALL_STATUS_OK) return true;
amiDebugLog("Error : amInstallExit.");
return false;
}
}
}
bool mxmEventLogAccessReadEventLogData(int deviceNum, unsigned long long address,
unsigned char *eventlog1, unsigned int *nBytes1,
unsigned char *eventlog2, unsigned int *nBytes2) {
if (nBytes1 == 0 || eventlog2 == NULL || nBytes2 == NULL) return false;
AM_EVENT_LOG_HEADER eventLogHeader;
ZeroMemory(&eventLogHeader, sizeof eventLogHeader);
char drivePath[256];
ZeroMemory(&drivePath, sizeof drivePath);
sprintf_s(drivePath, sizeof drivePath, "\\\\.\\PhysicalDrive%d", deviceNum);
HANDLE hFile =
CreateFileA(drivePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_SUPPORTS_REPARSE_POINTS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
amiDebugLog("Error : CreateFile error");
return false;
}
LARGE_INTEGER readAddress;
readAddress.QuadPart = address + LOG_OFFSET;
if (!SetFilePointerEx(hFile, readAddress, NULL, 0)) {
CloseHandle(hFile);
amiDebugLog("SetFilePointerEx error");
return false;
}
DWORD bytesRead;
if (!ReadFile(hFile, &eventLogHeader, sizeof eventLogHeader, &bytesRead, NULL)) {
CloseHandle(hFile);
amiDebugLog("ReadFile Header error");
return false;
}
if (bytesRead != sizeof eventLogHeader) {
CloseHandle(hFile);
amiDebugLog("Read Size error");
return false;
}
amiCrc32RInit();
unsigned int calcCrc =
amiCrc32RCalc(sizeof eventLogHeader - 4, (unsigned char *)(&eventLogHeader) + 4, 0);
if (calcCrc != eventLogHeader.m_crc32) {
CloseHandle(hFile);
return false;
}
if (eventLogHeader.m_nBytes[0] > LOG_MAX_SIZE || eventLogHeader.m_nBytes[1] > LOG_MAX_SIZE) {
CloseHandle(hFile);
amiDebugLog("Buffer Size error");
return false;
}
unsigned char *readBuffer = malloc(LOG_MAX_SIZE);
if (readBuffer == NULL) {
CloseHandle(hFile);
return false;
}
ZeroMemory(readBuffer, LOG_MAX_SIZE);
struct {
unsigned long long offset;
unsigned int srcSize;
unsigned int dstSize;
unsigned char *dst;
} readSetup[2] = {
{
.offset = LOG_1_OFFSET,
.dstSize = LOG_MAX_SIZE,
.dst = eventlog1,
},
{
.offset = LOG_2_OFFSET,
.dstSize = LOG_MAX_SIZE,
.dst = eventlog2,
},
};
for (int i = 0; i < 2; i++) {
readAddress.QuadPart = address + readSetup[i].offset;
if (!SetFilePointerEx(hFile, readAddress, NULL, 0)) {
free(readBuffer);
CloseHandle(hFile);
amiDebugLog("SetFilePointerEx error");
return false;
}
DWORD nRead = eventLogHeader.m_nBytes[i];
if ((nRead & 0x1FF) != 0) nRead += 512 - (nRead & 0x1FF);
if (!ReadFile(hFile, readBuffer, nRead, &bytesRead, NULL)) {
free(readBuffer);
CloseHandle(hFile);
amiDebugLog("ReadFile Evt error");
return false;
}
if (nRead != bytesRead) {
free(readBuffer);
CloseHandle(hFile);
amiDebugLog("Read Size error");
return false;
}
AmiMd5 md5;
amiMd5Init(&md5);
amiMd5Update(&md5, nRead, readBuffer);
amiMd5Finalise(&md5);
if (memcmp(md5.m_digest, eventLogHeader.m_md5[i], sizeof md5.m_digest) != 0) {
free(readBuffer);
CloseHandle(hFile);
amiDebugLog("Event Log is broken");
return false;
}
memcpy(readSetup[i].dst, readBuffer, readSetup[i].dstSize);
}
free(readBuffer);
CloseHandle(hFile);
return true;
}
DWORD mxmEventLogAccessWriteDataFile(char *filename, unsigned char *dataFile, unsigned int nBytes) {
HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, FILE_SUPPORTS_REPARSE_POINTS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
amiDebugLog("Error : CreateFile error");
return (DWORD)-1;
}
DWORD ret = (DWORD)-1;
DWORD bytesRead;
if (WriteFile(hFile, dataFile, nBytes, &bytesRead, NULL)) {
ret = bytesRead;
}
CloseHandle(hFile);
return ret;
}
bool mxmEventLogAccessCopyIntoDataFile(int deviceNum, unsigned long long address, char *filename,
unsigned int type) {
unsigned int nBytes1;
unsigned char *eventLog1 = malloc(LOG_MAX_SIZE);
if (eventLog1 == NULL) return false;
unsigned int nBytes2;
unsigned char *eventLog2 = malloc(LOG_MAX_SIZE);
if (eventLog2 == NULL) {
free(eventLog1);
return false;
}
if (!mxmEventLogAccessReadEventLogData(deviceNum, address, eventLog1, &nBytes1, eventLog2,
&nBytes2)) {
free(eventLog1);
free(eventLog2);
return false;
}
bool success;
if (type == 0) {
success = mxmEventLogAccessWriteDataFile(filename, eventLog2, nBytes1);
} else if (type == 1) {
success = mxmEventLogAccessWriteDataFile(filename, eventLog2, nBytes2);
} else {
free(eventLog1);
free(eventLog2);
return false;
}
free(eventLog1);
free(eventLog2);
if (success == (DWORD)-1) return false;
return true;
}
bool mxmEventLogAccessBackup(char *filename, int type) {
AM_INSTALL_BOOT_RECORD br;
ZeroMemory(&br, sizeof br);
int devNum = 0;
if (!mxmEventLogAccessGetMainStorageDeviceNum(&devNum)) return false;
if (!mxmEventLogAccessLoadEpbr(&br)) return false;
if (!mxmEventLogAccessCopyIntoDataFile(devNum, br.os, filename, type)) return false;
return true;
}

View File

@ -1,13 +1,29 @@
#include <Windows.h>
#include <stdbool.h>
#include "../lib/am/amInstall.h"
#include "../lib/ami/amiTimer.h"
typedef struct {
unsigned int Rsv00;
unsigned int Rsv04;
amtime_t m_last;
unsigned int m_numRecords;
char m_filename[MAX_PATH];
} mxmEventLogDesination_t;
#pragma pack(push, 1)
typedef struct {
unsigned int m_crc32;
char m_gameId[4];
unsigned char Rsv08[8];
unsigned int m_nBytes[2];
unsigned char Rsv18[8];
unsigned char m_md5[2][16];
unsigned char Rsv40[448];
} AM_EVENT_LOG_HEADER;
#pragma pack(pop)
#define NUM_LOGS 3
typedef struct {
bool m_init;
bool m_logDriveFound;
@ -15,11 +31,31 @@ typedef struct {
unsigned int m_backupCount;
unsigned int m_clearCount;
unsigned int m_interval;
mxmEventLogDesination_t m_desinations[3];
mxmEventLogDesination_t m_desinations[NUM_LOGS];
} mxmEventLog_t;
extern mxmEventLog_t MxmEventLog;
#define LOG_MAX_SIZE (1024 * 512)
// Offsets relative to [os] partition, in bytes
#define LOG_OFFSET (2047 * 512)
#define LOG_1_OFFSET (2048 * 512)
#define LOG_2_OFFSET (LOG_1_OFFSET + LOG_MAX_SIZE)
bool mxmEventLogGetTempPath(char *name, char *buffer);
bool mxmEventLogGetLogDrive(char *logPath);
int mxmEventLogSetDestination(char *name, unsigned int which);
void mxmEventLogInit(void);
bool mxmEventLogEraseLog(void);
bool mxmEventLogCheckLog(bool *valid);
bool mxmEventLogAccessGetMainStorageDeviceNum(int *devNum);
bool mxmEventLogAccessEraseEventLogData(int deviceNum, unsigned long long address);
bool mxmEventLogAccessCheckEventLogData(int deviceNum, unsigned long long address, bool *valid);
bool mxmEventLogAccessLoadEpbr(AM_INSTALL_BOOT_RECORD *bootRecord);
bool mxmEventLogAccessReadEventLogData(int deviceNum, unsigned long long address,
unsigned char *eventlog1, unsigned int *nBytes1,
unsigned char *eventlog2, unsigned int *nBytes2);
DWORD mxmEventLogAccessWriteDataFile(char *filename, unsigned char *dataFile, unsigned int nBytes);
bool mxmEventLogAccessCopyIntoDataFile(int deviceNum, unsigned long long address, char *filename,
unsigned int type);
bool mxmEventLogAccessBackup(char *filename, int type);

14
src/micetools/sysconf.h Normal file
View File

@ -0,0 +1,14 @@
// #define GAME_ID_0 'S'
// #define GAME_ID_1 'D'
// #define GAME_ID_2 'E'
// #define GAME_ID_3 'Y'
#define GAME_ID_0 'S'
#define GAME_ID_1 'D'
#define GAME_ID_2 'D'
#define GAME_ID_3 'K'
#define GAME_ID { GAME_ID_0, GAME_ID_1, GAME_ID_2, GAME_ID_3 }
#define HW_ID { 'A', 'A', 'S' }
#define MAIN_ID { 'A', 'A', 'S', 'E', '-', '0', '1', 'A', '6', '5', '6', '4' }
#define KEY_ID { 'A', '7', '2', 'E', '-', '0', '2', 'D', '1', '1', '2', '6', '1', '1', '1', '6' }

View File

@ -0,0 +1,134 @@
#include <Windows.h>
#include <setupapi.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "../lib/am/amDongle.h"
#include "../lib/am/amSerialId.h"
struct {
char keychipId[17];
char keychipSid[12];
char gameId[5];
unsigned char systemflag;
unsigned char modelType;
unsigned char region;
char networkAddress[16];
} amlibDongle;
AM_DONGLE_STATUS amlib_init_dongle(void) {
AM_DONGLE_STATUS err;
if ((err = amDongleInit()) != AM_DONGLE_STATUS_OK) return err;
do {
err = amDongleSetupKeychip();
} while (err == AM_DONGLE_STATUS_PENDING);
if (err != AM_DONGLE_STATUS_OK) return err;
if ((err = amDongleSetupKeychip()) != AM_DONGLE_STATUS_OK) return err;
if (!amDongleIsAvailable()) return AM_DONGLE_STATUS_NG;
if ((err = amDongleSetAuthConfig("toolmode")) != AM_DONGLE_STATUS_OK) return err;
if ((err = amDongleBillingGetKeychipId(amlibDongle.keychipId, AM_DONGLE_BLOCK)) !=
AM_DONGLE_STATUS_OK)
return err;
if (!amSerialIdConvert(amlibDongle.keychipId, amlibDongle.keychipSid))
return AM_DONGLE_STATUS_NG;
if ((err = amDongleGetGameId(amlibDongle.gameId, AM_DONGLE_BLOCK)) != AM_DONGLE_STATUS_OK)
return err;
if ((err = amDongleGetSystemFlag(&amlibDongle.systemflag, AM_DONGLE_BLOCK)) !=
AM_DONGLE_STATUS_OK)
return err;
if ((err = amDongleGetModelType(&amlibDongle.modelType, AM_DONGLE_BLOCK)) !=
AM_DONGLE_STATUS_OK)
return err;
if ((err = amDongleGetRegion(&amlibDongle.region, AM_DONGLE_BLOCK)) != AM_DONGLE_STATUS_OK)
return err;
unsigned int iNetworkAddress;
if ((err = amDongleGetNetworkAddress(&iNetworkAddress, AM_DONGLE_BLOCK)) != AM_DONGLE_STATUS_OK)
return err;
sprintf_s(amlibDongle.networkAddress, sizeof amlibDongle.networkAddress, "%d.%d.%d.%d",
iNetworkAddress & 0xff, (iNetworkAddress >> 8) & 0xff, (iNetworkAddress >> 16) & 0xff,
(iNetworkAddress >> 24) & 0xff);
return AM_DONGLE_STATUS_OK;
}
int main(int argc, char** argv) {
amDongleDebugLevel = 1;
if (argc != 3) {
fprintf(stderr, "Usage: %s <infile> <outfile>\n", argv[0]);
return -1;
}
if (!PathFileExistsA(argv[1])) {
fprintf(stderr, "%s: no such file or directory\n", argv[1]);
return -1;
}
// if (!PathFileExistsA(argv[2])) {
// fprintf(stderr, "%s: no such file or directory\n", argv[2]);
// return -1;
// }
WSADATA wsaData;
if (WSAStartup(2, &wsaData)) {
puts("Failed to WSAStartup");
return -1;
}
puts("Waiting for dongle");
AM_DONGLE_STATUS err;
err = amlib_init_dongle();
if (err != AM_DONGLE_STATUS_OK) {
printf("Failed to init dongle:%d\n", err);
amDongleExit();
return -1;
}
printf("Dumping using dongle %s, for %s\n", amlibDongle.keychipId, amlibDongle.gameId);
FILE* inFile;
FILE* outFile;
if (fopen_s(&inFile, argv[1], "rb")) {
puts("Failed to open infile");
amDongleExit();
return -1;
}
if (fopen_s(&outFile, argv[2], "wb")) {
puts("Failed to open outfile");
fclose(inFile);
amDongleExit();
return -1;
}
fseek(inFile, 0, 2);
size_t end = ftell(inFile);
fseek(inFile, 0, 0);
unsigned char ct[16];
unsigned char pt[16];
uint i = 0;
amDongleSetIv(AM_DONGLE_BLOCK);
while (1) {
if (fread_s(ct, sizeof ct, 16, 1, inFile) != 1) break;
amDongleDecrypt(ct, pt, AM_DONGLE_BLOCK);
fwrite(pt, 16, 1, outFile);
printf("\r%d/%d", i, end);
i += 16;
if (i % 512 == 0) fflush(outFile);
}
puts("");
fclose(inFile);
fclose(outFile);
puts("Done!");
amDongleExit();
return 0;
}

View File

@ -0,0 +1,341 @@
#include <Windows.h>
//
#include <SetupAPI.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "Setupapi.lib")
#include "../lib/am/amEeprom.h"
HANDLE mxkSmbusCreateDeviceFile() {
SP_DEVICE_INTERFACE_DATA interfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA_A interfaceDetail[204];
HDEVINFO DeviceInfoSet =
SetupDiGetClassDevsA(&MXSMBUS_GUID, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (DeviceInfoSet == INVALID_HANDLE_VALUE) {
return INVALID_HANDLE_VALUE;
}
interfaceData.cbSize = 28;
BOOL s;
s = SetupDiEnumDeviceInterfaces(DeviceInfoSet, NULL, &MXSMBUS_GUID, 0, &interfaceData);
if (!s) {
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return INVALID_HANDLE_VALUE;
}
interfaceDetail[0].cbSize = 5;
s = SetupDiGetDeviceInterfaceDetailA(DeviceInfoSet, &interfaceData, interfaceDetail,
sizeof interfaceDetail, NULL, NULL);
if (!s) {
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return INVALID_HANDLE_VALUE;
}
char fileName[260];
strcpy_s(fileName, sizeof fileName, interfaceDetail[0].DevicePath);
HANDLE device =
CreateFileA(fileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_SUPPORTS_GHOSTING, NULL);
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
return device;
}
typedef unsigned char byte;
typedef unsigned int uint;
#pragma pack(push, 1)
typedef struct {
unsigned char status;
unsigned char command;
unsigned short addr;
unsigned short command_code;
unsigned char nbytes;
unsigned char data[32];
} i2c_packet;
typedef struct {
unsigned char status;
unsigned char command;
unsigned char addr;
unsigned char command_code;
unsigned char nbytes;
unsigned char data[32];
} smb_packet;
#pragma pack(pop)
HANDLE MXSMBUS;
int smbusWriteI2C(byte addr, byte command, byte* buffer, byte nbytes) {
i2c_packet io_buf;
io_buf.addr = addr;
io_buf.command_code = (command << 8) | *buffer;
io_buf.nbytes = (char)nbytes - 1;
io_buf.status = 0;
io_buf.command = 8;
memcpy(io_buf.data, buffer + 1, (uint)io_buf.nbytes);
byte bVar3;
for (bVar3 = 0; bVar3 < 5; bVar3++) {
DWORD bytesReturned;
BOOL success = DeviceIoControl(MXSMBUS, IOCTL_MXSMBUS_I2C, &io_buf, sizeof io_buf, &io_buf,
sizeof io_buf, &bytesReturned, NULL);
if (!success || bytesReturned != sizeof io_buf) {
return -9;
}
if (io_buf.status == 0) break;
if (io_buf.status != 24) return -9;
Sleep(16);
}
return bVar3 == 5 ? -9 : 0;
}
int dsReadByte(byte addr, byte* readByte, byte cmd_code) {
smb_packet buffer;
buffer.command_code = cmd_code;
buffer.status = 0;
buffer.command = 5;
buffer.nbytes = 0;
buffer.data[0] = 0;
buffer.data[1] = 0;
buffer.addr = addr;
DWORD bytesReturned;
BOOL success = DeviceIoControl(MXSMBUS, IOCTL_MXSMBUS_REQUEST, &buffer, sizeof buffer, &buffer,
sizeof buffer, &bytesReturned, NULL);
if (success && buffer.status == 0 && bytesReturned == sizeof buffer) {
*readByte = buffer.data[0];
return 0;
}
return -8;
}
bool mxkDsExioWaitNotBusy(void) {
while (true) {
byte val = 0;
if (dsReadByte(0x54, &val, 0) == 0) return true;
Sleep(10);
}
return false;
}
int mxkDsExioWriteInputBuffer(byte* buffer) {
uint offset = 0;
uint uVar1 = 0;
while (uVar1 < 64) {
uint nbytes;
if (64 - uVar1 < 9) {
nbytes = 64 - offset & 0xffff;
} else {
nbytes = 8;
}
if (smbusWriteI2C(0x54, offset & 0xff, buffer, nbytes & 0xff) != 0) return -9;
if (!mxkDsExioWaitNotBusy()) return -10;
offset += nbytes;
uVar1 = offset & 0xffff;
buffer += nbytes;
}
return 0;
}
int smbusWriteByte(byte v_addr, byte command_code, byte data) {
smb_packet packet;
packet.command_code = command_code;
packet.data[0] = data;
packet.status = 0;
packet.command = 4;
packet.nbytes = 0;
packet.data[1] = 0xff;
packet.addr = v_addr;
DWORD bytesReturned;
BOOL success = DeviceIoControl(MXSMBUS, IOCTL_MXSMBUS_REQUEST, &packet, sizeof packet, &packet,
sizeof packet, &bytesReturned, NULL);
if (!success) {
printf("DIO failed %03x\n", GetLastError());
return -9;
}
if (packet.status != 0) {
printf("Packet status: %d\n", packet.status);
return -9;
}
if (bytesReturned != sizeof packet) return -9;
return 0;
}
int mxkDsExioRequestComputeMac(void) {
if (smbusWriteByte(0x54, 0x5c, 0x94) != 0) return -9;
if (!mxkDsExioWaitNotBusy()) return -10;
return 0;
}
int mxkDsExioReadMacOutputBuffer(byte* macBuffer) {
byte cmd_code = 0x40;
for (int i = 0; i < 20; i++, cmd_code++) {
if (dsReadByte(0x54, &(macBuffer[i]), cmd_code) != 0) return -8;
}
return 0;
}
int mxkDsKeychipReadEeprom(byte* pageData, byte page) {
if (page > 3) return -2;
byte addr = page << 5;
for (int i = 0; i < 32; i++, addr++) {
if (dsReadByte(0x55, &(pageData[i]), addr) != 0) return -8;
}
return 0;
}
byte INPUT_BUFFER[64] = {
// Random (0:4 bytes --> [takes the first 4 bytes of the secret])
0,
0,
0,
0,
// Eeprom (4:32 bytes)
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
// Challenge low (36:4 bytes)
0x76,
0x76,
0x76,
0x76,
// Page (40:1 byte)
0x43,
// ID (41:7 bytes)
0x41,
0x42,
0x43,
0x44,
0x45,
0x46,
0x47,
// Random (48:4 bytes --> takes the last 4 bytes of the secret)
0,
0,
0,
0,
// Challenge high (52:3 bytes)
0x77,
0x77,
0x77,
// Random (55:9 bytes)
0, // --> takes value 0x80
0, // --> takes 0
0, // > ...
0, // > ...
0, // > ...
0, // > ...
0, // > ...
0, // --> takes value 0x01
0, // --> takes value 0xB8
};
/**
* Expected output:
*
* 1a e7 2d 24 8c b4 e3 40 fb 62 7d be 63 65 eb 25 70 5f d4 e3
*/
int exio_mac_test(byte* buffer) {
// puts("mxkDsExioWriteInputBuffer...");
if (mxkDsExioWriteInputBuffer(buffer)) {
puts("mxkDsExioWriteInputBuffer failed");
return -1;
}
// puts("mxkDsExioRequestComputeMac...");
if (mxkDsExioRequestComputeMac()) {
puts("mxkDsExioRequestComputeMac failed");
return -1;
}
byte mac[20];
// puts("mxkDsExioReadMacOutputBuffer...");
if (mxkDsExioReadMacOutputBuffer(mac)) {
puts("mxkDsExioReadMacOutputBuffer failed");
return -1;
}
// puts("Output mac:");
for (int i = 0; i < 20; i++) {
printf("%02x", mac[i]);
}
puts("");
return 0;
}
int keychip_ds_eeprom_dump(void) {
byte pageData[32];
for (int page = 0; page < 4; page++) {
printf("Page %d\n", page);
if (mxkDsKeychipReadEeprom(pageData, page)) {
puts("Read failed");
}
for (int i = 0; i < 32; i++) {
printf("%02x", pageData[i]);
}
puts("");
}
return 0;
}
int main(int argc, char** argv) {
MXSMBUS = mxkSmbusCreateDeviceFile();
if (MXSMBUS == INVALID_HANDLE_VALUE) {
puts("Unable to open smbus");
return -1;
}
byte buffer[sizeof INPUT_BUFFER];
for (int i = 0; i < sizeof INPUT_BUFFER; i++) {
printf("%02d: ", i);
memcpy(buffer, INPUT_BUFFER, sizeof INPUT_BUFFER);
buffer[i] = 0x69;
exio_mac_test(buffer);
}
// keychip_ds_eeprom_dump();
CloseHandle(MXSMBUS);
return 0;
}

View File

@ -43,3 +43,31 @@ executable(
'micemonitor.c',
],
)
executable(
'exio_test',
win_subsystem: subsystem,
sources: [
'exio_test.c',
],
)
executable(
'dongleDecrypt',
win_subsystem: subsystem,
sources: [
'dongleDecrypt.c',
],
link_with: [
amDongle,
amSerialId,
],
)
executable(
'testBin',
win_subsystem: subsystem,
sources: [
'test.c',
],
)

View File

@ -46,9 +46,9 @@ AM_DONGLE_STATUS amlib_init_dongle(void) {
if ((err = amDongleGetNetworkAddress(&iNetworkAddress, AM_DONGLE_BLOCK)) != AM_DONGLE_STATUS_OK)
return err;
sprintf(amlibDongle.networkAddress, "%d.%d.%d.%d", iNetworkAddress & 0xff,
(iNetworkAddress >> 8) & 0xff, (iNetworkAddress >> 16) & 0xff,
(iNetworkAddress >> 24) & 0xff);
sprintf_s(amlibDongle.networkAddress, sizeof amlibDongle.networkAddress, "%d.%d.%d.%d",
iNetworkAddress & 0xff, (iNetworkAddress >> 8) & 0xff, (iNetworkAddress >> 16) & 0xff,
(iNetworkAddress >> 24) & 0xff);
return AM_DONGLE_STATUS_OK;
}
@ -94,5 +94,18 @@ void miceDumpKCMxkeychip(void) {
amDongleBillingGetNearfull(&billingData, AM_DONGLE_BLOCK);
printf(" Nearfull: %08x\n", billingData);
unsigned char seed[16];
amDongleGetSeed(seed, AM_DONGLE_BLOCK);
printf(" Seed: ");
for (int i = 0; i < sizeof seed; i++) printf("%02x", seed[i]);
puts("");
unsigned char keyfile[16];
amDongleSetIv(AM_DONGLE_BLOCK);
amDongleEncrypt(seed, keyfile, AM_DONGLE_BLOCK);
printf(" Keyfile: ");
for (int i = 0; i < sizeof keyfile; i++) printf("%02x", keyfile[i]);
puts("");
amDongleExit();
}

View File

@ -3,6 +3,10 @@
#include "../lib/am/amPlatform.h"
static const char* sBoardType[] = {
"RingEdge", "RingWide (Spec 1)", "RingWide (Spec 2)", "RingEdge 2", "Unknown",
};
void miceDumpPlatform(void) {
fprintf(stderr, "Dumping platform information using %s\n", amPlatformVersion);
@ -11,6 +15,6 @@ void miceDumpPlatform(void) {
AM_PLATFORM_PLATFORM_ID platformId;
amPlatformGetPlatformId(&platformId);
printf("Board type: %d\n", boardType);
printf("Board type: %s\n", sBoardType[boardType]);
printf("Platform ID: %s\n", platformId.strPlatformId);
}

View File

@ -32,8 +32,8 @@ BOOL change_region(BYTE region) {
puts("");
data[12] = region;
amCrc32RCreateTable();
((DWORD*)data)[0] = amCrc32RGet(sizeof data - 4, data + 4, 0);
amiCrc32RInit();
((DWORD*)data)[0] = amiCrc32RCalc(sizeof data - 4, data + 4, 0);
amEepromWrite(0, data, sizeof data);
amEepromRead(0, data, sizeof data);

55
src/micetools/util/test.c Normal file
View File

@ -0,0 +1,55 @@
#include <stdio.h>
#include <Windows.h>
char path[MAX_PATH * 1000];
int main(int argc, char** argv) {
// printf("%d", QueryDosDeviceA(NULL, path, sizeof path));
// printf(" %03x\n", GetLastError());
// char* pPath = path;
// while (1) {
// size_t len = strlen(pPath);
// if (!len) break;
// puts(pPath);
// pPath += len + 1;
// }
DWORD volumeSerialNumber;
// Crackproof-style call
BOOL ret = GetVolumeInformationA(
"C:\\",
NULL,
0,
&volumeSerialNumber,
NULL,
NULL,
NULL,
0
);
printf("volumeSerialNumber: %08x\n");
// Exhaustive call
CHAR volumeNameBuffer[MAX_PATH];
DWORD maximumComponentLength;
DWORD fileSystemFlags;
CHAR fileSystemName[MAX_PATH];
ret = GetVolumeInformationA(
"C:\\",
volumeNameBuffer,
sizeof volumeNameBuffer,
&volumeSerialNumber,
&maximumComponentLength,
&fileSystemFlags,
fileSystemName,
sizeof fileSystemName
);
printf("volumeNameBuffer: %s\n", volumeNameBuffer);
printf("volumeSerialNumber: %08x\n", volumeSerialNumber);
printf("maximumComponentLength: %08x\n", maximumComponentLength);
printf("fileSystemFlags: %08x\n", fileSystemFlags);
printf("fileSystemName: %s\n", fileSystemName);
return 0;
}

View File

@ -0,0 +1,21 @@
*00503de8: 00000000 > 01000000 # amBackupDebugLevel
*005052c0: 00000000 > 01000000 # amDipswDebugLevel
*00500990: 00000000 > 01000000 # amDongleDebugLevel
*00503de4: 00000000 > 01000000 # amEepromDebugLevel
*005057bc: 00000000 > 01000000 # amGcatcherDebugLevel
*00505cd4: 00000000 > 01000000 # amGdeliverDebugLevel
*0050674c: 00000000 > 01000000 # amGfetcherDebugLevel
*00504990: 00000000 > 01000000 # amHmDebugLevel
*00505d20: 00000000 > 01000000 # amInstallDebugLevel
*00500980: 00000000 > 01000000 # amiTimerDebugLevel
*005049a0: 00000000 > 01000000 # amMasterDebugLevel
*00504418: 00000000 > 01000000 # amNetworkDebugLevel
*00506798: 00000000 > 01000000 # amPlatformDebugLevel
*005041f8: 00000000 > 01000000 # amRtcDebugLevel
*00504410: 00000000 > 01000000 # amSramDebugLevel
*0050690c: 00000000 > 01000000 # libpcpDebugLevel
*004f48bc: 01000000 > 05000000 # ALPB_DEBUG_PRINT::m_systemLogLevel
*00506eec: 00000000 > 00000000 # ALPB_DEBUG_PRINT::m_debugPrintLevel

20
src/patches/nxAuth.patch Normal file
View File

@ -0,0 +1,20 @@
*0053bd94 : 00000000 > 01000000 # pcpDebugLevel
*0053bc18 : 00000000 > 01000000 # amEepromDebugLevel
*005376f8 : 00000000 > 01000000 # amDongleDebugLevel
*0053b068 : 00000000 > 01000000 # amHmDebugLevel
*0053b070 : 00000000 > 01000000 # amNetworkDebugLevel
*0053bc1c : 00000000 > 01000000 # amSramDebugLevel
*0053b5f0 : 00000000 > 01000000 # amBackupDebugLevel
*0053ba00 : 00000000 > 01000000 # amRtcDebugLevel
*0053b044 : 00000000 > 01000000 # amGcatcherDebugLevel
*005376e0 : 00000000 > 01000000 # amiTimerDebugLevel
*0053bc20 : 00000000 > 01000000 # amPlatformDebugLevel
*0040e284 : 896e08896c2424 > c7460801000000 # Manager debug level
*0040b9a0 : 895e08895c2418 > c7460801000000 # 1
*0040daa0 : 895e08895c2418 > c7460801000000 # 2
*0040e011 : 897e08897c241c > c7460801000000 # 3
*0040cf02 : 895e08895c241c > c7460801000000 # 4
*00410a52 : 897e08897c241c > c7460801000000 # 5
*00410e81 : 895e08895c241c > c7460801000000 # 6
*004115dd : c7460800000000 > c7460801000000 # 7
*0040939b : 895e088b442420 > c7460801000000 # 8

View File

@ -9,4 +9,6 @@ ALLNetProc.exe: ALLNetProc.patch
Game.exe: Game.patch
mxnetwork.exe: mxnetwork.patch
maimai_dump_.exe: maimai_dump_.patch
RingGame.exe: UnderNightInBirthExLate[st].patch
RingGame.exe: UnderNightInBirthExLate[st].patch
nxAuth.exe: nxAuth.patch
ALLNetProc_Win.exe: ALLNetProc_Win.patch