1
0
mirror of synced 2024-11-12 00:40:47 +01:00

Large amount of stuff leading up to fully networking maimai

This commit is contained in:
Bottersnike 2023-05-19 15:16:07 +01:00
parent d3ff2e7c24
commit 50737e6011
No known key found for this signature in database
69 changed files with 3423 additions and 445 deletions

View File

@ -81,10 +81,10 @@ short comdev_read_blocking(com_device_t* com, unsigned char* buffer, short bytes
}
return ringbuf_read(&com->in, buffer, bytes);
}
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes) {
short comdev_read(com_device_t* com, LPVOID buffer, short bytes) {
return ringbuf_read(&com->in, buffer, bytes);
}
bool comdev_write(com_device_t* com, const unsigned char* buffer, short bytes) {
bool comdev_write(com_device_t* com, LPCVOID buffer, short bytes) {
bool ret = ringbuf_write(&com->out, buffer, bytes);
SetEvent(com->dataOutReady);
return ret;
@ -93,7 +93,7 @@ short comdev_available(com_device_t* com) { return ringbuf_available(&com->in);
BYTE comdev_peek(com_device_t* com) { return com->in.buffer[com->in.read]; }
// Read data from a com device, unescaping as we go
void comio_read(com_device_t* com, BYTE* data, BYTE len) {
void comio_read(com_device_t* com, LPVOID data, BYTE len) {
BYTE one_byte;
for (; len; len--) {
comdev_read_blocking(com, &one_byte, 1);
@ -101,14 +101,14 @@ void comio_read(com_device_t* com, BYTE* data, BYTE len) {
comdev_read_blocking(com, &one_byte, 1);
one_byte++;
}
*(data++) = one_byte;
*(((LPBYTE)data)++) = one_byte;
}
}
// Write data to a com device, escaping as we go
void comio_write(com_device_t* com, BYTE* data, BYTE len) {
void comio_write(com_device_t* com, LPCVOID data, BYTE len) {
BYTE one_byte;
for (; len; len--) {
one_byte = *(data++);
one_byte = *(((LPBYTE)data)++);
if (one_byte == COMIO_MARK || one_byte == COMIO_SYNC) {
BYTE mark = COMIO_MARK;
comdev_write(com, &mark, 1);
@ -117,7 +117,7 @@ void comio_write(com_device_t* com, BYTE* data, BYTE len) {
comdev_write(com, &one_byte, 1);
}
}
unsigned char 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, LPVOID data) {
BYTE one_byte;
do {
if (comdev_available(com) < (sizeof *head + 1)) {
@ -140,7 +140,7 @@ unsigned char comio_next_req(com_device_t* com, comio_recv_head_t* head, BYTE* d
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) {
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len, LPCVOID data) {
BYTE one_byte;
one_byte = COMIO_SYNC;
comdev_write(com, &one_byte, 1);
@ -161,7 +161,7 @@ void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE le
// Checksum
one_byte = 0;
for (BYTE i = 0; i < sizeof resp; i++) one_byte += ((LPBYTE)&resp)[i];
for (BYTE i = 0; i < len; i++) one_byte += data[i];
for (BYTE i = 0; i < len; i++) one_byte += ((LPBYTE)data)[i];
comio_write(com, &one_byte, 1);
}

View File

@ -22,6 +22,7 @@ struct com_device {
};
com_device_t* com_devices[NUM_COM_PORTS];
#pragma pack(push, 1)
typedef struct {
BYTE frame_length;
BYTE dst;
@ -38,6 +39,7 @@ typedef struct {
BYTE status;
BYTE length;
} comio_resp_head_t;
#pragma pack(pop)
#define COMIO_SYNC 0xE0
#define COMIO_MARK 0xD0
@ -45,17 +47,17 @@ typedef struct {
#define COMIO_STATUS_OK 0
#define COMIO_STATUS_NG 1
short comdev_read_blocking(com_device_t* com, unsigned char* buffer, short bytes);
short comdev_read(com_device_t* com, unsigned char* buffer, short bytes);
bool comdev_write(com_device_t* com, const unsigned char* buffer, short bytes);
short comdev_read_blocking(com_device_t* com, LPVOID buffer, short bytes);
short comdev_read(com_device_t* com, LPVOID buffer, short bytes);
bool comdev_write(com_device_t* com, LPCVOID buffer, short bytes);
short comdev_available(com_device_t* com);
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_read(com_device_t* com, LPVOID data, BYTE len);
void comio_write(com_device_t* com, LPCVOID data, BYTE len);
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);
unsigned char comio_next_req(com_device_t* com, comio_recv_head_t* head, LPVOID data);
void comio_reply(com_device_t* com, comio_recv_head_t* req, BYTE status, BYTE len, LPCVOID data);
com_device_t* new_com_device(BYTE port);
BOOL attach_com_device(BYTE port, FnComDeviceThread* thread);

View File

@ -1,6 +1,8 @@
devices_files = files(
'_ds_sha.c',
'_devices.c',
'nfc/felica.c',
'nfc/bng.c',
# Serial devices
'ser_led_bd.c',
'ser_maitouch.c',

View File

@ -0,0 +1,127 @@
#include "bng.h"
#include <stdlib.h>
#include "../../../lib/mice/blowfish.h"
#include "../../../lib/mice/des.h"
// Are these SEGA-specific or used for all FeliCa cards?
// Commentary: The MAC validation code in bnacard can take a key as an argument
// and uses the below key if NULL is passed (which it is).
// The NbgiAccessCode library names this `ucFK` which doesn't feel
// like a name someone would pick out of the blue.
DWORD64 CK_GEN_KEY[3] = { 0x1223491caf37206d, 0x5f3f1d16badd58a2, 0xc2f2ea946a755ee7 };
#pragma pack(push, 1)
typedef struct BNG_SIGNED_BLOCK {
WORD m_BNAVersion;
BYTE m_Name[6];
DWORD m_BFLeft;
DWORD m_BFRight;
} BNG_SIGNED_BLOCK, *PBNG_SIGNED_BLOCK;
#pragma pack(pop)
typedef struct {
char m_Name[8];
BYTE m_Key[56];
BYTE Unk40[72];
} BLOWFISH_KEY;
static BLOWFISH_KEY DataKeyNBGIC[3] = {
{
.m_Name = { 'N', 'B', 'G', 'I', 'C', '0', '\0', '\0' },
.m_Key = { 0x6b, 0xf9, 0xe0, 0x22, 0x4b, 0x14, 0xa9, 0x51, 0xd4, 0x3d, 0xb6, 0x2d,
0x2a, 0x99, 0x47, 0xd8, 0xb2, 0x78, 0x80, 0x35, 0x8e, 0x71, 0x16, 0xeb,
0xa0, 0x00, 0x01, 0x3e, 0x8c, 0xfe, 0xf6, 0x09, 0x02, 0xa9, 0x59, 0x5d,
0x4c, 0x25, 0xfe, 0xff, 0x74, 0x3f, 0xc8, 0xd8, 0xe0, 0x75, 0x6a, 0xe6,
0x18, 0xef, 0x8b, 0x72, 0x12, 0xde, 0x5a, 0x4b },
.Unk40 = { 0x97, 0xba, 0xa5, 0x1b, 0x46, 0x04, 0x87, 0x43, 0x9f, 0x21, 0x5b, 0xe9,
0xe1, 0xd0, 0x98, 0x72, 0x27, 0x91, 0x31, 0xba, 0x8a, 0x82, 0x8f, 0xab,
0x50, 0x7f, 0x44, 0x7f, 0x8b, 0xc5, 0xe3, 0x4a, 0xc3, 0x32, 0xb7, 0xcb,
0xd8, 0x4f, 0xb1, 0x4c, 0x45, 0x21, 0x20, 0xe2, 0xa0, 0x71, 0x38, 0x4d,
0xe6, 0x95, 0x89, 0xc1, 0x5b, 0x04, 0x14, 0xc6, 0x9d, 0xcd, 0x03, 0x1c,
0xd0, 0xa8, 0x15, 0x3a, 0xf4, 0x6d, 0x3d, 0xea, 0x84, 0xec, 0xcd, 0x40 },
},
{
.m_Name = { 'N', 'B', 'G', 'I', 'C', '1', '\0', '\0' },
.m_Key = { 0x5e, 0x6b, 0xb1, 0x92, 0xc0, 0x52, 0x2f, 0x4c, 0xa0, 0x29, 0x6a, 0x1c,
0x98, 0x62, 0xfb, 0xeb, 0xac, 0xf5, 0xe1, 0xd7, 0x66, 0xe6, 0x34, 0x69,
0x40, 0x47, 0x5b, 0x96, 0xfe, 0x17, 0x89, 0x3d, 0x18, 0xae, 0x98, 0xf8,
0xbd, 0x6d, 0xfa, 0x12, 0xd6, 0xcd, 0xf5, 0x81, 0x7b, 0x78, 0xd6, 0x60,
0x71, 0x8f, 0x7a, 0x28, 0xca, 0x3c, 0xfd, 0x2f },
.Unk40 = { 0xa6, 0x29, 0x78, 0x80, 0x63, 0xae, 0xa3, 0xa7, 0x84, 0xdd, 0x24, 0x60,
0x62, 0x86, 0x10, 0x97, 0x80, 0x75, 0xb4, 0x3d, 0x44, 0x81, 0xc9, 0x9f,
0xf4, 0x4a, 0xf7, 0xfd, 0xe4, 0xc8, 0x96, 0xcb, 0x9c, 0x2f, 0x3b, 0x6d,
0x95, 0xfe, 0x49, 0x54, 0x9d, 0x36, 0xea, 0x58, 0xcb, 0xf4, 0x0e, 0x06,
0x42, 0xfa, 0x6f, 0xb5, 0x1b, 0xc7, 0x88, 0x50, 0xea, 0x7b, 0x5f, 0x60,
0x56, 0xdb, 0x6f, 0x03, 0xd7, 0x84, 0x75, 0x4e, 0x07, 0x9d, 0xbc, 0x05 },
},
{
.m_Name = { 'N', 'B', 'G', 'I', 'C', '2', '\0', '\0' },
.m_Key = { 0xde, 0x15, 0x00, 0x6f, 0x45, 0xe2, 0x73, 0x66, 0xaa, 0x74, 0x8f, 0x98,
0x14, 0x6e, 0x05, 0x7b, 0x52, 0x18, 0x29, 0xd5, 0x0a, 0x65, 0xa9, 0x0c,
0xfe, 0xca, 0xd3, 0x8e, 0x04, 0xcf, 0x3e, 0x72, 0x31, 0xfb, 0x76, 0x50,
0xfb, 0x8c, 0x67, 0x09, 0x95, 0x08, 0xff, 0xf0, 0xc2, 0x97, 0x31, 0x5f,
0xde, 0x6c, 0x54, 0x32, 0xec, 0x8e, 0x2c, 0x6c },
.Unk40 = { 0xc0, 0x6c, 0xa9, 0x7d, 0xd1, 0x10, 0x35, 0xc2, 0xa8, 0x6d, 0x52, 0xfc,
0x0a, 0x8c, 0x1a, 0xf7, 0xd1, 0x61, 0xea, 0x40, 0x49, 0x86, 0x7f, 0x37,
0x3f, 0xd1, 0x84, 0x2e, 0x98, 0xd9, 0x6d, 0x2c, 0x5e, 0x80, 0xe0, 0xe1,
0x92, 0x7c, 0xf2, 0x09, 0xef, 0x11, 0x44, 0x29, 0xe9, 0x4b, 0xb9, 0x3a,
0x87, 0x27, 0x5c, 0xa8, 0x05, 0xca, 0xfc, 0xcd, 0x3f, 0x21, 0x91, 0x17,
0xf5, 0x05, 0x6b, 0x82, 0x6b, 0x47, 0xdc, 0x06, 0x75, 0x1f, 0x04, 0x30 },
},
};
void NbgiWriteBNESignedBlock(PNFC_CARD lpCard, BYTE block, BYTE nKey, LPBYTE lpData) {
if (nKey > 2) return;
PBNG_SIGNED_BLOCK lpBlock = (PBNG_SIGNED_BLOCK)&lpCard->m_FeliCaData.m_UserBlocks[block].bytes;
lpBlock->m_BNAVersion = 0x200;
memcpy(lpBlock->m_Name, DataKeyNBGIC[nKey].m_Name, 6);
lpData[7] = lpData[0] ^ lpData[1] ^ lpData[2] ^ lpData[3] ^ lpData[4] ^ lpData[5] ^ lpData[6];
DWORD dataLeft = ((LPDWORD)lpData)[0];
DWORD dataRight = ((LPDWORD)lpData)[1];
BlowfishSetKey(DataKeyNBGIC[nKey].m_Key, _countof(DataKeyNBGIC[nKey].m_Key));
BlowfishEncrypt(&dataLeft, &dataRight);
lpBlock->m_BFLeft = dataLeft;
lpBlock->m_BFRight = dataRight;
}
static inline DWORD64 _FelicaMacCKNested(DWORD64 data, DWORD64 key) {
data = Mice3Des_3K(data, CK_GEN_KEY);
data ^= key;
data = Mice3Des_3K(data, CK_GEN_KEY);
return data;
}
void FelicaMacGenerateCK(DWORD64* ID, KEY_PAIR lpKeys) {
DWORD64 data = Mice3Des_3K(0x0, CK_GEN_KEY);
BOOL will_overflow = ((LPBYTE)&data)[0] & 0x80;
// Binary rotate left 1. While `<<= 1` would be lovely here, the carries
// are expected to be performed (incorrectly) to the right.
for (BYTE i = 0; i < 8; i++) {
if (i != 0 && ((LPBYTE)&data)[i] & 0x80) ((LPBYTE)&data)[i - 1] |= 1;
((LPBYTE)&data)[i] <<= 1;
}
if (will_overflow) ((LPBYTE)&data)[7] ^= 0x1b;
DWORD64 idKey = data ^ ID[1];
lpKeys[0] = _byteswap_uint64(_FelicaMacCKNested(ID[0], idKey));
((LPBYTE)&ID[0])[0] ^= 0x80;
lpKeys[1] = _byteswap_uint64(_FelicaMacCKNested(ID[0], idKey));
((LPBYTE)&ID[0])[0] ^= 0x80; // Undo our modification above
}
void FelicaMacGenerateSK(DWORD64* random, KEY_PAIR ck, KEY_PAIR lpSk) {
lpSk[0] = Mice3Des_2K(_byteswap_uint64(random[0]), ck);
lpSk[1] = lpSk[0] ^ _byteswap_uint64(random[1]);
lpSk[1] = Mice3Des_2K(lpSk[1], ck);
}
DWORD64 FelicaMacGenerateMAC(DWORD64* data, KEY_PAIR sk, DWORD64* random) {
DWORD64 mac = data[0] ^ random[0];
mac = Mice3Des_2K(_byteswap_uint64(mac), sk);
mac = mac ^ _byteswap_uint64(data[1]);
return Mice3Des_2K(mac, sk);
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <Windows.h>
#include "nfc.h"
typedef DWORD64 KEY_PAIR[2];
void NbgiWriteBNESignedBlock(PNFC_CARD lpCard, BYTE block, BYTE nKey, LPBYTE lpData);
void FelicaMacGenerateCK(DWORD64* ID, KEY_PAIR lpKeys);
void FelicaMacGenerateSK(DWORD64* random, KEY_PAIR ck, KEY_PAIR lpSk);
DWORD64 FelicaMacGenerateMAC(DWORD64* data, KEY_PAIR sk, DWORD64* random);

View File

@ -0,0 +1,423 @@
#include "../../../lib/mice/spad.h"
#include "../_devices.h"
#include "../ser_tn32msec.h"
#include "bng.h"
#include "nfc.h"
static const BYTE PMmTiming[6] = { 0x00, 0x00, 0x00, 0x01, 0x43, 0x00 };
#define DFC_BNG_EDY_0 0x8C
#define DFC_BNG_EDY_1 0xA2
#define DFC_BNG_LITE_0 0x00
#define DFC_BNG_LITE_1 0x3A
#define DFC_KNM_LITES_0 0x00
#define DFC_KNM_LITES_1 0x68
#define DFC_BNE_LITES_0 0x00
#define DFC_BNE_LITES_1 0x2A
#define DFC_SEGA_LITES_0 0x00
#define DFC_SEGA_LITES_1 0x78
#define DFC_TEST_0 0x00
#define DFC_TEST_1 0x00
static const BYTE ID_Arbitrary[6] = { 0x05, 0x73, 0x02, 0x01, 0x02, 0x00 };
inline static void _FelicaDumpChars(LPBYTE lpBytes, BYTE nBytes) {
printf("|");
for (int i = 0; i < nBytes; i++) {
BYTE chr = lpBytes[i];
if (' ' < chr && chr <= '~')
printf("%c", chr);
else
printf(".");
}
printf("|");
}
static void _FelicaDumpBlock(PNFC_CARD lpCard, BYTE block, BYTE nBytes, LPCSTR lpName) {
PFelicaBlock_t lpBlock;
if (block < 0xf)
lpBlock = &lpCard->m_FeliCaData.m_UserBlocks[block];
else
lpBlock = &lpCard->m_FeliCaData.m_SystemBlocks[block - 0x80];
printf("[%02X] ", block);
for (int i = 0; i < 8; i++) {
if (i < nBytes)
printf("%02X ", lpBlock->bytes[i]);
else
printf("-- ");
}
if (lpName)
printf("(%s)", lpName);
else
_FelicaDumpChars(lpBlock->bytes, 8);
printf("\n ");
for (int i = 8; i < 16; i++) {
if (i < nBytes)
printf("%02X ", lpBlock->bytes[i]);
else
printf("-- ");
}
if (!lpName) _FelicaDumpChars(&(lpBlock->bytes[8]), 8);
printf("\n");
}
void FelicaDumpCard(PNFC_CARD lpCard) {
for (BYTE block = 0; block < 15; block++) {
_FelicaDumpBlock(lpCard, block, 16, NULL);
}
_FelicaDumpBlock(lpCard, 0x80, 16, "RC");
_FelicaDumpBlock(lpCard, 0x81, 8, "MAC");
_FelicaDumpBlock(lpCard, 0x82, 16, "ID");
_FelicaDumpBlock(lpCard, 0x83, 16, "D_ID");
_FelicaDumpBlock(lpCard, 0x84, 2, "SER_C");
_FelicaDumpBlock(lpCard, 0x85, 2, "SYS_C");
_FelicaDumpBlock(lpCard, 0x86, 2, "CKV");
_FelicaDumpBlock(lpCard, 0x87, 16, "CK");
_FelicaDumpBlock(lpCard, 0x88, 13, "MC");
}
void FelicaPopulate(PNFC_CARD lpCard, PFELICA_ID lpFelicaId, PACCESS_CODE lpAccessCode) {
ZeroMemory(&lpCard->m_FeliCaData, sizeof lpCard->m_FeliCaData);
lpCard->m_Header.m_Type = CardType_FeliCa;
lpCard->m_Header.m_IdLen = sizeof(lpCard->m_FeliCa);
memcpy(&lpCard->m_FeliCa.m_IDm, lpFelicaId, sizeof *lpFelicaId);
// TODO: Toggle between suica and AIC mode.
lpCard->m_FeliCaData.m_EmuMode = FelicaEmulationMode_AIC;
lpCard->m_FeliCaData.m_AICVendor = FelicaAICVendor_Konami;
lpCard->m_FeliCa.m_PMm[0] = 0x00;
switch (lpCard->m_FeliCaData.m_EmuMode) {
case FelicaEmulationMode_Suica:
lpCard->m_FeliCa.m_PMm[1] = FelicaChipType_Mobile_Ver10;
lpCard->m_FeliCaData.m_SystemBlock_SYS_C.m_SYS_C = _byteswap_ushort(FelicaSystem_Suica);
// DFC shouldn't matter for Suica
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[0] = DFC_TEST_0;
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[1] = DFC_TEST_1;
break;
case FelicaEmulationMode_AIC:
lpCard->m_FeliCaData.m_SystemBlock_SYS_C.m_SYS_C =
_byteswap_ushort(FelicaSystem_FelicaLite);
/**
* The DFC code is used to identify the card manufacturer. Each
* manufacturer uses a different derivation algorithm for FeliCa ID
* to Access Code conversion, which AiMeDB is able to validate
* based on this information.
*
* This validation is performed as part of
* AiMe_DB_com_get_AiMeAccountS, added in AiMeDB version 4.0.0
*
* To the best of my knowledge this was added long after RingEdge
* was a dead platform, so isn't something we will need to concern
* ourselves with here.
*
* Maimai itself only does a check for if this is
* FelicaAICVendor_BandaiNamco_LiteS, in which case special
* handling is required.
*
* TODO: Right now things seem to test bad if it's _not_ a BNE card??
*/
switch (lpCard->m_FeliCaData.m_AICVendor) {
case FelicaAICVendor_BandaiNamcoGames:
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[0] = DFC_BNG_LITE_0;
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[1] = DFC_BNG_LITE_1;
break;
case FelicaAICVendor_BandaiNamcoEntertainment: {
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[0] = DFC_BNE_LITES_0;
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[1] = DFC_BNE_LITES_1;
BYTE block0D[8] = {
// TODO: Work backwards and figure out where the key is coming from
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, /*sum*/ 0x00,
};
NbgiWriteBNESignedBlock(lpCard, 0x0D, 0, block0D);
break;
}
case FelicaAICVendor_SEGA:
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[0] = DFC_SEGA_LITES_0;
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[1] = DFC_SEGA_LITES_1;
break;
case FelicaAICVendor_Konami:
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[0] = DFC_KNM_LITES_0;
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[1] = DFC_KNM_LITES_1;
break;
default:
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[0] = DFC_TEST_0;
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[1] = DFC_TEST_1;
break;
}
// Write the card IC type into the PMm
switch (lpCard->m_FeliCaData.m_AICVendor) {
case FelicaAICVendor_BandaiNamcoGames:
lpCard->m_FeliCa.m_PMm[1] = FelicaChipType_Lite;
break;
case FelicaAICVendor_BandaiNamcoEntertainment:
case FelicaAICVendor_SEGA:
case FelicaAICVendor_Konami:
default:
lpCard->m_FeliCa.m_PMm[1] = FelicaChipType_LiteS;
break;
}
break;
case FelicaEmulationMode_BNG:
default:
lpCard->m_FeliCa.m_PMm[1] = FelicaChipType_STD_RC_S915;
lpCard->m_FeliCaData.m_SystemBlock_SYS_C.m_SYS_C = _byteswap_ushort(FelicaSystem_NDEF);
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[0] = DFC_BNG_EDY_0;
lpCard->m_FeliCaData.m_SystemBlock_ID.m_DFC[1] = DFC_BNG_EDY_1;
break;
}
memcpy(&(lpCard->m_FeliCa.m_PMm[2]), PMmTiming, sizeof PMmTiming);
if (lpAccessCode) {
BYTE block0[16];
memcpy(&(block0[6]), lpAccessCode->m_AC, 10);
Spad0Encrypt(block0, block0);
memcpy(lpCard->m_FeliCaData.m_UserBlocks[0].bytes, block0, 16);
}
memset(lpCard->m_FeliCaData.m_UserBlocks[0x0e].bytes, 0xFF, 16);
memcpy(&lpCard->m_FeliCaData.m_SystemBlock_ID.m_FelicaId, lpFelicaId, sizeof *lpFelicaId);
memcpy(lpCard->m_FeliCaData.m_SystemBlock_ID.m_Arbitrary, ID_Arbitrary, sizeof ID_Arbitrary);
memcpy(&lpCard->m_FeliCaData.m_SystemBlock_D_ID.m_FelicaId, lpFelicaId, sizeof *lpFelicaId);
memcpy(lpCard->m_FeliCaData.m_SystemBlock_D_ID.m_PMm, lpCard->m_FeliCa.m_PMm,
sizeof lpCard->m_FeliCa.m_PMm);
#if 0
FelicaDumpCard(lpCard);
#endif
}
void FelicaPoll(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse, PNFC_CARD lpCard) {
FelicaPollRequest request = lpReq->m_Poll.m_Request;
lpResponse->m_FelicaLen = FelicaRespSize(lpResponse->m_Poll);
lpResponse->m_FelicaCommand = FelicaCommand_Poll_Response;
memcpy(&lpResponse->m_IDm, &lpReq->m_IDm, sizeof lpReq->m_IDm);
memcpy(lpResponse->m_Poll.m_PMm, lpCard->m_FeliCa.m_PMm, sizeof lpCard->m_FeliCa.m_PMm);
switch (request) {
case FelicaPollRequest_SystemCode:
lpResponse->m_Poll.m_Value = lpCard->m_FeliCaData.m_SystemBlock_SYS_C.m_SYS_C;
break;
default:
log_error(plfAime, "Unhnaldled poll request: %02x", request);
lpResponse->m_FelicaLen -= 2;
break;
}
}
void FelicaReadNoEnc(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse, PNFC_CARD lpCard) {
BYTE readIndex = 0;
BYTE serviceN = lpReq->m_ReadNoEnc.m_Rest[readIndex++];
for (BYTE i = 0; i < serviceN; i++) {
WORD service = *(LPWORD)(&lpReq->m_ReadNoEnc.m_Rest[readIndex++]);
readIndex++;
}
BYTE blockCount = lpReq->m_ReadNoEnc.m_Rest[readIndex++];
lpResponse->m_FelicaLen = FelicaRespSize(lpResponse->m_ReadNoEnc) + 16 * blockCount;
lpResponse->m_FelicaCommand = FelicaCommand_ReadNoEnc_Response;
memcpy(&lpResponse->m_IDm, &lpReq->m_ReadNoEnc.m_IDm, sizeof lpReq->m_ReadNoEnc.m_IDm);
lpResponse->m_ReadNoEnc.m_Status1 = FelicaStatus1_Success;
lpResponse->m_ReadNoEnc.m_Status2 = FelicaStatus2_Success;
lpResponse->m_ReadNoEnc.m_BlockCount = blockCount;
BYTE writeIndex = 0;
for (BYTE i = 0; i < blockCount; i++) {
BYTE blHeader = lpReq->m_ReadNoEnc.m_Rest[readIndex++];
BOOL isExtended = !(blHeader & 0x80);
BYTE serviceCodeOrder = blHeader & 0x0f;
BYTE accessMode = (blHeader & 0x70) >> 4;
WORD blockNumber;
if (isExtended) {
blockNumber = *(LPWORD)(&lpReq->m_ReadNoEnc.m_Rest[readIndex++]);
readIndex++;
} else {
blockNumber = lpReq->m_ReadNoEnc.m_Rest[readIndex++];
}
if (blockNumber < 0xf) {
memcpy(&lpResponse->m_ReadNoEnc.m_BlockData[writeIndex],
lpCard->m_FeliCaData.m_UserBlocks[blockNumber].bytes, 16);
log_warning(plfAime, "Felica read: s:%x block:%04x", serviceCodeOrder, blockNumber);
writeIndex += 16;
} else if (blockNumber >= 0x80 && blockNumber < 0x89) {
if (blockNumber - 0x80 == FelicaSystemBlock_MAC) {
log_info(plfAime, "MAC challenge requested");
DWORD64 ID[2] = { 0 };
memcpy(ID, &lpCard->m_FeliCaData.m_SystemBlock_ID, 16);
KEY_PAIR CK, SK;
DWORD64* RC = (DWORD64*)&lpCard->m_FeliCaData.m_SystemBlock_RC.m_RC;
FelicaMacGenerateCK(ID, CK);
FelicaMacGenerateSK(RC, CK, SK);
DWORD64 mac = FelicaMacGenerateMAC(ID, SK, RC);
mac = _byteswap_uint64(mac);
memcpy(&lpResponse->m_ReadNoEnc.m_BlockData[writeIndex], &mac, 8);
memset(&lpResponse->m_ReadNoEnc.m_BlockData[writeIndex + 8], 0, 8);
log_warning(plfAime, "Felica read: s:%x block:%04x", serviceCodeOrder, blockNumber);
writeIndex += 16;
} else {
memcpy(&lpResponse->m_ReadNoEnc.m_BlockData[writeIndex],
lpCard->m_FeliCaData.m_SystemBlocks[blockNumber - 0x80].bytes, 16);
log_warning(plfAime, "Felica read: s:%x block:%04x", serviceCodeOrder, blockNumber);
writeIndex += 16;
}
} else {
// Invalid block, but we're already committed to the success state because I'm lazy,
// so just write a bunch of nulls.
memset(&lpResponse->m_ReadNoEnc.m_BlockData[writeIndex], 0, 16);
log_warning(plfAime, "Felica read: s:%x block:%04x", serviceCodeOrder, blockNumber);
writeIndex += 16;
}
}
}
void FelicaWriteNoEnc(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse,
PNFC_CARD lpCard) {
BYTE readIndex = 0;
BYTE serviceN = lpReq->m_WriteNoEnc.m_Rest[readIndex++];
for (BYTE i = 0; i < serviceN; i++) {
WORD service = *(LPWORD)(&lpReq->m_WriteNoEnc.m_Rest[readIndex++]);
readIndex++;
}
BYTE blockCount = lpReq->m_WriteNoEnc.m_Rest[readIndex++];
for (BYTE i = 0; i < blockCount; i++) {
BYTE blHeader = lpReq->m_WriteNoEnc.m_Rest[readIndex++];
BOOL isExtended = !(blHeader & 0x80);
BYTE serviceCodeOrder = blHeader & 0x0f;
BYTE accessMode = (blHeader & 0x70) >> 4;
WORD blockNumber;
if (isExtended) {
blockNumber = *(LPWORD)(&lpReq->m_WriteNoEnc.m_Rest[readIndex++]);
readIndex++;
} else {
blockNumber = lpReq->m_WriteNoEnc.m_Rest[readIndex++];
}
log_warning(plfAime, "Felica write: s:%x block:%04x", serviceCodeOrder, blockNumber);
// TODO: Access controls!
if (blockNumber < 0xf) {
memcpy(lpCard->m_FeliCaData.m_UserBlocks[blockNumber].bytes,
&lpReq->m_WriteNoEnc.m_Rest[readIndex], 16);
readIndex += 16;
} else if (blockNumber >= 0x80 && blockNumber < 0x89) {
memcpy(lpCard->m_FeliCaData.m_SystemBlocks[blockNumber - 0x80].bytes,
&lpReq->m_WriteNoEnc.m_Rest[readIndex], 16);
readIndex += 16;
} else {
// Invalid block, but I'd rather just steamroll through it for the sake of
// compatability, so don't error.
readIndex += 16;
}
}
lpResponse->m_FelicaLen = FelicaRespSize(lpResponse->m_WriteNoEnc);
lpResponse->m_FelicaCommand = FelicaCommand_WriteNoEnc_Response;
memcpy(&lpResponse->m_IDm, &lpReq->m_WriteNoEnc.m_IDm, sizeof lpReq->m_WriteNoEnc.m_IDm);
lpResponse->m_WriteNoEnc.m_Status1 = FelicaStatus1_Success;
lpResponse->m_WriteNoEnc.m_Status2 = FelicaStatus2_Success;
}
void FelicaSystemCode(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse,
PNFC_CARD lpCard) {
lpResponse->m_FelicaLen = FelicaRespSize(lpResponse->m_SystemCode);
lpResponse->m_FelicaCommand = FelicaCommand_RequestSystemCode_Response;
memcpy(&lpResponse->m_IDm, &lpReq->m_SystemCode.m_IDm, sizeof lpReq->m_SystemCode.m_IDm);
lpResponse->m_SystemCode.m_SystemsCount = 1;
lpResponse->m_SystemCode.m_SystemCode = lpCard->m_FeliCaData.m_SystemBlock_SYS_C.m_SYS_C;
}
void FelicaMobileActive2(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse,
PNFC_CARD lpCard) {
lpResponse->m_FelicaLen = FelicaRespSize(lpResponse->m_Active2);
lpResponse->m_FelicaCommand = FelicaCommand_MobileActive2_Response;
switch (lpReq->m_Active2.m_Val) {
case 0: // Alive check
lpResponse->m_Active2.m_Data = 0;
break;
case 1: // OS Version
switch (lpCard->m_FeliCa.m_PMm[1]) {
case FelicaChipType_Mobile_Ver10:
lpResponse->m_Active2.m_Data = 1;
break;
case FelicaChipType_Mobile_Ver20:
lpResponse->m_Active2.m_Data = 0;
break;
default:
// I have no idea what other chips return
lpResponse->m_Active2.m_Data = 0;
break;
}
break;
case 2:
lpResponse->m_Active2.m_Data = 0xff;
break;
}
}
void FelicaEncap(com_device_t* dev, comio_recv_head_t* req, LPBYTE lpPacket, PNFC_CARD lpCard) {
if (lpCard->m_Header.m_Type != CardType_FeliCa) {
log_error(plfAime, "Reader %02x requested a FeliCa encap on a non-FeliCa card!", req->dst);
comio_reply(dev, req, TN32Error_CardError, 0, NULL);
return;
}
PFelicaEncapRequest lpReq = (PFelicaEncapRequest)lpPacket;
FelicaEncapResponse fResponse;
FelicaCommand felicaCmd = lpReq->m_FelicaCommand;
fResponse.m_FelicaCommand = felicaCmd + 1;
fResponse.m_FelicaLen = 0;
/**
* Suica devices will:
* - FelicaCommand_Poll
* - FelicaCommand_RequestSystemCode
* - FelicaCommand_MobileActive2
*
* Others (maimai does not appear to disambiguate?) will:
* - FelicaCommand_Poll
* - FelicaCommand_ReadNoEnc (block 82)
* - FelicaCommand_WriteNoEnc (block 80)
* - FelicaCommand_ReadNoEnc (block 82,21)
* - FelicaCommand_ReadNoEnc (block 0D)
*/
log_game(plfAime, "FeliCa command: %02x", felicaCmd);
switch (felicaCmd) {
case FelicaCommand_Poll:
FelicaPoll(lpReq, &fResponse, lpCard);
break;
case FelicaCommand_ReadNoEnc:
FelicaReadNoEnc(lpReq, &fResponse, lpCard);
break;
case FelicaCommand_WriteNoEnc:
FelicaWriteNoEnc(lpReq, &fResponse, lpCard);
break;
case FelicaCommand_RequestSystemCode:
FelicaSystemCode(lpReq, &fResponse, lpCard);
break;
case FelicaCommand_MobileActive2:
FelicaMobileActive2(lpReq, &fResponse, lpCard);
break;
default:
log_error(plfAime, "Unknown FeliCa command: %02x", felicaCmd);
break;
}
comio_reply(dev, req, TN32Error_OK, fResponse.m_FelicaLen, &fResponse);
}

View File

@ -0,0 +1,365 @@
#include <Windows.h>
#include "../_devices.h"
typedef struct FELICA_ID {
BYTE m_ID[8];
} FELICA_ID, *PFELICA_ID;
enum FelicaCommand {
FelicaCommand_Poll = 0x00,
FelicaCommand_Poll_Response = 0x01,
FelicaCommand_RequestService = 0x02,
FelicaCommand_RequestService_Response = 0x03,
FelicaCommand_RequestResponse = 0x04,
FelicaCommand_RequestResponse_Response = 0x05,
FelicaCommand_ReadNoEnc = 0x06,
FelicaCommand_ReadNoEnc_Response = 0x07,
FelicaCommand_WriteNoEnc = 0x08,
FelicaCommand_WriteNoEnc_Response = 0x09,
FelicaCommand_Search = 0x0a,
FelicaCommand_Search_Response = 0x0b,
FelicaCommand_RequestSystemCode = 0x0c,
FelicaCommand_RequestSystemCode_Response = 0x0d,
FelicaCommand_Authentication1 = 0x10,
FelicaCommand_Authentication1_Response = 0x11,
FelicaCommand_Authentication2 = 0x12,
FelicaCommand_Authentication2_Response = 0x13,
FelicaCommand_Read = 0x14,
FelicaCommand_Read_Response = 0x15,
FelicaCommand_Write = 0x16,
FelicaCommand_Write_Response = 0x17,
FelicaCommand_GetNodeProperty = 0x28,
FelicaCommand_GetNodeProperty_Response = 0x29,
FelicaCommand_RequestServiceV2 = 0x32,
FelicaCommand_RequestServiceV2_Response = 0x33,
FelicaCommand_InternalAuthAndRead = 0x34,
FelicaCommand_InternalAuthAndRead_Response = 0x35,
FelicaCommand_ExternalAuthAndRead = 0x36,
FelicaCommand_ExternalAuthAndRead_Response = 0x37,
FelicaCommand_GetSystemStatus = 0x38,
FelicaCommand_GetSystemStatus_Response = 0x39,
FelicaCommand_RequestSpecVersion = 0x3c,
FelicaCommand_RequestSpecVersion_Response = 0x3d,
FelicaCommand_ResetMode = 0x3e,
FelicaCommand_ResetMode_Response = 0x3f,
FelicaCommand_Authentication1V2 = 0x40,
FelicaCommand_Authentication1V2_Response = 0x41,
FelicaCommand_Authentication2V2 = 0x42,
FelicaCommand_Authentication2V2_Response = 0x43,
FelicaCommand_ReadV2 = 0x44,
FelicaCommand_ReadV2_Response = 0x45,
FelicaCommand_WriteV2 = 0x46,
FelicaCommand_WriteV2_Response = 0x47,
FelicaCommand_UpdateRandomID = 0x4C,
FelicaCommand_UpdateRandomID_Response = 0x4D,
FelicaCommand_SetNodeProperty = 0x78,
FelicaCommand_SetNodeProperty_Response = 0x79,
FelicaCommand_MobileActive2 = 0xa4,
FelicaCommand_MobileActive2_Response = 0xa5,
};
typedef BYTE FelicaCommand;
enum FelicaSystem {
FelicaSystem_Any = 0xffff,
FelicaSystem_NDEF = 0x12fc,
FelicaSystem_Emulator = 0x4000,
FelicaSystem_FelicaLite = 0x88b4,
FelicaSystem_FelicaSecureID = 0x957a,
FelicaSystem_JISX_Start = 0xaaa0,
FelicaSystem_JISX_End = 0xaafe,
FelicaSystem_CommonArea = 0xfe00,
FelicaSystem_FelicaPlug = 0xfee1,
FelicaSystem_Edy = 0xfe00,
FelicaSystem_Cyberne = 0x0003,
FelicaSystem_Suica = 0x0003,
FelicaSystem_Pasmo = 0x0003,
};
typedef WORD FelicaSystem;
enum FelicaService {
FelicaService_SuicaInOut = 0x108f,
FelicaService_SuicaHistory = 0x090f,
FelicaService_FelicaLiteRO = 0x0b00,
FelicaService_FelicaLiteEW = 0x0900,
};
typedef WORD FelicaService;
enum FelicaPollRequest {
FelicaPollRequest_NoRequest = 0x00,
FelicaPollRequest_SystemCode = 0x01,
FelicaPollRequest_CommPerformance = 0x02,
};
typedef BYTE FelicaPollRequest;
enum FelicaStatus1 {
FelicaStatus1_Success = 0x00,
// Everything between here is dynamically generated, and I cba
FelicaStatus1_Fatal = 0xFF,
};
typedef BYTE FelicaStatus1;
enum FelicaStatus2 {
// Generic
FelicaStatus2_Success = 0x00,
FelicaStatus2_Overflow = 0x01,
FelicaStatus2_CashbackExceeded = 0x02,
FelicaStatus2_PurseOutOfRange = 0x03,
FelicaStatus2_MemoryError = 0x70,
FelicaStatus2_RewritesExceeded = 0x71,
// Card specific
FelicaStatus2_IllegalServiceNumber = 0xA1,
FelicaStatus2_IllegalCommandPacket = 0xA2,
FelicaStatus2_IllegalBlockList = 0xA3,
FelicaStatus2_IllegalService = 0xA4,
FelicaStatus2_AccessDenied = 0xA5,
FelicaStatus2_IllegalServiceCode = 0xA6,
FelicaStatus2_IllegalBlockListAccess = 0xA7,
FelicaStatus2_IllegalBlockNumber = 0xA8,
FelicaStatus2_DataWriteFailure = 0xA9,
FelicaStatus2_KeyChangeFailure = 0xAA,
FelicaStatus2_IllegalParity = 0xAB,
FelicaStatus2_IllegalParameter = 0xAC,
FelicaStatus2_ServiceExists = 0xAD,
FelicaStatus2_IllegalSystemCode = 0xAE,
FelicaStatus2_TooManyWrites = 0xAF,
FelicaStatus2_IllegalPackage = 0xC0,
FelicaStatus2_PackageDiscrepancy = 0xC1,
FelicaStatus2_CommandDisabled = 0xC2,
FelicaStatus2_IllegalNodeProperty = 0xC3,
};
typedef BYTE FelicaStatus2;
// https://www.sony.net/Products/felica/business/tech-support/list.html
enum FelicaChipType {
FelicaChipType_STD_RC_S915 = 0x01,
FelicaChipType_STD_RC_S952 = 0x08,
FelicaChipType_STD_RC_S953 = 0x09,
FelicaChipType_STD_RC_S960 = 0x0D,
FelicaChipType_STD_RC_S962 = 0x20,
FelicaChipType_STD_RC_SA00_1 = 0x32,
FelicaChipType_STD_RC_SA20_1 = 0x44,
FelicaChipType_STD_RC_SA20_2 = 0x45,
FelicaChipType_Mobile_Ver10 = 0x06, // And 07h
FelicaChipType_Mobile_Ver20 = 0x10, // Up to 13h
FelicaChipType_Mobile_Ver30 = 0x14, // And 15h
FelicaChipType_Mobile_Ver40 = 0x17,
FelicaChipType_Mobile_Ver41 = 0x18, // Up to 1Fh
FelicaChipType_Lite = 0xf0, // RC-S965
FelicaChipType_LiteS = 0xf1, // RC-S966
FelicaChipType_Link_LiteS = 0xf2, // RC-S967
FelicaChipType_Link_Plug = 0xe1, // RC-S967
FelicaChipType_Link_NFC_DEP = 0xff, // RC-S967
FelicaChipType_Plug = 0xe0, // RC-S926
};
typedef BYTE FelicaChipType;
/**
* Multiple vendors make use of FeliCa cards for their amusement cards, but we
* can disamiguate them based on the specific FeliCa chip they use.
*
* Mobile phones will be using the Mobile chip versions. The specific OS
* version only matters for when the game is requesting to send mail or open a
* URL in the browser.
*
* The now-common Amusement IC cards all use FeliCa Lite or FeliCa LiteS. We
* choose to emulate our AIC cards as LiteS (RC-S966).
*
* Banapasses (BNG) also use FeliCa, however use FeliCa standard. We're going
* to keep things simple and just emulate RC-S915.
*/
typedef enum FelicaEmulationMode {
// Emulate a Suica mobile phone (FelicaChipType_Mobile_Ver**)
FelicaEmulationMode_Suica, // TODO: Which OS version do we want to emulate?
// Emulate an AmusementIC card (FelicaChipType_LiteS)
FelicaEmulationMode_AIC,
// Emulate a Banapass card (FelicaChipType_STD_RC_S915)
FelicaEmulationMode_BNG,
} FelicaEmulationMode;
typedef enum FelicaAICVendor {
FelicaAICVendor_BandaiNamcoGames, // FeliCa Lite, never used afaik
FelicaAICVendor_BandaiNamcoEntertainment, // FeliCa LiteS
FelicaAICVendor_SEGA, // FeliCa LiteS
FelicaAICVendor_Konami, // FeliCa LiteS
} FelicaAICVendor;
#define FelicaSystemBlock_RC 0x00
#define FelicaSystemBlock_MAC 0x01
#define FelicaSystemBlock_ID 0x02
#define FelicaSystemBlock_D_ID 0x03
#define FelicaSystemBlock_SER_C 0x04
#define FelicaSystemBlock_SYS_C 0x05
#define FelicaSystemBlock_CKV 0x06
#define FelicaSystemBlock_CK 0x07
#define FelicaSystemBlock_MC 0x08
#pragma pack(push, 1)
typedef struct FelicaBlock {
BYTE bytes[16];
} FelicaBlock_t, *PFelicaBlock_t;
typedef struct FelicaBlock_RC {
union {
struct {
DWORD64 m_RC1;
DWORD64 m_RC2;
};
DWORD64 m_RC[2];
};
} FelicaBlock_RC;
typedef struct FelicaBlock_MAC {
BYTE m_MAC[8];
BYTE Rsv08[8];
} FelicaBlock_MAC;
typedef struct FelicaBlock_ID {
FELICA_ID m_FelicaId;
BYTE m_DFC[2];
BYTE m_Arbitrary[6];
} FelicaBlock_ID;
typedef struct FelicaBlock_D_ID {
FELICA_ID m_FelicaId;
BYTE m_PMm[8];
} FelicaBlock_D_ID;
typedef struct FelicaBlock_SER_C {
BYTE m_SER_C[2];
BYTE Rsv02[14];
} FelicaBlock_SER_C;
typedef struct FelicaBlock_SYS_C {
WORD m_SYS_C;
BYTE Rsv02[14];
} FelicaBlock_SYS_C;
typedef struct FelicaBlock_CKV {
BYTE m_CKV[2];
BYTE Rsv02[14];
} FelicaBlock_CKV;
typedef struct FelicaBlock_CK {
BYTE m_CK1[8];
BYTE m_CK2[8];
} FelicaBlock_CK;
typedef struct FelicaBlock_MC {
// I really don't want to map this all out, and don't think I need to.
// So I'm not going to.
// Page 30 on the below URL if ever actually needed.
// https://www.sony.net/Products/felica/business/tech-support/data/fls_usmnl_1.31.pdf
BYTE Rsv00[16];
} FelicaBlock_MC;
typedef struct FelicaMemory {
FelicaEmulationMode m_EmuMode;
FelicaAICVendor m_AICVendor;
FelicaBlock_t m_UserBlocks[15];
union {
FelicaBlock_t m_SystemBlocks[9];
struct {
FelicaBlock_RC m_SystemBlock_RC;
FelicaBlock_MAC m_SystemBlock_MAC;
FelicaBlock_ID m_SystemBlock_ID;
FelicaBlock_D_ID m_SystemBlock_D_ID;
FelicaBlock_SER_C m_SystemBlock_SER_C;
FelicaBlock_SYS_C m_SystemBlock_SYS_C;
FelicaBlock_CKV m_SystemBlock_CKV;
FelicaBlock_CK m_SystemBlock_CK;
FelicaBlock_MC m_SystemBlock_MC;
};
};
} FelicaMemory_t;
typedef struct FelicaRequest_Poll {
FelicaSystem m_SystemCode;
FelicaPollRequest m_Request;
BYTE m_TimeSlot;
} FelicaRequest_Poll, *PFelicaRequest_Poll;
typedef struct FelicaResponse_Poll {
BYTE m_PMm[8];
WORD m_Value;
} FelicaResponse_Poll, *PFelicaResponse_Poll;
typedef struct FelicaRequest_ReadNoEnc {
FELICA_ID m_IDm;
BYTE m_Rest[];
} FelicaRequest_ReadNoEnc, *PFelicaRequest_ReadNoEnc;
typedef struct FelicaResponse_ReadNoEnc {
BYTE m_Status1;
BYTE m_Status2;
BYTE m_BlockCount;
BYTE m_BlockData[];
} FelicaResponse_ReadNoEnc, *PFelicaResponse_ReadNoEnc;
typedef struct FelicaRequest_WriteNoEnc {
FELICA_ID m_IDm;
BYTE m_Rest[];
} FelicaRequest_WriteNoEnc, *PFelicaRequest_WriteNoEnc;
typedef struct FelicaResponse_WriteNoEnc {
BYTE m_Status1;
BYTE m_Status2;
} FelicaResponse_WriteNoEnc, *PFelicaResponse_WriteNoEnc;
typedef struct FelicaRequest_SystemCode {
FELICA_ID m_IDm;
} FelicaRequest_SystemCode, *PFelicaRequest_SystemCode;
typedef struct FelicaResponse_SystemCode {
BYTE m_SystemsCount;
WORD m_SystemCode;
} FelicaResponse_SystemCode, *PFelicaResponse_SystemCode;
typedef struct FelicaRequest_Active2 {
FELICA_ID m_IDm;
BYTE m_Val;
} FelicaRequest_Active2, *PFelicaRequest_Active2;
typedef struct FelicaResponse_Active2 {
BYTE m_Data;
} FelicaResponse_Active2, *PFelicaResponse_Active2;
typedef struct FelicaEncapRequest {
FELICA_ID m_IDm;
BYTE m_FelicaLen;
BYTE m_FelicaCommand;
union {
FelicaRequest_Poll m_Poll;
FelicaRequest_ReadNoEnc m_ReadNoEnc;
FelicaRequest_WriteNoEnc m_WriteNoEnc;
FelicaRequest_SystemCode m_SystemCode;
FelicaRequest_Active2 m_Active2;
BYTE m_Body[238];
};
} FelicaEncapRequest, *PFelicaEncapRequest;
typedef struct FelicaEncapResponse {
BYTE m_FelicaLen;
BYTE m_FelicaCommand;
FELICA_ID m_IDm;
union {
FelicaResponse_Poll m_Poll;
FelicaResponse_ReadNoEnc m_ReadNoEnc;
FelicaResponse_WriteNoEnc m_WriteNoEnc;
FelicaResponse_SystemCode m_SystemCode;
FelicaResponse_Active2 m_Active2;
BYTE m_Body[246];
};
} FelicaEncapResponse, *PFelicaEncapResponse;
#pragma pack(pop)
#define FelicaRespSize(x) (10 + sizeof x)
#ifndef _NFC_H
typedef struct NFC_CARD NFC_CARD, *PNFC_CARD;
typedef struct ACCESS_CODE ACCESS_CODE, *PACCESS_CODE;
#define _NFC_H
#endif
void FelicaPoll(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse, PNFC_CARD lpCard);
void FelicaReadNoEnc(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse, PNFC_CARD lpCard);
void FelicaWriteNoEnc(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse, PNFC_CARD lpCard);
void FelicaSystemCode(PFelicaEncapRequest lpReq, PFelicaEncapResponse lpResponse, PNFC_CARD lpCard);
void FelicaEncap(com_device_t* dev, comio_recv_head_t* req, LPBYTE lpPacket, PNFC_CARD lpCard);
void FelicaPopulate(PNFC_CARD lpCard, PFELICA_ID lpFelicaId, PACCESS_CODE lpAccessCode);

View File

@ -0,0 +1,15 @@
#include <Windows.h>
#pragma pack(push, 1)
typedef struct MifareBlock {
BYTE bytes[16];
} MifareBlock_t;
typedef struct MifareSector {
MifareBlock_t blocks[4];
} MifareSector_t;
typedef struct MifareMemory_t {
MifareSector_t sectors[16];
} MifareMemory_t;
#pragma pack(pop)

View File

@ -0,0 +1,65 @@
#pragma once
#include <Windows.h>
#include "felica.h"
#include "mifare.h"
enum CardType {
CardType_Unknown = 0x00,
CardType_Mifare = 0x10,
CardType_FeliCa = 0x20,
};
typedef BYTE CardType;
struct ACCESS_CODE {
BYTE m_AC[10];
};
#ifndef _NFC_H
typedef struct NFC_CARD NFC_CARD, *PNFC_CARD;
typedef struct ACCESS_CODE ACCESS_CODE, *PACCESS_CODE;
#define _NFC_H
#endif
#pragma pack(push, 1)
struct NFC_CARD {
struct {
BYTE m_Type;
BYTE m_IdLen;
} m_Header;
union {
struct {
union {
FELICA_ID m_IDm;
struct {
WORD m_Code; // Manufacturer code
WORD m_Machine; // Manufacturer machine
INT16 m_Date; // Days since 2000-01-01
WORD m_Serial; // Daily serial
};
};
union {
BYTE m_PMm[8];
struct {
BYTE m_RomType;
FelicaChipType m_ICType;
BYTE m_Response[6]; // Response time information
};
};
} m_FeliCa;
struct {
DWORD m_Uid;
} m_Mifare;
struct {
BYTE Unk00[7];
} m_Amiibo;
};
union {
MifareMemory_t m_MifareData;
FelicaMemory_t m_FeliCaData;
};
};
#pragma pack(pop)
#define NFC_FeliCaSize (sizeof((PNFC_CARD)0)->m_Header + sizeof((PNFC_CARD)0)->m_FeliCa)
#define NFC_MifareSize (sizeof((PNFC_CARD)0)->m_Header + sizeof((PNFC_CARD)0)->m_Mifare)

View File

@ -1,218 +1,290 @@
/*
FeliCa Lite:
AIC cards starting with 300x, 302x, and 303x contain their AIC number in block 0D
*/
#include "ser_tn32msec.h"
#include "../../lib/mice/solitaire.h"
#include "_devices.h"
#include "nfc/nfc.h"
static BYTE read_one(com_device_t* dev) {
while (!comdev_available(dev)) Sleep(50);
BYTE data;
comdev_read(dev, &data, 1);
return data;
static BYTE extra[0xff];
BYTE cardLED_RGB_P1[3];
BYTE cardLED_RGB_P2[3];
static char* OpcodeNames[256];
typedef enum TN32_FwVer {
TN32_FwVer_10 = 0x10, // 1.0
TN32_FwVer_12 = 0x12, // 1.2
} TN32_FwVer;
TN32_FwVer FIRMWARE_VERSION = TN32_FwVer_10;
static const char FWVer00[] = "TN32MSEC003S F/W Ver0.0"; // Not a real firmware version
static const char FWVer10[] = "TN32MSEC003S F/W Ver1.0";
static const char FWVer12[] = "TN32MSEC003S F/W Ver1.2";
static const char HWVer[] = "TN32MSEC003S H/W Ver3.0";
NFC_CARD nfcCardReaderP1;
NFC_CARD nfcCardReaderP2;
#define READER_P1_ADDR 0x00
#define READER_P2_ADDR 0x01
#define READER_P1_LED_ADDR 0x08
#define READER_P2_LED_ADDR 0x09
CHAR cardIdentifier1P[32];
CHAR cardIdentifier2P[32];
static LPCSTR GetCardIdentifier(DWORD player) {
LPCSTR card = player == 0 ? MiceConfig.aime.player1_card : MiceConfig.aime.player2_card;
LPCSTR cardFile =
player == 0 ? MiceConfig.aime.player1_cardfile : MiceConfig.aime.player2_cardfile;
LPSTR cardIdentifier = player == 0 ? cardIdentifier1P : cardIdentifier2P;
if (_PathFileExistsA(cardFile)) {
log_info(plfAime, "Reading P%d card from %s", player + 1, cardFile);
HANDLE hFile =
_CreateFileA(cardFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
log_warning(plfAime, "Failed to open %s for reading", cardFile);
} else {
DWORD nRead;
if (!_ReadFile(hFile, cardIdentifier, 32, &nRead, NULL)) {
log_error(plfAime, "Failed to read from %s", cardFile);
} else {
card = cardIdentifier;
}
_CloseHandle(hFile);
}
} else if (card == NULL || strlen(card) == 0) {
log_error(plfAime,
"No card specified for Player %d. Either specify a card in settings, or place a "
"card ID into %s",
player + 1, cardFile);
}
return card == NULL ? "" : card;
}
BYTE extra[0xff];
/**
* 51 and 55 are guesses based on the code. Makes sense given their opcodes
* too.
* TODO: Validate against a real board
* @brief Convert a card identification string to either an access code or felica ID
*
* Supported card formats:
* Access codes (AiMe Mifare cards):
* "1234-1234-1234-1234-1234"
* "1234 1234 1234 1234 1234"
* "12341234123412341234"
* FeliCa IDm (AIC cards):
* "0134567890123456"
* "01 34 56 78 90 12 34 56"
*/
enum TN32_Opcode {
TN32Op_GetFWVersion = 0x30,
TN32Op_GetHWVersion = 0x32,
static CardType TN32GetCardInfo(LPCSTR lpIdentifier, PACCESS_CODE lpAccessCode,
PFELICA_ID lpFelicaId) {
DWORD nChars;
DWORD len = strlen(lpIdentifier);
TN32Op_RadioOn = 0x40,
TN32Op_RadioOff = 0x41,
TN32Op_Poll = 0x42,
TN32Op_MifareSelectTag = 0x43,
TN32Op_CardHalt = 0x44,
TN32Op_SetKeyBana = 0x50,
TN32Op_GetKeyBana = 0x51,
TN32Op_ReadBlock = 0x52,
TN32Op_WriteBlock = 0x53,
TN32Op_SetKeyAime = 0x54,
TN32Op_GetKeyAime = 0x55,
// Firmware update
TN32Op_EnterUpdaterMode = 0x60,
TN32Op_SendHex = 0x61,
TN32Op_Reset = 0x62,
TN32Op_SendBindata = 0x63,
TN32Op_BindataExec = 0x64,
// Felica
TN32Op_FelicaPush = 0x70,
TN32Op_FelicaEncap = 0x71,
// No responses to either
Led_SetColour = 0x80,
Led_SetColourRGB = 0x81,
Led_GetInfo = 0xf0,
Led_FirmwareSum = 0xf2,
Led_SendHex = 0xf3,
Led_EnterBootMode = 0xf4,
Led_Reset = 0xf5,
};
char* OpcodeNames[256];
const char FWVer[] = "TN32MSEC003S F/W Ver1.2";
const char HWVer[] = "TN32MSEC003S H/W Ver3.0";
#define CardType_Mifare 0x10
#define CardType_FeliCa 0x20
#pragma pack(push, 1)
typedef struct NFCMifare {
BYTE type;
BYTE id_len;
DWORD uid;
} NFCMifare_t;
typedef struct NFCFelica {
BYTE type;
BYTE id_len;
uint64_t IDm;
uint64_t PMm;
} NFCFelica_t;
typedef struct MifareBlock {
BYTE bytes[16];
} MifareBlock_t;
typedef struct MifareSector {
MifareBlock_t blocks[4];
} MifareSector_t;
typedef struct MifareMemory_t {
MifareSector_t sectors[16];
} MifareMemory_t;
typedef struct FelicaBlock {
BYTE bytes[16];
} FelicaBlock_t;
typedef struct FelicaMemory {
FelicaBlock_t dataBlocks[15];
FelicaBlock_t systemBlocks[9];
} FelicaMemory_t;
#pragma pack(pop)
MifareMemory_t mifareMemory;
FelicaMemory_t felicaMemory;
BYTE luid[10] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0x01, 0x23, 0x45, 0x67, 0x89 };
#define PMm_VALUE 0x00F1000000014300ULL
#define FelicaSystemBlock_RC 0x00
#define FelicaSystemBlock_MAC 0x01
#define FelicaSystemBlock_ID 0x02
#define FelicaSystemBlock_D_ID 0x03
#define FelicaSystemBlock_SER_C 0x04
#define FelicaSystemBlock_SYS_C 0x05
#define FelicaSystemBlock_CKV 0x06
#define FelicaSystemBlock_CK 0x07
#define FelicaSystemBlock_MC 0x08
void populate_felica(NFCFelica_t* card) {
card->type = CardType_FeliCa;
card->id_len = sizeof(card->IDm) + sizeof(card->PMm);
card->IDm = _byteswap_uint64(0x012E4CD8A30A39B3ULL);
card->PMm = _byteswap_uint64(PMm_VALUE);
// Key name
felicaMemory.dataBlocks[0x0D].bytes[0] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[1] = 0x02;
felicaMemory.dataBlocks[0x0D].bytes[2] = 'N';
felicaMemory.dataBlocks[0x0D].bytes[3] = 'B';
felicaMemory.dataBlocks[0x0D].bytes[4] = 'G';
felicaMemory.dataBlocks[0x0D].bytes[5] = 'I';
felicaMemory.dataBlocks[0x0D].bytes[6] = 'C';
felicaMemory.dataBlocks[0x0D].bytes[7] = '0';
// Setup the fake blowfish data
felicaMemory.dataBlocks[0x0D].bytes[8] = 0x89;
felicaMemory.dataBlocks[0x0D].bytes[9] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[10] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[11] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[12] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[13] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[14] = 0x00;
felicaMemory.dataBlocks[0x0D].bytes[15] = 0x00;
BYTE block0[16] = {
0xC2, 0x1C, 0xCB, 0xC7, 0x58, 0xCA, 0x81, 0xB7,
0xC0, 0x0B, 0x8E, 0x3A, 0x45, 0x43, 0xFE, 0xFC,
};
memcpy(felicaMemory.dataBlocks[0].bytes, block0, 16);
memset(felicaMemory.dataBlocks[0x0e].bytes, 0xFF, 16);
BYTE blockID[16] = {
// IDd (=IDm)
0x01, 0x2E, 0x4C, 0xD8, 0xA3, 0x0A, 0x39, 0xB3,
// ID
0x00, 0x2a, 0x05, 0x73, 0x02, 0x01, 0x03, 0x00,
// ^DFC^ ^~~~~~ arbitary value
};
memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_ID].bytes, blockID, 16);
BYTE blockDID[16] = {
// IDd (=IDm)
0x01,
0x2E,
0x4C,
0xD8,
0xA3,
0x0A,
0x39,
0xB3,
// PMm
0x00,
0xF1,
0x00,
0x00,
0x00,
0x01,
0x43,
0x00,
};
memcpy(felicaMemory.systemBlocks[FelicaSystemBlock_D_ID].bytes, blockDID, 16);
if (len == 24) {
if (sscanf_s(lpIdentifier,
"%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%n",
&lpAccessCode->m_AC[0], &lpAccessCode->m_AC[1], &lpAccessCode->m_AC[2],
&lpAccessCode->m_AC[3], &lpAccessCode->m_AC[4], &lpAccessCode->m_AC[5],
&lpAccessCode->m_AC[6], &lpAccessCode->m_AC[7], &lpAccessCode->m_AC[8],
&lpAccessCode->m_AC[9], &nChars) == 10 &&
nChars == 24) {
return CardType_Mifare;
}
if (sscanf_s(lpIdentifier,
"%02hhx%02hhx %02hhx%02hhx %02hhx%02hhx %02hhx%02hhx %02hhx%02hhx%n",
&lpAccessCode->m_AC[0], &lpAccessCode->m_AC[1], &lpAccessCode->m_AC[2],
&lpAccessCode->m_AC[3], &lpAccessCode->m_AC[4], &lpAccessCode->m_AC[5],
&lpAccessCode->m_AC[6], &lpAccessCode->m_AC[7], &lpAccessCode->m_AC[8],
&lpAccessCode->m_AC[9], &nChars) == 10 &&
nChars == 24) {
return CardType_Mifare;
}
} else if (len == 20) {
if (sscanf_s(lpIdentifier, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%n",
&lpAccessCode->m_AC[0], &lpAccessCode->m_AC[1], &lpAccessCode->m_AC[2],
&lpAccessCode->m_AC[3], &lpAccessCode->m_AC[4], &lpAccessCode->m_AC[5],
&lpAccessCode->m_AC[6], &lpAccessCode->m_AC[7], &lpAccessCode->m_AC[8],
&lpAccessCode->m_AC[9], &nChars) == 10 &&
nChars == 20)
return CardType_Mifare;
} else if (len == 16) {
if (sscanf_s(lpIdentifier, "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%n",
&lpFelicaId->m_ID[0], &lpFelicaId->m_ID[1], &lpFelicaId->m_ID[2],
&lpFelicaId->m_ID[3], &lpFelicaId->m_ID[4], &lpFelicaId->m_ID[5],
&lpFelicaId->m_ID[6], &lpFelicaId->m_ID[7], &nChars) == 8 &&
nChars == 16)
return CardType_FeliCa;
} else if (len == 23) {
if (sscanf_s(lpIdentifier, "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx%n",
&lpFelicaId->m_ID[0], &lpFelicaId->m_ID[1], &lpFelicaId->m_ID[2],
&lpFelicaId->m_ID[3], &lpFelicaId->m_ID[4], &lpFelicaId->m_ID[5],
&lpFelicaId->m_ID[6], &lpFelicaId->m_ID[7], &nChars) == 8 &&
nChars == 23)
return CardType_FeliCa;
}
return CardType_Unknown;
}
void populate_mifare(NFCMifare_t* card) {
card->type = CardType_Mifare;
card->id_len = sizeof(card->uid);
card->uid = _byteswap_ulong(0x01020304);
// TODO: Better state haha
// Flash the card memory
#define ACKEY_ACCESSCODE_LEN 20
#define ACKEY_ACCESSHEADER_ID_LEN 5
#define ACKEY_SERIAL_LEN 8
static DWORD AccessCodeToSerial(PACCESS_CODE lpAccessCode) {
char accessCode[ACKEY_ACCESSCODE_LEN + 1];
sprintf_s(accessCode, sizeof accessCode, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
lpAccessCode->m_AC[0], lpAccessCode->m_AC[1], lpAccessCode->m_AC[2],
lpAccessCode->m_AC[3], lpAccessCode->m_AC[4], lpAccessCode->m_AC[5],
lpAccessCode->m_AC[6], lpAccessCode->m_AC[7], lpAccessCode->m_AC[8],
lpAccessCode->m_AC[9]);
char hashed_id_wrk[ACKEY_SERIAL_LEN + 1];
char id_wrk[ACKEY_SERIAL_LEN + 1];
memcpy_s(hashed_id_wrk, sizeof(hashed_id_wrk), &accessCode[ACKEY_ACCESSHEADER_ID_LEN],
ACKEY_SERIAL_LEN);
hashed_id_wrk[ACKEY_SERIAL_LEN] = '\0';
SolitaireCipherDecode(&accessCode[ACKEY_ACCESSHEADER_ID_LEN + ACKEY_SERIAL_LEN], hashed_id_wrk,
id_wrk);
return atoi(id_wrk);
}
static void MifarePopulate(PNFC_CARD lpCard, PACCESS_CODE lpAccessCode) {
lpCard->m_Header.m_IdLen = sizeof(lpCard->m_Mifare);
DWORD nSerial = AccessCodeToSerial(lpAccessCode);
lpCard->m_Mifare.m_Uid = nSerial;
printf("Serial: %d\n", nSerial);
// Block 0: Manufacture data (only used by BNG)
// Block 1: Game ID information (kCARD_DETECT_KEY_B_READ_1)
const char GAME_ID[4] = { 'S', 'B', 'S', 'D' };
memcpy_s(&lpCard->m_MifareData.sectors[0].blocks[1].bytes[0],
sizeof lpCard->m_MifareData.sectors[0].blocks[1].bytes, GAME_ID, 4);
lpCard->m_MifareData.sectors[0].blocks[1].bytes[12] = (nSerial >> 24) & 0xff;
lpCard->m_MifareData.sectors[0].blocks[1].bytes[13] = (nSerial >> 16) & 0xff;
lpCard->m_MifareData.sectors[0].blocks[1].bytes[14] = (nSerial >> 8) & 0xff;
lpCard->m_MifareData.sectors[0].blocks[1].bytes[15] = nSerial & 0xff;
// Block 2: Access code (kCARD_DETECT_KEY_B_READ_2)
memcpy_s(&lpCard->m_MifareData.sectors[0].blocks[2].bytes[6],
sizeof lpCard->m_MifareData.sectors[0].blocks[2].bytes - 6, lpAccessCode->m_AC,
sizeof lpAccessCode->m_AC);
}
void AmiiboPopulate(PNFC_CARD lpCard) {
// What _is_ the ID though?
lpCard->m_Header.m_IdLen = sizeof(lpCard->m_Mifare);
// Write the card
for (BYTE i = 0; i < 10; i++) {
BYTE b = luid[i];
mifareMemory.sectors[0].blocks[2].bytes[i + 6] = b;
mifareMemory.sectors[0].blocks[1].bytes[i + 6] = b;
lpCard->m_MifareData.sectors[0].blocks[21].bytes[i] = 0;
}
}
void nfc_poll(com_device_t* dev, comio_recv_head_t* req) {
BYTE TN32PopulateCard(PNFC_CARD lpCard, LPCSTR lpIdentifier) {
ACCESS_CODE accessCode;
FELICA_ID felicaId;
CardType type = TN32GetCardInfo(lpIdentifier, &accessCode, &felicaId);
if (type == CardType_Unknown) {
log_error(plfAime, "Unable to parse card: %s", lpIdentifier);
return 0;
}
lpCard->m_Header.m_Type = type;
if (type == CardType_Mifare) {
log_info(plfAime,
"Inserting card: %02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx",
accessCode.m_AC[0], accessCode.m_AC[1], accessCode.m_AC[2], accessCode.m_AC[3],
accessCode.m_AC[4], accessCode.m_AC[5], accessCode.m_AC[6], accessCode.m_AC[7],
accessCode.m_AC[8], accessCode.m_AC[9]);
MifarePopulate(lpCard, &accessCode);
return NFC_MifareSize;
} else if (type == CardType_FeliCa) {
log_info(plfAime, "Inserting card: %02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
felicaId.m_ID[0], felicaId.m_ID[1], felicaId.m_ID[2], felicaId.m_ID[3],
felicaId.m_ID[4], felicaId.m_ID[5], felicaId.m_ID[6], felicaId.m_ID[7]);
// TODO: FeliCa AIC cards can take an access code in their first block,
// and we support this. Figure out a nice way to allow this to be
// specified by users. That said, I'm not sure if anything in the Ring
// series actually uses this.
FelicaPopulate(lpCard, &felicaId, NULL);
return NFC_FeliCaSize;
}
return 0;
}
static void nfc_poll(com_device_t* dev, comio_recv_head_t* req) {
BYTE data[256];
data[0] = 0;
BYTE nbytes = 1;
// felica present
if (GetAsyncKeyState('L') < 0) {
NFCFelica_t card;
populate_felica(&card);
memcpy(data + nbytes, &card, sizeof card);
nbytes += sizeof card;
data[0]++;
}
// mifare (aime, bana) present
if (GetAsyncKeyState('P') < 0) {
NFCMifare_t card;
populate_mifare(&card);
memcpy(data + nbytes, &card, sizeof card);
nbytes += sizeof card;
data[0]++;
}
BOOL p1 = req->dst == READER_P1_ADDR;
comio_reply(dev, req, COMIO_STATUS_OK, nbytes, data);
PNFC_CARD lpCard = p1 ? &nfcCardReaderP1 : &nfcCardReaderP2;
SHORT key = GetAsyncKeyState(p1 ? 'P' : 'L');
if (key < 0) {
LPCSTR cardId = GetCardIdentifier(p1 ? 0 : 1);
BYTE nCardBytes = TN32PopulateCard(lpCard, cardId);
if (nCardBytes) {
memcpy(data + nbytes, lpCard, nCardBytes);
nbytes += nCardBytes;
data[0]++;
}
}
comio_reply(dev, req, TN32Error_OK, nbytes, data);
}
BYTE AIME_KEY[6];
BYTE BANA_KEY[6];
// Games don't expect this to be preloaded, but we might as well
BYTE AIME_KEY[6] = { 0x57, 0x43, 0x43, 0x46, 0x76, 0x32 };
BYTE BANA_KEY[6] = { 0x60, 0x90, 0xd0, 0x06, 0x32, 0xf5 };
void MifareBlockRead(com_device_t* dev, comio_recv_head_t* req, LPBYTE lpPacket, PNFC_CARD lpCard) {
// langth = 4 bytes uid + 1 byte block
if (req->length != 5) {
log_warning(plfAime, "Mifare read packet bad: %d", req->length);
comio_reply(dev, req, TN32Error_InvalidData, 0, NULL);
return;
}
if (lpCard->m_Header.m_Type != CardType_Mifare) {
log_error(plfAime, "Reader %02x requested a Mifare read on a non-Mifare card!", req->dst);
comio_reply(dev, req, TN32Error_CardError, 0, NULL);
return;
}
DWORD uid = *((LPDWORD)(&lpPacket[0]));
BYTE blockNo = lpPacket[4];
if (blockNo > 3) {
log_warning(plfAime, "Mifare block out of range: %d", blockNo);
comio_reply(dev, req, TN32Error_CardError, 0, NULL);
return;
}
if (lpCard->m_Mifare.m_Uid != uid) {
log_error(plfAime,
"Reader %02x requested to read card %08x. Currently present card is %08x.", uid,
lpCard->m_Mifare.m_Uid);
comio_reply(dev, req, TN32Error_CardError, 0, NULL);
return;
}
log_misc(plfAime, "Read mifare block: %d", blockNo);
MifareBlock_t* block = &(lpCard->m_MifareData.sectors[0].blocks[blockNo]);
comio_reply(dev, req, TN32Error_OK, sizeof *block, block->bytes);
}
DWORD WINAPI aime_bd_thread(com_device_t* dev) {
static int fwNumBytes = 0;
@ -224,80 +296,167 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
comio_recv_head_t req;
unsigned char sum = comio_next_req(dev, &req, extra);
log_info(plfAime, "(%d) %02x(%d) = %s", req.dst, req.op, req.length, OpcodeNames[req.op]);
log_trace(plfAime, "(%d) %02x(%d) = %s", req.dst, req.op, req.length, OpcodeNames[req.op]);
// Proxy 1P reader to hardware COM1. Used for debugging; preserved because it might end up
// useful again in the future. Allowing proxying to hardware a first-party feature could be
// cool down the line, but would need much much nicer code than this :D
/*
if (req.dst == READER_P1_ADDR) {
HANDLE hCom = _CreateFileA("\\\\.\\COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
DWORD nWrote;
BYTE data = 0xE0;
BYTE mark = 0xD0;
_WriteFile(hCom, &data, 1, &nWrote, NULL);
for (int i = 0; i < sizeof req; i++) {
data = ((LPBYTE)&req)[i];
if (data == 0xE0 || data == 0xD0) {
_WriteFile(hCom, &mark, 1, &nWrote, NULL);
data--;
}
_WriteFile(hCom, &data, 1, &nWrote, NULL);
}
for (int i = 0; i < req.length; i++) {
data = extra[i];
if (data == 0xE0 || data == 0xD0) {
_WriteFile(hCom, &mark, 1, &nWrote, NULL);
data--;
}
_WriteFile(hCom, &data, 1, &nWrote, NULL);
}
data = sum;
if (data == 0xE0 || data == 0xD0) {
_WriteFile(hCom, &mark, 1, &nWrote, NULL);
data--;
}
_WriteFile(hCom, &data, 1, &nWrote, NULL);
Sleep(250);
BYTE readBuf[4096];
DWORD nRead;
_ReadFile(hCom, readBuf, 4096, &nRead, NULL);
log_game(plfAime, "Transact read: %d", nRead);
for (DWORD i = 0; i < nRead; i++) printf("%02x ", readBuf[i]);
puts("");
comdev_write(dev, readBuf, nRead);
_CloseHandle(hCom);
continue;
}
*/
if (req.dst == READER_P1_ADDR || req.dst == READER_P2_ADDR) {
PNFC_CARD lpCard = req.dst == READER_P1_ADDR ? &nfcCardReaderP1 : &nfcCardReaderP2;
if (req.dst == 0x00 || req.dst == 0x01) {
// Aime readers
switch (req.op) {
case TN32Op_Reset:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
break;
// Core
case TN32Op_GetFWVersion:
// BYTE fver = 0x10;
// comio_reply(dev, &req, COMIO_STATUS_OK, 1, &fver);
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof FWVer - 1, (LPBYTE)FWVer);
if (FIRMWARE_VERSION == TN32_FwVer_10)
comio_reply(dev, &req, TN32Error_OK, sizeof FWVer10 - 1, (LPBYTE)FWVer10);
else if (FIRMWARE_VERSION == TN32_FwVer_12)
comio_reply(dev, &req, TN32Error_OK, sizeof FWVer12 - 1, (LPBYTE)FWVer12);
else
comio_reply(dev, &req, TN32Error_OK, sizeof FWVer00 - 1, (LPBYTE)FWVer00);
break;
case TN32Op_GetHWVersion:
// BYTE hver = 0x10;
// comio_reply(dev, &req, COMIO_STATUS_OK, 1, &hver);
comio_reply(dev, &req, COMIO_STATUS_OK, sizeof HWVer - 1, (LPBYTE)HWVer);
comio_reply(dev, &req, TN32Error_OK, sizeof HWVer - 1, (LPBYTE)HWVer);
break;
case TN32Op_SetKeyAime:
if (req.length != sizeof AIME_KEY) {
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
} else {
memcpy(AIME_KEY, extra, sizeof AIME_KEY);
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
log_info(plfAime, "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:
if (req.length != sizeof BANA_KEY) {
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
} else {
memcpy(BANA_KEY, extra, sizeof BANA_KEY);
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
log_info(plfAime, "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;
// Radio
case TN32Op_RadioOn:
radio = true;
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
case TN32Op_RadioOff:
radio = false;
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
case TN32Op_Poll:
case TN32Op_CardDetect:
nfc_poll(dev, &req);
break;
case TN32Op_GetKeyBana:
case TN32Op_GetKeyAime:
if (req.length != 5) {
//
}
case TN32Op_CardHalt:
case TN32Op_MifareSelectTag:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
// TODO: What's this?
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
case TN32Op_CardSelect:
// TODO: Card stacks, for games that need those
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
// Mifare
case TN32Op_MifareKeySetA:
if (req.length != sizeof BANA_KEY) {
comio_reply(dev, &req, TN32Error_InvalidData, 0, NULL);
} else {
memcpy(BANA_KEY, extra, sizeof BANA_KEY);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
log_misc(plfAime, "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_MifareKeySetB:
if (req.length != sizeof AIME_KEY) {
comio_reply(dev, &req, TN32Error_InvalidData, 0, NULL);
} else {
memcpy(AIME_KEY, extra, sizeof AIME_KEY);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
log_misc(plfAime, "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_MifareRead:
/**
* All Mifare reads AiMeLib can perform:
*
* kCARD_DETECT_KEY_B_READ_0: [0]
* kCARD_DETECT_KEY_B_READ_1: [1]
* kCARD_DETECT_KEY_B_READ_2: [2]
* kCARD_DETECT_KEY_A_READ_0: [0]
* kCARD_DETECT_KEY_A_READ_1: [1]
* kCARD_DETECT_KEY_A_READ_2: [2]
*
* kCARD_DETECT_NAUTH_READ: [21] Amiibo things
* https://www.reddit.com/r/amiibo/comments/38rdll/my_research_on_amiibo_id_this_time_about/
* > Pages 21 and 22 are character IDs
* https://www.reddit.com/r/amiibo/comments/38p4a0/my_research_on_amiibo_id_including_variants_types/
*
* Supporting Amiibos is probably not worth doing until we find a game that
* actually uses them!
*/
MifareBlockRead(dev, &req, extra, lpCard);
break;
case TN32Op_MifareWrite:
// TODO: Do we want to support writing?
comio_reply(dev, &req, TN32Error_InvalidCommand, 0, NULL);
break;
case TN32Op_MifareAuthorizeA:
case TN32Op_MifareAuthorizeB:
// TODO: We probably should?
if (req.length != 5) {
}
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
// Firmware control
case TN32Op_EnterUpdaterMode:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
case TN32Op_SendHex:
// null-terminated line of the firmware hex!
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
log_info(plfAime, "Recv firmware: %s", extra);
break;
case TN32Op_Reset:
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
case TN32Op_SendBindata:
fwNumBytes = 0;
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
case TN32Op_BindataExec:
// Raw binary firmware data
@ -319,35 +478,61 @@ DWORD WINAPI aime_bd_thread(com_device_t* dev) {
if (fwNumBytes >= 0x3000)
;
else
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
// TODO: These
case TN32Op_ReadBlock:
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
// Felica
case TN32Op_FelicaPush:
// TODO: Implement mail and url opening?
comio_reply(dev, &req, TN32Error_InvalidCommand, 0, NULL);
break;
case TN32Op_FelicaEncap:
comio_reply(dev, &req, COMIO_STATUS_NG, 0, NULL);
if (FIRMWARE_VERSION == TN32_FwVer_12) {
FelicaEncap(dev, &req, extra, lpCard);
} else {
/**
* Firmware version 1.0 has no support for FeliCa
* proxying, and just returns Invalid Command for 70h
* and 71h. maimai is absolutely happy with this, and
* will just use the IDm from the Poll request without
* querying the card further.
*
* In fact, maimai _cannot_ function with newer
* firmware, due to an outdated restriction within
* AiMeLib that only allows BNG cards.
*/
comio_reply(dev, &req, TN32Error_InvalidCommand, 0, NULL);
}
break;
}
} else if (req.dst == 0x08 || req.dst == 0x09) {
} else if (req.dst == READER_P1_LED_ADDR || req.dst == READER_P2_LED_ADDR) {
// LED sub-boards
switch (req.op) {
case Led_Reset:
comio_reply(dev, &req, COMIO_STATUS_OK, 0, NULL);
comio_reply(dev, &req, TN32Error_OK, 0, NULL);
break;
case Led_GetInfo:
// 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");
// Format:
// 0xff-delimited board info string
// 1 byte, board version
comio_reply(dev, &req, TN32Error_OK, 9, (BYTE*)"15084\xff\x10");
break;
case Led_SetColour:
log_misc(plfAime, "Set LED: %02x @ %02x intensity", extra[0], extra[1]);
break;
case Led_SetColourRGB:
log_misc(plfAime, "Set LED: #%02x%02x%02x", extra[0], extra[1], extra[2]);
printf(
"\033[48;2;%d;%d;%dm "
" \033[0m",
extra[0], extra[1], extra[2]);
// No response expected here!
// TODO: Bring this back, in a nicer way
if (req.dst == READER_P1_LED_ADDR) {
cardLED_RGB_P1[0] = extra[0];
cardLED_RGB_P1[1] = extra[1];
cardLED_RGB_P1[2] = extra[2];
} else {
cardLED_RGB_P2[0] = extra[0];
cardLED_RGB_P2[1] = extra[1];
cardLED_RGB_P2[2] = extra[2];
}
break;
}
}
@ -362,15 +547,15 @@ void install_aime_bd() {
OpcodeNames[TN32Op_GetHWVersion] = "GetHWVersion";
OpcodeNames[TN32Op_RadioOn] = "RadioOn";
OpcodeNames[TN32Op_RadioOff] = "RadioOff";
OpcodeNames[TN32Op_Poll] = "Poll";
OpcodeNames[TN32Op_MifareSelectTag] = "MifareSelectTag";
OpcodeNames[TN32Op_CardDetect] = "CardDetect";
OpcodeNames[TN32Op_CardSelect] = "CardSelect";
OpcodeNames[TN32Op_CardHalt] = "CardHalt";
OpcodeNames[TN32Op_SetKeyBana] = "SetKeyBana";
OpcodeNames[TN32Op_GetKeyBana] = "GetKeyBana";
OpcodeNames[TN32Op_ReadBlock] = "ReadBlock";
OpcodeNames[TN32Op_WriteBlock] = "WriteBlock";
OpcodeNames[TN32Op_SetKeyAime] = "SetKeyAime";
OpcodeNames[TN32Op_GetKeyAime] = "GetKeyAime";
OpcodeNames[TN32Op_MifareKeySetA] = "MifareKeySetA";
OpcodeNames[TN32Op_MifareAuthorizeA] = "MifareAuthorizeA";
OpcodeNames[TN32Op_MifareRead] = "MifareRead";
OpcodeNames[TN32Op_MifareWrite] = "MifareWrite";
OpcodeNames[TN32Op_MifareKeySetB] = "MifareKeySetB";
OpcodeNames[TN32Op_MifareAuthorizeB] = "MifareAuthorizeB";
OpcodeNames[TN32Op_EnterUpdaterMode] = "EnterUpdaterMode";
OpcodeNames[TN32Op_SendHex] = "SendHex";
OpcodeNames[TN32Op_Reset] = "Reset";

View File

@ -0,0 +1,72 @@
#pragma once
#include <Windows.h>
#include <stdint.h>
#include "nfc/nfc.h"
enum TN32Error {
TN32Error_OK,
TN32Error_CardError,
TN32Error_NoAccept,
TN32Error_InvalidCommand,
TN32Error_InvalidData,
TN32Error_SumError,
TN32Error_HexError,
};
typedef BYTE TN32Error;
enum TN32ErrorLED {
TN32ErrorLED_OK,
TN32ErrorLED_CommandUnknown,
TN32ErrorLED_OverflowErr,
TN32ErrorLED_ParityErr,
TN32ErrorLED_OverrunErr,
TN32ErrorLED_FramingErr,
TN32ErrorLED_SumErr,
TN32ErrorLED_ParameterErr,
TN32ErrorLED_HexErr,
};
typedef BYTE TN32ErrorLED;
/**
* 51 and 55 are guesses based on the code. Makes sense given their opcodes
* too.
* TODO: Validate against a real board
*/
enum TN32_Opcode {
TN32Op_GetFWVersion = 0x30,
TN32Op_GetHWVersion = 0x32,
TN32Op_RadioOn = 0x40,
TN32Op_RadioOff = 0x41,
TN32Op_CardDetect = 0x42,
TN32Op_CardSelect = 0x43,
TN32Op_CardHalt = 0x44,
TN32Op_MifareKeySetA = 0x50, // BNG key
TN32Op_MifareAuthorizeA = 0x51,
TN32Op_MifareRead = 0x52,
TN32Op_MifareWrite = 0x53,
TN32Op_MifareKeySetB = 0x54, // AiMe key
TN32Op_MifareAuthorizeB = 0x55,
// Firmware update
TN32Op_EnterUpdaterMode = 0x60,
TN32Op_SendHex = 0x61,
TN32Op_Reset = 0x62,
TN32Op_SendBindata = 0x63,
TN32Op_BindataExec = 0x64,
// Felica
TN32Op_FelicaPush = 0x70,
TN32Op_FelicaEncap = 0x71,
// No responses to either
Led_SetColour = 0x80,
Led_SetColourRGB = 0x81,
Led_GetInfo = 0xf0,
Led_FirmwareSum = 0xf2,
Led_SendHex = 0xf3,
Led_EnterBootMode = 0xf4,
Led_Reset = 0xf5,
};

View File

@ -42,13 +42,16 @@ void set_eeprom_static_config() {
.m_Region = MiceConfig.sysconf.region & (1 | 2 | 4 | 8),
.m_Rental = MiceConfig.sysconf.rental,
};
strcpy_s(Static.m_strSerialId, sizeof Static.m_strSerialId, MiceConfig.sysconf.serial);
ZeroMemory(Static.m_strSerialId, sizeof Static.m_strSerialId);
DWORD len = strlen(MiceConfig.sysconf.serial);
if (len > sizeof Static.m_strSerialId - 1) len = sizeof Static.m_strSerialId - 1;
memcpy(Static.m_strSerialId, MiceConfig.sysconf.serial, len);
fix_crc(Static);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_STATIC_REG], &Static, sizeof Static);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_STATIC_DUP], &Static, sizeof Static);
}
void build_eeprom() { // return;
void build_eeprom() { // return;
log_info(plfEeprom, "Building default EEPROM file");
memset(EEPROM_DATA, 0xff, EEPROM_SIZE);
@ -97,10 +100,10 @@ void eeprom_fixup() {
set_eeprom_static_config();
set_eeprom_network_config();
AmHistory.m_Region = MiceConfig.sysconf.region & (1 | 2 | 4 | 8);
fix_crc(AmHistory);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_REG], &AmHistory, sizeof AmHistory);
memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_DUP], &AmHistory, sizeof AmHistory);
// AmHistory.m_Region = MiceConfig.sysconf.region & (1 | 2 | 4 | 8);
// fix_crc(AmHistory);
// memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_REG], &AmHistory, sizeof AmHistory);
// memcpy(&EEPROM_DATA[AM_SYSDATAwH_HISTORY_DUP], &AmHistory, sizeof AmHistory);
}
void ensure_valid_eeprom() {

View File

@ -143,7 +143,7 @@ void init_injection(HMODULE hModule) {
if (success) success &= MiceFSAddDevLayers();
MiceFSSetCwd(RING_MOUNT_GAME);
MiceFSSetCwd(RING_MOUNT_GAME "\\");
// Setup default COM devices
init_com_devices();
@ -187,8 +187,10 @@ void init_injection(HMODULE hModule) {
// OPENSSL_add_all_algorithms_noconf (old exe)
// ((void (*)(void))(0x00459770 + imageOffset))();
// OPENSSL_add_all_algorithms_noconf (new exe)
((void (*)(void))(0x00463480 + imageOffset))();
// OPENSSL_add_all_algorithms_noconf (pink exe)
// ((void (*)(void))(0x00463480 + imageOffset))();
// TODO: Find finale offset
}
setup_hooks();

View File

@ -76,6 +76,7 @@ static bool showFps = false;
static bool showEeprom = false;
static bool showSram = false;
static bool showControl = false;
static bool showCardP1 = false;
void InitImGui(unsigned int hookType, IDirect3DDevice9* pDevice) {
if (hookType == UI_HOOK_DX9) {
@ -117,6 +118,34 @@ void InitImGui(unsigned int hookType, IDirect3DDevice9* pDevice) {
}
}
extern BYTE cardLED_RGB_P1[3];
extern BYTE cardLED_RGB_P2[3];
void hud_card(ImGuiKey open_key) {
if (igIsKeyPressed_Bool(open_key, false)) showCardP1 = !showCardP1;
if (!showCardP1) return;
igBegin("Card Reader", NULL, 0);
ImVec4 col;
col.w = 1.0f;
col.x = cardLED_RGB_P1[0] / 511.0f;
col.y = cardLED_RGB_P1[1] / 511.0f;
col.z = cardLED_RGB_P1[2] / 511.0f;
igPushStyleColor_Vec4(ImGuiCol_Button, col);
igButton("Insert card P1", vec0);
igPopStyleColor(1);
col.x = cardLED_RGB_P2[0] / 511.0f;
col.y = cardLED_RGB_P2[1] / 511.0f;
col.z = cardLED_RGB_P2[2] / 511.0f;
igPushStyleColor_Vec4(ImGuiCol_Button, col);
igButton("Insert card P2", vec0);
igPopStyleColor(1);
igEnd();
}
void hud_fps() {
if (igBegin("FPS", NULL,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
@ -898,6 +927,26 @@ void tab_main_keybinds() {
}
}
void tab_main_aime_cards() {
igText(
"Specify the cards to be inserted when using the TN32MSEC AiMe reader module.\nCards can be "
"specified as either an NFC ID or an access code.\nIf a card file is present, it will be "
"used preferentially.");
igColumns(2, "AimeWindow", true);
igSeparator();
bool changed = false;
changed |= AddSettingString("Player 1 Card ID", NULL, &MiceConfig.aime.player1_card);
changed |= AddSettingString("Player 2 Card ID", NULL, &MiceConfig.aime.player2_card);
changed |= AddSettingString("Player 1 Card File", NULL, &MiceConfig.aime.player1_cardfile);
changed |= AddSettingString("Player 2 Card File", NULL, &MiceConfig.aime.player2_cardfile);
igEndColumns();
if (changed) save_current_config();
}
void hud_control(ImGuiKey open_key) {
if (igIsKeyPressed_Bool(open_key, false)) showControl = !showControl;
if (!showControl) return;
@ -919,6 +968,12 @@ void hud_control(ImGuiKey open_key) {
igEndChild();
igEndTabItem();
}
if (igBeginTabItem("AiMe Cards", NULL, 0)) {
igBeginChild_Str("AiMe Cards", vec0, FALSE, 0);
tab_main_aime_cards();
igEndChild();
igEndTabItem();
}
if (igBeginTabItem("Settings", NULL, 0)) {
igBeginChild_Str("Settings", vec0, FALSE, 0);
tab_main_settings();
@ -935,7 +990,7 @@ void hud_control(ImGuiKey open_key) {
void __stdcall hud_gui(unsigned int hookType, IDirect3DDevice9* dev) {
static bool lastAnyOpen = false;
bool anyOpen = showControl || showEeprom || showSram;
bool anyOpen = showControl || showEeprom || showSram || showCardP1;
if (anyOpen != lastAnyOpen) {
changeCursorState = anyOpen ? 1 : 0;
lastAnyOpen = anyOpen;
@ -964,6 +1019,7 @@ void __stdcall hud_gui(unsigned int hookType, IDirect3DDevice9* dev) {
hud_eeprom(ImGuiKey_F11);
hud_sram(ImGuiKey_F10);
hud_control(ImGuiKey_F4);
hud_card(ImGuiKey_F5);
if (hookType == UI_HOOK_DX9) {
igEndFrame();

View File

@ -62,6 +62,26 @@ physical_disk_t UPDATE_USB = {
},
.m_Extended = {{ 0 }},
};
physical_disk_t DOWNLOAD_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_DL",
},
},
},
.m_Extended = {{ 0 }},
};
physical_disk_t LOG_USB = {
.m_BusType = BusTypeUsb,
.m_VID = "13FE",
@ -83,6 +103,27 @@ physical_disk_t LOG_USB = {
},
.m_Extended = {{ 0 }},
};
physical_disk_t MAI_USB_DONGLE = {
.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 = {
// 4 GB partition
{
.m_Size = 0x100000,
.m_Filesystem = MBR_FS_NTFS,
.m_Volume = {
.m_Name = "USBDONGLE",
.m_MountPoint = 'U',
},
},
},
.m_Extended = {{ 0 }},
};
physical_disk_t ALPHA_DVD = {
.m_BusType = BusTypeScsi,
.m_DeviceType = DeviceTypeCdRom,
@ -124,9 +165,12 @@ physical_disk_t APM_HDD = {
physical_disk_t* PHYSICAL_DISKS[] = {
&SSD,
&UPDATE_USB,
// &UPDATE_USB,
// &DOWNLOAD_USB,
// &APM_HDD,
// &MAI_USB_DONGLE,
// &LOG_USB,
// &ALPHA_DVD,
};

View File

@ -366,6 +366,8 @@ inline static BOOL matchVolume(disk_volume_t* volume, LPCSTR lpRootPathName, DWO
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;
if (lpRootPathName[1] == ':' && lpRootPathName[2] == '\\' && lpRootPathName[3] == '\0')
return TRUE;
}
}
return FALSE;

View File

@ -113,20 +113,24 @@ void hook_drives();
#define MBR_FS_NTFS 0x07
#define MBR_FS_EXT_LBA 0x0F
#define MBR_BOOTSTRAP_SIZE 446
#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];
typedef struct MBR_PARTITION {
BYTE status;
BYTE start_chs[3];
BYTE type;
BYTE end_chs[3];
DWORD lba;
DWORD sectors;
} MBR_PARTITION, *PMBR_PARTITION;
typedef struct MBR_HEADER {
BYTE bootstrap_code[MBR_BOOTSTRAP_SIZE];
MBR_PARTITION partitions[4];
BYTE sig[2];
} mbr_t;
} MBR_HEADER, *PMBR_HEADER;
#pragma pack(pop)
typedef MBR_HEADER mbr_t;
#define IOCTL_CDROM_GET_DRIVE_GEOMETRY 0x2404c // #include <Ntddcdrm.h> causes errors

View File

@ -89,6 +89,7 @@ BOOL WINAPI FakeGetVolumeInformationA(LPCSTR lpRootPathName, LPSTR lpVolumeNameB
LPDWORD lpMaximumComponentLength, LPDWORD lpFileSystemFlags,
LPSTR lpFileSystemNameBuffer, DWORD nFileSystemNameSize) {
disk_volume_t* volume = getVolumeByPath(lpRootPathName, VOL_MATCH_ALL);
log_game(plfDrive, "GetVolumeInformationA(%s) = %p", lpRootPathName, volume);
if (volume == NULL) return FALSE;
if (lpVolumeSerialNumber) *lpVolumeSerialNumber = volume->m_pDrive->m_SerialNumber;
@ -130,7 +131,8 @@ BOOL WINAPI FakeGetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint, L
DWORD cchBufferLength) {
log_trace(plfDrive, "GetVolumeNameForVolumeMountPointA(%s)", lpszVolumeMountPoint);
disk_volume_t* volume = getVolumeByPath(lpszVolumeMountPoint, VOL_MATCH_PATH);
disk_volume_t* volume =
getVolumeByPath(lpszVolumeMountPoint, VOL_MATCH_PATH | VOL_MATCH_DOS_DEVICE);
if (volume == NULL) {
SetLastError(ERROR_FILE_NOT_FOUND);
return FALSE;
@ -141,7 +143,7 @@ BOOL WINAPI FakeGetVolumeNameForVolumeMountPointA(LPCSTR lpszVolumeMountPoint, L
}
BOOL WINAPI FakeGetVolumePathNamesForVolumeNameA(LPCSTR lpszVolumeName, LPCH lpszVolumePathNames,
DWORD cchBufferLength, PDWORD lpcchReturnLength) {
log_trace(plfDrive, "GetVolumeNameForVolumeMountPointA(%s)", lpszVolumeName);
log_trace(plfDrive, "FakeGetVolumePathNamesForVolumeNameA(%s)", lpszVolumeName);
disk_volume_t* volume = getVolumeByPath(lpszVolumeName, VOL_MATCH_GUID);
if (volume == NULL) {

View File

@ -128,7 +128,10 @@ HANDLE WINAPI FakeCreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD d
MiceFSRedirectPathW(lpFileName, &lpFileName);
handle = TrueCreateFileW(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
log_misc(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
if (handle == INVALID_HANDLE_VALUE)
log_warning(plfHooks, "CreateFileW(%ls) failed", lpFileName);
else
log_misc(plfHooks, "CreateFileW(%ls) -> 0x%p", lpFileName, handle);
return handle;
}
@ -149,7 +152,10 @@ HANDLE WINAPI FakeCreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dw
MiceFSRedirectPathA(lpFileName, &lpFileName);
HANDLE handle = TrueCreateFileA(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
log_misc(plfHooks, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
if (handle == INVALID_HANDLE_VALUE)
log_warning(plfHooks, "CreateFileA(%s) failed", lpFileName);
else
log_misc(plfHooks, "CreateFileA(%s) -> 0x%p", lpFileName, handle);
return handle;
}
@ -320,17 +326,33 @@ BOOL WINAPI FakeCloseHandle(HANDLE hObject) {
return TrueCloseHandle(hObject);
}
int WINAPIV Fake_stat64i32(const char* path, struct _stat64i32* buffer) {
MiceFSRedirectPathA((char*)path, &path);
return True_stat64i32(path, buffer);
};
void FileTimeToTimet(__time64_t* t, LPFILETIME pft) {
ULARGE_INTEGER time_value;
time_value.HighPart = pft->dwHighDateTime;
time_value.LowPart = pft->dwLowDateTime;
*t = (time_value.QuadPart - 116444736000000000LL) / 10000000LL;
}
int WINAPIV Fake_stat64i32(const char* path, _stat64i32_t* buffer) {
MiceFSRedirectPathA(path, &path);
// NOTE: We can't use True_stat64i32 because it has issues with another other than dir-relative
// child paths
WIN32_FILE_ATTRIBUTE_DATA fileInformation;
if (!GetFileAttributesEx(path, GetFileExInfoStandard, &fileInformation)) return -1;
// TODO: Populate other values. ALLNetProc and OpenSSL only need st_size. atime/ctime are free
// so were added too.
buffer->st_size = fileInformation.nFileSizeLow;
FileTimeToTimet(&buffer->st_atime, &fileInformation.ftLastAccessTime);
FileTimeToTimet(&buffer->st_ctime, &fileInformation.ftCreationTime);
return 0x800;
}
DWORD WINAPI FakeGetFileAttributesA(LPCSTR lpFileName) {
// The game quits out if MiniDump is present!
if (PathEqual(lpFileName, "Y:\\MiniDump\\")) {
return 0;
}
MiceFSRedirectPathA(lpFileName, &lpFileName);
return TrueGetFileAttributesA(lpFileName);
}
@ -338,18 +360,36 @@ DWORD WINAPI FakeGetFileAttributesW(LPCWSTR lpFileName) {
MiceFSRedirectPathW(lpFileName, &lpFileName);
return TrueGetFileAttributesW(lpFileName);
}
BOOL WINAPI FakeCreateDirectoryA(LPCSTR lpFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) {
MiceFSRedirectPathA(lpFileName, &lpFileName);
return TrueCreateDirectoryA(lpFileName, lpSecurityAttributes);
}
BOOL WINAPI FakeCreateDirectoryW(LPCWSTR lpFileName, LPSECURITY_ATTRIBUTES lpSecurityAttributes) {
MiceFSRedirectPathW(lpFileName, &lpFileName);
return TrueCreateDirectoryW(lpFileName, lpSecurityAttributes);
}
HANDLE WINAPI FakeFindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData) {
MiceFSRedirectPathA(lpFileName, &lpFileName);
return TrueFindFirstFileA(lpFileName, lpFindFileData);
}
DWORD WINAPI FakeGetCurrentDirectoryA(DWORD nBufferLength, LPSTR lpBuffer) {
strcpy_s(lpBuffer, nBufferLength, MiceFSGetCwd());
return strnlen_s(lpBuffer, nBufferLength);
LPCSTR cwd = MiceFSGetCwd();
DWORD length = strlen(cwd);
if (nBufferLength < length + 1) {
return length + 1;
}
strcpy_s(lpBuffer, nBufferLength, cwd);
return length;
}
DWORD WINAPI FakeGetCurrentDirectoryW(DWORD nBufferLength, LPWSTR lpBuffer) {
MultiByteToWideChar(CP_ACP, 0, MiceFSGetCwd(), -1, lpBuffer, nBufferLength);
return wcsnlen_s(lpBuffer, nBufferLength);
LPCSTR cwd = MiceFSGetCwd();
DWORD length = strlen(cwd);
if (nBufferLength < (length + 1) * 2) {
return (length + 1) * 2;
}
MultiByteToWideChar(CP_ACP, 0, cwd, -1, lpBuffer, nBufferLength);
return length;
}
void hook_io() {
@ -380,6 +420,10 @@ void hook_io() {
(void**)&TrueGetFileAttributesA);
hook("Kernel32.dll", "GetFileAttributesW", FakeGetFileAttributesW,
(void**)&TrueGetFileAttributesW);
hook("Kernel32.dll", "CreateDirectoryA", FakeCreateDirectoryA,
(void**)&TrueCreateDirectoryA);
hook("Kernel32.dll", "CreateDirectoryW", FakeCreateDirectoryW,
(void**)&TrueCreateDirectoryW);
hook("MSVCR90.DLL", "_stat64i32", Fake_stat64i32, (void**)&True_stat64i32);
}

View File

@ -5,6 +5,20 @@
#define _MICE_FILES extern
#endif
typedef struct {
unsigned int st_dev;
unsigned short st_ino;
unsigned short st_mode;
short st_nlink;
short st_uid;
short st_gid;
unsigned int st_rdev;
long st_size;
__time64_t st_atime;
__time64_t st_mtime;
__time64_t st_ctime;
} _stat64i32_t;
_MICE_FILES HANDLE(WINAPI* TrueCreateFileA)(LPCSTR lpFileName, DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
@ -40,6 +54,11 @@ _MICE_FILES BOOL(WINAPI* TrueDeleteFileW)(LPCWSTR lpFileName);
_MICE_FILES HANDLE(WINAPI* TrueFindFirstFileA)(LPCSTR lpFileName, LPWIN32_FIND_DATA lpFindFileData);
_MICE_FILES DWORD(WINAPI* TrueGetFileAttributesA)(LPCSTR lpFileName);
_MICE_FILES DWORD(WINAPI* TrueGetFileAttributesW)(LPCWSTR lpFileName);
_MICE_FILES BOOL(WINAPI* TrueCreateDirectoryA)(LPCSTR lpFileName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes);
_MICE_FILES BOOL(WINAPI* TrueCreateDirectoryW)(LPCWSTR lpFileName,
LPSECURITY_ATTRIBUTES lpSecurityAttributes);
_MICE_FILES DWORD(WINAPI* TrueGetCurrentDirectoryA)(DWORD nBufferLength, LPSTR lpBuffer);
_MICE_FILES DWORD(WINAPI* TrueGetCurrentDirectoryW)(DWORD nBufferLength, LPWSTR lpBuffer);
@ -65,7 +84,6 @@ typedef BOOL(FnReadFile)(file_context_t* ctx, LPVOID lpBuffer, DWORD nNumberOfBy
typedef BOOL(FnGetFileSizeEx)(file_context_t* ctx, PLARGE_INTEGER lpFileSize);
typedef struct _stat64i32 _stat64i32_t;
static int(WINAPIV* True_stat64i32)(const char* path, _stat64i32_t* buffer);
#define _WriteFile (TrueWriteFile ? TrueWriteFile : WriteFile)

View File

@ -75,7 +75,7 @@ DWORD WINAPI FakeGetIfTable(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder)
typedef struct {
char* name;
unsigned int* address;
const unsigned int* address;
} dns;
dns INTERCEPT_DNS[] = {
@ -114,7 +114,7 @@ DNS_STATUS WINAPI FakeDnsQuery_A(PCSTR pszName, WORD wType, DWORD Options, PVOID
}
}
}
log_warning(plfNetwork, "DNS passthrough for %s", pszName);
log_info(plfNetwork, "DNS passthrough for %s", pszName);
return TrueDnsQuery_A(pszName, wType, Options, pExtra, ppQueryResults, pReserved);
};
@ -129,17 +129,41 @@ INT WSAAPI FakeWSAStringToAddressA(LPSTR AddressString, INT AddressFamily,
lpAddress->sa_family = AF_INET;
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);
*addr = _byteswap_ulong(*INTERCEPT_DNS[i].address);
return ERROR_SUCCESS;
}
}
log_warning(plfNetwork, "WSA DNS passthrough for %s", AddressString);
log_info(plfNetwork, "WSA DNS passthrough for %s", AddressString);
return TrueWSAStringToAddressA(AddressString, AddressFamily, lpProtocolInfo, lpAddress,
lpAddressLength);
}
INT WINAPI Fake_getaddrinfo(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA* pHints,
PADDRINFOA* ppResult) {
if (!pNodeName) return True_getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
for (size_t i = 0; i < sizeof INTERCEPT_DNS / sizeof INTERCEPT_DNS[0]; i++) {
if (strcmp(pNodeName, INTERCEPT_DNS[i].name) == 0) {
char szNewAddress[16];
sprintf_s(szNewAddress, sizeof szNewAddress, "%d.%d.%d.%d",
(*INTERCEPT_DNS[i].address >> 24) & 0xff,
(*INTERCEPT_DNS[i].address >> 16) & 0xff,
(*INTERCEPT_DNS[i].address >> 8) & 0xff, *INTERCEPT_DNS[i].address & 0xff);
szNewAddress[sizeof szNewAddress - 1] = '\0';
log_info(plfNetwork, "GAI DNS Replacing %s with %s:%s", pNodeName, szNewAddress,
pServiceName);
return True_getaddrinfo(szNewAddress, pServiceName, pHints, ppResult);
}
}
// Exclude a few known services
if (strcmp(pNodeName, "0.0.0.0") != 0 && strcmp(pNodeName, "127.0.0.0") != 0 &&
strcmp(pNodeName, "240.0.0.0") != 0)
log_info(plfNetwork, "GAI DNS passthrough for %s:%s", pNodeName, pServiceName);
return True_getaddrinfo(pNodeName, pServiceName, pHints, ppResult);
}
int __stdcall Fake_socket(int domain, int type, int protocol) {
int sock = True_socket(domain, type, protocol);
log_trace(plfNetwork, "Creating new socket: %d/%s/%d -> %d", domain,
@ -179,9 +203,9 @@ int __stdcall Fake_sendto(SOCKET s, const char* buf, int len, int flags, const P
memcpy(&toLocalhost, to, sizeof toLocalhost);
toLocalhost.sin_addr.S_un.S_addr = 0x0100007f; // 127.0.0.1
log_warning(plfNetwork, "(probable) Ping to: %d.%d.%d.%d (%d). Redirecting to localhost",
addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, addr >> 24,
((PSOCKADDR_IN)to)->sin_port, seq);
log_info(plfNetwork, "(probable) Ping to: %d.%d.%d.%d (%d). Redirecting to localhost",
addr & 0xff, (addr >> 8) & 0xff, (addr >> 16) & 0xff, addr >> 24,
((PSOCKADDR_IN)to)->sin_port, seq);
return True_sendto(s, buf, len, flags, (PSOCKADDR)&toLocalhost, tolen);
}
@ -189,13 +213,32 @@ int __stdcall Fake_sendto(SOCKET s, const char* buf, int len, int flags, const P
return True_sendto(s, buf, len, flags, to, tolen);
}
ULONG WINAPI FakeGetAdaptersAddresses(ULONG Family, ULONG Flags, PVOID Reserved,
PIP_ADAPTER_ADDRESSES AdapterAddresses, PULONG SizePointer) {
if (SizePointer == NULL || *SizePointer < sizeof *AdapterAddresses) {
if (SizePointer != NULL) *SizePointer = sizeof *AdapterAddresses;
return ERROR_BUFFER_OVERFLOW;
}
AdapterAddresses->PhysicalAddressLength = 6;
AdapterAddresses->PhysicalAddress[0] = MAC_PREFIX_0;
AdapterAddresses->PhysicalAddress[1] = MAC_PREFIX_1;
AdapterAddresses->PhysicalAddress[2] = MAC_PREFIX_2;
AdapterAddresses->PhysicalAddress[3] = (MiceConfig.network.mac >> 16) & 0xff;
AdapterAddresses->PhysicalAddress[4] = (MiceConfig.network.mac >> 8) & 0xff;
AdapterAddresses->PhysicalAddress[5] = MiceConfig.network.mac & 0xff;
return ERROR_SUCCESS;
};
void hook_network() {
hook("Ws2_32.dll", "connect", Fake_connect, (void**)&True_connect);
hook("Ws2_32.dll", "socket", Fake_socket, (void**)&True_socket);
hook("Ws2_32.dll", "bind", Fake_bind, (void**)&True_bind);
hook("Ws2_32.dll", "sendto", Fake_sendto, (void**)&True_sendto);
hook("Ws2_32.dll", "getaddrinfo", Fake_getaddrinfo, (void**)&True_getaddrinfo);
// hook("Ws2_32.dll", "sendto", Fake_sendto, (void**)&True_sendto);
hook("Ws2_32.dll", "WSAStringToAddressA", FakeWSAStringToAddressA,
(void**)&TrueWSAStringToAddressA);
hook("Iphlpapi.dll", "GetIfTable", FakeGetIfTable, (void**)&TrueGetIfTable);
hook("Dnsapi.dll", "DnsQuery_A", FakeDnsQuery_A, (void**)&TrueDnsQuery_A);
hook("Iphlpapi.dll", "GetAdaptersAddresses", FakeGetAdaptersAddresses, NULL);
}

View File

@ -6,6 +6,8 @@ static int(WINAPI* True_connect)(SOCKET s, const SOCKADDR* name, int namelen);
static int(WINAPI* True_bind)(SOCKET s, const SOCKADDR* addr, int namelen);
static int(WINAPI* True_sendto)(SOCKET s, const char* buf, int len, int flags,
const struct sockaddr* to, int tolen);
static INT(WINAPI* True_getaddrinfo)(PCSTR pNodeName, PCSTR pServiceName, const ADDRINFOA* pHints,
PADDRINFOA* ppResult);
static DWORD(WINAPI* TrueGetIfTable)(PMIB_IFTABLE pIfTable, PULONG pdwSize, BOOL bOrder);

View File

@ -15,8 +15,9 @@ BOOL WINAPI FakeCreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine,
lpProcessInformation);
}
if (strcmp(lpCommandLine, "s:\\mxkeychip.exe") == 0 ||
strcmp(lpCommandLine, "C:\\WINDOWS\\system32\\regini.exe S:\\default_regset.txt") == 0) {
if (lpCommandLine &&
(strcmp(lpCommandLine, "s:\\mxkeychip.exe") == 0 ||
strcmp(lpCommandLine, "C:\\WINDOWS\\system32\\regini.exe S:\\default_regset.txt") == 0)) {
if (lpProcessInformation) {
lpProcessInformation->hProcess = CreateEventA(NULL, FALSE, TRUE, NULL);
lpProcessInformation->hThread = CreateEventA(NULL, FALSE, TRUE, NULL);
@ -51,7 +52,11 @@ BOOL WINAPI FakeCreateProcessW(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
LPPROCESS_INFORMATION lpProcessInformation) {
log_info(plfProcesses, "CreateProcessW %ls %ls", lpApplicationName, lpCommandLine);
if (wcsncmp(lpCommandLine, L"chkdsk.exe", wcslen(L"chkdsk.exe")) == 0) {
// if (lpCommandLine && (wcscmp(lpCommandLine, L"chkdsk.exe") == 0 ||
// wcscmp(lpCommandLine, L"ALLNetProc_Win.exe") == 0 ||
// wcscmp(lpCommandLine, L"ALLNetProc_Ring.exe") == 0 ||
// wcscmp(lpCommandLine, L"ALLNetProc.exe") == 0)) {
if (lpCommandLine && (wcscmp(lpCommandLine, L"chkdsk.exe") == 0)) {
if (lpProcessInformation) {
lpProcessInformation->hProcess = CreateEventA(NULL, FALSE, TRUE, NULL);
lpProcessInformation->hThread = CreateEventA(NULL, FALSE, TRUE, NULL);

View File

@ -24,7 +24,7 @@ static void print_help(char* exe) {
static bool parse_cmdline(int argc, char* argv[]) {
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-h") == 0) {
if (strcmp(argv[i], "--mice-h") == 0) {
print_help(argv[0]);
} else if (strcmp(argv[i], "-b") == 0) {
if (i + 1 == argc) print_help(argv[0]);
@ -92,7 +92,7 @@ static DWORD WINAPI MiceMailslotWatcher(HANDLE* pSlot) {
HANDLE hLogFile = INVALID_HANDLE_VALUE;
if (MiceConfig.mice.log_to_file) {
hLogFile = CreateFileA(MiceConfig.mice.log_file, GENERIC_WRITE, FILE_SHARE_READ, NULL,
hLogFile = CreateFileA(MiceConfig.mice.log_file, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
CREATE_ALWAYS, 0, NULL);
if (hLogFile == INVALID_HANDLE_VALUE) {
fprintf(stderr, "Failed to initialise logging: open %s failed: %d",
@ -174,7 +174,41 @@ BOOL WINAPI MiceHandlerRoutine(DWORD CtrlType) {
ExitProcess(terminate(0));
}
#include "../lib/mice/spad.h"
int main(int argc, char* argv[]) {
// unsigned char spad_new_bytes[16] = {
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x06,
// 0x94, 0x87, 0x82, 0x60, 0x37, 0x73, 0x12, 0x13,
// };
// unsigned char spn[16];
// Spad0Encrypt(spn, spad_new_bytes);
// for (int i = 0; i < 8; i++) printf("%02x", spn[i]);
// puts("");
// for (int i = 8; i < 16; i++) printf("%02x", spn[i]);
// puts("");
// puts("--");
// unsigned char back_out[16];
// Spad0Decrypt(back_out, spn);
// for (int i = 0; i < 8; i++) printf("%02x", back_out[i]);
// puts("");
// for (int i = 8; i < 16; i++) printf("%02x", back_out[i]);
// puts("");
// unsigned char bng[16] = {
// 0xE6, 0xBC, 0x6D, 0x56, 0x83, 0xF6, 0xB6, 0x48,
// 0x4C, 0x24, 0xE4, 0x83, 0xD5, 0xE8, 0x93, 0x7F,
// };
// Spad0Decrypt(back_out, bng);
// for (int i = 0; i < 8; i++) printf("%02x", back_out[i]);
// puts("");
// for (int i = 8; i < 16; i++) printf("%02x", back_out[i]);
// puts("");
// return -1;
load_mice_config();
if (!setup_mailslot()) return 1;
setup_logging();

View File

@ -2,9 +2,9 @@
#define AM_LIB_C_HEADER(name, storage_type) \
int name##DebugLevel = 0; \
struct _##storage_type name; \
struct storage_type name; \
char* name##Version = #name " Ver.mice" MICE_VERSION " Build:" __DATE__ " " __TIME__;
#define AM_LIB_H_HEADER(name, storage_type) \
extern int name##DebugLevel; \
extern struct _##storage_type name; \
extern struct storage_type name; \
extern char* name##Version;

View File

@ -0,0 +1,71 @@
#include "amCmos.h"
AM_LIB_C_HEADER(amCmos, AM_CMOS)
AM_CMOS_STATUS amCmosInit(AM_CMOS_CONFIG *lpConfig) {
if (amCmos.m_bInit != 0) return AM_CMOS_STATUS_ERR_ALREADY_INIT;
if (lpConfig == NULL) return AM_CMOS_STATUS_ERR_INVALID_PARAM;
HANDLE hMutex = CreateMutexA(NULL, 0, "AM_CMOS_MUTEX");
if (hMutex == NULL) return AM_CMOS_STATUS_ERR_SYS;
HANDLE hCmos = CreateFileA("\\\\.\\mxcmos", 0xc0000000, 3, NULL, 3, 0, NULL);
if (hCmos == INVALID_HANDLE_VALUE) {
CloseHandle(hMutex);
return AM_CMOS_STATUS_ERR_OPEN_FAILED;
}
amCmos.m_bInit = TRUE;
amCmos.m_hMutex = hMutex;
amCmos.m_hCmos = hCmos;
memcpy(&amCmos.m_Config, lpConfig, sizeof *lpConfig);
return AM_CMOS_STATUS_OK;
}
AM_CMOS_STATUS amCmosExit(void) {
if (amCmos.m_bInit == 0) return AM_CMOS_STATUS_ERR_NO_INIT;
if (amCmos.m_hMutex != NULL) {
CloseHandle(amCmos.m_hMutex);
amCmos.m_hMutex = NULL;
}
if (amCmos.m_hCmos != INVALID_HANDLE_VALUE) {
CloseHandle(amCmos.m_hCmos);
amCmos.m_hCmos = INVALID_HANDLE_VALUE;
}
amCmos.m_bInit = FALSE;
return AM_CMOS_STATUS_OK;
}
AM_CMOS_STATUS amCmosReadByteInRearpart(BYTE nIndex, LPBYTE lpData) {
if (amCmos.m_bInit == 0) return AM_CMOS_STATUS_ERR_NO_INIT;
if (lpData == NULL || nIndex > 0x7f) return AM_CMOS_STATUS_ERR_INVALID_PARAM;
if (WaitForSingleObject(amCmos.m_hMutex, 0) != WAIT_OBJECT_0) return AM_CMOS_STATUS_ERR_LOCK;
BYTE request[2];
request[0] = nIndex;
request[1] = 0;
DWORD nBytesReturned;
BOOL bErr = DeviceIoControl(amCmos.m_hCmos, IOCTL_MXCMOS_READ, request, sizeof request, lpData,
1, &nBytesReturned, NULL);
int iRet = 0;
if (!bErr) {
iRet = AM_CMOS_STATUS_ERR_SYS;
} else {
iRet = nBytesReturned == 1 ? AM_CMOS_STATUS_OK : AM_CMOS_STATUS_ERR_SYS;
}
if (!ReleaseMutex(amCmos.m_hMutex)) {
if (amCmosDebugLevel > 0)
amiDebugLog("ReleaseMutex Error!! Error Code is %ld!!", GetLastError());
return AM_CMOS_STATUS_ERR_SYS;
}
return iRet;
}

View File

@ -1,3 +1,39 @@
void amCmosReadByteInRearpart(void);
void amCmosSetPartition(void);
#pragma once
#include <Windows.h>
#include "../../dll/smbus.h"
#include "../_am.h"
AM_LIB_H_HEADER(amCmos, AM_CMOS)
typedef enum {
AM_CMOS_STATUS_OK = 0,
AM_CMOS_STATUS_NG = -1,
AM_CMOS_STATUS_ERR_INVALID_PARAM = -2,
AM_CMOS_STATUS_ERR_NO_INIT = -3,
AM_CMOS_STATUS_ERR_ALREADY_INIT = -4,
AM_CMOS_STATUS_ERR_SYS = -5,
AM_CMOS_STATUS_ERR_OPEN_FAILED = -6,
AM_CMOS_STATUS_ERR_LOCK = -7,
} AM_CMOS_STATUS;
typedef struct AM_CMOS_CONFIG {
BYTE index[4];
BYTE m_MbrCount;
} AM_CMOS_CONFIG;
typedef struct AM_CMOS {
BOOL m_bInit;
HANDLE m_hMutex;
HANDLE m_hCmos;
AM_CMOS_CONFIG m_Config;
} AM_CMOS;
AM_CMOS_STATUS amCmosInit(AM_CMOS_CONFIG* lpConfig);
AM_CMOS_STATUS amCmosExit(void);
AM_CMOS_STATUS amCmosReadByteInRearpart(BYTE param_1, LPBYTE param_2);
void amCmosWriteByteInRearpart(void);
void amCmosSetPartition(void);

View File

@ -0,0 +1,118 @@
#include "amDipsw.h"
#include <setupapi.h>
AM_LIB_C_HEADER(amDipsw, AM_DIPSW)
int amDipswCreateMutex(AM_DIPSW *this) {
SECURITY_ATTRIBUTES securityAttributes;
SECURITY_DESCRIPTOR securityDescriptor;
SID_IDENTIFIER_AUTHORITY sid;
PSID *ppSid = &this->m_Sid;
sid.Value[0] = '\0';
sid.Value[1] = '\0';
sid.Value[2] = '\0';
sid.Value[3] = '\0';
sid.Value[4] = '\0';
sid.Value[5] = '\x01';
if (!AllocateAndInitializeSid(&sid, '\x01', 0, 0, 0, 0, 0, 0, 0, 0, ppSid)) {
if (amDipswDebugLevel > 0) amiDebugLog("AllocateAndInitializeSid Error in amDipswInit.");
*ppSid = NULL;
goto fail_cleanup;
}
if (!InitializeSecurityDescriptor(&securityDescriptor, 1)) {
if (amDipswDebugLevel > 0)
amiDebugLog("InitializeSecurityDescriptor Error in amDipswInit.");
goto fail_cleanup;
}
if (!SetSecurityDescriptorDacl(&securityDescriptor, 1, NULL, 0)) {
if (amDipswDebugLevel > 0) amiDebugLog("SetSecurityDescriptorDacl Error in amDipswInit.");
goto fail_cleanup;
}
securityAttributes.lpSecurityDescriptor = &securityDescriptor;
securityAttributes.nLength = 0xc;
securityAttributes.bInheritHandle = 0;
HANDLE mutex = CreateMutexA(&securityAttributes, 0, "Global\\AM_PCA9535_MUTEX");
this->m_Mutex = mutex;
if (mutex != NULL) return 0;
if (amDipswDebugLevel > 0) amiDebugLog("CreateMutexA Error(%ld).", GetLastError());
fail_cleanup:
if (this->m_Mutex != NULL) {
CloseHandle(this->m_Mutex);
this->m_Mutex = NULL;
}
if (*ppSid != NULL) {
FreeSid(*ppSid);
*ppSid = NULL;
}
return -5;
}
HANDLE amDipswCreateDeviceFile(GUID *guid, DWORD memberIndex, char *name) {
HDEVINFO deviceInfoSet;
BOOL BVar3;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData;
SP_DEVICE_INTERFACE_DETAIL_DATA_A deviceInterfaceDetailData[204];
if (guid == NULL) {
if (amDipswDebugLevel > 0) amiDebugLog("PARAM Error.");
return INVALID_HANDLE_VALUE;
}
deviceInfoSet = SetupDiGetClassDevsA(guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (deviceInfoSet == INVALID_HANDLE_VALUE) {
if (amDipswDebugLevel > 0) amiDebugLog("SetupDiGetClassDevs Error(%ld).", GetLastError());
return INVALID_HANDLE_VALUE;
}
char szFilename[260];
ZeroMemory(szFilename, 4);
deviceInterfaceData.cbSize = 0x1c;
if (!SetupDiEnumDeviceInterfaces(deviceInfoSet, NULL, guid, memberIndex, &deviceInterfaceData)) {
if (amDipswDebugLevel > 0)
amiDebugLog("SetupDiEnumDeviceInterfaces Error(%ld).", GetLastError());
} else {
deviceInterfaceDetailData[0].cbSize = 5;
if (SetupDiGetDeviceInterfaceDetailA(deviceInfoSet, &deviceInterfaceData,
deviceInterfaceDetailData, 0x400, NULL, NULL)) {
strcpy_s(szFilename, 4, deviceInterfaceDetailData[0].DevicePath);
if (name != NULL) {
strcat_s(szFilename, 4, "\\");
strcat_s(szFilename, 4, name);
}
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return CreateFileA(szFilename, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
FILE_SUPPORTS_GHOSTING, NULL);
}
if (amDipswDebugLevel > 0) amiDebugLog("SetupDiGetClassDevs Error(%ld).", GetLastError());
}
SetupDiDestroyDeviceInfoList(deviceInfoSet);
return INVALID_HANDLE_VALUE;
}
void amDipswExit(void);
void amDipswGetDriverVerision(void);
void amDipswInit(void);
void amDipswModifyByte(void);
void amDipswModifyByteEx(void);
void amDipswModifyByteInternal(void);
void amDipswModifyByteInternalEx(void);
void amDipswMxsmbusStatusCheck(void);
void amDipswReadByte(void);
void amDipswReadByteInternal(void);
void amDipswReadByteInternalEx(void);
void amDipswRequestGetDipsw(void);
void amDipswRequestGetPushsw(void);
void amDipswRequestReadByte(void);
void amDipswRequestSetJvsIoctl(void);
void amDipswRequestSetLed(void);
void amDipswResponse(void);
void amDipswResponseInternalEx(void);
void amDipswWriteByte(void);
void amDipswWriteByteInternal(void);
void amDipswWriteByteInternalEx(void);

View File

@ -1,5 +1,24 @@
void amDipswCreateDeviceFile(void);
void amDipswCreateMutex(void);
#pragma once
#include <Windows.h>
#include "../_am.h"
AM_LIB_H_HEADER(amDipsw, AM_DIPSW)
typedef struct AM_DIPSW {
BOOL m_Init;
HANDLE m_Mutex;
HANDLE m_Handle;
BYTE m_Addr;
//
OVERLAPPED m_Overlapped;
PSID m_Sid;
} AM_DIPSW;
int amDipswCreateMutex(AM_DIPSW *this);
HANDLE amDipswCreateDeviceFile(GUID *guid, DWORD memberIndex, char *name);
void amDipswExit(void);
void amDipswGetDriverVerision(void);
void amDipswInit(void);

View File

@ -5,12 +5,12 @@
#include "../_am.h"
#include "../libpcp/pcpa.h"
typedef struct _AM_DONGLE_DS_CHALLENGE {
typedef struct AM_DONGLE_DS_CHALLENGE {
byte challenge[7];
byte pages[4][20];
} AM_DONGLE_DS_CHALLENGE;
typedef struct _AM_DONGLE_SSD_CHALLENGE {
typedef struct AM_DONGLE_SSD_CHALLENGE {
byte challenge[16];
byte response[16];
} AM_DONGLE_SSD_CHALLENGE;
@ -25,7 +25,7 @@ typedef enum {
AM_DONGLE_SEQ_DONE = 8,
} AM_DONGLE_SEQ;
typedef struct _AM_DONGLE {
typedef struct AM_DONGLE {
BOOL m_init;
BOOL done_init;
BOOL available;

View File

@ -26,7 +26,7 @@ typedef struct {
int WriteTimeout;
} AM_EEPROM_TIMEOUT;
typedef struct _AM_EEPROM {
typedef struct AM_EEPROM {
BOOL m_init;
AM_EEPROM_TIMEOUT m_timeout;
HANDLE m_mutex;

View File

@ -144,7 +144,7 @@ typedef enum {
AM_INSTALL_REQUEST_18 = 18,
} AM_INSTALL_REQUEST;
typedef struct _AM_INSTALL {
typedef struct AM_INSTALL {
BOOL m_init;
AM_INSTALL_SEQ m_nextSeq;
AM_INSTALL_REQUEST m_requestCode;

View File

@ -13,3 +13,4 @@ void amNetworkResponseCheck(void);
void amNetworkSendAndRecvEx(void);
void amNetworkSendRequest(void);
void amNetworkSetCommandModifyProperty(void);
void amNetworkPcpAddCommandInterface(void);

View File

@ -14,7 +14,7 @@ typedef struct {
DWORD m_elementCount;
} AM_COLUMBA_REQUEST;
typedef struct _AM_OEMSTRING {
typedef struct AM_OEMSTRING {
BOOL m_loaded;
CHAR m_biosVersion[32];
CHAR m_biosDate[11];

View File

@ -158,12 +158,12 @@ AM_PLATFORM_STATUS amPlatformGetPlatformId(AM_PLATFORM_PLATFORM_ID *platformId)
strncpy_s(amPlatform.m_platformId.strPlatformId,
sizeof amPlatform.m_platformId.strPlatformId, oemstringPlatform, 0xffffffff);
} else if (amOemstringGetManufacturer(oemstringManufacturer) == AM_OEMSTRING_STATUS_OK) {
if (strcmp(oemstringManufacturer, "NEC") == 0) {
if (strcmp(oemstringManufacturer, MANUFACTURER_RE) == 0) {
strncpy_s(amPlatform.m_platformId.strPlatformId,
sizeof amPlatform.m_platformId.strPlatformId, PLATFORM_RINGEDGE,
0xffffffff);
} else if (strcmp(oemstringManufacturer, "Supermicro") == 0 ||
strcmp(oemstringManufacturer, "Advantech") == 0) {
} else if (strcmp(oemstringManufacturer, MANUFACTURER_RW_1) == 0 ||
strcmp(oemstringManufacturer, MANUFACTURER_RW_2) == 0) {
strncpy_s(amPlatform.m_platformId.strPlatformId,
sizeof amPlatform.m_platformId.strPlatformId, PLATFORM_RINGWIDE,
0xffffffff);
@ -198,9 +198,9 @@ AM_PLATFORM_STATUS amPlatformGetBoardType(AM_PLATFORM_BOARD_TYPE *boardType) {
}
if (strcmp(platformId.strPlatformId, PLATFORM_RINGWIDE) == 0) {
if (strcmp(oemstringManufacturer, "Supermicro") == 0) {
if (strcmp(oemstringManufacturer, MANUFACTURER_RW_1) == 0) {
*boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_RW_SPEC_1;
} else if (strcmp(oemstringManufacturer, "Advantech") == 0) {
} else if (strcmp(oemstringManufacturer, MANUFACTURER_RW_2) == 0) {
*boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_RW_SPEC_2;
} else {
*boardType = amPlatform.m_boardType = AM_PLATFORM_BOARD_TYPE_UNKNOWN;
@ -211,7 +211,7 @@ AM_PLATFORM_STATUS amPlatformGetBoardType(AM_PLATFORM_BOARD_TYPE *boardType) {
}
if (strcmp(platformId.strPlatformId, PLATFORM_RINGEDGE) == 0) {
if (strcmp(oemstringManufacturer, "NEC") == 0) {
if (strcmp(oemstringManufacturer, MANUFACTURER_RE) == 0) {
ZeroMemory(oemstring4, sizeof oemstring4);
if (amOemstringGetOemstring(oemstring4, 4) != AM_OEMSTRING_STATUS_OK) {

View File

@ -10,6 +10,10 @@ AM_LIB_H_HEADER(amPlatform, AM_PLATFORM)
#define PLATFORM_RINGEDGE "AAL"
#define PLATFORM_RINGEDGE2 "AAL2" // Also AAS in places
#define MANUFACTURER_RE "NEC"
#define MANUFACTURER_RW_1 "Supermicro"
#define MANUFACTURER_RW_2 "Advantech"
typedef struct {
char strPlatformId[4];
} AM_PLATFORM_PLATFORM_ID;
@ -22,7 +26,7 @@ typedef enum {
AM_PLATFORM_BOARD_TYPE_UNKNOWN = 4,
} AM_PLATFORM_BOARD_TYPE;
typedef struct _AM_PLATFORM {
typedef struct AM_PLATFORM {
BOOL m_boardTypeCached;
AM_PLATFORM_BOARD_TYPE m_boardType;
BOOL m_platformIdCached;

View File

@ -6,7 +6,7 @@
AM_LIB_H_HEADER(amSerialId, AM_SERIAL_ID)
typedef struct _AM_SERIAL_ID {
typedef struct AM_SERIAL_ID {
unsigned char Rsv00;
} AM_SERIAL_ID;

View File

@ -6,7 +6,7 @@
AM_LIB_H_HEADER(amSram, AM_SRAM)
typedef struct _AM_SRAM {
typedef struct AM_SRAM {
DWORD m_init;
HANDLE m_handle;
LARGE_INTEGER m_size;

View File

@ -68,3 +68,13 @@ amInstall = static_library(
libpcp,
],
)
amCmos = static_library(
'amCmos',
sources: [
'amCmos.c',
],
link_with: [
amiDebug,
],
)

View File

@ -6,7 +6,7 @@
AM_LIB_H_HEADER(amiCrc, AMI_CRC)
typedef struct _AMI_CRC {
typedef struct AMI_CRC {
uint32_t m_init;
uint32_t m_table[256];
} AMI_CRC;

View File

@ -6,7 +6,7 @@
#include "../_am.h"
typedef struct _AM_DEBUG {
typedef struct AM_DEBUG {
unsigned char Rsv00;
} AM_DEBUG;
AM_LIB_H_HEADER(amiDebug, AM_DEBUG)

View File

@ -6,7 +6,7 @@
AM_LIB_H_HEADER(amiTimer, AMI_TIMER)
typedef struct _AMI_TIMER {
typedef struct AMI_TIMER {
unsigned char Rsv00;
} AMI_TIMER;

View File

@ -0,0 +1,233 @@
#include "blowfish.h"
static DWORD INIT_BLOWFISH_P[18] = {
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344, 0xA4093822, 0x299F31D0,
0x082EFA98, 0xEC4E6C89, 0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917, 0x9216D5D9, 0x8979FB1B,
};
static DWORD INIT_BLOWFISH_S[4][256] = {
{
0xD1310BA6, 0x98DFB5AC, 0x2FFD72DB, 0xD01ADFB7, 0xB8E1AFED, 0x6A267E96, 0xBA7C9045,
0xF12C7F99, 0x24A19947, 0xB3916CF7, 0x0801F2E2, 0x858EFC16, 0x636920D8, 0x71574E69,
0xA458FEA3, 0xF4933D7E, 0x0D95748F, 0x728EB658, 0x718BCD58, 0x82154AEE, 0x7B54A41D,
0xC25A59B5, 0x9C30D539, 0x2AF26013, 0xC5D1B023, 0x286085F0, 0xCA417918, 0xB8DB38EF,
0x8E79DCB0, 0x603A180E, 0x6C9E0E8B, 0xB01E8A3E, 0xD71577C1, 0xBD314B27, 0x78AF2FDA,
0x55605C60, 0xE65525F3, 0xAA55AB94, 0x57489862, 0x63E81440, 0x55CA396A, 0x2AAB10B6,
0xB4CC5C34, 0x1141E8CE, 0xA15486AF, 0x7C72E993, 0xB3EE1411, 0x636FBC2A, 0x2BA9C55D,
0x741831F6, 0xCE5C3E16, 0x9B87931E, 0xAFD6BA33, 0x6C24CF5C, 0x7A325381, 0x28958677,
0x3B8F4898, 0x6B4BB9AF, 0xC4BFE81B, 0x66282193, 0x61D809CC, 0xFB21A991, 0x487CAC60,
0x5DEC8032, 0xEF845D5D, 0xE98575B1, 0xDC262302, 0xEB651B88, 0x23893E81, 0xD396ACC5,
0x0F6D6FF3, 0x83F44239, 0x2E0B4482, 0xA4842004, 0x69C8F04A, 0x9E1F9B5E, 0x21C66842,
0xF6E96C9A, 0x670C9C61, 0xABD388F0, 0x6A51A0D2, 0xD8542F68, 0x960FA728, 0xAB5133A3,
0x6EEF0B6C, 0x137A3BE4, 0xBA3BF050, 0x7EFB2A98, 0xA1F1651D, 0x39AF0176, 0x66CA593E,
0x82430E88, 0x8CEE8619, 0x456F9FB4, 0x7D84A5C3, 0x3B8B5EBE, 0xE06F75D8, 0x85C12073,
0x401A449F, 0x56C16AA6, 0x4ED3AA62, 0x363F7706, 0x1BFEDF72, 0x429B023D, 0x37D0D724,
0xD00A1248, 0xDB0FEAD3, 0x49F1C09B, 0x075372C9, 0x80991B7B, 0x25D479D8, 0xF6E8DEF7,
0xE3FE501A, 0xB6794C3B, 0x976CE0BD, 0x04C006BA, 0xC1A94FB6, 0x409F60C4, 0x5E5C9EC2,
0x196A2463, 0x68FB6FAF, 0x3E6C53B5, 0x1339B2EB, 0x3B52EC6F, 0x6DFC511F, 0x9B30952C,
0xCC814544, 0xAF5EBD09, 0xBEE3D004, 0xDE334AFD, 0x660F2807, 0x192E4BB3, 0xC0CBA857,
0x45C8740F, 0xD20B5F39, 0xB9D3FBDB, 0x5579C0BD, 0x1A60320A, 0xD6A100C6, 0x402C7279,
0x679F25FE, 0xFB1FA3CC, 0x8EA5E9F8, 0xDB3222F8, 0x3C7516DF, 0xFD616B15, 0x2F501EC8,
0xAD0552AB, 0x323DB5FA, 0xFD238760, 0x53317B48, 0x3E00DF82, 0x9E5C57BB, 0xCA6F8CA0,
0x1A87562E, 0xDF1769DB, 0xD542A8F6, 0x287EFFC3, 0xAC6732C6, 0x8C4F5573, 0x695B27B0,
0xBBCA58C8, 0xE1FFA35D, 0xB8F011A0, 0x10FA3D98, 0xFD2183B8, 0x4AFCB56C, 0x2DD1D35B,
0x9A53E479, 0xB6F84565, 0xD28E49BC, 0x4BFB9790, 0xE1DDF2DA, 0xA4CB7E33, 0x62FB1341,
0xCEE4C6E8, 0xEF20CADA, 0x36774C01, 0xD07E9EFE, 0x2BF11FB4, 0x95DBDA4D, 0xAE909198,
0xEAAD8E71, 0x6B93D5A0, 0xD08ED1D0, 0xAFC725E0, 0x8E3C5B2F, 0x8E7594B7, 0x8FF6E2FB,
0xF2122B64, 0x8888B812, 0x900DF01C, 0x4FAD5EA0, 0x688FC31C, 0xD1CFF191, 0xB3A8C1AD,
0x2F2F2218, 0xBE0E1777, 0xEA752DFE, 0x8B021FA1, 0xE5A0CC0F, 0xB56F74E8, 0x18ACF3D6,
0xCE89E299, 0xB4A84FE0, 0xFD13E0B7, 0x7CC43B81, 0xD2ADA8D9, 0x165FA266, 0x80957705,
0x93CC7314, 0x211A1477, 0xE6AD2065, 0x77B5FA86, 0xC75442F5, 0xFB9D35CF, 0xEBCDAF0C,
0x7B3E89A0, 0xD6411BD3, 0xAE1E7E49, 0x00250E2D, 0x2071B35E, 0x226800BB, 0x57B8E0AF,
0x2464369B, 0xF009B91E, 0x5563911D, 0x59DFA6AA, 0x78C14389, 0xD95A537F, 0x207D5BA2,
0x02E5B9C5, 0x83260376, 0x6295CFA9, 0x11C81968, 0x4E734A41, 0xB3472DCA, 0x7B14A94A,
0x1B510052, 0x9A532915, 0xD60F573F, 0xBC9BC6E4, 0x2B60A476, 0x81E67400, 0x08BA6FB5,
0x571BE91F, 0xF296EC6B, 0x2A0DD915, 0xB6636521, 0xE7B9F9B6, 0xFF34052E, 0xC5855664,
0x53B02D5D, 0xA99F8FA1, 0x8BA4799, 0x6E85076A,
},
{
0x4B7A70E9, 0xB5B32944, 0xDB75092E, 0xC4192623, 0xAD6EA6B0, 0x49A7DF7D, 0x9CEE60B8,
0x8FEDB266, 0xECAA8C71, 0x699A17FF, 0x5664526C, 0xC2B19EE1, 0x193602A5, 0x75094C29,
0xA0591340, 0xE4183A3E, 0x3F54989A, 0x5B429D65, 0x6B8FE4D6, 0x99F73FD6, 0xA1D29C07,
0xEFE830F5, 0x4D2D38E6, 0xF0255DC1, 0x4CDD2086, 0x8470EB26, 0x6382E9C6, 0x021ECC5E,
0x09686B3F, 0x3EBAEFC9, 0x3C971814, 0x6B6A70A1, 0x687F3584, 0x52A0E286, 0xB79C5305,
0xAA500737, 0x3E07841C, 0x7FDEAE5C, 0x8E7D44EC, 0x5716F2B8, 0xB03ADA37, 0xF0500C0D,
0xF01C1F04, 0x0200B3FF, 0xAE0CF51A, 0x3CB574B2, 0x25837A58, 0xDC0921BD, 0xD19113F9,
0x7CA92FF6, 0x94324773, 0x22F54701, 0x3AE5E581, 0x37C2DADC, 0xC8B57634, 0x9AF3DDA7,
0xA9446146, 0x0FD0030E, 0xECC8C73E, 0xA4751E41, 0xE238CD99, 0x3BEA0E2F, 0x3280BBA1,
0x183EB331, 0x4E548B38, 0x4F6DB908, 0x6F420D03, 0xF60A04BF, 0x2CB81290, 0x24977C79,
0x5679B072, 0xBCAF89AF, 0xDE9A771F, 0xD9930810, 0xB38BAE12, 0xDCCF3F2E, 0x5512721F,
0x2E6B7124, 0x501ADDE6, 0x9F84CD87, 0x7A584718, 0x7408DA17, 0xBC9F9ABC, 0xE94B7D8C,
0xEC7AEC3A, 0xDB851DFA, 0x63094366, 0xC464C3D2, 0xEF1C1847, 0x3215D908, 0xDD433B37,
0x24C2BA16, 0x12A14D43, 0x2A65C451, 0x50940002, 0x133AE4DD, 0x71DFF89E, 0x10314E55,
0x81AC77D6, 0x5F11199B, 0x043556F1, 0xD7A3C76B, 0x3C11183B, 0x5924A509, 0xF28FE6ED,
0x97F1FBFA, 0x9EBABF2C, 0x1E153C6E, 0x86E34570, 0xEAE96FB1, 0x860E5E0A, 0x5A3E2AB3,
0x771FE71C, 0x4E3D06FA, 0x2965DCB9, 0x99E71D0F, 0x803E89D6, 0x5266C825, 0x2E4CC978,
0x9C10B36A, 0xC6150EBA, 0x94E2EA78, 0xA5FC3C53, 0x1E0A2DF4, 0xF2F74EA7, 0x361D2B3D,
0x1939260F, 0x19C27960, 0x5223A708, 0xF71312B6, 0xEBADFE6E, 0xEAC31F66, 0xE3BC4595,
0xA67BC883, 0xB17F37D1, 0x018CFF28, 0xC332DDEF, 0xBE6C5AA5, 0x65582185, 0x68AB9802,
0xEECEA50F, 0xDB2F953B, 0x2AEF7DAD, 0x5B6E2F84, 0x1521B628, 0x29076170, 0xECDD4775,
0x619F1510, 0x13CCA830, 0xEB61BD96, 0x0334FE1E, 0xAA0363CF, 0xB5735C90, 0x4C70A239,
0xD59E9E0B, 0xCBAADE14, 0xEECC86BC, 0x60622CA7, 0x9CAB5CAB, 0xB2F3846E, 0x648B1EAF,
0x19BDF0CA, 0xA02369B9, 0x655ABB50, 0x40685A32, 0x3C2AB4B3, 0x319EE9D5, 0xC021B8F7,
0x9B540B19, 0x875FA099, 0x95F7997E, 0x623D7DA8, 0xF837889A, 0x97E32D77, 0x11ED935F,
0x16681281, 0x0E358829, 0xC7E61FD6, 0x96DEDFA1, 0x7858BA99, 0x57F584A5, 0x1B227263,
0x9B83C3FF, 0x1AC24696, 0xCDB30AEB, 0x532E3054, 0x8FD948E4, 0x6DBC3128, 0x58EBF2EF,
0x34C6FFEA, 0xFE28ED61, 0xEE7C3C73, 0x5D4A14D9, 0xE864B7E3, 0x42105D14, 0x203E13E0,
0x45EEE2B6, 0xA3AAABEA, 0xDB6C4F15, 0xFACB4FD0, 0xC742F442, 0xEF6ABBB5, 0x654F3B1D,
0x41CD2105, 0xD81E799E, 0x86854DC7, 0xE44B476A, 0x3D816250, 0xCF62A1F2, 0x5B8D2646,
0xFC8883A0, 0xC1C7B6A3, 0x7F1524C3, 0x69CB7492, 0x47848A0B, 0x5692B285, 0x095BBF00,
0xAD19489D, 0x1462B174, 0x23820E00, 0x58428D2A, 0x0C55F5EA, 0x1DADF43E, 0x233F7061,
0x3372F092, 0x8D937E41, 0xD65FECF1, 0x6C223BDB, 0x7CDE3759, 0xCBEE7460, 0x4085F2A7,
0xCE77326E, 0xA6078084, 0x19F8509E, 0xE8EFD855, 0x61D99735, 0xA969A7AA, 0xC50C06C2,
0x5A04ABFC, 0x800BCADC, 0x9E447A2E, 0xC3453484, 0xFDD56705, 0x0E1E9EC9, 0xDB73DBD3,
0x105588CD, 0x675FDA79, 0xE3674340, 0xC5C43465, 0x713E38D8, 0x3D28F89E, 0xF16DFF20,
0x153E21E7, 0x8FB03D4A, 0xE6E39F2B, 0xDB83ADF7,
},
{
0xE93D5A68, 0x948140F7, 0xF64C261C, 0x94692934, 0x411520F7, 0x7602D4F7, 0xBCF46B2E,
0xD4A20068, 0xD4082471, 0x3320F46A, 0x43B7D4B7, 0x500061AF, 0x1E39F62E, 0x97244546,
0x14214F74, 0xBF8B8840, 0x4D95FC1D, 0x96B591AF, 0x70F4DDD3, 0x66A02F45, 0xBFBC09EC,
0x03BD9785, 0x7FAC6DD0, 0x31CB8504, 0x96EB27B3, 0x55FD3941, 0xDA2547E6, 0xABCA0A9A,
0x28507825, 0x530429F4, 0x0A2C86DA, 0xE9B66DFB, 0x68DC1462, 0xD7486900, 0x680EC0A4,
0x27A18DEE, 0x4F3FFEA2, 0xE887AD8C, 0xB58CE006, 0x7AF4D6B6, 0xAACE1E7C, 0xD3375FEC,
0xCE78A399, 0x406B2A42, 0x20FE9E35, 0xD9F385B9, 0xEE39D7AB, 0x3B124E8B, 0x1DC9FAF7,
0x4B6D1856, 0x26A36631, 0xEAE397B2, 0x3A6EFA74, 0xDD5B4332, 0x6841E7F7, 0xCA7820FB,
0xFB0AF54E, 0xD8FEB397, 0x454056AC, 0xBA489527, 0x55533A3A, 0x20838D87, 0xFE6BA9B7,
0xD096954B, 0x55A867BC, 0xA1159A58, 0xCCA92963, 0x99E1DB33, 0xA62A4A56, 0x3F3125F9,
0x5EF47E1C, 0x9029317C, 0xFDF8E802, 0x04272F70, 0x80BB155C, 0x05282CE3, 0x95C11548,
0xE4C66D22, 0x48C1133F, 0xC70F86DC, 0x07F9C9EE, 0x41041F0F, 0x404779A4, 0x5D886E17,
0x325F51EB, 0xD59BC0D1, 0xF2BCC18F, 0x41113564, 0x257B7834, 0x602A9C60, 0xDFF8E8A3,
0x1F636C1B, 0x0E12B4C2, 0x02E1329E, 0xAF664FD1, 0xCAD18115, 0x6B2395E0, 0x333E92E1,
0x3B240B62, 0xEEBEB922, 0x85B2A20E, 0xE6BA0D99, 0xDE720C8C, 0x2DA2F728, 0xD0127845,
0x95B794FD, 0x647D0862, 0xE7CCF5F0, 0x5449A36F, 0x877D48FA, 0xC39DFD27, 0xF33E8D1E,
0x0A476341, 0x992EFF74, 0x3A6F6EAB, 0xF4F8FD37, 0xA812DC60, 0xA1EBDDF8, 0x991BE14C,
0xDB6E6B0D, 0xC67B5510, 0x6D672C37, 0x2765D43B, 0xDCD0E804, 0xF1290DC7, 0xCC00FFA3,
0xB5390F92, 0x690FED0B, 0x667B9FFB, 0xCEDB7D9C, 0xA091CF0B, 0xD9155EA3, 0xBB132F88,
0x515BAD24, 0x7B9479BF, 0x763BD6EB, 0x37392EB3, 0xCC115979, 0x8026E297, 0xF42E312D,
0x6842ADA7, 0xC66A2B3B, 0x12754CCC, 0x782EF11C, 0x6A124237, 0xB79251E7, 0x06A1BBE6,
0x4BFB6350, 0x1A6B1018, 0x11CAEDFA, 0x3D25BDD8, 0xE2E1C3C9, 0x44421659, 0x0A121386,
0xD90CEC6E, 0xD5ABEA2A, 0x64AF674E, 0xDA86A85F, 0xBEBFE988, 0x64E4C3FE, 0x9DBC8057,
0xF0F7C086, 0x60787BF8, 0x6003604D, 0xD1FD8346, 0xF6381FB0, 0x7745AE04, 0xD736FCCC,
0x83426B33, 0xF01EAB71, 0xB0804187, 0x3C005E5F, 0x77A057BE, 0xBDE8AE24, 0x55464299,
0xBF582E61, 0x4E58F48F, 0xF2DDFDA2, 0xF474EF38, 0x8789BDC2, 0x5366F9C3, 0xC8B38E74,
0xB475F255, 0x46FCD9B9, 0x7AEB2661, 0x8B1DDF84, 0x846A0E79, 0x915F95E2, 0x466E598E,
0x20B45770, 0x8CD55591, 0xC902DE4C, 0xB90BACE1, 0xBB8205D0, 0x11A86248, 0x7574A99E,
0xB77F19B6, 0xE0A9DC09, 0x662D09A1, 0xC4324633, 0xE85A1F02, 0x09F0BE8C, 0x4A99A025,
0x1D6EFE10, 0x1AB93D1D, 0x0BA5A4DF, 0xA186F20F, 0x2868F169, 0xDCB7DA83, 0x573906FE,
0xA1E2CE9B, 0x4FCD7F52, 0x50115E01, 0xA70683FA, 0xA002B5C4, 0x0DE6D027, 0x9AF88C27,
0x773F8641, 0xC3604C06, 0x61A806B5, 0xF0177A28, 0xC0F586E0, 0x006058AA, 0x30DC7D62,
0x11E69ED7, 0x2338EA63, 0x53C2DD94, 0xC2C21634, 0xBBCBEE56, 0x90BCB6DE, 0xEBFC7DA1,
0xCE591D76, 0x6F05E409, 0x4B7C0188, 0x39720A3D, 0x7C927C24, 0x86E3725F, 0x724D9DB9,
0x1AC15BB4, 0xD39EB8FC, 0xED545578, 0x08FCA5B5, 0xD83D7CD3, 0x4DAD0FC4, 0x1E50EF5E,
0xB161E6F8, 0xA28514D9, 0x6C51133C, 0x6FD5C7E7, 0x56E14EC4, 0x362ABFCE, 0xDDC6C837,
0xD79A3234, 0x92638212, 0x670EFA8E, 0x406000E0,
},
{
0x3A39CE37, 0xD3FAF5CF, 0xABC27737, 0x5AC52D1B, 0x5CB0679E, 0x4FA33742, 0xD3822740,
0x99BC9BBE, 0xD5118E9D, 0xBF0F7315, 0xD62D1C7E, 0xC700C47B, 0xB78C1B6B, 0x21A19045,
0xB26EB1BE, 0x6A366EB4, 0x5748AB2F, 0xBC946E79, 0xC6A376D2, 0x6549C2C8, 0x530FF8EE,
0x468DDE7D, 0xD5730A1D, 0x4CD04DC6, 0x2939BBDB, 0xA9BA4650, 0xAC9526E8, 0xBE5EE304,
0xA1FAD5F0, 0x6A2D519A, 0x63EF8CE2, 0x9A86EE22, 0xC089C2B8, 0x43242EF6, 0xA51E03AA,
0x9CF2D0A4, 0x83C061BA, 0x9BE96A4D, 0x8FE51550, 0xBA645BD6, 0x2826A2F9, 0xA73A3AE1,
0x4BA99586, 0xEF5562E9, 0xC72FEFD3, 0xF752F7DA, 0x3F046F69, 0x77FA0A59, 0x80E4A915,
0x87B08601, 0x9B09E6AD, 0x3B3EE593, 0xE990FD5A, 0x9E34D797, 0x2CF0B7D9, 0x022B8B51,
0x96D5AC3A, 0x017DA67D, 0xD1CF3ED6, 0x7C7D2D28, 0x1F9F25CF, 0xADF2B89B, 0x5AD6B472,
0x5A88F54C, 0xE029AC71, 0xE019A5E6, 0x47B0ACFD, 0xED93FA9B, 0xE8D3C48D, 0x283B57CC,
0xF8D56629, 0x79132E28, 0x785F0191, 0xED756055, 0xF7960E44, 0xE3D35E8C, 0x15056DD4,
0x88F46DBA, 0x03A16125, 0x0564F0BD, 0xC3EB9E15, 0x3C9057A2, 0x97271AEC, 0xA93A072A,
0x1B3F6D9B, 0x1E6321F5, 0xF59C66FB, 0x26DCF319, 0x7533D928, 0xB155FDF5, 0x03563482,
0x8ABA3CBB, 0x28517711, 0xC20AD9F8, 0xABCC5167, 0xCCAD925F, 0x4DE81751, 0x3830DC8E,
0x379D5862, 0x9320F991, 0xEA7A90C2, 0xFB3E7BCE, 0x5121CE64, 0x774FBE32, 0xA8B6E37E,
0xC3293D46, 0x48DE5369, 0x6413E680, 0xA2AE0810, 0xDD6DB224, 0x69852DFD, 0x09072166,
0xB39A460A, 0x6445C0DD, 0x586CDECF, 0x1C20C8AE, 0x5BBEF7DD, 0x1B588D40, 0xCCD2017F,
0x6BB4E3BB, 0xDDA26A7E, 0x3A59FF45, 0x3E350A44, 0xBCB4CDD5, 0x72EACEA8, 0xFA6484BB,
0x8D6612AE, 0xBF3C6F47, 0xD29BE463, 0x542F5D9E, 0xAEC2771B, 0xF64E6370, 0x740E0D8D,
0xE75B1357, 0xF8721671, 0xAF537D5D, 0x4040CB08, 0x4EB4E2CC, 0x34D2466A, 0x0115AF84,
0xE1B00428, 0x95983A1D, 0x06B89FB4, 0xCE6EA048, 0x6F3F3B82, 0x3520AB82, 0x011A1D4B,
0x277227F8, 0x611560B1, 0xE7933FDC, 0xBB3A792B, 0x344525BD, 0xA08839E1, 0x51CE794B,
0x2F32C9B7, 0xA01FBAC9, 0xE01CC87E, 0xBCC7D1F6, 0xCF0111C3, 0xA1E8AAC7, 0x1A908749,
0xD44FBD9A, 0xD0DADECB, 0xD50ADA38, 0x0339C32A, 0xC6913667, 0x8DF9317C, 0xE0B12B4F,
0xF79E59B7, 0x43F5BB3A, 0xF2D519FF, 0x27D9459C, 0xBF97222C, 0x15E6FC2A, 0x0F91FC71,
0x9B941525, 0xFAE59361, 0xCEB69CEB, 0xC2A86459, 0x12BAA8D1, 0xB6C1075E, 0xE3056A0C,
0x10D25065, 0xCB03A442, 0xE0EC6E0E, 0x1698DB3B, 0x4C98A0BE, 0x3278E964, 0x9F1F9532,
0xE0D392DF, 0xD3A0342B, 0x8971F21E, 0x1B0A7441, 0x4BA3348C, 0xC5BE7120, 0xC37632D8,
0xDF359F8D, 0x9B992F2E, 0xE60B6F47, 0x0FE3F11D, 0xE54CDA54, 0x1EDAD891, 0xCE6279CF,
0xCD3E7E6F, 0x1618B166, 0xFD2C1D05, 0x848FD2C5, 0xF6FB2299, 0xF523F357, 0xA6327623,
0x93A83531, 0x56CCCD02, 0xACF08162, 0x5A75EBB5, 0x6E163697, 0x88D273CC, 0xDE966292,
0x81B949D0, 0x4C50901B, 0x71C65614, 0xE6C6C7BD, 0x327A140A, 0x45E1D006, 0xC3F27B9A,
0xC9AA53FD, 0x62A80F00, 0xBB25BFE2, 0x35BDD2F6, 0x71126905, 0xB2040222, 0xB6CBCF7C,
0xCD769C2B, 0x53113EC0, 0x1640E3D3, 0x38ABBD60, 0x2547ADF0, 0xBA38209C, 0xF746CE76,
0x77AFA1C5, 0x20756060, 0x85CBFE4E, 0x8AE88DD8, 0x7AAAF9B0, 0x4CF9AA7E, 0x1948C25C,
0x02FB8A8C, 0x01C36AE4, 0xD6EBE1F9, 0x90D4F869, 0xA65CDEA0, 0x3F09252D, 0xC208E69F,
0xB74E6132, 0xCE77E25B, 0x578FDFE3, 0x3AC372E6,
}
};
static DWORD BLOWFISH_P[18];
static DWORD BLOWFISH_S[4][256];
static inline DWORD _BlowfishF(DWORD x) {
DWORD h = BLOWFISH_S[0][x >> 24] + BLOWFISH_S[1][x >> 16 & 0xff];
return (h ^ BLOWFISH_S[2][x >> 8 & 0xff]) + BLOWFISH_S[3][x & 0xff];
}
static inline void swap(LPDWORD x, LPDWORD y) {
DWORD tmp = *x;
*x = *y;
*y = tmp;
}
void BlowfishEncrypt(LPDWORD lpLeft, LPDWORD lpRight) {
for (short r = 0; r < 16; r++) {
*lpLeft ^= BLOWFISH_P[r];
*lpRight ^= _BlowfishF(*lpLeft);
swap(lpLeft, lpRight);
}
swap(lpLeft, lpRight);
*lpRight ^= BLOWFISH_P[16];
*lpLeft ^= BLOWFISH_P[17];
}
void BlowfishDecrypt(LPDWORD lpLeft, LPDWORD lpRight) {
for (short r = 17; r > 1; r--) {
*lpLeft ^= BLOWFISH_P[r];
*lpRight ^= _BlowfishF(*lpLeft);
swap(lpLeft, lpRight);
}
swap(lpLeft, lpRight);
*lpRight ^= BLOWFISH_P[1];
*lpLeft ^= BLOWFISH_P[0];
}
void BlowfishSetKey(LPBYTE lpKey, DWORD nKeyLen) {
memcpy(BLOWFISH_P, INIT_BLOWFISH_P, sizeof BLOWFISH_P);
memcpy(BLOWFISH_S, INIT_BLOWFISH_S, sizeof BLOWFISH_S);
// Initialise P-box
DWORD k;
for (short i = 0, p = 0; i < 18; i++) {
k = 0;
for (short j = 0; j < 4; j++) {
k = (k << 8) | lpKey[p];
p = (p + 1) % nKeyLen;
}
BLOWFISH_P[i] ^= k;
}
// Key expansion
DWORD l = 0, r = 0;
for (short i = 0; i < 18; i += 2) {
BlowfishEncrypt(&l, &r);
BLOWFISH_P[i] = l;
BLOWFISH_P[i + 1] = r;
}
for (short i = 0; i < 4; i++) {
for (short j = 0; j < 256; j += 2) {
BlowfishEncrypt(&l, &r);
BLOWFISH_S[i][j] = l;
BLOWFISH_S[i][j + 1] = r;
}
}
}

View File

@ -0,0 +1,5 @@
#include <Windows.h>
void BlowfishEncrypt(LPDWORD lpLeft, LPDWORD lpRight);
void BlowfishDecrypt(LPDWORD lpLeft, LPDWORD lpRight);
void BlowfishSetKey(LPBYTE lpKey, DWORD nKeyLen);

View File

@ -114,6 +114,13 @@ CFG_str(devices, com7, "", "")
CFG_str(devices, com8, "", "")
ENDSECTION(devices)
SECTION(aime, "Aime cards used when a TN32MSEC reader is attached\nSpecify either an access code or FeliCa ID")
CFG_str(aime, player1_card, "", "")
CFG_str(aime, player1_cardfile, "aime1.txt", "")
CFG_str(aime, player2_card, "", "")
CFG_str(aime, player2_cardfile, "aime2.txt", "")
ENDSECTION(aime)
#undef CFG_str
#undef CFG_int
#undef CFG_bool

View File

@ -0,0 +1,179 @@
#include <Windows.h>
#include <stdlib.h>
#include "des.h"
static BYTE IP[] = {
58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 62, 54, 46, 38, 30, 22,
14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35,
27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7,
};
static BYTE PI[] = {
40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 38, 6, 46, 14, 54, 22,
62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11,
51, 19, 59, 27, 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25,
};
static BYTE E[] = {
32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17,
16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1,
};
static BYTE P[] = {
16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25,
};
static BYTE SBOX[8][64] = {
{
14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 0, 15, 7, 4, 14, 2,
13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7,
3, 10, 5, 0, 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13,
},
{
15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 3, 13, 4, 7, 15, 2,
8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6,
9, 3, 2, 15, 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9,
},
{
10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 13, 7, 0, 9, 3, 4,
6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12,
5, 10, 14, 7, 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12,
},
{
7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 13, 8, 11, 5, 6, 15,
0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14,
5, 2, 8, 4, 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14,
},
{
2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 14, 11, 2, 12, 4, 7,
13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5,
6, 3, 0, 14, 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3,
},
{
12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 10, 15, 4, 2, 7, 12,
9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10,
1, 13, 11, 6, 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13,
},
{
4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 13, 0, 11, 7, 4, 9,
1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8,
0, 5, 9, 2, 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12,
},
{
13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 1, 15, 13, 8, 10, 3,
7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13,
15, 3, 5, 8, 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11,
},
};
static BYTE PC1[] = {
57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4,
};
static BYTE PC2[] = {
14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32,
};
static BYTE ITERATION_SHIFT[] = { 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 };
#define DesModeDecrypt 0
#define DesModeEncrypt 1
DWORD64 MiceDesCrypt(DWORD64 nData, DWORD64 nKey, BYTE mode) {
nData = _byteswap_uint64(nData);
nKey = _byteswap_uint64(nKey);
DWORD64 init_perm_res = 0;
for (int i = 0; i < 64; i++) {
init_perm_res <<= 1;
init_perm_res |= (nData >> (64 - IP[i])) & 1;
}
DWORD L = (DWORD)(init_perm_res >> 32) & 0xffffffff;
DWORD R = (DWORD)init_perm_res & 0xffffffff;
DWORD64 permuted_choice_1 = 0;
for (int i = 0; i < 56; i++) {
permuted_choice_1 <<= 1;
permuted_choice_1 |= (nKey >> (64 - PC1[i])) & 1;
}
DWORD C = (DWORD)((permuted_choice_1 >> 28) & 0x0fffffff);
DWORD D = (DWORD)(permuted_choice_1 & 0x0fffffff);
DWORD64 sub_key[16] = { 0 };
for (int i = 0; i < 16; i++) {
for (int j = 0; j < ITERATION_SHIFT[i]; j++) {
C = 0x0fffffff & (C << 1) | 1 & (C >> 27);
D = 0x0fffffff & (D << 1) | 1 & (D >> 27);
}
DWORD64 permuted_choice_2 = (((DWORD64)C) << 28) | (DWORD64)D;
sub_key[i] = 0;
for (int j = 0; j < 48; j++) {
sub_key[i] <<= 1;
sub_key[i] |= (permuted_choice_2 >> (56 - PC2[j])) & 1;
}
}
for (int i = 0; i < 16; i++) {
DWORD64 s_input = 0;
for (int j = 0; j < 48; j++) {
s_input <<= 1;
s_input |= (DWORD64)((R >> (32 - E[j])) & 1);
}
s_input ^= sub_key[mode == DesModeDecrypt ? 15 - i : i];
DWORD s_output = 0;
for (int j = 0; j < 8; j++) {
BYTE row = (BYTE)((s_input & (0x0000840000000000 >> (6 * j))) >> (42 - 6 * j));
row = (row >> 4) | row & 0x01;
BYTE column = (BYTE)((s_input & (0x0000780000000000 >> (6 * j))) >> (43 - 6 * j));
s_output <<= 4;
s_output |= (DWORD)(SBOX[j][16 * row + column] & 0x0f);
}
DWORD f_function_res = 0;
for (int j = 0; j < 32; j++) {
f_function_res <<= 1;
f_function_res |= (s_output >> (32 - P[j])) & 1;
}
DWORD temp = R;
R = L ^ f_function_res;
L = temp;
}
DWORD64 pre = (((DWORD64)R) << 32) | (DWORD64)L;
DWORD64 result = 0;
for (int i = 0; i < 64; i++) {
result <<= 1;
result |= (pre >> (64 - PI[i])) & 1;
}
return _byteswap_uint64(result);
}
DWORD64 MiceDesEncrypt(DWORD64 nData, DWORD64 nKey) {
return MiceDesCrypt(nData, nKey, DesModeEncrypt);
}
DWORD64 MiceDesDecrypt(DWORD64 nData, DWORD64 nKey) {
return MiceDesCrypt(nData, nKey, DesModeDecrypt);
}
DWORD64 Mice3Des_3K(DWORD64 nData, DWORD64 lpKeys[3]) {
nData = MiceDesEncrypt(nData, lpKeys[0]);
nData = MiceDesDecrypt(nData, lpKeys[1]);
return MiceDesEncrypt(nData, lpKeys[2]);
}
DWORD64 Mice3Des_2K(DWORD64 nData, DWORD64 lpKeys[2]) {
nData = MiceDesEncrypt(nData, lpKeys[0]);
nData = MiceDesDecrypt(nData, lpKeys[1]);
return MiceDesEncrypt(nData, lpKeys[0]);
}
DWORD64 Mice3Des_1K(DWORD64 nData, DWORD64 nKey) {
nData = MiceDesEncrypt(nData, nKey);
nData = MiceDesDecrypt(nData, nKey);
return MiceDesEncrypt(nData, nKey);
}

View File

@ -0,0 +1,7 @@
#include <Windows.h>
DWORD64 MiceDesEncrypt(DWORD64 nData, DWORD64 nKey);
DWORD64 MiceDesDecrypt(DWORD64 nData, DWORD64 nKey);
DWORD64 Mice3Des_3K(DWORD64 nData, DWORD64 lpKeys[3]);
DWORD64 Mice3Des_2K(DWORD64 nData, DWORD64 lpKeys[2]);
DWORD64 Mice3Des_1K(DWORD64 nData, DWORD64 nKey);

View File

@ -11,7 +11,7 @@ bool inject_debug_wait(HANDLE process) {
do {
Sleep(1000);
if (FAILED(CheckRemoteDebuggerPresent(process, &present))) {
log_error(plfBoot, "Fatal: CheckRemoteDebuggerPresent failed: %d", GetLastError());
log_error(plfBoot, "CheckRemoteDebuggerPresent failed: %d", GetLastError());
return false;
}
} while (!present);
@ -24,33 +24,33 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result
LPVOID arg_addr =
VirtualAllocEx(process, NULL, nchars + 1, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (arg_addr == NULL) {
log_error(plfProcesses, "Fatal: VirtualAllocEx failed: %d", GetLastError());
log_error(plfProcesses, "VirtualAllocEx failed: %d", GetLastError());
return false;
}
if (FAILED(WriteProcessMemory(process, arg_addr, argument, nchars + 1, NULL))) {
log_error(plfProcesses, "Fatal: WriteProcessMemory failed: %d", GetLastError());
log_error(plfProcesses, "WriteProcessMemory failed: %d", GetLastError());
return false;
}
HANDLE remote_thread =
CreateRemoteThread(process, NULL, 0, (LPTHREAD_START_ROUTINE)function, arg_addr, 0, NULL);
if (remote_thread == INVALID_HANDLE_VALUE) {
log_error(plfProcesses, "Fatal: CreateRemoteThread failed: %d", GetLastError());
log_error(plfProcesses, "CreateRemoteThread failed: %d", GetLastError());
return false;
}
if (WaitForSingleObject(remote_thread, INFINITE) != WAIT_OBJECT_0) {
log_error(plfProcesses, "Fatal: WaitForSingleObject failed: %d", GetLastError());
log_error(plfProcesses, "WaitForSingleObject failed: %d", GetLastError());
return false;
}
if (FAILED(GetExitCodeThread(remote_thread, result))) {
log_error(plfProcesses, "Fatal: GetExitCodeThread failed: %d", GetLastError());
log_error(plfProcesses, "GetExitCodeThread failed: %d", GetLastError());
return false;
}
if (*result == 0) {
log_error(plfProcesses, "Fatal: GetExitCodeThread failed: result == 0");
log_error(plfProcesses, "GetExitCodeThread failed: result == 0");
return false;
}
@ -59,13 +59,13 @@ bool remote_call(HANDLE process, LPVOID function, LPCSTR argument, DWORD* result
bool inject_dll(HANDLE process, LPCSTR inject) {
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
if (kernel32 == NULL) {
log_error(plfProcesses, "Fatal: GetModuleHandleA failed: %d", GetLastError());
log_error(plfProcesses, "GetModuleHandleA failed: %d", GetLastError());
return false;
}
LPVOID addr_LoadLibraryA = (LPVOID)GetProcAddress(kernel32, "LoadLibraryA");
if (addr_LoadLibraryA == NULL) {
log_error(plfProcesses, "Fatal: GetProcAddress failed: %d", GetLastError());
log_error(plfProcesses, "GetProcAddress failed: %d", GetLastError());
return false;
}
@ -90,14 +90,14 @@ BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BO
// Does the exe we're starting exist?
found = SearchPathA(NULL, path, NULL, 0, NULL, NULL);
if (found == 0) {
log_error(plfProcesses, "Fatal: Cannot start %s: not found", path);
log_error(plfProcesses, "Cannot start %s: not found", path);
goto abort;
}
if (inject != NULL) {
// Does the DLL we want to inject exist?
found = SearchPathA(NULL, inject, NULL, 0, NULL, NULL);
if (found == 0) {
log_error(plfProcesses, "Fatal: Cannot inject %s: not found", inject);
log_error(plfProcesses, "Cannot inject %s: not found", inject);
goto abort;
}
}
@ -106,7 +106,7 @@ BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BO
flags |= CREATE_SUSPENDED;
if (!CreateProcessA(path, cmdline, NULL, NULL, FALSE, flags, NULL, NULL, &startupInfo,
&processInformation)) {
log_error(plfProcesses, "Fatal: CreateProcessA(%s, %s) failed: %d", path, cmdline,
log_error(plfProcesses, "CreateProcessA(%s, %s) failed: %d", path, cmdline,
GetLastError());
goto abort;
}
@ -140,7 +140,7 @@ BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BO
// Injection completed, let the program continue execution
if (FAILED(ResumeThread(processInformation.hThread))) {
log_error(plfProcesses, "Fatal: ResumeThread failed: %d", GetLastError());
log_error(plfProcesses, "ResumeThread failed: %d", GetLastError());
goto abort;
}
@ -153,14 +153,14 @@ BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BO
abort:
if (processInformation.hProcess && processInformation.hProcess != INVALID_HANDLE_VALUE) {
if (!CloseHandle(processInformation.hThread) && GetLastError() != ERROR_INVALID_HANDLE)
log_error(plfProcesses, "Fatal: CloseHandle(hProcess) failed: %d", GetLastError());
log_error(plfProcesses, "CloseHandle(hProcess) failed: %d", GetLastError());
if (!TerminateProcess(processInformation.hProcess, 1))
log_error(plfProcesses, "Fatal: TerminateProcess failed: %d", GetLastError());
log_error(plfProcesses, "TerminateProcess failed: %d", GetLastError());
}
if (processInformation.hThread && processInformation.hThread != INVALID_HANDLE_VALUE) {
if (!CloseHandle(processInformation.hThread) && GetLastError() != ERROR_INVALID_HANDLE)
log_error(plfProcesses, "Fatal: CloseHandle(hThread) failed: %d", GetLastError());
log_error(plfProcesses, "CloseHandle(hThread) failed: %d", GetLastError());
}
return FALSE;

View File

@ -85,6 +85,13 @@
#define IOCTL_MXPARALLEL_READ_FLAGS \
(DWORD) CTL_CODE(FILE_DEVICE_SEGA, 0x807, METHOD_BUFFERED, FILE_READ_ACCESS)
// amCmosReadByteInRearpart
#define IOCTL_MXCMOS_READ \
(DWORD) CTL_CODE(FILE_DEVICE_SEGA, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
// amCmosWriteByteInRearpart
#define IOCTL_MXCMOS_WRITE \
(DWORD) CTL_CODE(FILE_DEVICE_SEGA, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
// CrackProof
#define IOCTL_CRACKPROOF_10 CTL_CODE(FILE_DEVICE_HTSYS, 0x810, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_CRACKPROOF_11 CTL_CODE(FILE_DEVICE_HTSYS, 0x811, METHOD_BUFFERED, FILE_ANY_ACCESS)

View File

@ -5,7 +5,7 @@
#include "../../segastructs.h"
#pragma pack(push, 1)
typedef struct _AM_KCF {
typedef struct AM_KCF {
AM_APPBOOT m_Header;
BYTE m_AppData[216];
BYTE m_Seed[16];

View File

@ -8,6 +8,10 @@ mice_lib = static_library(
'config.c',
'kcf.c',
'micefs.c',
'des.c',
'blowfish.c',
'solitaire.c',
'spad.c',
],
link_with: [
inih.get_variable('lib_inih'),

View File

@ -118,6 +118,8 @@ BOOL MiceFSAddDevLayers(VOID) {
BOOL success = TRUE;
for (int i = 0; i < 26; i++) {
if (i == 2) continue; // TODO: DON'T SKIP C
szMountPoint[0] = 'A' + (char)i;
szMountPoint[1] = ':';
szMountPoint[2] = '\\';
@ -134,7 +136,7 @@ BOOL MiceFSAddRingedgeLayers(BOOL bIsOsupdate) {
// Windows file systems
success &= MiceFSAddLayer(RING_MOUNT_OS, "mount/os");
success &= MiceFSAddLayer(RING_MOUNT_EXTEND, "mount/extend");
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND, "mount/extend");
success &= MiceFSAddLayer(RING_MOUNT_RECOVERY, "mount/os_recovery");
// TrueCrypt Volumes
@ -145,8 +147,8 @@ BOOL MiceFSAddRingedgeLayers(BOOL bIsOsupdate) {
success &= MiceFSAddLayer(RING_MOUNT_OS_UPDATE, "mount/os_update");
success &= MiceFSAddLayer(RING_MOUNT_OS_DEFAULT_DRVIERS, "mount/os_default_drivers");
} else {
success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, "mount/extend/extend");
success &= MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, "mount/extend/extend2");
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND_VOL, "mount/extend/extend");
// success &= MiceFSAddLayer(RING_MOUNT_EXTEND2_VOL, "mount/extend/extend2");
}
// geminifs

View File

@ -0,0 +1,143 @@
#include "solitaire.h"
#include <memory.h>
#define DECK_SIZE 22
#define JOKER_A 21
#define JOKER_B 22
typedef struct {
char m_Deck[DECK_SIZE];
} DECK, *PDECK;
static DECK SOL_INIT_DECK = {
.m_Deck = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 },
};
#define char2num(c) ((c) - '0' + 1)
static inline char num2char(char num) {
while (num < 1) num = num + 10;
return (num - 1) % 10 + '0';
}
static void SolMoveCard(PDECK lpDeck, char card) {
int p = 0;
for (int i = 0; i < DECK_SIZE; i++) {
if (lpDeck->m_Deck[i] == card) {
p = i;
break;
}
}
if (p < DECK_SIZE - 1) {
lpDeck->m_Deck[p] = lpDeck->m_Deck[p + 1];
lpDeck->m_Deck[p + 1] = card;
} else {
for (int i = DECK_SIZE - 1; i > 1; i--) lpDeck->m_Deck[i] = lpDeck->m_Deck[i - 1];
lpDeck->m_Deck[1] = card;
}
}
static void SolCutDeck(PDECK lpDeck, char point) {
DECK tmp;
memcpy(tmp.m_Deck, &lpDeck->m_Deck[point], DECK_SIZE - point - 1);
memcpy(&tmp.m_Deck[DECK_SIZE - point - 1], lpDeck->m_Deck, point);
memcpy(lpDeck->m_Deck, tmp.m_Deck, DECK_SIZE - 1);
}
static void SolSwapOutsideJoker(PDECK lpDeck) {
int j1 = -1;
int j2 = -1;
DECK tmp;
for (int i = 0; i < DECK_SIZE; i++) {
if (lpDeck->m_Deck[i] == JOKER_A || lpDeck->m_Deck[i] == JOKER_B) {
if (j1 == -1) {
j1 = i;
} else {
j2 = i;
}
}
}
if (0 < DECK_SIZE - j2 - 1) memcpy(tmp.m_Deck, &lpDeck->m_Deck[j2 + 1], DECK_SIZE - j2 - 1);
tmp.m_Deck[DECK_SIZE - j2 - 1] = lpDeck->m_Deck[j1];
if (0 < j2 - j1 - 1) memcpy(&tmp.m_Deck[DECK_SIZE - j2], &lpDeck->m_Deck[j1 + 1], j2 - j1 - 1);
tmp.m_Deck[DECK_SIZE - j1 - 1] = lpDeck->m_Deck[j2];
if (0 < j1) memcpy(&tmp.m_Deck[DECK_SIZE - j1], lpDeck->m_Deck, j1);
memcpy(lpDeck->m_Deck, tmp.m_Deck, DECK_SIZE);
}
static void SolCutByBottomCard(PDECK lpDeck) {
char p = lpDeck->m_Deck[DECK_SIZE - 1];
if (p == JOKER_B) p = JOKER_A;
SolCutDeck(lpDeck, p);
}
static char SolGetTopCardNum(PDECK lpDeck) {
char p = lpDeck->m_Deck[0];
if (p == JOKER_B) p = JOKER_A;
return lpDeck->m_Deck[p];
}
static void SolDeckHash(PDECK lpDeck) {
char p;
do {
SolMoveCard(lpDeck, JOKER_A);
SolMoveCard(lpDeck, JOKER_B);
SolMoveCard(lpDeck, JOKER_B);
SolSwapOutsideJoker(lpDeck);
SolCutByBottomCard(lpDeck);
p = SolGetTopCardNum(lpDeck);
} while (p == JOKER_A || p == JOKER_B);
}
static void SolCreateDeck(PDECK lpDeck, const char *key) {
memcpy_s(lpDeck, sizeof *lpDeck, &SOL_INIT_DECK, sizeof SOL_INIT_DECK);
int p = 0;
while (key[p] != '\0') {
SolDeckHash(lpDeck);
char c = char2num(key[p]);
SolCutDeck(lpDeck, c);
p++;
}
}
void SolitaireCipherEncode(const char *szKey, const char *szSrc, char *szDst) {
DECK deck;
SolCreateDeck(&deck, szKey);
int i = 0;
while (szSrc[i] != '\0') {
SolDeckHash(&deck);
char p = SolGetTopCardNum(&deck);
szDst[i] = num2char(char2num(szSrc[i]) + p);
i++;
}
szDst[i] = '\0';
}
void SolitaireCipherDecode(const char *szKey, const char *szSrc, char *szDst) {
DECK deck;
SolCreateDeck(&deck, szKey);
int i = 0;
while (szSrc[i] != '\0') {
SolDeckHash(&deck);
char p = SolGetTopCardNum(&deck);
szDst[i] = num2char(char2num(szSrc[i]) - p);
i++;
}
szDst[i] = '\0';
}
void SolitaireCipher(int nMode, const char *szKey, const char *szSrc, char *szDst) {
if (nMode == 0)
SolitaireCipherEncode(szKey, szSrc, szDst);
else if (nMode == 1)
SolitaireCipherDecode(szKey, szSrc, szDst);
}

View File

@ -0,0 +1,3 @@
void SolitaireCipherDecode(const char *szKey, const char *szSrc, char *szDst);
void SolitaireCipherEncode(const char *szKey, const char *szSrc, char *szDst);
void SolitaireCipher(int mode, const char *key, const char *src_str, char *dest_str);

View File

@ -0,0 +1,224 @@
#include "spad.h"
#include <memory.h>
#define HASH_ADD 5
BYTE SPAD0_SPN_TABLE[9][256] = {
{
175, 168, 99, 169, 36, 192, 241, 190, 231, 179, 172, 22, 133, 185, 17, 111, 16, 49,
50, 174, 177, 120, 35, 210, 162, 202, 249, 43, 69, 184, 60, 98, 26, 109, 130, 140,
0, 217, 226, 122, 70, 25, 42, 204, 19, 167, 228, 183, 132, 155, 142, 255, 251, 139,
3, 137, 48, 41, 211, 135, 1, 191, 53, 218, 89, 92, 205, 9, 127, 112, 65, 129,
108, 95, 83, 194, 114, 212, 121, 72, 149, 180, 91, 57, 68, 157, 253, 81, 113, 246,
215, 213, 45, 159, 237, 51, 234, 170, 90, 23, 106, 186, 189, 233, 156, 206, 77, 124,
24, 59, 13, 238, 12, 128, 161, 10, 143, 181, 107, 247, 63, 209, 71, 37, 198, 54,
232, 125, 123, 62, 243, 153, 117, 5, 28, 224, 207, 52, 187, 158, 235, 145, 173, 38,
141, 199, 102, 8, 230, 88, 64, 20, 166, 197, 250, 18, 236, 196, 240, 33, 138, 134,
214, 225, 6, 182, 96, 116, 46, 227, 254, 39, 47, 94, 244, 178, 104, 40, 86, 239,
154, 97, 34, 163, 201, 11, 2, 150, 79, 219, 229, 144, 74, 76, 146, 203, 152, 105,
208, 87, 100, 14, 55, 80, 171, 188, 222, 118, 7, 200, 61, 73, 252, 119, 148, 248,
193, 151, 101, 58, 75, 131, 110, 115, 136, 30, 93, 4, 84, 103, 223, 21, 176, 195,
147, 44, 56, 221, 245, 164, 85, 15, 78, 29, 160, 31, 32, 165, 220, 67, 242, 216,
126, 82, 27, 66,
},
{
3, 75, 184, 151, 183, 143, 13, 113, 220, 73, 167, 144, 255, 160, 157, 248, 35, 95,
32, 108, 17, 249, 105, 142, 239, 203, 240, 20, 223, 27, 122, 198, 54, 91, 197, 147,
182, 40, 53, 178, 59, 209, 236, 243, 159, 128, 100, 37, 5, 207, 84, 175, 70, 63,
150, 6, 229, 16, 251, 170, 222, 98, 65, 81, 89, 231, 41, 181, 77, 61, 242, 55,
106, 232, 22, 139, 92, 168, 30, 87, 226, 9, 235, 50, 201, 46, 180, 241, 164, 118,
211, 193, 165, 112, 96, 18, 177, 234, 102, 225, 74, 146, 161, 109, 58, 244, 213, 111,
218, 216, 10, 88, 24, 99, 43, 163, 93, 103, 119, 107, 57, 195, 219, 76, 2, 186,
206, 187, 85, 1, 23, 133, 39, 228, 48, 114, 200, 141, 252, 120, 25, 185, 67, 45,
8, 155, 26, 217, 205, 38, 250, 130, 204, 127, 117, 121, 158, 101, 254, 237, 145, 199,
49, 208, 82, 42, 72, 132, 116, 221, 125, 233, 174, 110, 51, 71, 214, 80, 12, 83,
166, 189, 34, 172, 138, 4, 137, 66, 64, 179, 69, 90, 68, 230, 169, 29, 196, 129,
227, 21, 31, 86, 135, 212, 62, 15, 149, 215, 224, 148, 171, 36, 104, 7, 162, 152,
123, 238, 245, 176, 136, 192, 56, 156, 153, 94, 173, 210, 60, 44, 33, 202, 140, 126,
28, 97, 194, 52, 124, 47, 11, 131, 154, 79, 190, 78, 188, 115, 19, 0, 246, 14,
134, 191, 253, 247,
},
{
65, 7, 147, 138, 64, 255, 14, 47, 84, 252, 172, 212, 30, 176, 200, 137, 223, 0,
100, 79, 243, 203, 44, 192, 143, 110, 23, 191, 149, 153, 42, 13, 81, 173, 75, 202,
247, 105, 85, 56, 76, 198, 104, 195, 163, 31, 131, 62, 11, 112, 199, 178, 78, 207,
254, 77, 253, 139, 180, 150, 206, 249, 241, 211, 67, 96, 174, 213, 179, 219, 74, 185,
229, 234, 106, 72, 93, 167, 135, 218, 184, 6, 45, 148, 193, 102, 36, 38, 177, 154,
37, 8, 92, 89, 166, 175, 39, 146, 136, 242, 237, 27, 28, 17, 210, 34, 22, 118,
86, 103, 20, 159, 238, 95, 220, 91, 164, 70, 221, 16, 51, 41, 127, 90, 201, 151,
132, 133, 66, 188, 171, 119, 60, 161, 194, 170, 55, 73, 97, 53, 156, 134, 25, 87,
94, 230, 226, 160, 4, 109, 209, 168, 157, 236, 2, 189, 216, 71, 98, 26, 5, 125,
1, 63, 24, 111, 117, 68, 228, 122, 246, 169, 232, 114, 244, 107, 251, 126, 235, 54,
82, 222, 121, 35, 141, 231, 113, 99, 152, 108, 217, 233, 59, 19, 144, 3, 120, 116,
32, 129, 186, 52, 50, 250, 123, 49, 214, 61, 48, 10, 227, 18, 142, 15, 29, 187,
165, 115, 83, 130, 128, 181, 215, 225, 58, 43, 208, 224, 33, 190, 205, 21, 101, 182,
239, 204, 145, 245, 12, 196, 46, 158, 88, 240, 197, 155, 57, 9, 162, 124, 69, 183,
40, 140, 248, 80,
},
{
118, 205, 22, 127, 233, 107, 149, 58, 78, 187, 110, 204, 210, 179, 105, 169, 114, 175,
199, 130, 56, 111, 188, 55, 166, 40, 54, 189, 195, 207, 133, 70, 10, 153, 99, 151,
131, 86, 136, 161, 2, 100, 172, 121, 85, 101, 255, 194, 239, 122, 89, 43, 28, 224,
140, 143, 90, 228, 180, 159, 252, 247, 69, 71, 74, 234, 192, 13, 235, 200, 120, 201,
103, 3, 5, 49, 20, 222, 211, 115, 250, 31, 182, 80, 19, 4, 183, 123, 73, 26,
249, 23, 77, 79, 134, 32, 193, 253, 160, 165, 72, 225, 60, 96, 242, 11, 48, 15,
76, 238, 141, 109, 190, 142, 198, 246, 216, 8, 148, 27, 42, 181, 158, 162, 147, 245,
34, 168, 52, 38, 167, 124, 236, 63, 14, 59, 178, 244, 41, 206, 46, 66, 129, 50,
37, 95, 102, 219, 125, 215, 231, 45, 67, 106, 91, 25, 173, 62, 155, 197, 171, 132,
196, 108, 51, 218, 251, 138, 17, 84, 254, 87, 75, 61, 126, 9, 163, 145, 64, 191,
104, 229, 185, 243, 150, 248, 81, 202, 154, 176, 152, 174, 30, 156, 94, 232, 0, 57,
18, 220, 12, 16, 139, 93, 214, 44, 39, 213, 97, 135, 83, 186, 35, 113, 47, 29,
116, 137, 157, 221, 53, 21, 208, 68, 177, 203, 240, 98, 88, 164, 119, 227, 24, 212,
230, 128, 209, 170, 144, 112, 1, 36, 241, 33, 217, 6, 117, 184, 65, 92, 146, 223,
237, 7, 226, 82,
},
{
170, 148, 153, 116, 146, 214, 28, 70, 71, 121, 47, 86, 122, 247, 181, 10, 201, 6,
215, 250, 64, 17, 165, 255, 31, 232, 0, 140, 221, 183, 66, 110, 53, 240, 190, 194,
29, 202, 182, 142, 226, 68, 78, 159, 81, 129, 139, 76, 93, 89, 56, 211, 143, 37,
179, 9, 49, 173, 11, 107, 14, 80, 187, 216, 150, 136, 222, 73, 234, 180, 74, 154,
48, 109, 44, 15, 205, 246, 126, 79, 82, 217, 251, 40, 7, 99, 25, 164, 238, 1,
248, 235, 210, 245, 61, 13, 145, 91, 103, 184, 87, 243, 43, 230, 104, 22, 123, 111,
101, 195, 118, 227, 60, 46, 65, 62, 207, 84, 225, 23, 167, 69, 45, 90, 252, 198,
130, 239, 203, 120, 172, 52, 186, 113, 39, 34, 242, 18, 63, 26, 36, 168, 193, 158,
199, 24, 228, 95, 254, 108, 175, 200, 55, 197, 119, 189, 2, 41, 125, 253, 94, 131,
233, 191, 42, 92, 115, 229, 218, 231, 236, 128, 106, 3, 88, 59, 33, 19, 209, 83,
112, 147, 188, 161, 16, 244, 100, 133, 135, 176, 97, 177, 241, 67, 98, 196, 249, 162,
174, 212, 4, 134, 223, 38, 208, 171, 54, 30, 75, 224, 96, 144, 204, 152, 149, 58,
156, 155, 21, 27, 51, 141, 77, 35, 157, 132, 206, 178, 5, 166, 12, 185, 20, 72,
213, 163, 117, 8, 124, 237, 127, 220, 137, 102, 169, 192, 57, 114, 32, 151, 138, 160,
85, 105, 219, 50,
},
{
222, 90, 27, 105, 60, 66, 163, 81, 64, 56, 241, 23, 40, 28, 184, 172, 232, 153,
69, 160, 18, 104, 206, 21, 201, 71, 109, 200, 70, 78, 30, 166, 17, 248, 62, 49,
250, 230, 45, 253, 50, 20, 156, 1, 177, 237, 87, 113, 227, 48, 207, 14, 231, 204,
55, 74, 120, 171, 29, 150, 234, 37, 133, 32, 73, 77, 117, 82, 238, 239, 175, 84,
51, 249, 9, 158, 129, 225, 115, 42, 242, 61, 34, 19, 146, 139, 240, 192, 132, 13,
168, 4, 220, 141, 187, 44, 148, 3, 245, 209, 208, 46, 93, 235, 94, 98, 111, 33,
176, 145, 254, 203, 10, 236, 183, 47, 52, 36, 214, 233, 102, 130, 198, 25, 31, 217,
193, 167, 246, 136, 2, 135, 7, 221, 216, 103, 197, 185, 41, 164, 194, 101, 211, 83,
170, 59, 121, 224, 114, 215, 6, 26, 88, 147, 126, 12, 144, 110, 116, 15, 76, 11,
228, 108, 67, 210, 65, 54, 189, 219, 53, 89, 95, 169, 159, 85, 128, 57, 142, 243,
213, 229, 99, 195, 119, 162, 91, 123, 127, 174, 186, 161, 16, 223, 75, 43, 155, 22,
188, 0, 199, 24, 251, 100, 255, 244, 247, 190, 5, 86, 205, 8, 79, 106, 154, 118,
122, 181, 149, 202, 80, 125, 124, 107, 165, 196, 58, 138, 39, 218, 182, 97, 35, 134,
112, 72, 151, 157, 252, 143, 92, 68, 178, 173, 131, 191, 38, 212, 179, 96, 152, 226,
63, 140, 180, 137,
},
{
25, 46, 93, 122, 91, 124, 126, 57, 239, 139, 47, 204, 134, 27, 194, 140, 32, 251,
89, 95, 33, 205, 159, 148, 167, 11, 186, 14, 71, 123, 165, 6, 183, 216, 201, 38,
240, 157, 104, 242, 94, 18, 58, 101, 176, 92, 226, 34, 153, 130, 16, 245, 68, 80,
116, 161, 249, 66, 168, 37, 77, 234, 8, 62, 150, 146, 196, 45, 162, 35, 52, 169,
69, 107, 121, 127, 200, 76, 67, 103, 41, 4, 250, 181, 30, 5, 198, 180, 175, 29,
187, 247, 48, 237, 236, 171, 64, 224, 152, 233, 75, 17, 135, 21, 24, 190, 238, 120,
177, 2, 87, 144, 50, 142, 97, 203, 60, 230, 215, 117, 49, 185, 84, 54, 225, 221,
108, 151, 98, 172, 65, 137, 156, 96, 246, 99, 188, 20, 125, 119, 213, 9, 149, 223,
23, 74, 12, 43, 82, 56, 254, 182, 51, 164, 81, 115, 109, 79, 179, 191, 113, 235,
105, 63, 19, 0, 28, 111, 155, 53, 202, 163, 42, 118, 141, 128, 1, 22, 3, 61,
229, 131, 112, 143, 90, 88, 136, 243, 227, 15, 195, 7, 70, 255, 73, 253, 232, 206,
133, 209, 220, 241, 184, 211, 110, 212, 160, 173, 114, 218, 231, 59, 132, 248, 210, 40,
222, 193, 26, 100, 145, 10, 228, 197, 36, 106, 214, 83, 199, 129, 44, 192, 147, 217,
13, 166, 219, 174, 207, 244, 85, 102, 31, 55, 252, 189, 72, 170, 78, 86, 39, 158,
208, 138, 178, 154,
},
{
84, 217, 66, 80, 184, 116, 171, 50, 166, 36, 72, 111, 240, 126, 215, 48, 180, 109,
6, 162, 136, 214, 89, 57, 76, 44, 175, 110, 168, 43, 102, 92, 185, 28, 231, 83,
25, 86, 138, 17, 216, 97, 95, 7, 3, 218, 181, 176, 8, 208, 39, 69, 0, 195,
245, 177, 121, 107, 196, 91, 33, 226, 85, 61, 160, 254, 49, 154, 54, 15, 236, 203,
187, 114, 41, 26, 249, 118, 135, 106, 174, 201, 82, 183, 235, 123, 243, 5, 148, 4,
1, 198, 161, 244, 55, 227, 251, 193, 79, 186, 158, 128, 40, 47, 90, 246, 145, 62,
207, 65, 173, 190, 182, 51, 155, 252, 206, 192, 104, 238, 63, 81, 191, 78, 210, 73,
169, 247, 143, 134, 200, 42, 103, 56, 228, 77, 199, 46, 99, 127, 239, 223, 151, 170,
93, 98, 11, 112, 209, 230, 19, 153, 146, 248, 211, 18, 60, 100, 132, 167, 10, 178,
156, 234, 27, 204, 94, 67, 30, 205, 141, 147, 225, 113, 59, 242, 163, 35, 233, 194,
221, 152, 139, 115, 150, 87, 34, 53, 14, 165, 172, 12, 212, 159, 9, 219, 58, 22,
96, 229, 137, 133, 45, 119, 29, 129, 32, 197, 122, 237, 202, 20, 131, 250, 31, 38,
24, 71, 157, 2, 224, 88, 16, 253, 37, 117, 188, 70, 222, 164, 21, 64, 120, 52,
74, 23, 213, 13, 105, 101, 220, 75, 124, 149, 232, 142, 255, 125, 144, 140, 130, 108,
179, 189, 68, 241,
},
{
195, 11, 184, 21, 0, 164, 61, 217, 253, 22, 233, 8, 32, 230, 141, 196, 71, 56,
37, 147, 94, 170, 236, 42, 16, 110, 88, 149, 38, 83, 4, 30, 146, 158, 47, 139,
189, 10, 105, 169, 59, 65, 240, 208, 218, 106, 161, 113, 19, 99, 239, 144, 148, 176,
235, 231, 220, 115, 185, 120, 122, 228, 199, 109, 127, 163, 172, 133, 80, 243, 145, 234,
54, 250, 155, 142, 247, 174, 193, 67, 28, 192, 202, 143, 78, 162, 49, 18, 116, 44,
157, 241, 173, 63, 104, 187, 53, 154, 124, 3, 251, 9, 35, 39, 212, 77, 23, 222,
76, 238, 118, 156, 160, 225, 117, 219, 91, 17, 167, 33, 175, 2, 66, 75, 131, 211,
206, 159, 205, 204, 48, 43, 82, 34, 203, 89, 125, 20, 249, 177, 112, 84, 224, 129,
90, 29, 14, 74, 244, 132, 237, 150, 26, 215, 201, 130, 137, 45, 135, 51, 226, 92,
81, 58, 27, 246, 229, 216, 50, 13, 95, 114, 136, 214, 183, 198, 221, 31, 128, 55,
100, 181, 123, 223, 255, 210, 64, 252, 96, 5, 182, 102, 97, 200, 40, 153, 188, 165,
52, 25, 248, 254, 36, 72, 209, 12, 85, 98, 107, 134, 179, 186, 138, 46, 111, 166,
103, 101, 1, 232, 24, 62, 126, 119, 41, 140, 242, 7, 108, 168, 121, 79, 68, 70,
6, 194, 171, 15, 180, 178, 190, 152, 213, 73, 227, 245, 207, 151, 93, 191, 87, 60,
57, 197, 69, 86,
}
};
BYTE SPAD0_SPN_INV_TABLE[9][256];
BOOL _SPAD0_SPN_INV_TABLE_INIT = FALSE;
void Spad0Encrypt(LPBYTE spad0_encrypted, const BYTE* spad0) {
if (spad0_encrypted != spad0)
memcpy(spad0_encrypted, spad0, 16);
int hashLoopCount = (spad0[15] >> 4) + 7;
int hashTableNo = spad0[15] & 0x7;
// Primary encryption loop
for (int i = 0; i < hashLoopCount; i++) {
for (int j = 0; j < 15; j++)
spad0_encrypted[j] = SPAD0_SPN_TABLE[hashTableNo][spad0_encrypted[j]];
// Rotate the first 15 bytes left by 5 bits
BYTE prior = spad0_encrypted[0];
for (int j = 14; j >= 0; j--) {
BYTE new = ((spad0_encrypted[j] & 0x7) << 5) | (prior >> 3);
prior = spad0_encrypted[j];
spad0_encrypted[j] = new;
}
hashTableNo = (hashTableNo + HASH_ADD) & 0x7;
}
// Apply the outer encryption layer to mask the parameters
for (int i = 0; i < 16; i++) spad0_encrypted[i] = SPAD0_SPN_TABLE[8][spad0_encrypted[i]];
}
void Spad0Decrypt(LPBYTE spad0, const BYTE* spad0_encrypted) {
// Build the inversed table
if (!_SPAD0_SPN_INV_TABLE_INIT) {
for (int i = 0; i < 9; i++)
for (int j = 0; j < 256; j++) SPAD0_SPN_INV_TABLE[i][SPAD0_SPN_TABLE[i][j]] = (BYTE)j;
_SPAD0_SPN_INV_TABLE_INIT = TRUE;
}
for (int i = 0; i < 16; i++) spad0[i] = SPAD0_SPN_INV_TABLE[8][spad0_encrypted[i]];
// Removing the outer layer gives us access to the cipher parameters
int hashLoopCount = ((spad0[15] >> 4) & 0xf) + 7;
int hashTableNo = spad0[15] & 0x7;
// We're doing this in reverse, so start from the final value
for (int i = 0; i < hashLoopCount - 1; i++) hashTableNo += HASH_ADD;
hashTableNo &= 0x7;
// Primary decryption loop
for (int i = 0; i < hashLoopCount; i++) {
// Rotate the first 15 bytes right by 5 bits
BYTE prior = spad0[14];
for (int j = 0; j < 15; j++) {
BYTE new = (spad0[j] >> 5) | ((prior & 0x1f) << 3);
prior = spad0[j];
spad0[j] = new;
}
for (int j = 0; j < 15; j++) spad0[j] = SPAD0_SPN_INV_TABLE[hashTableNo][spad0[j]];
hashTableNo = ((hashTableNo | 8) - HASH_ADD) & 0x7;
}
}

View File

@ -0,0 +1,4 @@
#include <Windows.h>
void Spad0Encrypt(LPBYTE spad0_encrypted, const BYTE* spad0);
void Spad0Decrypt(LPBYTE spad0, const BYTE* spad0_encrypted);

View File

@ -78,28 +78,33 @@ byte CA_CERTIFICATION[CA_CERT_BUF_MAX];
int CA_CERT_LEN = 0;
void mxkPcpPbCaCertification(pcpa_t* stream, void* data) {
if (CA_CERT_LEN == 0) {
FILE* fCert;
fopen_s(&fCert, Config.billing_cacert, "r");
if (fCert == NULL)
CA_CERT_LEN = -1;
else {
fseek(fCert, 0, SEEK_END);
CA_CERT_LEN = ftell(fCert);
HANDLE hFile = CreateFileA(Config.billing_cacert, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hFile == INVALID_HANDLE_VALUE) {
CA_CERT_LEN = 0;
} else {
CA_CERT_LEN = GetFileSize(hFile, NULL);
if (CA_CERT_LEN > CA_CERT_BUF_MAX) CA_CERT_LEN = CA_CERT_BUF_MAX;
rewind(fCert);
fread(CA_CERTIFICATION, CA_CERT_LEN, 1, fCert);
fclose(fCert);
DWORD numberOfBytesRead;
int read_remaining = CA_CERT_LEN;
int read_offset = 0;
while (read_remaining) {
printf("Remaining: %d, offset: %d\n", read_remaining, read_offset);
if (!ReadFile(hFile, CA_CERTIFICATION, CA_CERT_BUF_MAX, &numberOfBytesRead, NULL)) {
printf("Read failed: %d", GetLastError());
}
// int nread = fread(&CA_CERTIFICATION[read_offset], 1, read_remaining, fCert);
read_remaining -= numberOfBytesRead;
read_offset += numberOfBytesRead;
}
printf("Read done %d\n", CA_CERT_LEN);
CloseHandle(hFile);
}
}
if (CA_CERT_LEN == -1) {
// TODO: Fix this maybe?
pcpaSetBinaryMode(stream, binary_mode_none);
pcpaSetSendPacket(stream, BIL_CACERT, "-1");
return;
}
pcpaSetBinaryMode(stream, binary_mode_send);
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);

View File

@ -24,8 +24,19 @@ void mxkPcpTdPut(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, TRA_PUT, "0");
}
void mxkPcpTdGet(pcpa_t* stream, void* data) {
// TODO: lol
pcpaSetSendPacket(stream, TRA_GET, "");
char* sPut = pcpaGetCommand(stream, TRA_GET);
pcpaSetSendPacket(stream, TRA_GET, "0");
if (sPut && strcmp(sPut, "?") == 0) {
pcpaAddSendPacket(stream, "address", "0");
} else {
pcpaSetBinaryMode(stream, binary_mode_send);
pcpaSetBeforeBinaryModeCallBackFunc(stream, mxkBinaryCallback, NULL);
BINARY_DATA_LEN = 0;
pcpaSetRecvBinaryBuffer(stream, BINARY_DATA, BINARY_DATA_LEN);
pcpaAddSendPacket(stream, "port", "40107");
pcpaAddSendPacket(stream, "size", "0");
}
}
void mxkPcpTdLogicalErase(pcpa_t* stream, void* data) {
pcpaSetSendPacket(stream, TRA_LOGICALERASE, "");

View File

@ -3,7 +3,7 @@
#include <stdint.h>
#pragma pack(push, 1)
typedef struct _AM_APPBOOT {
typedef struct AM_APPBOOT {
uint32_t m_Crc;
uint32_t m_Format;
char m_GameId[4];
@ -16,13 +16,13 @@ typedef struct _AM_APPBOOT {
uint32_t m_NetworkAddr;
} AM_APPBOOT;
typedef struct _AM_APPBOOT_128 {
typedef struct AM_APPBOOT_128 {
AM_APPBOOT m_Header;
uint8_t Rsv18[88];
uint8_t m_Seed[16];
} AM_APPBOOT_128;
typedef struct _AM_APPBOOT_256 {
typedef struct AM_APPBOOT_256 {
AM_APPBOOT m_Header;
uint8_t Rsv18[216];
uint8_t m_Seed[16];

View File

@ -11,6 +11,7 @@ executable(
'micedump/platform.c',
'micedump/sram.c',
# 'micedump/superio.c',
'micedump/cmos.c',
],
link_with: [
mxklib,
@ -21,6 +22,7 @@ executable(
amPlatform,
amDongle,
amSerialId,
amCmos,
],
)
@ -77,3 +79,15 @@ executable(
amiDebug,
],
)
executable(
'micereset',
win_subsystem: subsystem,
sources: [
'micereset.c',
],
link_with: [
amiTimer,
amEeprom,
amSram,
],
)

View File

@ -0,0 +1,57 @@
#include <Windows.h>
#include <stdio.h>
/*
Cmos:
00-01: 00 21 <- "00 21" = "Boot: USB, HDD", "10 20" = "Boot HDD,USB"
02-0F: 43 65 87 a9 0b 21 43 65 87 a9 3b 93 99 54
10-19: 35 25 00 00 00 40 4f 40 50 08
1A-1B: 1a 08
1C-1D: 1a 08 <- USB flags(?). 08 = normal, 09 = disabled
1E-1F: 1a 0a
20-2F: 03 14 1d 12 28 00 00 00 00 07 00 00 00 00 00 08
30-3F: 01 80 ce 10 14 00 8a 48 06 01 d4 ff ff 1f 04 00
40-4B: 60 a0 9f 0b a0 29 47 15 7d 80 90 3f
4C: 00 <- SEGA flags. 00 = None, 02 = Security freeze, 03 = Freeze + Certified
4D: 9d
4E: 00 <- 00 = Boot HDD first, 01 = Boot USB first
4F: b4
50-5F: 25 d6 e7 8f 7f 22 72 af b5 1a 00 8f 1c 3c c0 90
60: 00
61: 00
62-6F: 06 37 50 8c 66 bd ac 38 7b 52 4a 04 4c dc
70-7F: 82 62 0d 2a 5d 1c 32 6e 05 af 44 c3 45 2e 08 96
*/
#include "../lib/am/amCmos.h"
AM_CMOS_CONFIG config = {
.index = { 0, 0, 0, 0 },
.m_MbrCount = 0,
};
BOOL miceDumpCMOS() {
amCmosDebugLevel = 1;
fprintf(stderr, "Dumping RTC CMOS using %s\n", amCmosVersion);
AM_CMOS_STATUS err = amCmosInit(&config);
if (err != AM_CMOS_STATUS_OK) {
fprintf(stderr, "amCmosInit failed: %d\n", err);
amCmosExit();
return FALSE;
}
for (BYTE index = 0; index < 0x80; index++) {
BYTE data;
amCmosReadByteInRearpart(index, &data);
printf(" %02x", data);
}
puts("");
amCmosExit();
return TRUE;
}

View File

@ -53,7 +53,7 @@ AM_DONGLE_STATUS amlib_init_dongle(void) {
return AM_DONGLE_STATUS_OK;
}
void miceDumpKCMxkeychip(void) {
BOOL miceDumpKCMxkeychip(void) {
amDongleDebugLevel = 1;
fprintf(stderr, "Dumping dongle using %s\n", amDongleVersion);
@ -61,7 +61,7 @@ void miceDumpKCMxkeychip(void) {
WSADATA wsaData;
if (WSAStartup(2, &wsaData)) {
puts("Failed to WSAStartup");
return;
return FALSE;
}
AM_DONGLE_STATUS err;
@ -69,7 +69,7 @@ void miceDumpKCMxkeychip(void) {
if (err != AM_DONGLE_STATUS_OK) {
printf("Failed to init dongle:%d\n", err);
amDongleExit();
return;
return FALSE;
}
printf("Keychip ID: %s\n", amlibDongle.keychipId);
@ -108,4 +108,5 @@ void miceDumpKCMxkeychip(void) {
puts("");
amDongleExit();
return TRUE;
}

View File

@ -5,14 +5,14 @@
#include "../lib/am/amSerialId.h"
#include "../lib/mxk/mxk.h"
void miceDumpKCPIC() {
BOOL miceDumpKCPIC() {
fprintf(stderr, "Dumping dongle using mxk\n");
MXK_STATUS status;
status = mxkInit();
if (status != MXK_STATUS_OK) {
amiDebugLog("Failed to mxkInit(): %d", status);
return;
return FALSE;
}
/**
@ -45,4 +45,6 @@ void miceDumpKCPIC() {
char gameId[4];
mxkAbGameId(MXK_CACHE_USE, gameId, &err);
printf(" Game ID: %.*s\n", 4, gameId);
return TRUE;
}

View File

@ -17,6 +17,8 @@ int main(int argc, char** argv) {
miceDumpKCMxkeychip();
else if (strcmp(argv[i], "kcpic") == 0)
miceDumpKCPIC();
else if (strcmp(argv[i], "cmos") == 0)
miceDumpCMOS();
else
printf("Unknown dump type: %s\n", argv[i]);
}

View File

@ -1,8 +1,11 @@
void miceDumpDMI(void);
void miceDumpEEPROM(void);
void miceDumpKCMxkeychip(void);
void miceDumpKCN2(void);
void miceDumpKCPIC(void);
void miceDumpPlatform(void);
void miceDumpSRAM(void);
void miceDumpSuperIO(void);
#include <Windows.h>
BOOL miceDumpDMI(void);
BOOL miceDumpEEPROM(void);
BOOL miceDumpKCMxkeychip(void);
BOOL miceDumpKCN2(void);
BOOL miceDumpKCPIC(void);
BOOL miceDumpPlatform(void);
BOOL miceDumpSRAM(void);
BOOL miceDumpSuperIO(void);
BOOL miceDumpCMOS(void);

View File

@ -7,7 +7,7 @@ static const char* sBoardType[] = {
"RingEdge", "RingWide (Spec 1)", "RingWide (Spec 2)", "RingEdge 2", "Unknown",
};
void miceDumpPlatform(void) {
BOOL miceDumpPlatform(void) {
fprintf(stderr, "Dumping platform information using %s\n", amPlatformVersion);
AM_PLATFORM_BOARD_TYPE boardType;
@ -17,4 +17,6 @@ void miceDumpPlatform(void) {
printf("Board type: %s\n", sBoardType[boardType]);
printf("Platform ID: %s\n", platformId.strPlatformId);
return TRUE;
}

View File

@ -0,0 +1,54 @@
#include <Windows.h>
#include <setupapi.h>
#include <shellapi.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "../lib/am/amEeprom.h"
#include "../lib/am/amSram.h"
BOOL wipe_eeprom() {
if (amEepromInit(NULL) != AM_EEPROM_STATUS_OK) return FALSE;
BYTE data[0x20];
memset(data, 0xff, sizeof data);
// Static = 0 and 32
// Game data is 1000-1fff = block 128-255
for (int i = 0; i < 256; i++) {
if (i == 0) continue;
if (i == 32) continue;
printf("Wiping EEPROM block %d\n", i);
amEepromWrite(i * 0x20, data, sizeof data);
}
amEepromExit();
return TRUE;
}
BOOL wipe_sram() {
if (amSramInit() != AM_SRAM_STATUS_OK) return FALSE;
DWORD nbytes = amSram.m_size.LowPart;
printf("Wiping %d bytes of SRAM\n", nbytes);
BYTE* buffer = malloc(nbytes);
ZeroMemory(buffer, nbytes);
amSramWrite(buffer, 0, nbytes);
free(buffer);
amSramExit();
return TRUE;
}
// void wait_for_dip() {
// puts("Press Test or System to continue");
// amDipswInit();
// }
int main(int argc, char** argv) {
wipe_eeprom();
wipe_sram();
return 0;
}

View File

@ -3,6 +3,53 @@
#include "../dll/hooks/drive/drive.h"
#define SECTOR_SIZE BLOCK_SIZE_HDD
#define HEADS_PER_CYLINDER 255
#define SECTORS_PER_TRACK 63
#define TRUECRYPT "\"C:\\Program Files (x86)\\TrueCrypt\\TrueCrypt.exe\""
#define OSR_PASSWORD "nogamenolife"
#define OSR_MOUNTPOINT "R:"
#define OSR_FLAGS "/w /q /m ro"
BYTE WINDOWS_MBR_BOOTSTRAP[MBR_BOOTSTRAP_SIZE] = {
0x33, 0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0xfb, 0x50, 0x07, 0x50, 0x1f, 0xfc, 0xbe, 0x1b, 0x7c,
0xbf, 0x1b, 0x06, 0x50, 0x57, 0xb9, 0xe5, 0x01, 0xf3, 0xa4, 0xcb, 0xbd, 0xbe, 0x07, 0xb1, 0x04,
0x38, 0x6e, 0x00, 0x7c, 0x09, 0x75, 0x13, 0x83, 0xc5, 0x10, 0xe2, 0xf4, 0xcd, 0x18, 0x8b, 0xf5,
0x83, 0xc6, 0x10, 0x49, 0x74, 0x19, 0x38, 0x2c, 0x74, 0xf6, 0xa0, 0xb5, 0x07, 0xb4, 0x07, 0x8b,
0xf0, 0xac, 0x3c, 0x00, 0x74, 0xfc, 0xbb, 0x07, 0x00, 0xb4, 0x0e, 0xcd, 0x10, 0xeb, 0xf2, 0x88,
0x4e, 0x10, 0xe8, 0x46, 0x00, 0x73, 0x2a, 0xfe, 0x46, 0x10, 0x80, 0x7e, 0x04, 0x0b, 0x74, 0x0b,
0x80, 0x7e, 0x04, 0x0c, 0x74, 0x05, 0xa0, 0xb6, 0x07, 0x75, 0xd2, 0x80, 0x46, 0x02, 0x06, 0x83,
0x46, 0x08, 0x06, 0x83, 0x56, 0x0a, 0x00, 0xe8, 0x21, 0x00, 0x73, 0x05, 0xa0, 0xb6, 0x07, 0xeb,
0xbc, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x74, 0x0b, 0x80, 0x7e, 0x10, 0x00, 0x74, 0xc8, 0xa0,
0xb7, 0x07, 0xeb, 0xa9, 0x8b, 0xfc, 0x1e, 0x57, 0x8b, 0xf5, 0xcb, 0xbf, 0x05, 0x00, 0x8a, 0x56,
0x00, 0xb4, 0x08, 0xcd, 0x13, 0x72, 0x23, 0x8a, 0xc1, 0x24, 0x3f, 0x98, 0x8a, 0xde, 0x8a, 0xfc,
0x43, 0xf7, 0xe3, 0x8b, 0xd1, 0x86, 0xd6, 0xb1, 0x06, 0xd2, 0xee, 0x42, 0xf7, 0xe2, 0x39, 0x56,
0x0a, 0x77, 0x23, 0x72, 0x05, 0x39, 0x46, 0x08, 0x73, 0x1c, 0xb8, 0x01, 0x02, 0xbb, 0x00, 0x7c,
0x8b, 0x4e, 0x02, 0x8b, 0x56, 0x00, 0xcd, 0x13, 0x73, 0x51, 0x4f, 0x74, 0x4e, 0x32, 0xe4, 0x8a,
0x56, 0x00, 0xcd, 0x13, 0xeb, 0xe4, 0x8a, 0x56, 0x00, 0x60, 0xbb, 0xaa, 0x55, 0xb4, 0x41, 0xcd,
0x13, 0x72, 0x36, 0x81, 0xfb, 0x55, 0xaa, 0x75, 0x30, 0xf6, 0xc1, 0x01, 0x74, 0x2b, 0x61, 0x60,
0x6a, 0x00, 0x6a, 0x00, 0xff, 0x76, 0x0a, 0xff, 0x76, 0x08, 0x6a, 0x00, 0x68, 0x00, 0x7c, 0x6a,
0x01, 0x6a, 0x10, 0xb4, 0x42, 0x8b, 0xf4, 0xcd, 0x13, 0x61, 0x61, 0x73, 0x0e, 0x4f, 0x74, 0x0b,
0x32, 0xe4, 0x8a, 0x56, 0x00, 0xcd, 0x13, 0xeb, 0xd6, 0x61, 0xf9, 0xc3, 0x49, 0x6e, 0x76, 0x61,
0x6c, 0x69, 0x64, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x61,
0x62, 0x6c, 0x65, 0x00, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x69, 0x6e,
0x67, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74,
0x65, 0x6d, 0x00, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61,
0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 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, 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, 0x2c, 0x44, 0x63, 0x46, 0xa4, 0x2b, 0xd1, 0x00, 0x00,
};
// Assumes a SECTOR_SIZE of 512
#define _KiB(x) (DWORD)(x * 2)
#define _MiB(x) (DWORD)(x * 1024 * 2)
#define _GiB(x) (DWORD)(x * 1024 * 1024 * 2)
#define _GMKiB(g, m, k) (_GiB(g) + _MiB(m) + _KiB(k))
physical_disk_t newSSD = {
.m_SerialNumber = 0x00144DB0,
@ -10,27 +57,27 @@ physical_disk_t newSSD = {
.m_BootPartition = 1,
.m_HasSegaboot = TRUE,
.m_BlockSize = BLOCK_SIZE_HDD,
.m_TotalSize = 64 * 1024 * 1024 * (1024 / BLOCK_SIZE_HDD),
.m_TotalSize = 0, // Force re-calculation
.m_DiskType = DiskType_HardDisk,
.m_IsFormatted = true,
.m_Partitions = {
// 1.5GB boot partition
{ .m_Size = 0x300B85, .m_Filesystem = MBR_FS_NTFS },
{ .m_Size = _GMKiB(1, 513, 450.5), .m_Filesystem = MBR_FS_NTFS },
// 1.5GB OS recovery
{ .m_Size = 0x300BC4, .m_Filesystem = MBR_FS_NTFS },
{ .m_Size = _GMKiB(1, 513, 482), .m_Filesystem = MBR_FS_NTFS },
},
.m_Extended = {
{ 0x102d83, MBR_FS_FAT16, SPD_OS }, // 512MB OS update
{ 0x403947, MBR_FS_FAT16, SPD_Patch0 }, // 2GB patch0
{ 0x403947, MBR_FS_FAT16, SPD_Patch1 }, // 2GB patch1
{ 0x48ed459, MBR_FS_NTFS, SPD_AppData }, // 40GB appdata
{ 0x20014aa, MBR_FS_FAT16, SPD_Original0 }, // 16GB original0
{ _GMKiB(0, 517, 705.5), MBR_FS_FAT16, SPD_OS }, // 512MB OS update
{ _GMKiB(0, 2055, 163.5), MBR_FS_FAT16, SPD_Patch0 }, // 2GB patch0
{ _GMKiB(0, 2055, 163.5), MBR_FS_FAT16, SPD_Patch1 }, // 2GB patch1
{ _GMKiB(36, 474, 556.5), MBR_FS_NTFS, SPD_AppData }, // 40GB appdata
{ _GMKiB(16, 2, 597), MBR_FS_FAT16, SPD_Original0 }, // 16GB original0
{ 0 }, // End of table
},
};
sbr_t SegaBootRecord0;
sbr_t SegaBootRecord1;
sbr_t SegaBootRecord0 = { 0 };
sbr_t SegaBootRecord1 = { 0 };
sbr_slot_t* get_sbr_slot(spd_slot_t slot) {
switch (slot) {
case SPD_Original0:
@ -132,6 +179,8 @@ void init_pd(physical_disk_t* pConfig) {
if (extendedPartNo) {
pConfig->m_Partitions[extendedPartNo - 1].m_Size = currentLBA - extendedStart;
}
pConfig->m_TotalSize = currentLBA;
} else {
// Raw disks have just a single spanning volume
pConfig->m_Partitions[0].m_PartitionNumber = 1;
@ -142,21 +191,47 @@ void init_pd(physical_disk_t* pConfig) {
}
}
BYTE writeBuffer[1024];
void write_buffer(HANDLE hDisk, LONG nOffset, DWORD nBytes, physical_disk_t* pConfig) {
LARGE_INTEGER offset;
offset.QuadPart = nOffset * pConfig->m_BlockSize;
SetFilePointerEx(hDisk, offset, NULL, FILE_BEGIN);
DWORD nOut;
WriteFile(hDisk, writeBuffer, nBytes, &nOut, NULL);
inline void set_chs(BYTE* chs, WORD cylinder, BYTE head, BYTE sector) {
chs[0] = head;
chs[1] = ((sector & 0x3f) | ((cylinder & 0x300) >> 2)) & 0xff;
chs[2] = cylinder & 0xff;
}
inline void set_chs_from_lba(BYTE* chs, DWORD lba) {
WORD cylinder = (lba / (HEADS_PER_CYLINDER * SECTORS_PER_TRACK)) & 0xffff;
BYTE head = ((lba / SECTORS_PER_TRACK) % HEADS_PER_CYLINDER) & 0xff;
BYTE sector = ((lba % SECTORS_PER_TRACK) + 1) & 0xff;
set_chs(chs, cylinder, head, sector);
}
inline void fix_partition_chs(PMBR_PARTITION partition) {
set_chs_from_lba(partition->start_chs, partition->lba);
set_chs_from_lba(partition->end_chs, partition->lba + partition->sectors - 1);
}
BYTE writeBuffer[1024];
void write_buffer(HANDLE hDisk, DWORD nBlock, DWORD nBytes, physical_disk_t* pConfig) {
LARGE_INTEGER offset;
offset.HighPart = 0;
offset.LowPart = nBlock;
offset.QuadPart *= pConfig->m_BlockSize;
SetFilePointerEx(hDisk, offset, NULL, FILE_BEGIN);
printf("Performing write: %d@%08x%08x\n", nBytes, offset.HighPart, offset.LowPart);
DWORD nOut;
WriteFile(hDisk, writeBuffer, nBytes, &nOut, NULL);
if (nOut != nBytes) {
printf("WRITE FAILED!! %d\n", GetLastError());
CloseHandle(hDisk);
exit(1);
}
}
// TODO: Write start_chs lol
void write_mbr(HANDLE hDisk, LONG nOffset, physical_disk_t* pConfig) {
printf("Writing MBR at block %d\n", nOffset);
mbr_t* mbr = (mbr_t*)writeBuffer;
PMBR_HEADER mbr = (PMBR_HEADER)writeBuffer;
memset(mbr, 0, sizeof *mbr);
memcpy_s(mbr->bootstrap_code, sizeof mbr->bootstrap_code, WINDOWS_MBR_BOOTSTRAP,
sizeof WINDOWS_MBR_BOOTSTRAP);
mbr->sig[0] = 0x55;
mbr->sig[1] = 0xAA;
@ -168,14 +243,17 @@ void write_mbr(HANDLE hDisk, LONG nOffset, physical_disk_t* pConfig) {
mbr->partitions[i].type = pConfig->m_Partitions[i].m_Filesystem;
mbr->partitions[i].lba = pConfig->m_Partitions[i].m_PhysicalLBA;
mbr->partitions[i].sectors = pConfig->m_Partitions[i].m_Size;
fix_partition_chs(&(mbr->partitions[i]));
}
write_buffer(hDisk, nOffset, sizeof *mbr, pConfig);
}
void write_ext_header(HANDLE hDisk, LONG nOffset, physical_disk_t* pConfig, DWORD nPartition) {
printf("Writing extended header at block %d\n", nOffset);
printf(" -> Part %d = %d\n", nPartition + 5, nOffset);
mbr_t* mbr = (mbr_t*)writeBuffer;
PMBR_HEADER mbr = (PMBR_HEADER)writeBuffer;
memset(mbr, 0, sizeof *mbr);
mbr->sig[0] = 0x55;
@ -183,23 +261,33 @@ void write_ext_header(HANDLE hDisk, LONG nOffset, physical_disk_t* pConfig, DWOR
mbr->partitions[0].status = MBR_FLAG_NONE;
mbr->partitions[0].type = pConfig->m_Extended[nPartition].m_Filesystem;
mbr->partitions[0].lba = EXT_HEADER_GAP;
mbr->partitions[0].lba = pConfig->m_Extended[nPartition].m_PhysicalLBA;
mbr->partitions[0].sectors = pConfig->m_Extended[nPartition].m_Size;
fix_partition_chs(&(mbr->partitions[0]));
// Write the EBR value
mbr->partitions[0].lba = EXT_HEADER_GAP;
if (pConfig->m_Extended[nPartition + 1].m_Size) {
mbr->partitions[1].status = MBR_FLAG_NONE;
// ! mxinstaller expects to see CHS here, then uses the LBA values
mbr->partitions[1].type = MBR_FS_EXT_CHS;
mbr->partitions[1].lba = pConfig->m_Extended[nPartition + 1].m_PhysicalLBA - EXT_HEADER_GAP;
mbr->partitions[1].sectors = pConfig->m_Extended[nPartition + 1].m_Size + EXT_HEADER_GAP;
fix_partition_chs(&(mbr->partitions[1]));
// Write the EBR values
mbr->partitions[1].lba = pConfig->m_Extended[nPartition + 1].m_PhysicalLBA -
pConfig->m_Extended[0].m_PhysicalLBA;
mbr->partitions[1].sectors = pConfig->m_Extended[nPartition + 1].m_Size + EXT_HEADER_GAP;
mbr->partitions[1].end_chs[0] = 0xFE;
mbr->partitions[1].end_chs[1] = 0xFF;
mbr->partitions[1].end_chs[2] = 0xFF;
}
write_buffer(hDisk, nOffset, sizeof *mbr, pConfig);
}
void write_pd(HANDLE hDisk, physical_disk_t* pConfig) {
puts("Force-allocating disk space");
printf("Pre-allocating disk space (0x%x blocks)\n", pConfig->m_TotalSize);
write_buffer(hDisk, pConfig->m_TotalSize - 1, pConfig->m_BlockSize, pConfig);
// Write MBR headers
@ -209,10 +297,9 @@ void write_pd(HANDLE hDisk, physical_disk_t* pConfig) {
write_ext_header(hDisk, headerLBA, pConfig, i);
if (i == 0 && pConfig->m_HasSegaboot) {
puts("Writing segaboot");
// SEGA Partition Description
spd_t* spd = (spd_t*)writeBuffer;
ZeroMemory(spd, sizeof *spd);
spd->version = SPD_VERSION;
for (size_t j = 0; pConfig->m_Extended[j].m_Size; j++) {
@ -225,25 +312,159 @@ void write_pd(HANDLE hDisk, physical_disk_t* pConfig) {
spd->crc = amiCrc32RCalc(sizeof *spd - 4, &(spd->version), 0);
write_buffer(hDisk, headerLBA + SPD_OFFSET, sizeof *spd, pConfig);
// TODO: Actually populate the SBRs
// SEGA Boot Record 0 and 1. The two are a redundant copy of each other
memcpy(writeBuffer, &SegaBootRecord0, sizeof SegaBootRecord0);
write_buffer(hDisk, headerLBA + SBR0_OFFSET, sizeof SegaBootRecord0, pConfig);
memcpy(writeBuffer, &SegaBootRecord1, sizeof SegaBootRecord1);
write_buffer(hDisk, headerLBA + SBR1_OFFSET, sizeof SegaBootRecord1, pConfig);
printf(" -> SEGA structures = %d+[1/2/3]\n", headerLBA);
}
}
}
void print_bar(LONGLONG nCurrent, LONGLONG nMax) {
printf("[");
DWORD filled = ((float)nCurrent / (float)nMax) * 40;
int i = 0;
for (; i < filled; i++) printf("=");
for (; i < 40; i++) printf(" ");
printf("] %3.2f%%\r", (float)nCurrent / (float)nMax * 100);
}
void end_bar() { printf("[========================================] 100.00%%\n"); }
BOOL mount_OSR(LPSTR lpOSRPath) {
char szTcCommand[1024];
sprintf_s(szTcCommand, sizeof szTcCommand, "%s /p %s /v %s /l %s %s", TRUECRYPT, OSR_PASSWORD,
lpOSRPath, OSR_MOUNTPOINT, OSR_FLAGS);
int dTcRet = system(szTcCommand);
if (dTcRet != 0) {
printf("Failed to mount OSR: %d\n", dTcRet);
printf("Command used was: %s\n", szTcCommand);
return FALSE;
}
return TRUE;
}
BOOL dismount_OSR() {
char szTcCommand[1024];
sprintf_s(szTcCommand, sizeof szTcCommand, "%s /q /d %s", TRUECRYPT, OSR_MOUNTPOINT, OSR_FLAGS);
int dTcRet = system(szTcCommand);
if (dTcRet != 0) {
printf("Failed to dismount OSR: %d\n", dTcRet);
printf("Command used was: %s\n", szTcCommand);
return FALSE;
}
return TRUE;
}
void install_OSR(HANDLE hDisk, LPSTR lpOSRPath) {
if (!mount_OSR(lpOSRPath)) return;
HANDLE hOSR = CreateFileA("\\\\.\\" OSR_MOUNTPOINT, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hOSR == INVALID_HANDLE_VALUE) {
printf("Failed to open OSR! %d\n", GetLastError());
return;
}
DISK_GEOMETRY dg;
DWORD nBytesReturned;
DeviceIoControl(hOSR, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &dg, sizeof dg, &nBytesReturned,
NULL);
LONGLONG nBytes =
dg.BytesPerSector * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.Cylinders.QuadPart;
SetFilePointer(hDisk, 63 * 512, NULL, FILE_BEGIN);
puts("Installing Operating System");
BYTE block[4096];
int print_tick = 0;
for (LONGLONG i = 0; nBytes;) {
DWORD nRead = sizeof block;
if (nRead > nBytes) nRead = (DWORD)nBytes;
ReadFile(hOSR, block, nRead, &nRead, NULL);
if (nRead == 0) {
if (GetLastError() == ERROR_SUCCESS) break;
printf("Failed to read OSR. Code: %d\n", GetLastError());
goto end;
return;
}
DWORD nWrote = 0;
WriteFile(hDisk, block, nRead, &nWrote, NULL);
if (nWrote != nRead) {
printf("Failed to write OSR to disk. Code: %d\n", GetLastError());
goto end;
return;
}
if (print_tick++ == 512) {
print_tick = 0;
print_bar(i, nBytes);
}
i += nRead;
}
end_bar();
end:
CloseHandle(hOSR);
dismount_OSR();
}
void install_OSR_xcopy(LPSTR lpDiskPath, LPSTR lpOSRPath) {
if (!mount_OSR(lpOSRPath)) return;
printf("Installing OS using xcopy %s -> %s\n", OSR_MOUNTPOINT, lpDiskPath);
char szXcCommand[1024];
sprintf_s(szXcCommand, sizeof szXcCommand, "xcopy %s %s /e /c /h /y /q", OSR_MOUNTPOINT, lpDiskPath);
int dTcRet = system(szXcCommand);
if (dTcRet != 0) {
printf("Failed to xcopy OSR: %d\n", dTcRet);
printf("Command used was: %s\n", szXcCommand);
return FALSE;
}
return TRUE;
dismount_OSR();
}
int main(int argc, char* argv[]) {
amiCrc32RInit();
init_pd(&newSSD);
HANDLE hDisk = INVALID_HANDLE_VALUE;
SetLastError(0);
hDisk = CreateFileA("H:\\NewDiskImage.img", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
// hDisk = CreateFileA("H:\\NewDiskImage.img", GENERIC_READ | GENERIC_WRITE,
// FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
// FILE_ATTRIBUTE_NORMAL, NULL);
hDisk = CreateFileA("\\\\.\\PHYSICALDRIVE4", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (hDisk == INVALID_HANDLE_VALUE) {
printf("Failed to open disk! %d\n", GetLastError());
return 1;
}
write_pd(hDisk, &newSSD);
// install_OSR(hDisk, "H:\\Arcades\\RingOS\\RecoverOS\\0009\\Minint\\system32\\OSR");
// install_OSR_xcopy(hDisk, "H:\\Arcades\\RingOS\\RecoverOS\\0009\\Minint\\system32\\OSR");
puts("Please mount OS at W:");
system("pause");
install_OSR_xcopy("W:", "H:\\Arcades\\RingOS\\RecoverOS\\0009\\Minint\\system32\\OSR");
FlushFileBuffers(hDisk);
CloseHandle(hDisk);
return 0;
}

View File

@ -19,3 +19,5 @@
*00c89320 : 00000000 > 01000000 # amBackupDebugLevel
*00c88bb4 : 00000000 > 01000000 # amHwResetDebugLevel
*00c830e8 : 00000000 > 01000000 # LOG_EN
*00b93c30 : 680074007400700073003a002f002f006d0079002d00610069006d0065002e006e00650074002f00610069006d0065002f0069002f0072006500670069007300740071002e00680074006d006c003f00610063003d000000 > 680074007400700073003a002f002f006d006900630065006e00650074002e006300610074006700690072006c002e00610072006d0079002f00710072003f00610063003d00000000000000000000000000000000000000 # aime URL