Idk if this is even stable
This commit is contained in:
parent
8bd3bb38cb
commit
eb7bcb1a1b
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,4 +3,3 @@ build/
|
||||
builddir/
|
||||
srcdir/
|
||||
.vscode/
|
||||
openssl-1.0.1/
|
||||
|
3
Makefile
3
Makefile
@ -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"
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
45
src/micetools/dll/devices/_ds_sha.c
Normal file
45
src/micetools/dll/devices/_ds_sha.c
Normal 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;
|
||||
}
|
||||
}
|
1
src/micetools/dll/devices/_ds_sha.h
Normal file
1
src/micetools/dll/devices/_ds_sha.h
Normal file
@ -0,0 +1 @@
|
||||
void ComputeDallasSha(unsigned char *MT, long *A, long *B, long *C, long *D, long *E);
|
@ -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',
|
||||
)
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
#define EEPROM_DUMP L"dev/eeprom.bin"
|
||||
|
||||
#include "../../sysconf.h"
|
||||
|
||||
// 8192 x 8 (64kbit) of eeprom
|
||||
BYTE EEPROM_DATA[0x2000];
|
||||
|
||||
@ -41,7 +43,7 @@ void eeprom_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)
|
||||
|
||||
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);
|
15
src/micetools/dll/devices/smb_at24c64an.h
Normal file
15
src/micetools/dll/devices/smb_at24c64an.h
Normal 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)
|
@ -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;
|
||||
}
|
||||
}
|
144
src/micetools/dll/devices/smb_ds2460.c
Normal file
144
src/micetools/dll/devices/smb_ds2460.c
Normal 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;
|
||||
}
|
||||
}
|
42
src/micetools/dll/devices/smb_ds2460.h
Normal file
42
src/micetools/dll/devices/smb_ds2460.h
Normal 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))
|
200
src/micetools/dll/devices/smb_ds28cn01.c
Normal file
200
src/micetools/dll/devices/smb_ds28cn01.c
Normal 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;
|
||||
}
|
||||
}
|
43
src/micetools/dll/devices/smb_ds28cn01.h
Normal file
43
src/micetools/dll/devices/smb_ds28cn01.h
Normal 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))
|
@ -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;
|
||||
}
|
||||
}
|
@ -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' },
|
||||
N2_KEYCHIP_INFO n2_keychip_info = { .m_KeyId = KEY_ID,
|
||||
.m_Appboot = {
|
||||
.m_Format = 1,
|
||||
.m_GameId = { 'S' , 'D', 'E', 'Y' },
|
||||
.m_GameId = GAME_ID,
|
||||
.m_Region = 0xff,
|
||||
.m_ModelType = 2,
|
||||
.m_SystemFlag = 0x24,
|
||||
.m_PlatformId = {'A', 'A', 'S'},
|
||||
.m_PlatformId = HW_ID,
|
||||
.m_DvdFlag = 1,
|
||||
.m_NetworkAddr = (192 << 0) | (168 << 8) | (103 << 16) | (0 << 24),
|
||||
}
|
||||
};
|
||||
.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 { \
|
||||
|
@ -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
|
||||
|
14
src/micetools/dll/devices/smb_pca9535.h
Normal file
14
src/micetools/dll/devices/smb_pca9535.h
Normal 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)
|
@ -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;
|
||||
|
@ -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'},
|
||||
@ -496,56 +502,6 @@ jvs_board_t under_night_jvs_config[2] = {
|
||||
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_13551_ID,
|
||||
},
|
||||
{
|
||||
.test_keybind = VK_OEM_4, // [{
|
||||
.coin_keybinds = {0, 0},
|
||||
.keybinds = {
|
||||
{
|
||||
0, 0, 0, 0, 0, 0,
|
||||
'J', // D (EXCs)
|
||||
@ -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;
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
||||
*/
|
||||
}
|
110
src/micetools/dll/hooks/drive/disks.c
Normal file
110
src/micetools/dll/hooks/drive/disks.c
Normal 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,
|
||||
};
|
82
src/micetools/dll/hooks/drive/disks.h
Normal file
82
src/micetools/dll/hooks/drive/disks.h
Normal 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[];
|
||||
};
|
743
src/micetools/dll/hooks/drive/drive.c
Normal file
743
src/micetools/dll/hooks/drive/drive.c
Normal 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
|
||||
*/
|
||||
}
|
149
src/micetools/dll/hooks/drive/drive.h
Normal file
149
src/micetools/dll/hooks/drive/drive.h
Normal 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;
|
279
src/micetools/dll/hooks/drive/hooks.c
Normal file
279
src/micetools/dll/hooks/drive/hooks.c
Normal 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);
|
||||
}
|
375
src/micetools/dll/hooks/drive/irb.h
Normal file
375
src/micetools/dll/hooks/drive/irb.h
Normal 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;
|
417
src/micetools/dll/hooks/drive/physicalDrive.c
Normal file
417
src/micetools/dll/hooks/drive/physicalDrive.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +1,16 @@
|
||||
#pragma once
|
||||
#include "../common.h"
|
||||
#include <stdint.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
|
||||
|
||||
// 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,
|
133
src/micetools/dll/hooks/drivers/framework.c
Normal file
133
src/micetools/dll/hooks/drivers/framework.c
Normal 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
|
||||
}
|
483
src/micetools/dll/hooks/drivers/framework.h
Normal file
483
src/micetools/dll/hooks/drivers/framework.h
Normal 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);
|
59
src/micetools/dll/hooks/drivers/mxhwreset.c
Normal file
59
src/micetools/dll/hooks/drivers/mxhwreset.c
Normal 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;
|
||||
}
|
@ -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) {
|
||||
}
|
||||
}
|
||||
|
||||
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())) {
|
||||
// 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] == '\\')) {
|
||||
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,
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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',
|
||||
)
|
@ -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,
|
||||
// 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);
|
||||
}
|
||||
|
@ -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;
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -25,6 +25,7 @@ shared_library(
|
||||
dmi_lib,
|
||||
mice_lib,
|
||||
amiTimer,
|
||||
amiMd5,
|
||||
mxklib,
|
||||
],
|
||||
include_directories: [
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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))) {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
129
src/micetools/lib/ami/amiMd5.c
Normal file
129
src/micetools/lib/ami/amiMd5.c
Normal 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];
|
||||
}
|
@ -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);
|
@ -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) {
|
||||
|
@ -18,3 +18,10 @@ amiDebug = static_library(
|
||||
'amiDebug.c',
|
||||
],
|
||||
)
|
||||
|
||||
amiMd5 = static_library(
|
||||
'amiMd5',
|
||||
sources: [
|
||||
'amiMd5.c',
|
||||
],
|
||||
)
|
||||
|
@ -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: ??
|
||||
|
@ -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)) {
|
||||
|
@ -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) \
|
||||
|
@ -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")
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
goto LAB_0040574e;
|
||||
code_r0x004056a9:
|
||||
if (appLauncher->m_createdThread) {
|
||||
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;
|
||||
}
|
||||
// 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_processStateChange = false;
|
||||
}
|
||||
|
||||
// mxMaster->m_serverState = 2;
|
||||
// while (1) {
|
||||
// err = mxmPcpServer(mxMaster);
|
||||
// if (err != e_pcpp_ok) amiDebugLog("Server tick: %d", err);
|
||||
// }
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -19,6 +19,8 @@ executable(
|
||||
amiDebug,
|
||||
amDongle,
|
||||
amInstall,
|
||||
amiMd5,
|
||||
amiCrc,
|
||||
],
|
||||
include_directories: incdir,
|
||||
dependencies: [],
|
||||
|
@ -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;
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
14
src/micetools/sysconf.h
Normal 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' }
|
134
src/micetools/util/dongleDecrypt.c
Normal file
134
src/micetools/util/dongleDecrypt.c
Normal 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;
|
||||
}
|
341
src/micetools/util/exio_test.c
Normal file
341
src/micetools/util/exio_test.c
Normal 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;
|
||||
}
|
@ -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',
|
||||
],
|
||||
)
|
||||
|
@ -46,8 +46,8 @@ 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,
|
||||
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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
@ -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
55
src/micetools/util/test.c
Normal 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;
|
||||
}
|
21
src/patches/ALLNetProc_Win.patch
Normal file
21
src/patches/ALLNetProc_Win.patch
Normal 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
20
src/patches/nxAuth.patch
Normal 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
|
@ -10,3 +10,5 @@ Game.exe: Game.patch
|
||||
mxnetwork.exe: mxnetwork.patch
|
||||
maimai_dump_.exe: maimai_dump_.patch
|
||||
RingGame.exe: UnderNightInBirthExLate[st].patch
|
||||
nxAuth.exe: nxAuth.patch
|
||||
ALLNetProc_Win.exe: ALLNetProc_Win.patch
|
||||
|
Loading…
Reference in New Issue
Block a user