521 lines
16 KiB
C
521 lines
16 KiB
C
#include <Windows.h>
|
|
#include <setupapi.h>
|
|
#include <shellapi.h>
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#pragma comment(lib, "Setupapi.lib")
|
|
|
|
#include "../lib/am/amEeprom.h"
|
|
#include "../lib/mxk/mxk.h"
|
|
|
|
#define OpenDriver(x) \
|
|
CreateFileA("\\\\.\\" x, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)
|
|
|
|
#define RULE "-----------------------------------------"
|
|
#define SECTION_HEAD(x) \
|
|
puts(""); \
|
|
puts(RULE); \
|
|
puts(x); \
|
|
puts(RULE); \
|
|
puts("");
|
|
|
|
typedef struct {
|
|
uint64_t physAddr;
|
|
DWORD dType;
|
|
DWORD size;
|
|
} columba_request_t;
|
|
|
|
void scan_for_dmi(HANDLE columba, DWORD *stable_addr) {
|
|
DWORD bytesOut;
|
|
// short *stable_len;
|
|
columba_request_t request;
|
|
unsigned char readBuf[0x8010];
|
|
|
|
uint64_t search_addr = 0xf0000;
|
|
while (1) {
|
|
request.physAddr = search_addr;
|
|
request.dType = 1;
|
|
request.size = sizeof readBuf;
|
|
|
|
BOOL succ = DeviceIoControl(columba, IOCTL_COLUMBA_READ, &request, sizeof request, &readBuf,
|
|
sizeof readBuf, &bytesOut, NULL);
|
|
if (succ && bytesOut == sizeof readBuf) {
|
|
for (unsigned int offset = 0; offset < 0x8008; offset++) {
|
|
if (readBuf[offset] == '_' && readBuf[offset + 1] == 'D' &&
|
|
readBuf[offset + 2] == 'M' && readBuf[offset + 3] == 'I' &&
|
|
readBuf[offset + 4] == '_') {
|
|
*stable_addr = *(DWORD *)&readBuf[offset + 8];
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
search_addr += 0x7ff0;
|
|
if (search_addr > 0xfffdf) return;
|
|
}
|
|
}
|
|
|
|
BOOL dump_columba() {
|
|
SECTION_HEAD("columba");
|
|
|
|
HANDLE columba = OpenDriver("columba");
|
|
if (columba == INVALID_HANDLE_VALUE) return FALSE;
|
|
|
|
DWORD stable_addr = 0;
|
|
scan_for_dmi(columba, &stable_addr);
|
|
if (stable_addr == 0) {
|
|
CloseHandle(columba);
|
|
return FALSE;
|
|
}
|
|
|
|
columba_request_t request;
|
|
unsigned char readBuf[0x10000];
|
|
|
|
printf("Found DMI at: %d\n", stable_addr);
|
|
|
|
request.physAddr = stable_addr;
|
|
request.dType = 1;
|
|
if (stable_addr + 0x10000 < 0x100001) {
|
|
request.size = 0x10000;
|
|
} else {
|
|
request.size = 0x100000 - stable_addr;
|
|
}
|
|
DWORD bytesReturned;
|
|
|
|
BOOL s = DeviceIoControl(columba, IOCTL_COLUMBA_READ, &request, sizeof request, readBuf,
|
|
sizeof readBuf, &bytesReturned, NULL);
|
|
if (!s || bytesReturned != sizeof readBuf) {
|
|
CloseHandle(columba);
|
|
return FALSE;
|
|
}
|
|
|
|
puts("DMI read sucessful.");
|
|
FILE *dmi;
|
|
fopen_s(&dmi, "dmi.bin", "wb");
|
|
fwrite(readBuf, 1, sizeof readBuf, dmi);
|
|
fclose(dmi);
|
|
puts(" -> Written to dmi.bin");
|
|
|
|
CloseHandle(columba);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL dump_eeprom() {
|
|
SECTION_HEAD("mxSMBus");
|
|
|
|
HANDLE mxsmbus = amEepromCreateDeviceFile(&MXSMBUS_GUID, NULL, 0);
|
|
if (mxsmbus == INVALID_HANDLE_VALUE) return FALSE;
|
|
|
|
DWORD _dummy;
|
|
DWORD version;
|
|
DeviceIoControl(mxsmbus, IOCTL_MXSMBUS_GET_VERSION, NULL, 0, &version, sizeof version, &_dummy,
|
|
NULL);
|
|
printf("mxSMBus version: %08x\n", version);
|
|
|
|
BYTE data[0x20];
|
|
for (WORD reg = 0; reg < 256; reg++) {
|
|
if (!amEepromReadBlock(mxsmbus, reg & 0xFF, 0x20, data)) continue;
|
|
printf("%02x: ", reg);
|
|
for (int i = 0; i < 0x20; i++) printf("%02x ", data[i]);
|
|
puts("");
|
|
}
|
|
|
|
CloseHandle(mxsmbus);
|
|
return TRUE;
|
|
}
|
|
|
|
unsigned char sram_buf[1024 * 2048];
|
|
BOOL dump_sram() {
|
|
SECTION_HEAD("mxSRAM");
|
|
|
|
HANDLE mxsram = OpenDriver("mxsram");
|
|
if (mxsram == INVALID_HANDLE_VALUE) return FALSE;
|
|
|
|
DWORD _dummy;
|
|
BOOL s;
|
|
|
|
DWORD version;
|
|
s = DeviceIoControl(mxsram, IOCTL_MXSRAM_PING, NULL, 0, &version, sizeof version, &_dummy,
|
|
NULL);
|
|
if (!s) {
|
|
CloseHandle(mxsram);
|
|
return FALSE;
|
|
}
|
|
printf("mxSRAM version: %04x\n", version);
|
|
|
|
DISK_GEOMETRY geom;
|
|
s = DeviceIoControl(mxsram, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geom, sizeof geom, &_dummy,
|
|
NULL);
|
|
if (!s) {
|
|
CloseHandle(mxsram);
|
|
return FALSE;
|
|
}
|
|
puts("mxSRAM geometry:");
|
|
printf(":: Cylinders: %lld\n", geom.Cylinders.QuadPart);
|
|
printf(":: MediaType: %d\n", geom.MediaType);
|
|
printf(":: TracksPerCylinder: %d\n", geom.TracksPerCylinder);
|
|
printf(":: SectorsPerTrack: %d\n", geom.SectorsPerTrack);
|
|
printf(":: BytesPerSector: %d\n", geom.BytesPerSector);
|
|
|
|
DWORD ssize;
|
|
s = DeviceIoControl(mxsram, IOCTL_MXSRAM_GET_SECTOR_SIZE, NULL, 0, &ssize, sizeof ssize,
|
|
&_dummy, NULL);
|
|
if (!s) {
|
|
CloseHandle(mxsram);
|
|
return FALSE;
|
|
}
|
|
printf(":: Sector Size: %d\n", ssize);
|
|
|
|
DWORD read;
|
|
if (!ReadFile(mxsram, sram_buf, sizeof sram_buf, &read, NULL)) {
|
|
CloseHandle(mxsram);
|
|
return FALSE;
|
|
}
|
|
printf("Read %d bytes\n", read);
|
|
if (read != sizeof sram_buf) puts("W: incomplete");
|
|
|
|
FILE *sram;
|
|
fopen_s(&sram, "sram.bin", "wb");
|
|
fwrite(sram_buf, 1, sizeof sram_buf, sram);
|
|
fclose(sram);
|
|
puts(" -> Written to sram.bin");
|
|
CloseHandle(mxsram);
|
|
return TRUE;
|
|
}
|
|
|
|
BYTE superio_read(HANDLE mxsuperio, BYTE chip, BYTE device, BYTE index) {
|
|
DWORD _dummy;
|
|
BYTE payload[4] = { chip, device, index, 0 };
|
|
DeviceIoControl(mxsuperio, IOCTL_MXSUPERIO_READ, payload, sizeof payload, payload,
|
|
sizeof payload, &_dummy, NULL);
|
|
return payload[3];
|
|
}
|
|
|
|
#define SUPERIO_LD_FDC 0
|
|
#define SUPERIO_LD_PARALLEL 1
|
|
#define SUPERIO_LD_UART_A 2
|
|
#define SUPERIO_LD_UART_B 3
|
|
#define SUPERIO_LD_KEYBOARD 5
|
|
#define SUPERIO_LD_UART_C 6
|
|
#define SUPERIO_LD_GPIO34 7
|
|
#define SUPERIO_LD_WDTO_PLED_GPIO56 8
|
|
#define SUPERIO_LD_GPIO12_SUSLED 9
|
|
#define SUPERIO_LD_ACPI 10
|
|
#define SUPERIO_LD_HWMON 11
|
|
#define SUPERIO_LD_PECI_SST 12
|
|
#define SUPERIO_LD_UART_D 13
|
|
#define SUPERIO_LD_UART_E 14
|
|
#define SUPERIO_LD_UART_F 15
|
|
|
|
BOOL dump_superio() {
|
|
SECTION_HEAD("mxSuperIO");
|
|
|
|
HANDLE mxsuperio = OpenDriver("mxsuperio");
|
|
if (mxsuperio == INVALID_HANDLE_VALUE) return FALSE;
|
|
BOOL s;
|
|
DWORD _dummy;
|
|
|
|
DWORD version;
|
|
s = DeviceIoControl(mxsuperio, IOCTL_MXSUPERIO_PING, NULL, 0, &version, sizeof version, &_dummy,
|
|
NULL);
|
|
if (!s) {
|
|
CloseHandle(mxsuperio);
|
|
return FALSE;
|
|
}
|
|
printf("mxSuperIO version: %08x\n", version);
|
|
|
|
BYTE ver_msb;
|
|
ver_msb = superio_read(mxsuperio, 0, SUPERIO_LD_FDC, 0x20);
|
|
if (ver_msb != 0xff) {
|
|
puts(":: Chip 0 present");
|
|
printf(" -> Version: %02x%02x\n", ver_msb,
|
|
superio_read(mxsuperio, 0, SUPERIO_LD_FDC, 0x21));
|
|
} else
|
|
puts(":: Chip 0 unpopulated");
|
|
ver_msb = superio_read(mxsuperio, 1, SUPERIO_LD_FDC, 0x20);
|
|
if (ver_msb != 0xff) {
|
|
puts(":: Chip 1 present");
|
|
printf(" -> Version: %02x%02x\n", ver_msb,
|
|
superio_read(mxsuperio, 1, SUPERIO_LD_FDC, 0x21));
|
|
} else
|
|
puts(":: Chip 1 unpopulated");
|
|
|
|
puts(":: Super lazy dump of chip 1, bank 0:");
|
|
for (uint8_t reg = 0; reg < 0xff; reg++) {
|
|
unsigned char packet[3] = { 1, reg, 0 };
|
|
DeviceIoControl(mxsuperio, IOCTL_MXSUPERIO_HWMONITOR_LPC_READ, &packet, sizeof packet,
|
|
&packet, sizeof packet, &_dummy, NULL);
|
|
printf(" -> %02x: %02x\n", reg, packet[2]);
|
|
}
|
|
|
|
CloseHandle(mxsuperio);
|
|
return TRUE;
|
|
}
|
|
|
|
void kc_experiments(HANDLE mxparallel) {
|
|
BYTE packet[16];
|
|
BYTE test;
|
|
|
|
// Returns FF all the time!
|
|
// puts("Attempting to rekey key!!");
|
|
// // OLD ID: A72E-02D11266103
|
|
// ZeroMemory(packet, 16);
|
|
// packet[0] = 23;
|
|
// mxkSendPacket(mxparallel, packet);
|
|
// memcpy(packet, "A72E-69696969696", 16);
|
|
// mxkSendPacket(mxparallel, packet);
|
|
// mxkRecvPacket(mxparallel, packet);
|
|
// puts("Response:");
|
|
// for (int i = 0; i < 16; i++) {
|
|
// printf("%02x ", packet[i]);
|
|
// }
|
|
// puts("");
|
|
|
|
/*
|
|
15: seems to send random bytes back? rng?
|
|
16: echo, but byte 0 == 0
|
|
17: echo, but byte 0 == 0
|
|
18: hangs. need to send some more payload?
|
|
19: as 18
|
|
|
|
26:
|
|
*/
|
|
// puts("KEY_R:");
|
|
// for (int i = 0; i < 16; i++) {
|
|
// printf("%02x ", KEY_R[i]);
|
|
// }
|
|
// puts("");
|
|
// puts("KEY_S:");
|
|
// for (int i = 0; i < 16; i++) {
|
|
// printf("%02x ", KEY_S[i]);
|
|
// }
|
|
// puts("");
|
|
|
|
// for (int i = 0; i < 10; i++) {
|
|
// for (int j = 0; j < 2; j++) {
|
|
// for (test = 15; test < 16; test++) {
|
|
// ZeroMemory(packet, 16);
|
|
// packet[0] = test;
|
|
// printf("Sending %d\n", test);
|
|
// mxkSendPacket(mxparallel, packet);
|
|
// mxkRecvPacket(mxparallel, packet);
|
|
// puts("Response:");
|
|
// for (int i = 0; i < 16; i++) {
|
|
// printf("%02x ", packet[i]);
|
|
// }
|
|
// puts("");
|
|
// }
|
|
// }
|
|
// Sleep(250);
|
|
// }
|
|
|
|
ZeroMemory(packet, 16);
|
|
for (int i = 0; i < 16; i++) packet[i] = i;
|
|
packet[0] = 17;
|
|
printf("Sending %d\n", 17);
|
|
mxkSendPacket(mxparallel, packet);
|
|
|
|
/**
|
|
* 18:
|
|
* Returns the same stuff for all keychips
|
|
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
* returns: 21 D8 A8 21 2A CD A9 4A 5C D9 7A 35 43 ED 83 7A
|
|
* 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
* returns: 65 FA F5 BE 9F 93 8D 02 6E C4 D5 60 6E C1 74 D6
|
|
* 19:
|
|
* 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
* returns: 57 45 43 37 D0 80 48 B1 86 26 A7 81 70 1D 1F 4F
|
|
* */
|
|
BYTE response[16];
|
|
mxkRecvPacket(mxparallel, response);
|
|
puts("Response:");
|
|
for (int i = 0; i < 16; i++) {
|
|
printf("%02x ", response[i]);
|
|
}
|
|
puts("");
|
|
|
|
puts("Sending DoAs");
|
|
packet[0] = EepromWrite;
|
|
packet[1] = 0x20;
|
|
mxkSendPacket(mxparallel, packet);
|
|
ZeroMemory(packet, 16);
|
|
packet[0] = 'D';
|
|
packet[1] = 'o';
|
|
packet[2] = 'A';
|
|
packet[3] = 's';
|
|
mxkSendPacket(mxparallel, packet);
|
|
mxkRecvPacket(mxparallel, packet);
|
|
if (packet[0] == 0xff) puts("Failed to DoAs");
|
|
else puts("DoAs'd");
|
|
|
|
}
|
|
|
|
BYTE KEYCHIP_ID[16];
|
|
BYTE MAIN_ID[16];
|
|
BOOL dump_keychip() {
|
|
SECTION_HEAD("keychip");
|
|
FILE *fd;
|
|
|
|
HANDLE mxparallel = OpenDriver("mxparallel");
|
|
if (mxparallel == INVALID_HANDLE_VALUE) return FALSE;
|
|
|
|
mxkTransportInitPic(mxparallel);
|
|
if (!mxkExchengeAesKey(mxparallel)) {
|
|
puts("Failed to exchange keys!");
|
|
return FALSE;
|
|
}
|
|
|
|
unsigned short version;
|
|
if (!mxkVersion(mxparallel, &version)) {
|
|
puts("Failed to request version!");
|
|
} else {
|
|
printf("Version:\t%02x%02x\n", version & 0xff, version >> 8);
|
|
}
|
|
|
|
ZeroMemory(MAIN_ID, 16);
|
|
if (!mxkGetMainId(mxparallel, MAIN_ID)) {
|
|
puts("Failed to request main ID!");
|
|
} else {
|
|
printf("Main ID:\t%.16s\n", MAIN_ID);
|
|
}
|
|
|
|
ZeroMemory(MAIN_ID, 16);
|
|
if (!mxkSetMainId(mxparallel, MAIN_ID)) {
|
|
puts("Failed to zero main ID!");
|
|
}
|
|
|
|
ZeroMemory(KEYCHIP_ID, 16);
|
|
if (!mxkGetKeyId(mxparallel, KEYCHIP_ID)) {
|
|
puts("Failed to request key ID!");
|
|
} else {
|
|
printf("Keychip ID:\t%.16s\n", KEYCHIP_ID);
|
|
}
|
|
|
|
appboot_t appboot;
|
|
if (!mxkGetAppBootInfo(mxparallel, &appboot)) {
|
|
puts("Failed to request appboot info!");
|
|
} else {
|
|
printf("Game ID:\t%.4s\n", appboot.game_id);
|
|
printf("Region:\t\t%02x\n", appboot.region);
|
|
printf("Model Type:\t%02x\n", appboot.model_type);
|
|
printf("Sys Flag:\t%02x\n", appboot.system_flag);
|
|
printf("Platform ID:\t%.3s\n", appboot.platform_id);
|
|
printf("DVD Flag:\t%02x\n", appboot.dvd_flag);
|
|
printf("Network addr:\t%d.%d.%d.%d\n", appboot.network_addr & 0xff,
|
|
(appboot.network_addr >> 8) & 0xff, (appboot.network_addr >> 16) & 0xff,
|
|
(appboot.network_addr >> 24) & 0xff);
|
|
puts("Appboot seed:");
|
|
for (int i = 0; i < 16; i++) {
|
|
printf(" %02x", appboot.seed[i]);
|
|
}
|
|
puts("");
|
|
}
|
|
|
|
DWORD playcount;
|
|
if (!mxkGetPlayCounter(mxparallel, &playcount)) {
|
|
puts("Failed to request playcount!");
|
|
} else {
|
|
printf("Playcount:\t%d\n", playcount);
|
|
}
|
|
|
|
kc_experiments(mxparallel);
|
|
|
|
goto skip_kc_dump;
|
|
|
|
unsigned char eeprom_block[0x10];
|
|
puts("Dumping EEPROM...");
|
|
fopen_s(&fd, "eeprom.bin", "wb");
|
|
for (int page = 0; page < 0x80; page++) {
|
|
if (!mxkEepromRead(mxparallel, page, eeprom_block)) {
|
|
printf("\nFailed to read EEPROM:%02x\n", page);
|
|
} else {
|
|
fseek(fd, page * 16, SEEK_SET);
|
|
fwrite(eeprom_block, sizeof eeprom_block, 1, fd);
|
|
printf("Wrote EEPROM:%02x to eeprom.bin\r", page);
|
|
}
|
|
}
|
|
puts("\nEEPROM dump complete");
|
|
fclose(fd);
|
|
|
|
unsigned char nvram_block[0x100];
|
|
puts("Dumping NVRAM...");
|
|
fopen_s(&fd, "nvram.bin", "wb");
|
|
for (int addr = 0; addr < 0x800; addr += 16 * 16) {
|
|
if (!mxkNvramRead(mxparallel, addr, 16, nvram_block)) {
|
|
printf("\nFailed to read NVRAM:%03x\n", addr);
|
|
} else {
|
|
fseek(fd, addr, SEEK_SET);
|
|
fwrite(nvram_block, sizeof nvram_block, 1, fd);
|
|
printf("Wrote NVRAM:%03x to nvram.bin\r", addr);
|
|
}
|
|
}
|
|
puts("\nNVRAM dump complete");
|
|
fclose(fd);
|
|
|
|
unsigned char billing[0x10c];
|
|
if (!mxkFlashRead(mxparallel, 0x7a000, 0x10c, billing)) {
|
|
puts("Failed to request billing information");
|
|
} else {
|
|
fopen_s(&fd, "billing.bin", "wb");
|
|
fwrite(billing, sizeof billing, 1, fd);
|
|
fclose(fd);
|
|
puts("Wrote billing information to billing.bin");
|
|
}
|
|
|
|
unsigned char billing_copy[0x10c];
|
|
if (!mxkFlashRead(mxparallel, 0x7b000, 0x10c, billing_copy)) {
|
|
puts("Failed to request backup billing information");
|
|
} else {
|
|
if (memcmp(billing, billing_copy, 0x10c) == 0) {
|
|
puts("Billing backup [OK]");
|
|
} else {
|
|
puts("Billing backup miss-match!");
|
|
fopen_s(&fd, "billing-backup.bin", "wb");
|
|
fwrite(billing_copy, sizeof billing_copy, 1, fd);
|
|
fclose(fd);
|
|
puts("Wrote billing backup information to billing-backup.bin");
|
|
}
|
|
}
|
|
|
|
unsigned char flash[0x1000];
|
|
puts("Attempting to dump flash...");
|
|
fopen_s(&fd, "flash.bin", "wb");
|
|
for (int addr = 0; addr < 0x80000; addr += sizeof flash) {
|
|
if (!mxkFlashRead(mxparallel, addr, sizeof flash, flash)) {
|
|
printf("\nFailed to read flash:%05x\n", addr);
|
|
} else {
|
|
fseek(fd, addr, SEEK_SET);
|
|
fwrite(flash, sizeof flash, 1, fd);
|
|
printf("Wrote flash:%05x to flash.bin\r", addr);
|
|
}
|
|
}
|
|
puts("\nFlash dump complete");
|
|
fclose(fd);
|
|
|
|
skip_kc_dump:
|
|
CloseHandle(mxparallel);
|
|
return TRUE;
|
|
}
|
|
|
|
int main() {
|
|
// if (!dump_columba()) {
|
|
// printf("Failed to dump DMI: %03x\n", GetLastError());
|
|
// }
|
|
if (!dump_keychip()) {
|
|
printf("Failed to dump keychip: %03x\n", GetLastError());
|
|
}
|
|
// if (!dump_eeprom()) {
|
|
// printf("Failed to dump EEPROM: %03x\n", GetLastError());
|
|
// }
|
|
// if (!dump_sram()) {
|
|
// printf("Failed to dump SRAM: %03x\n", GetLastError());
|
|
// }
|
|
// if (!dump_superio()) {
|
|
// printf("Failed to dump SuperIO: %03x\n", GetLastError());
|
|
// }
|
|
return 0;
|
|
}
|