Lots of work on keychip communication
This commit is contained in:
parent
b88e279b32
commit
09bd2e4792
@ -115,6 +115,8 @@ BOOL smbus_ds28cn01_write(ich9_cmd_t cmd, WORD code, BYTE dlen, BYTE* data) {
|
|||||||
memcpy(&MAC_INPUT_BUFFER[4], USER_EEPROM[page], DS28CN01_EEPROM_PAGE_SIZE);
|
memcpy(&MAC_INPUT_BUFFER[4], USER_EEPROM[page], DS28CN01_EEPROM_PAGE_SIZE);
|
||||||
memcpy(&MAC_INPUT_BUFFER[36], &data[0], 4);
|
memcpy(&MAC_INPUT_BUFFER[36], &data[0], 4);
|
||||||
MAC_INPUT_BUFFER[40] = 0x40 | page;
|
MAC_INPUT_BUFFER[40] = 0x40 | page;
|
||||||
|
// TODO: Where did I get that the unique number is factored in?
|
||||||
|
// This seems like it would cause sums to calculate wrong!
|
||||||
memcpy(&MAC_INPUT_BUFFER[41], UNIQUE_NUMBER, 7);
|
memcpy(&MAC_INPUT_BUFFER[41], UNIQUE_NUMBER, 7);
|
||||||
memcpy(&MAC_INPUT_BUFFER[48], &SECRET[4], 4);
|
memcpy(&MAC_INPUT_BUFFER[48], &SECRET[4], 4);
|
||||||
memcpy(&MAC_INPUT_BUFFER[52], &data[4], 3);
|
memcpy(&MAC_INPUT_BUFFER[52], &data[4], 3);
|
||||||
|
@ -13,8 +13,9 @@ LOG_FACILITY _lf = {
|
|||||||
};
|
};
|
||||||
PLOG_FACILITY plf = &_lf;
|
PLOG_FACILITY plf = &_lf;
|
||||||
|
|
||||||
#define N2_IO_BUFFER 0x1000
|
#define N2_IO_BUFFER 512
|
||||||
|
|
||||||
|
BYTE n2_auth_level = 1;
|
||||||
BYTE n2_in_buffer[N2_IO_BUFFER];
|
BYTE n2_in_buffer[N2_IO_BUFFER];
|
||||||
WORD n2_in_pointer = 0;
|
WORD n2_in_pointer = 0;
|
||||||
BYTE n2_out_buffer[N2_IO_BUFFER];
|
BYTE n2_out_buffer[N2_IO_BUFFER];
|
||||||
@ -25,7 +26,7 @@ WORD n2_error_code = 0;
|
|||||||
BYTE n2_auth_key[20] = { 0x96, 0xed, 0x31, 0xb2, 0x28, 0x71, 0x05, 0xa5, 0xa3, 0x30,
|
BYTE n2_auth_key[20] = { 0x96, 0xed, 0x31, 0xb2, 0x28, 0x71, 0x05, 0xa5, 0xa3, 0x30,
|
||||||
0x54, 0x0f, 0x25, 0xbe, 0xd8, 0x51, 0xa5, 0xc8, 0x36, 0x21 };
|
0x54, 0x0f, 0x25, 0xbe, 0xd8, 0x51, 0xa5, 0xc8, 0x36, 0x21 };
|
||||||
|
|
||||||
BYTE n2_session_nonce[20];
|
BYTE n2_session_salt[20];
|
||||||
struct {
|
struct {
|
||||||
BYTE key[16];
|
BYTE key[16];
|
||||||
BYTE iv[16];
|
BYTE iv[16];
|
||||||
@ -67,7 +68,8 @@ typedef struct {
|
|||||||
} N2_KEYCHIP_INFO, *PN2_KEYCHIP_INFO;
|
} N2_KEYCHIP_INFO, *PN2_KEYCHIP_INFO;
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
N2_KEYCHIP_INFO n2_keychip_info = { .m_KeyId = KEY_ID,
|
N2_KEYCHIP_INFO n2_keychip_info = {
|
||||||
|
.m_KeyId = KEY_ID,
|
||||||
.m_Appboot = {
|
.m_Appboot = {
|
||||||
.m_Format = 1,
|
.m_Format = 1,
|
||||||
.m_GameId = GAME_ID,
|
.m_GameId = GAME_ID,
|
||||||
@ -78,13 +80,14 @@ N2_KEYCHIP_INFO n2_keychip_info = { .m_KeyId = KEY_ID,
|
|||||||
.m_DvdFlag = 1,
|
.m_DvdFlag = 1,
|
||||||
.m_NetworkAddr =
|
.m_NetworkAddr =
|
||||||
(192 << 0) | (168 << 8) | (103 << 16) | (0 << 24),
|
(192 << 0) | (168 << 8) | (103 << 16) | (0 << 24),
|
||||||
} };
|
},
|
||||||
|
};
|
||||||
|
|
||||||
WORD n2_enable_session(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) {
|
WORD n2_enable_session(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) {
|
||||||
*nOut = 20;
|
*nOut = 20;
|
||||||
|
|
||||||
RAND_bytes(n2_session_nonce, sizeof n2_session_nonce);
|
RAND_bytes(n2_session_salt, sizeof n2_session_salt);
|
||||||
memcpy(dataOut, n2_session_nonce, sizeof n2_session_nonce);
|
memcpy(dataOut, n2_session_salt, sizeof n2_session_salt);
|
||||||
|
|
||||||
log_misc(plf, "Session open");
|
log_misc(plf, "Session open");
|
||||||
return N2_SUCCESS;
|
return N2_SUCCESS;
|
||||||
@ -97,6 +100,8 @@ WORD n2_set_auth_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut)
|
|||||||
mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn, pt, sizeof pt);
|
mxkCryptDecryptAes128CBC(n2_enc_key.key, n2_enc_key.iv, dataIn, pt, sizeof pt);
|
||||||
memcpy(n2_auth_key, pt, sizeof n2_auth_key);
|
memcpy(n2_auth_key, pt, sizeof n2_auth_key);
|
||||||
|
|
||||||
|
n2_auth_level = 2;
|
||||||
|
|
||||||
return N2_SUCCESS;
|
return N2_SUCCESS;
|
||||||
}
|
}
|
||||||
WORD n2_set_enc_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) {
|
WORD n2_set_enc_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) {
|
||||||
@ -108,11 +113,13 @@ WORD n2_set_enc_key(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut)
|
|||||||
memcpy(n2_enc_key.key, pt, sizeof n2_enc_key.key);
|
memcpy(n2_enc_key.key, pt, sizeof n2_enc_key.key);
|
||||||
memcpy(n2_enc_key.iv, pt + sizeof n2_enc_key.key, sizeof n2_enc_key.iv);
|
memcpy(n2_enc_key.iv, pt + sizeof n2_enc_key.key, sizeof n2_enc_key.iv);
|
||||||
|
|
||||||
|
n2_auth_level = 3;
|
||||||
|
|
||||||
return N2_SUCCESS;
|
return N2_SUCCESS;
|
||||||
}
|
}
|
||||||
WORD n2_get_auth_level(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) {
|
WORD n2_get_auth_level(WORD paramSize, LPBYTE dataIn, LPBYTE dataOut, LPWORD nOut) {
|
||||||
*nOut = 1;
|
*nOut = 1;
|
||||||
dataOut[0] = 3; // TODO: ?
|
dataOut[0] = n2_auth_level;
|
||||||
log_misc(plf, "Auth level get");
|
log_misc(plf, "Auth level get");
|
||||||
return N2_SUCCESS;
|
return N2_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -241,6 +248,9 @@ void n2_install_commands() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) {
|
void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) {
|
||||||
|
EVP_MD_CTX* ctx;
|
||||||
|
unsigned int outlen;
|
||||||
|
|
||||||
n2_install_commands();
|
n2_install_commands();
|
||||||
|
|
||||||
log_info(plf, "Processing command: %04x/%04x (%d bytes)", tag, command, paramSize);
|
log_info(plf, "Processing command: %04x/%04x (%d bytes)", tag, command, paramSize);
|
||||||
@ -257,6 +267,39 @@ void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) {
|
|||||||
WORD expectedExtraData = N2_CHECKSUM_SIZE + N2_HEADER_SIZE;
|
WORD expectedExtraData = N2_CHECKSUM_SIZE + N2_HEADER_SIZE;
|
||||||
if (tag == N2_TAG_RQU_AUTH_COMMAND) expectedExtraData += N2_AUTH_SIZE;
|
if (tag == N2_TAG_RQU_AUTH_COMMAND) expectedExtraData += N2_AUTH_SIZE;
|
||||||
|
|
||||||
|
unsigned char sha1sum[20];
|
||||||
|
ctx = EVP_MD_CTX_create();
|
||||||
|
EVP_DigestInit(ctx, EVP_sha1());
|
||||||
|
EVP_DigestUpdate(ctx, n2_in_buffer, N2_HEADER_SIZE + paramSize - expectedExtraData);
|
||||||
|
EVP_DigestFinal_ex(ctx, sha1sum, &outlen);
|
||||||
|
EVP_MD_CTX_destroy(ctx);
|
||||||
|
|
||||||
|
HMAC_CTX hmac_ctx;
|
||||||
|
if (tag == N2_TAG_RQU_COMMAND) {
|
||||||
|
if (memcmp(sha1sum, n2_in_buffer + paramSize - N2_CHECKSUM_SIZE, N2_CHECKSUM_SIZE) != 0) {
|
||||||
|
log_error(plf, "SHA1Sum chek failed!");
|
||||||
|
result = N2_SUMFAIL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unsigned char nonce[20];
|
||||||
|
memcpy_s(nonce, 20, n2_in_buffer + paramSize - N2_CHECKSUM_SIZE - N2_AUTH_SIZE, 20);
|
||||||
|
unsigned char hmac[20];
|
||||||
|
|
||||||
|
HMAC_CTX_init(&hmac_ctx);
|
||||||
|
HMAC_Init_ex(&hmac_ctx, auth_key, sizeof auth_key, EVP_sha1(), NULL);
|
||||||
|
HMAC_Update(&hmac_ctx, sha1sum, N2_CHECKSUM_SIZE);
|
||||||
|
HMAC_Update(&hmac_ctx, n2_session_salt, N2_CHECKSUM_SIZE);
|
||||||
|
HMAC_Update(&hmac_ctx, nonce, N2_CHECKSUM_SIZE);
|
||||||
|
HMAC_Final(&hmac_ctx, hmac, &outlen);
|
||||||
|
HMAC_CTX_cleanup(&hmac_ctx);
|
||||||
|
|
||||||
|
if (memcmp(hmac, n2_in_buffer + paramSize - N2_AUTH_SIZE, N2_AUTH_SIZE) != 0) {
|
||||||
|
log_error(plf, "HMAC check failed!");
|
||||||
|
result = N2_AUTHFAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == N2_SUCCESS) {
|
||||||
n2_command handler = N2_COMMANDS[command & 0xff];
|
n2_command handler = N2_COMMANDS[command & 0xff];
|
||||||
if (handler.handler == NULL) {
|
if (handler.handler == NULL) {
|
||||||
result = N2_BAD_ORDINAL;
|
result = N2_BAD_ORDINAL;
|
||||||
@ -268,15 +311,13 @@ void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) {
|
|||||||
result = (*handler.handler)(paramSize, n2_in_buffer + N2_HEADER_SIZE,
|
result = (*handler.handler)(paramSize, n2_in_buffer + N2_HEADER_SIZE,
|
||||||
n2_out_buffer + N2_HEADER_SIZE, &bodyLength);
|
n2_out_buffer + N2_HEADER_SIZE, &bodyLength);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WORD paramSizeOut = bodyLength + expectedExtraData;
|
WORD paramSizeOut = bodyLength + expectedExtraData;
|
||||||
((PWORD)n2_out_buffer)[0] = fix_endian(tag + 2);
|
((PWORD)n2_out_buffer)[0] = fix_endian(tag + 2);
|
||||||
((PWORD)n2_out_buffer)[1] = fix_endian(paramSizeOut);
|
((PWORD)n2_out_buffer)[1] = fix_endian(paramSizeOut);
|
||||||
((PWORD)n2_out_buffer)[2] = fix_endian(result);
|
((PWORD)n2_out_buffer)[2] = fix_endian(result);
|
||||||
|
|
||||||
EVP_MD_CTX* ctx;
|
|
||||||
unsigned int outlen;
|
|
||||||
|
|
||||||
WORD fixed_command = fix_endian(command);
|
WORD fixed_command = fix_endian(command);
|
||||||
|
|
||||||
// Calculate a SHA1 of the packet, and append it
|
// Calculate a SHA1 of the packet, and append it
|
||||||
@ -291,26 +332,16 @@ void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) {
|
|||||||
// At this point: packet = header | data | SHA(header | command | data)
|
// At this point: packet = header | data | SHA(header | command | data)
|
||||||
|
|
||||||
if (tag == N2_TAG_RQU_AUTH_COMMAND) {
|
if (tag == N2_TAG_RQU_AUTH_COMMAND) {
|
||||||
BYTE crypto_buffer[N2_CHECKSUM_SIZE];
|
// TODO: Further investigation might be needed here.
|
||||||
|
// The following code checks out against mxkeychip, but repeating the
|
||||||
// Calculate a new SHA1 of the packet, including the SHA1 we just appeneded
|
// packet sum twice feels wrong.
|
||||||
// crypto_buffer = SHA1(header | command | data)
|
|
||||||
ctx = EVP_MD_CTX_create();
|
|
||||||
EVP_DigestInit(ctx, EVP_sha1());
|
|
||||||
EVP_DigestUpdate(ctx, n2_out_buffer, N2_HEADER_SIZE);
|
|
||||||
EVP_DigestUpdate(ctx, &fixed_command, 2);
|
|
||||||
EVP_DigestUpdate(ctx, n2_out_buffer + N2_HEADER_SIZE, bodyLength);
|
|
||||||
EVP_DigestFinal_ex(ctx, crypto_buffer, &outlen);
|
|
||||||
EVP_MD_CTX_destroy(ctx);
|
|
||||||
|
|
||||||
// Calculate an HMAC, and append it
|
// Calculate an HMAC, and append it
|
||||||
HMAC_CTX hmac_ctx;
|
|
||||||
HMAC_CTX_init(&hmac_ctx);
|
HMAC_CTX_init(&hmac_ctx);
|
||||||
HMAC_Init_ex(&hmac_ctx, auth_key, sizeof auth_key, EVP_sha1(), NULL);
|
HMAC_Init_ex(&hmac_ctx, auth_key, sizeof auth_key, EVP_sha1(), NULL);
|
||||||
|
|
||||||
// SHA1(header | command | data)
|
// SHA1(header | command | data)
|
||||||
HMAC_Update(&hmac_ctx, crypto_buffer, sizeof crypto_buffer);
|
HMAC_Update(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength, N2_CHECKSUM_SIZE);
|
||||||
// SHA1(header | auth | data)
|
|
||||||
HMAC_Update(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength, N2_CHECKSUM_SIZE);
|
HMAC_Update(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength, N2_CHECKSUM_SIZE);
|
||||||
// Request nonce
|
// Request nonce
|
||||||
HMAC_Update(&hmac_ctx, n2_in_buffer + paramSize - N2_AUTH_SIZE - N2_CHECKSUM_SIZE,
|
HMAC_Update(&hmac_ctx, n2_in_buffer + paramSize - N2_AUTH_SIZE - N2_CHECKSUM_SIZE,
|
||||||
@ -319,6 +350,10 @@ void do_n2_command(WORD tag, WORD paramSize, WORD command, LPBYTE data) {
|
|||||||
HMAC_Final(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength + N2_CHECKSUM_SIZE,
|
HMAC_Final(&hmac_ctx, n2_out_buffer + N2_HEADER_SIZE + bodyLength + N2_CHECKSUM_SIZE,
|
||||||
&outlen);
|
&outlen);
|
||||||
HMAC_CTX_cleanup(&hmac_ctx);
|
HMAC_CTX_cleanup(&hmac_ctx);
|
||||||
|
|
||||||
|
// Update session salt
|
||||||
|
memcpy_s(n2_session_salt, sizeof n2_session_salt,
|
||||||
|
n2_out_buffer + N2_HEADER_SIZE + bodyLength, N2_CHECKSUM_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -376,6 +411,7 @@ BOOL smbus_N2_write(ich9_cmd_t cmd, WORD code, BYTE nbytes, LPBYTE data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL smbus_N2_read(ich9_cmd_t cmd, WORD code, BYTE nbytes, BYTE* data) {
|
BOOL smbus_N2_read(ich9_cmd_t cmd, WORD code, BYTE nbytes, BYTE* data) {
|
||||||
|
// TODO: Unaligned mxk reads poke into this for the final byte!
|
||||||
log_error(plf, "Unsupported read mode: %01x (%02x)", cmd, code);
|
log_error(plf, "Unsupported read mode: %01x (%02x)", cmd, code);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
#include "../common.h"
|
#include "../common.h"
|
||||||
|
|
||||||
FARPROC (*TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
|
FARPROC(WINAPI* TrueGetProcAddress)(HMODULE hModule, LPCSTR lpProcName);
|
||||||
HMODULE (*TrueGetModuleHandleA)(LPCSTR lpModuleName);
|
HMODULE(WINAPI* TrueGetModuleHandleA)(LPCSTR lpModuleName);
|
||||||
|
HMODULE(WINAPI* TrueLoadLibraryA)(LPCSTR lpLibFileName);
|
||||||
|
HMODULE(WINAPI* TrueLoadLibraryW)(LPCWSTR lpLibFileName);
|
||||||
|
|
||||||
void hook_system();
|
void hook_system();
|
||||||
|
@ -8,6 +8,8 @@ shared_library(
|
|||||||
name_prefix: '',
|
name_prefix: '',
|
||||||
vs_module_defs: 'mice.def',
|
vs_module_defs: 'mice.def',
|
||||||
sources: [
|
sources: [
|
||||||
|
'amvStub/amv.c',
|
||||||
|
|
||||||
'util/misc.c',
|
'util/misc.c',
|
||||||
'util/hook.c',
|
'util/hook.c',
|
||||||
'util/path.c',
|
'util/path.c',
|
||||||
|
@ -9,7 +9,9 @@
|
|||||||
bool debug_wait = false;
|
bool debug_wait = false;
|
||||||
int boot_delay = 0;
|
int boot_delay = 0;
|
||||||
char exe_name[MAX_PATH + 1] = "";
|
char exe_name[MAX_PATH + 1] = "";
|
||||||
char commandline[MAX_PATH + 1] = "";
|
|
||||||
|
size_t nCommandLine = 256;
|
||||||
|
char* commandLine = NULL;
|
||||||
|
|
||||||
static void print_help(char* exe) {
|
static void print_help(char* exe) {
|
||||||
log_info(plfBoot, "Usage: %s [-h] [-t] [-b executable.exe] [-d]", exe);
|
log_info(plfBoot, "Usage: %s [-h] [-t] [-b executable.exe] [-d]", exe);
|
||||||
@ -69,10 +71,13 @@ static bool parse_cmdline(int argc, char* argv[]) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (commandline[0] == 0)
|
size_t newLength = nCommandLine + 1 + strlen(argv[i]) + 1;
|
||||||
snprintf(commandline, sizeof commandline, "%s", argv[i]);
|
if (newLength > nCommandLine) {
|
||||||
else
|
nCommandLine = newLength;
|
||||||
snprintf(commandline, sizeof commandline, "%s %s", commandline, argv[i]);
|
commandLine = realloc(commandLine, nCommandLine);
|
||||||
|
}
|
||||||
|
strcat_s(commandLine, nCommandLine, " ");
|
||||||
|
strcat_s(commandLine, nCommandLine, argv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -176,6 +181,13 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
log_info(plfBoot, "Micetools version: %s", MICE_VERSION);
|
log_info(plfBoot, "Micetools version: %s", MICE_VERSION);
|
||||||
|
|
||||||
|
commandLine = malloc(nCommandLine);
|
||||||
|
if (commandLine == NULL) {
|
||||||
|
log_error(plfBoot, "Fatal: Failed to malloc(commandLine)");
|
||||||
|
return terminate(-1);
|
||||||
|
}
|
||||||
|
commandLine[0] = '\0';
|
||||||
|
|
||||||
CHAR workDir[MAX_PATH + 1];
|
CHAR workDir[MAX_PATH + 1];
|
||||||
GetCurrentDirectory(MAX_PATH, workDir);
|
GetCurrentDirectory(MAX_PATH, workDir);
|
||||||
log_info(plfBoot, "Current directory: %s", workDir);
|
log_info(plfBoot, "Current directory: %s", workDir);
|
||||||
@ -203,7 +215,7 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
spawn_pcp_processes();
|
spawn_pcp_processes();
|
||||||
|
|
||||||
log_info(plfBoot, "exec: %s %s", exe_name, commandline);
|
log_info(plfBoot, "exec: %s %s", exe_name, commandLine);
|
||||||
|
|
||||||
char micepath[MAX_PATH + 1];
|
char micepath[MAX_PATH + 1];
|
||||||
if (!locate_library(micepath, MAX_PATH + 1)) {
|
if (!locate_library(micepath, MAX_PATH + 1)) {
|
||||||
@ -216,18 +228,30 @@ int main(int argc, char* argv[]) {
|
|||||||
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
|
||||||
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info);
|
SetInformationJobObject(hJob, JobObjectExtendedLimitInformation, &info, sizeof info);
|
||||||
|
|
||||||
|
size_t nFullCommandLine = nCommandLine + strlen(exe_name) + 1;
|
||||||
|
char* fullCommandLine = malloc(nFullCommandLine);
|
||||||
|
snprintf(fullCommandLine, nFullCommandLine, "%s %s", exe_name, commandLine);
|
||||||
|
free(commandLine);
|
||||||
|
|
||||||
char* extra_injections = MiceConfig.launcher.inject;
|
char* extra_injections = MiceConfig.launcher.inject;
|
||||||
PROCESS_INFORMATION pi;
|
PROCESS_INFORMATION pi;
|
||||||
if (!start_and_inject(hJob, exe_name, commandline, micepath, debug_wait, boot_delay,
|
if (!start_and_inject(hJob, exe_name, fullCommandLine, micepath, debug_wait, boot_delay,
|
||||||
extra_injections, 0, &pi))
|
extra_injections, 0, &pi)) {
|
||||||
|
free(fullCommandLine);
|
||||||
return terminate(-1);
|
return terminate(-1);
|
||||||
|
}
|
||||||
|
free(fullCommandLine);
|
||||||
|
|
||||||
SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE);
|
SetConsoleCtrlHandler(MiceHandlerRoutine, TRUE);
|
||||||
|
|
||||||
if (FAILED(WaitForSingleObject(pi.hProcess, INFINITE))) {
|
if (FAILED(WaitForSingleObject(pi.hProcess, INFINITE))) {
|
||||||
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
|
log_error(plfBoot, "Fatal: WaitForSingleObject failed: %03x", GetLastError());
|
||||||
} else {
|
} else {
|
||||||
log_info(plfBoot, "Shutting down");
|
DWORD exitCode;
|
||||||
|
if (GetExitCodeProcess(pi.hProcess, &exitCode))
|
||||||
|
log_info(plfBoot, "Shutting down (ret:%d)", exitCode);
|
||||||
|
else
|
||||||
|
log_info(plfBoot, "Shutting down (failed to get exit code)");
|
||||||
CloseHandle(pi.hProcess);
|
CloseHandle(pi.hProcess);
|
||||||
}
|
}
|
||||||
return terminate(0);
|
return terminate(0);
|
||||||
|
@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
AM_LIB_C_HEADER(amiCrc, AMI_CRC)
|
AM_LIB_C_HEADER(amiCrc, AMI_CRC)
|
||||||
|
|
||||||
void amiCrc32RCreateTable(unsigned int *table) {
|
void amiCrc32RCreateTable(uint32_t *table) {
|
||||||
for (int i = 0; i < 256; i++) {
|
for (int i = 0; i < 256; i++) {
|
||||||
unsigned int value = (~i & 1) - 1 & CRC32_POLYNOMIAL;
|
uint32_t value = (~i & 1) - 1 & CRC32_POLYNOMIAL;
|
||||||
value = ((i >> 1 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
|
value = ((i >> 1 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
|
||||||
value = ((i >> 2 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
|
value = ((i >> 2 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
|
||||||
value = ((i >> 3 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
|
value = ((i >> 3 ^ ~value) & 1) - 1 & CRC32_POLYNOMIAL ^ value >> 1;
|
||||||
@ -18,13 +18,12 @@ void amiCrc32RCreateTable(unsigned int *table) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int amiCrc32RGet(unsigned int *table, int length, unsigned char *data,
|
uint32_t amiCrc32RGet(uint32_t *table, int length, void *data, uint32_t initial) {
|
||||||
unsigned int initial) {
|
uint32_t value = ~initial;
|
||||||
unsigned int value = ~initial;
|
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
value = value >> 8 ^ table[(data[0] ^ value) & 0xff];
|
value = value >> 8 ^ table[(((unsigned char *)data)[0] ^ value) & 0xff];
|
||||||
length += -1;
|
length += -1;
|
||||||
data++;
|
((unsigned char *)data)++;
|
||||||
}
|
}
|
||||||
return ~value;
|
return ~value;
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "../_am.h"
|
#include "../_am.h"
|
||||||
|
|
||||||
AM_LIB_H_HEADER(amiCrc, AMI_CRC)
|
AM_LIB_H_HEADER(amiCrc, AMI_CRC)
|
||||||
|
|
||||||
typedef struct _AMI_CRC {
|
typedef struct _AMI_CRC {
|
||||||
unsigned int m_init;
|
uint32_t m_init;
|
||||||
unsigned int m_table[256];
|
uint32_t m_table[256];
|
||||||
} AMI_CRC;
|
} AMI_CRC;
|
||||||
|
|
||||||
void amiCrc32RCreateTable(unsigned int *table);
|
void amiCrc32RCreateTable(uint32_t *table);
|
||||||
unsigned int amiCrc32RGet(unsigned int *table, int length, unsigned char *data,
|
uint32_t amiCrc32RGet(uint32_t *table, int length, void *data, uint32_t initial);
|
||||||
unsigned int initial);
|
|
||||||
|
|
||||||
#define amiCrc32RInit() \
|
#define amiCrc32RInit() \
|
||||||
do { \
|
do { \
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait,
|
BOOL start_and_inject(HANDLE hJob, LPCSTR path, LPSTR cmdline, LPCSTR inject, BOOL debug_wait,
|
||||||
DWORD delay, LPCSTR extra_injections, DWORD flags, LPPROCESS_INFORMATION lpProcessInformation);
|
DWORD delay, LPCSTR extra_injections, DWORD flags,
|
||||||
|
LPPROCESS_INFORMATION lpProcessInformation);
|
||||||
|
|
||||||
#define MICELIB "mice.dll"
|
#define MICELIB "mice.dll"
|
||||||
|
@ -177,7 +177,7 @@ BOOL mxkNvramRead(unsigned short addr, unsigned char blocks, unsigned char* data
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool mxkValidString(const char* string, unsigned int length) {
|
bool mxkValidString(const char* string, unsigned int length) {
|
||||||
for (int i = 0; i < length; i++) {
|
for (unsigned int i = 0; i < length; i++) {
|
||||||
char c = string[i];
|
char c = string[i];
|
||||||
if (isalnum(c)) continue;
|
if (isalnum(c)) continue;
|
||||||
if (c != '.' && c != '_' && c != '-' && c != ':' && c != '@' && c != '%' && c != '/' &&
|
if (c != '.' && c != '_' && c != '-' && c != ':' && c != '@' && c != '%' && c != '/' &&
|
||||||
@ -187,7 +187,52 @@ bool mxkValidString(const char* string, unsigned int length) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MXK_STATUS mxkInit() {
|
MXK_STATUS mxkGetKeychipIdFromN2(void) {
|
||||||
|
N2KeychipId_t kcId;
|
||||||
|
|
||||||
|
memset(&kcId, 0, sizeof kcId);
|
||||||
|
int err = mxkN2CmdReadKeychipID(&kcId);
|
||||||
|
if (err != 0) {
|
||||||
|
amiDebugLog("Error: mxkN2CmdReadKeychipID().ErrorCode %d", err);
|
||||||
|
return MXK_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
amiCrc32RInit();
|
||||||
|
uint32_t crcCalc = amiCrc32RCalc((sizeof kcId.m_AppBoot) - 4, (LPBYTE)&kcId.m_AppBoot + 4, 0);
|
||||||
|
if (crcCalc != kcId.m_AppBoot.m_Crc) {
|
||||||
|
amiDebugLog("Error AppBootInfo CRC!!!");
|
||||||
|
return MXK_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
crcCalc = amiCrc32RCalc(sizeof kcId - 4, (LPBYTE)&kcId + 4, 0);
|
||||||
|
if (crcCalc != kcId.m_Crc) {
|
||||||
|
amiDebugLog("Error KeychipID CRC!!!");
|
||||||
|
return MXK_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// N2 keychip ID is a smaller, more compact, format than normal appboot. Restructure it to match
|
||||||
|
// before committing it to memory!
|
||||||
|
unsigned char keyId[16];
|
||||||
|
appboot_t appboot;
|
||||||
|
|
||||||
|
memcpy_s(keyId, sizeof keyId, kcId.m_KeyId, sizeof kcId.m_KeyId);
|
||||||
|
memcpy_s(&appboot, sizeof appboot, &kcId.m_AppBoot,
|
||||||
|
sizeof kcId.m_AppBoot - sizeof kcId.m_AppBoot.m_Seed);
|
||||||
|
memcpy_s(appboot.seed, sizeof appboot.seed, kcId.m_AppBoot.m_Seed,
|
||||||
|
sizeof kcId.m_AppBoot.m_Seed);
|
||||||
|
|
||||||
|
printf("Got N2 key ID: %.16s\n", keyId);
|
||||||
|
printf("Got N2 game ID: %.4s\n", kcId.m_AppBoot.m_GameId);
|
||||||
|
|
||||||
|
// ...but we're not actually committing it to memory at the moment!
|
||||||
|
// memcpy_s(&APPBOOT, 256, &appboot, sizeof appboot);
|
||||||
|
// memcpy_s(N2_KEYID, 16, keyId, 16);
|
||||||
|
// DAT_004adc95 = 0;
|
||||||
|
// DAT_004adda4 = 0;
|
||||||
|
return MXK_STATUS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
MXK_STATUS mxkInit(void) {
|
||||||
mxkVersionDirty = true;
|
mxkVersionDirty = true;
|
||||||
AppBoot.m_cacheDirty = true;
|
AppBoot.m_cacheDirty = true;
|
||||||
|
|
||||||
@ -203,7 +248,6 @@ MXK_STATUS mxkInit() {
|
|||||||
amiDebugLog("Error mxkExchengeAesKey!!");
|
amiDebugLog("Error mxkExchengeAesKey!!");
|
||||||
return MXK_STATUS_ERROR;
|
return MXK_STATUS_ERROR;
|
||||||
}
|
}
|
||||||
// TODO: N2
|
|
||||||
if (mxkSmbusInit() != MXK_STATUS_OK) {
|
if (mxkSmbusInit() != MXK_STATUS_OK) {
|
||||||
amiDebugLog("Error mxkSmbusInit!!");
|
amiDebugLog("Error mxkSmbusInit!!");
|
||||||
return MXK_STATUS_ERROR;
|
return MXK_STATUS_ERROR;
|
||||||
@ -226,9 +270,15 @@ MXK_STATUS mxkInit() {
|
|||||||
// eeprom_playcount();
|
// eeprom_playcount();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO:
|
if (mxkN2Init() != 0) {
|
||||||
mxkN2CmdSetDeviceInfo();
|
amiDebugLog("Error mxkN2Init!!");
|
||||||
mxkN2Authentication();
|
return MXK_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mxkGetKeychipIdFromN2() != 0) {
|
||||||
|
amiDebugLog("Error mxkGetKeychipIdFromN2!!");
|
||||||
|
return MXK_STATUS_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
return MXK_STATUS_OK;
|
return MXK_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "mxkCrypt.h"
|
#include "mxkCrypt.h"
|
||||||
|
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/pem.h>
|
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
|
||||||
// These three should be initialised to null, and populated by mxkCryptInit, but we already know
|
// These three should be initialised to null, and populated by mxkCryptInit, but we already know
|
||||||
// their values and aren't trying to hide them from anyone! mxkCryptInit is still fully implemented,
|
// their values and aren't trying to hide them from anyone! mxkCryptInit is still fully implemented,
|
||||||
@ -153,8 +153,8 @@ void mxkSwapKeys() {
|
|||||||
memcpy(KEY_S, temp, 16);
|
memcpy(KEY_S, temp, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv,
|
MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv, void* ct,
|
||||||
unsigned char* ct, const unsigned char* pt, size_t nbytes) {
|
const void* pt, size_t nbytes) {
|
||||||
if (key == NULL || iv == NULL || ct == NULL || pt == NULL) {
|
if (key == NULL || iv == NULL || ct == NULL || pt == NULL) {
|
||||||
amiDebugLog("Error: Invalid param.");
|
amiDebugLog("Error: Invalid param.");
|
||||||
return MXK_STATUS_INVALID_PARAM;
|
return MXK_STATUS_INVALID_PARAM;
|
||||||
@ -173,7 +173,7 @@ MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned cha
|
|||||||
}
|
}
|
||||||
|
|
||||||
MXK_STATUS mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned char* iv,
|
MXK_STATUS mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned char* iv,
|
||||||
const unsigned char* ct, unsigned char* pt, size_t nbytes) {
|
const void* ct, void* pt, size_t nbytes) {
|
||||||
if (key == NULL || iv == NULL || ct == NULL || pt == NULL) {
|
if (key == NULL || iv == NULL || ct == NULL || pt == NULL) {
|
||||||
amiDebugLog("Error: Invalid param.");
|
amiDebugLog("Error: Invalid param.");
|
||||||
return MXK_STATUS_INVALID_PARAM;
|
return MXK_STATUS_INVALID_PARAM;
|
||||||
|
@ -4,23 +4,34 @@
|
|||||||
#include "../ami/ami.h"
|
#include "../ami/ami.h"
|
||||||
#include "mxkDefs.h"
|
#include "mxkDefs.h"
|
||||||
|
|
||||||
|
#define SHA1_SUM_SIZE 20
|
||||||
|
#define HMAC_SUM_SIZE 20
|
||||||
|
#define HMAC_KEY_SIZE 20
|
||||||
|
|
||||||
|
typedef char Sha1Sum_t[SHA1_SUM_SIZE];
|
||||||
|
typedef char (*PSha1Sum_t)[SHA1_SUM_SIZE];
|
||||||
|
typedef char HmacSum_t[HMAC_SUM_SIZE];
|
||||||
|
typedef char (*PHmacSum_t)[HMAC_SUM_SIZE];
|
||||||
|
typedef char HmacKey_t[HMAC_SUM_SIZE];
|
||||||
|
typedef char (*PHmacKey_t)[HMAC_SUM_SIZE];
|
||||||
|
|
||||||
void mxkSetKeyS(unsigned char* key_s);
|
void mxkSetKeyS(unsigned char* key_s);
|
||||||
void mxkSetKeyR(unsigned char* key_r);
|
void mxkSetKeyR(unsigned char* key_r);
|
||||||
void mxkSwapKeys();
|
void mxkSwapKeys();
|
||||||
|
|
||||||
MXK_STATUS mxkCryptInit(void);
|
MXK_STATUS mxkCryptInit(void);
|
||||||
|
|
||||||
int mxkCryptCalcHashWithHmacSha1(void* key, unsigned char* md, size_t* nbuffer,
|
int mxkCryptCalcHashWithHmacSha1(PHmacKey_t key, PHmacSum_t md, size_t* nbuffer,
|
||||||
unsigned char* buffer, size_t nin);
|
unsigned char* buffer, size_t nin);
|
||||||
void mxkCryptCalcHashWithSha1(unsigned char* data, size_t nbytes, unsigned char* sum);
|
void mxkCryptCalcHashWithSha1(unsigned char* data, size_t nbytes, PSha1Sum_t sum);
|
||||||
|
|
||||||
void mxkCryptCreateDigest(void);
|
void mxkCryptCreateDigest(void);
|
||||||
void mxkCryptRsaSignVerify(void);
|
void mxkCryptRsaSignVerify(void);
|
||||||
|
|
||||||
MXK_STATUS mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned char* iv,
|
MXK_STATUS mxkCryptDecryptAes128CBC(const unsigned char* key, const unsigned char* iv,
|
||||||
const unsigned char* ct, unsigned char* pt, size_t nbytes);
|
const void* ct, void* pt, size_t nbytes);
|
||||||
MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv,
|
MXK_STATUS mxkCryptEncryptAes128CBC(const unsigned char* key, const unsigned char* iv, void* ct,
|
||||||
unsigned char* pt, const unsigned char* ct, size_t nbytes);
|
const void* pt, size_t nbytes);
|
||||||
|
|
||||||
MXK_STATUS mxkCryptDecryptData(const unsigned char* ct, unsigned char* pt);
|
MXK_STATUS mxkCryptDecryptData(const unsigned char* ct, unsigned char* pt);
|
||||||
MXK_STATUS mxkCryptEncryptData(unsigned char* ct, const unsigned char* pt);
|
MXK_STATUS mxkCryptEncryptData(unsigned char* ct, const unsigned char* pt);
|
||||||
|
@ -57,7 +57,7 @@ int mxkDsKeychipComputeMac(unsigned char page, void *challenge, unsigned char *m
|
|||||||
Sleep(16);
|
Sleep(16);
|
||||||
status = mxkDsWaitNotBusy(&INT_004ab34c);
|
status = mxkDsWaitNotBusy(&INT_004ab34c);
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
if (!mxkSmbusI2CReadBlock(KC_DS_ADDRESS, DS28CN01_REG_MAC, mac, 20)) {
|
if (mxkSmbusI2CReadBlock(KC_DS_ADDRESS, DS28CN01_REG_MAC, mac, 20) != 0) {
|
||||||
amiDebugLog("Error mxkSmbusI2CReadBlock()!!!");
|
amiDebugLog("Error mxkSmbusI2CReadBlock()!!!");
|
||||||
error = -8;
|
error = -8;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
#include "mxkN2.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
@ -7,30 +9,47 @@
|
|||||||
#include "mxkCrypt.h"
|
#include "mxkCrypt.h"
|
||||||
#include "mxkSmbus.h"
|
#include "mxkSmbus.h"
|
||||||
|
|
||||||
#define N2_ADDR 0x30
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char m_Key[16];
|
unsigned char m_Key[16];
|
||||||
unsigned char m_IV[16];
|
unsigned char m_IV[16];
|
||||||
} AESKey_t;
|
} AESKey_t;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned short m_Tag;
|
unsigned short m_Tag;
|
||||||
unsigned short m_ParamSize;
|
unsigned short m_ParamSize;
|
||||||
unsigned short m_Command;
|
unsigned short m_Command;
|
||||||
unsigned char m_Body[506];
|
unsigned char m_Body[N2_DATA_MAX];
|
||||||
} N2Packet_t;
|
} N2Packet_t;
|
||||||
|
typedef struct {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
Sha1Sum_t m_ShaSum;
|
||||||
|
} rqu;
|
||||||
|
struct {
|
||||||
|
N2Nonce_t m_Nonce;
|
||||||
|
HmacSum_t m_Hmac;
|
||||||
|
} sign;
|
||||||
|
};
|
||||||
|
} N2PacketFooter_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
BOOL MXK_HAS_INIT = FALSE;
|
BOOL MXK_HAS_INIT = FALSE;
|
||||||
BOOL MXK_N2_INIT = FALSE;
|
BOOL MXK_N2_INIT = FALSE;
|
||||||
|
#define CheckN2Init \
|
||||||
|
do { \
|
||||||
|
if (!MXK_N2_INIT) { \
|
||||||
|
amiDebugLog("Error: Uninitialized."); \
|
||||||
|
return -3; \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char m_Addr;
|
unsigned char m_Addr;
|
||||||
unsigned char m_HmacKey[20];
|
HmacKey_t m_HmacKey;
|
||||||
AESKey_t m_AESKey;
|
AESKey_t m_AESKey;
|
||||||
unsigned char m_AuthKey[20];
|
N2AuthKey_t m_AuthKey;
|
||||||
unsigned char m_EncKey[16];
|
AESKey_t m_EncKey;
|
||||||
unsigned char Unk[16];
|
HmacSum_t m_HmacSalt;
|
||||||
unsigned char m_HmacOut[20];
|
|
||||||
} N2DeviceInfo_t;
|
} N2DeviceInfo_t;
|
||||||
N2DeviceInfo_t N2DeviceInfo;
|
N2DeviceInfo_t N2DeviceInfo;
|
||||||
|
|
||||||
@ -41,14 +60,16 @@ unsigned char N2_KEY_HMAC[2][20] = {
|
|||||||
0x1d, 0x1e, 0x1f, 0x11, 0xee, 0xb0, 0xf4, 0xd4, 0x20, 0x24 }
|
0x1d, 0x1e, 0x1f, 0x11, 0xee, 0xb0, 0xf4, 0xd4, 0x20, 0x24 }
|
||||||
};
|
};
|
||||||
|
|
||||||
AESKey_t N2_KEY_AES[2] = { { { 0xd7, 0xf6, 0x86, 0xfb, 0x63, 0x44, 0xff, 0xa5, 0x60, 0x9d, 0x4e,
|
AESKey_t N2_KEY_AES[2] = {
|
||||||
0xf0, 0x18, 0xe9, 0x45, 0xb4 },
|
{ { 0xd7, 0xf6, 0x86, 0xfb, 0x63, 0x44, 0xff, 0xa5, 0x60, 0x9d, 0x4e, 0xf0, 0x18, 0xe9, 0x45,
|
||||||
{ 0x12, 0x6c, 0xb1, 0xdb, 0x9e, 0x00, 0x8c, 0xc6, 0xae, 0xa1, 0x73,
|
0xb4 },
|
||||||
0xec, 0xe7, 0x2f, 0x5a, 0xc4 } },
|
{ 0x12, 0x6c, 0xb1, 0xdb, 0x9e, 0x00, 0x8c, 0xc6, 0xae, 0xa1, 0x73, 0xec, 0xe7, 0x2f, 0x5a,
|
||||||
{ { 0xa1, 0x1a, 0xc4, 0x4d, 0xcd, 0x48, 0x4f, 0xed, 0x70, 0xcc, 0x3f,
|
0xc4 } },
|
||||||
0x5d, 0x94, 0x5b, 0xbe, 0xb3 },
|
{ { 0xa1, 0x1a, 0xc4, 0x4d, 0xcd, 0x48, 0x4f, 0xed, 0x70, 0xcc, 0x3f, 0x5d, 0x94, 0x5b, 0xbe,
|
||||||
{ 0x9c, 0x5c, 0xba, 0x7f, 0xb0, 0x15, 0xc7, 0x69, 0xcb, 0xb4, 0x41,
|
0xb3 },
|
||||||
0x19, 0x97, 0x2b, 0x45, 0x9f } } };
|
{ 0x9c, 0x5c, 0xba, 0x7f, 0xb0, 0x15, 0xc7, 0x69, 0xcb, 0xb4, 0x41, 0x19, 0x97, 0x2b, 0x45,
|
||||||
|
0x9f } },
|
||||||
|
};
|
||||||
|
|
||||||
int mxkN2CmdInit(void) {
|
int mxkN2CmdInit(void) {
|
||||||
if (MXK_N2_INIT) {
|
if (MXK_N2_INIT) {
|
||||||
@ -65,7 +86,7 @@ int mxkN2CmdSetDeviceInfo(void) {
|
|||||||
|
|
||||||
if (mxkN2CmdInit() != 0) return -5;
|
if (mxkN2CmdInit() != 0) return -5;
|
||||||
|
|
||||||
unsigned char hmacKey[20];
|
HmacKey_t hmacKey;
|
||||||
AESKey_t aesKey;
|
AESKey_t aesKey;
|
||||||
for (int i = 0; i < sizeof hmacKey; i++) hmacKey[i] = N2_KEY_HMAC[0][i] ^ N2_KEY_HMAC[1][i];
|
for (int i = 0; i < sizeof hmacKey; i++) hmacKey[i] = N2_KEY_HMAC[0][i] ^ N2_KEY_HMAC[1][i];
|
||||||
for (int i = 0; i < sizeof aesKey.m_Key; i++)
|
for (int i = 0; i < sizeof aesKey.m_Key; i++)
|
||||||
@ -88,17 +109,18 @@ int mxkN2CmdSetDeviceInfo(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Better name
|
// TODO: Better name
|
||||||
void _randomBytes(unsigned char *buf, int nbytes) {
|
void _randomBytes(void *buf, int nbytes) {
|
||||||
FILETIME fileTime;
|
FILETIME fileTime;
|
||||||
amtime_t amTime;
|
amtime_t amTime;
|
||||||
|
|
||||||
for (int i = 0; i < nbytes; i++) {
|
for (int i = 0; i < nbytes; i++) {
|
||||||
amiTimerGet(&amTime);
|
amiTimerGet(&amTime);
|
||||||
GetSystemTimeAsFileTime(&fileTime);
|
GetSystemTimeAsFileTime(&fileTime);
|
||||||
buf[i] = (amTime.microseconds ^ fileTime.dwLowDateTime ^ fileTime.dwHighDateTime) & 0xff;
|
((unsigned char *)buf)[i] =
|
||||||
|
(amTime.microseconds ^ fileTime.dwLowDateTime ^ fileTime.dwHighDateTime) & 0xff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void mxkN2GetPacketNonce(unsigned char *nonce) { _randomBytes(nonce, 20); }
|
void mxkN2GetPacketNonce(PN2Nonce_t nonce) { _randomBytes(nonce, 20); }
|
||||||
|
|
||||||
int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numStreams,
|
int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numStreams,
|
||||||
va_list args) {
|
va_list args) {
|
||||||
@ -110,10 +132,11 @@ int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numSt
|
|||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
size_t max = *count;
|
size_t max = *count;
|
||||||
for (size_t i = 0; i < numStreams && i < max; i++) {
|
for (size_t i = 0; i < numStreams && i < max; i++) {
|
||||||
size_t n = va_arg(args, size_t);
|
|
||||||
unsigned char *b = va_arg(args, unsigned char *);
|
unsigned char *b = va_arg(args, unsigned char *);
|
||||||
if (i + n > max) n = max - i;
|
size_t n = va_arg(args, size_t);
|
||||||
memcpy(out + offset, b, i);
|
if (offset + n > max) n = max - offset;
|
||||||
|
memcpy(out + offset, b, n);
|
||||||
|
offset += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
*count = offset;
|
*count = offset;
|
||||||
@ -129,46 +152,49 @@ void mxkN2UtilCatenateData(unsigned char *concatinated, size_t *count, unsigned
|
|||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mxkN2UtilSha1Many(unsigned char *sum, int numStreams, ...) {
|
void mxkN2UtilSha1Many(PSha1Sum_t sum, int numStreams, ...) {
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, numStreams);
|
va_start(args, numStreams);
|
||||||
|
|
||||||
unsigned char sumout[20];
|
Sha1Sum_t sumout;
|
||||||
unsigned char concatinated[0x200];
|
unsigned char concatinated[0x200];
|
||||||
size_t size = sizeof concatinated;
|
size_t size = sizeof concatinated;
|
||||||
|
|
||||||
mxkN2UtilVCatenateData(concatinated, &size, numStreams, args);
|
mxkN2UtilVCatenateData(concatinated, &size, numStreams, args);
|
||||||
mxkCryptCalcHashWithSha1(concatinated, size, sumout);
|
mxkCryptCalcHashWithSha1(concatinated, size, &sumout);
|
||||||
memcpy_s(sum, 20, sumout, 20);
|
memcpy_s(sum, sizeof *sum, sumout, sizeof sumout);
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
int mxkN2UtilHmacPacket(void *val1, unsigned char *sha1, void *nonce, void *key,
|
int mxkN2UtilHmacPacket(PSha1Sum_t packetSha, PHmacSum_t hmacSalt, PN2Nonce_t nonce, PHmacKey_t key,
|
||||||
unsigned char *hash_out) {
|
PHmacSum_t computedHash) {
|
||||||
unsigned char hash[20];
|
HmacSum_t hash;
|
||||||
unsigned char data_in[60];
|
unsigned char data_in[sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce];
|
||||||
|
|
||||||
size_t count = 60;
|
size_t count = sizeof *packetSha + sizeof *hmacSalt + sizeof *nonce;
|
||||||
size_t nout = 20;
|
size_t nout = HMAC_SUM_SIZE;
|
||||||
mxkN2UtilCatenateData(data_in, &count, 3, val1, 20, sha1, 20, nonce, 20);
|
mxkN2UtilCatenateData(data_in, &count, 3, packetSha, sizeof *packetSha, hmacSalt,
|
||||||
|
sizeof *hmacSalt, nonce, sizeof *nonce);
|
||||||
|
|
||||||
int iVar1 = mxkCryptCalcHashWithHmacSha1(key, hash, &nout, data_in, count);
|
int err = mxkCryptCalcHashWithHmacSha1(key, &hash, &nout, data_in, count);
|
||||||
if (iVar1 != -2 && nout == 20) {
|
if (err == -2 || nout != HMAC_SUM_SIZE) return -2;
|
||||||
memcpy(hash_out, hash, 20);
|
|
||||||
|
memcpy_s(computedHash, sizeof *computedHash, hash, HMAC_SUM_SIZE);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
|
|
||||||
int mxkN2CmdWriteData(unsigned char addr, unsigned char *data, unsigned short nbytes,
|
int mxkN2CmdWriteData(unsigned char addr, void *data, unsigned short nbytes,
|
||||||
unsigned short *nbytesOut) {
|
unsigned short *nbytesOut) {
|
||||||
unsigned int ptr_;
|
unsigned int ptr_;
|
||||||
unsigned char nstep;
|
unsigned char nstep;
|
||||||
int status;
|
int status;
|
||||||
unsigned short position;
|
unsigned short position;
|
||||||
|
|
||||||
if (mxkSmbusRequestMutex() != 0) return -6;
|
if (mxkSmbusRequestMutex() != 0) {
|
||||||
|
amiDebugLog("Error: mxkSmbusRequestMutex");
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
|
||||||
status = 0;
|
status = 0;
|
||||||
position = 0;
|
position = 0;
|
||||||
@ -178,14 +204,14 @@ int mxkN2CmdWriteData(unsigned char addr, unsigned char *data, unsigned short nb
|
|||||||
if ((int)(nbytes - ptr_) < 5) {
|
if ((int)(nbytes - ptr_) < 5) {
|
||||||
nstep = (byte)(nbytes - ptr_);
|
nstep = (byte)(nbytes - ptr_);
|
||||||
if (nstep != 1) goto LAB_0040ae51;
|
if (nstep != 1) goto LAB_0040ae51;
|
||||||
status = mxkSmbusWriteByte(addr, 0xcc, data[ptr_]);
|
status = mxkSmbusWriteByte(addr, 0xcc, ((unsigned char *)data)[ptr_]);
|
||||||
} else {
|
} else {
|
||||||
nstep = 4;
|
nstep = 4;
|
||||||
LAB_0040ae51:
|
LAB_0040ae51:
|
||||||
status = mxkSmbusI2CWriteBlock(addr, 0xcc, data + ptr_, nstep);
|
status = mxkSmbusI2CWriteBlock(addr, 0xcc, &((unsigned char *)data)[ptr_], nstep);
|
||||||
}
|
}
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
amiDebugLog("Error: Data write failed. Position %d. ErrorCode %d.\n", position,
|
amiDebugLog("Error: Data write failed. Position %d. ErrorCode %d.", position,
|
||||||
status);
|
status);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -196,118 +222,410 @@ int mxkN2CmdWriteData(unsigned char addr, unsigned char *data, unsigned short nb
|
|||||||
}
|
}
|
||||||
*nbytesOut = position;
|
*nbytesOut = position;
|
||||||
|
|
||||||
if (!mxkSmbusReleaseMutex()) return -6;
|
if (mxkSmbusReleaseMutex() != 0) {
|
||||||
|
amiDebugLog("Error: mxkSmbusReleaseMutex");
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mxkN2CmdWriteCommand(unsigned char *param_1, unsigned char *packet, unsigned short tag,
|
int mxkN2CmdWriteCommand(PN2Nonce_t requestNonce, PHmacSum_t hmacSalt, N2Tag_t tag,
|
||||||
unsigned short command, unsigned char *auth_key, unsigned char addr,
|
N2Command_t command, PHmacKey_t hmacKey, unsigned char addr,
|
||||||
void *data, size_t nbytes) {
|
N2Byte_t *data, unsigned short nbytes) {
|
||||||
int iVar1;
|
Sha1Sum_t sha1sum;
|
||||||
unsigned short real_tag;
|
N2Packet_t packet;
|
||||||
unsigned short paramsize;
|
int ret;
|
||||||
|
|
||||||
N2Packet_t cmd;
|
|
||||||
|
|
||||||
if (data == NULL && nbytes != 0) return -2;
|
if (data == NULL && nbytes != 0) return -2;
|
||||||
|
|
||||||
memset(&cmd, 0, 0x200);
|
N2PacketFooter_t *footer = (N2PacketFooter_t *)(packet.m_Body + nbytes);
|
||||||
paramsize = (tag == N2_TAG_RQU_COMMAND ? 20 : 0) + 0x14 + (nbytes & 0xffff) + 6;
|
|
||||||
real_tag = (tag != N2_TAG_RQU_COMMAND) + 0xc1;
|
|
||||||
cmd.m_Tag = real_tag * 0x100 | real_tag >> 8;
|
|
||||||
cmd.m_ParamSize = (unsigned short)paramsize << 8 | (unsigned short)paramsize >> 8;
|
|
||||||
cmd.m_Command = command << 8 | command >> 8;
|
|
||||||
if (data != NULL) memcpy_s(cmd.m_Body, sizeof cmd.m_Body, data, nbytes);
|
|
||||||
|
|
||||||
// SHA1(header | data)
|
ZeroMemory(&packet, sizeof packet);
|
||||||
unsigned char packet_sha[20];
|
unsigned short paramsize =
|
||||||
mxkN2UtilSha1Many(packet_sha, 1, &cmd, nbytes + 6);
|
N2_HEADER_SIZE + nbytes +
|
||||||
|
(tag == N2_TAG_RQU_COMMAND ? N2_FOOTER_RQU_SIZE : N2_FOOTER_SIGN_SIZE);
|
||||||
|
|
||||||
|
N2Tag_t realTag = tag == N2_TAG_RQU_COMMAND ? N2_TAG_RQU_COMMAND : N2_TAG_RQU_AUTH_COMMAND;
|
||||||
|
packet.m_Tag = _byteswap_ushort(realTag);
|
||||||
|
packet.m_ParamSize = _byteswap_ushort(paramsize);
|
||||||
|
packet.m_Command = _byteswap_ushort(command);
|
||||||
|
|
||||||
|
if (data != NULL) memcpy_s(packet.m_Body, sizeof packet.m_Body, data, nbytes);
|
||||||
|
|
||||||
|
mxkN2UtilSha1Many(&sha1sum, 1, &packet, nbytes + N2_HEADER_SIZE);
|
||||||
|
|
||||||
if (tag == N2_TAG_RQU_COMMAND) {
|
if (tag == N2_TAG_RQU_COMMAND) {
|
||||||
memcpy(cmd.m_Body, packet_sha, 20);
|
memcpy_s(footer->rqu.m_ShaSum, sizeof footer->rqu.m_ShaSum, sha1sum, sizeof sha1sum);
|
||||||
} else {
|
} else {
|
||||||
unsigned char nonce[20];
|
if (requestNonce == NULL || hmacKey == NULL) return -2;
|
||||||
mxkN2GetPacketNonce(nonce);
|
|
||||||
memcpy(cmd.m_Body + nbytes, nonce, 20);
|
|
||||||
mxkN2UtilHmacPacket(packet_sha, param_1, nonce, auth_key, cmd.m_Body + nbytes + 20);
|
|
||||||
|
|
||||||
puts("Dodgy HMAC");
|
mxkN2GetPacketNonce(requestNonce);
|
||||||
exit(1);
|
memcpy_s(footer->sign.m_Nonce, sizeof footer->sign.m_Nonce, requestNonce,
|
||||||
|
sizeof *requestNonce);
|
||||||
|
|
||||||
|
mxkN2UtilHmacPacket(&sha1sum, hmacSalt, &footer->sign.m_Nonce, hmacKey,
|
||||||
|
&footer->sign.m_Hmac);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short nWrote;
|
unsigned short nBytesOut;
|
||||||
iVar1 = mxkN2CmdWriteData(addr, (unsigned char *)&cmd, paramsize, &nWrote);
|
ret = mxkN2CmdWriteData(addr, &packet, paramsize, &nBytesOut);
|
||||||
if (iVar1 == 0) {
|
if (ret != 0) {
|
||||||
iVar1 = 0;
|
amiDebugLog("Error: Data write failed. ErrorCode %d.", ret);
|
||||||
} else {
|
return -8;
|
||||||
amiDebugLog("Error: Data write failed. ErrorCode %d.", iVar1);
|
|
||||||
iVar1 = -8;
|
|
||||||
}
|
}
|
||||||
return iVar1;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mxkN2CmdReadData(unsigned char addr, N2Packet_t *lpPacket, unsigned short nReadSize,
|
||||||
|
unsigned short *lpBytesRead) {
|
||||||
|
int err;
|
||||||
|
*lpBytesRead = 0;
|
||||||
|
|
||||||
|
if (nReadSize < 4 || lpPacket == NULL) {
|
||||||
|
amiDebugLog("Error: Invalid param.");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
if (mxkSmbusRequestMutex() != 0) return -6;
|
||||||
|
|
||||||
|
unsigned char *buffer = (unsigned char *)lpPacket;
|
||||||
|
|
||||||
|
// Read until m_ParamSize
|
||||||
|
err = mxkSmbusI2CReadBlock(addr, 0xc3, buffer, 4);
|
||||||
|
|
||||||
|
unsigned short readPosition = 4;
|
||||||
|
if (err == 0) {
|
||||||
|
unsigned short paramSize = _byteswap_ushort(lpPacket->m_ParamSize);
|
||||||
|
if (nReadSize < paramSize - 4) {
|
||||||
|
amiDebugLog("mxkSmbusI2CReadBlock data : %04X %04X", lpPacket->m_Tag,
|
||||||
|
lpPacket->m_ParamSize);
|
||||||
|
amiDebugLog("Error: Data size is too small.(readSize:%04X, m_paramSize:%04X)",
|
||||||
|
nReadSize, (lpPacket->m_ParamSize << 8 | lpPacket->m_ParamSize >> 8) - 4);
|
||||||
|
return -11;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (4 < paramSize) {
|
||||||
|
while (readPosition < paramSize) {
|
||||||
|
unsigned short blockSize = paramSize - readPosition;
|
||||||
|
if (blockSize > 4) blockSize = 4;
|
||||||
|
|
||||||
|
if (blockSize == 1)
|
||||||
|
err = mxkSmbusReadByte(addr, buffer + readPosition, 0xc3);
|
||||||
|
else
|
||||||
|
err = mxkSmbusI2CReadBlock(addr, 0xc3, buffer + readPosition, blockSize & 0xff);
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
amiDebugLog("Error: Data read failed. Position %d. ErrorCode %d.", readPosition,
|
||||||
|
err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
readPosition += blockSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*lpBytesRead = readPosition;
|
||||||
|
if (mxkSmbusReleaseMutex() != 0) {
|
||||||
|
amiDebugLog("Error: ReleaseMutex(). ErrorCode %d.", GetLastError());
|
||||||
|
return -6;
|
||||||
|
}
|
||||||
|
if (err) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mxkN2CmdIsValidOutParam(N2Packet_t *packet, unsigned tag, unsigned short paramSize) {
|
||||||
|
unsigned short tagPacket = _byteswap_ushort(packet->m_Tag);
|
||||||
|
unsigned short paramSizePacket = _byteswap_ushort(packet->m_ParamSize);
|
||||||
|
unsigned short returnCode = _byteswap_ushort(packet->m_Command);
|
||||||
|
if (tagPacket == tag && paramSizePacket == paramSize && returnCode == 0) return true;
|
||||||
|
|
||||||
|
amiDebugLog("tag: %04x, paramSize: %d, returnCode: %04x", tagPacket, paramSizePacket,
|
||||||
|
returnCode);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mxkN2CmdReadResponce(PN2Nonce_t requestNonce, PHmacSum_t hmacSalt, N2Tag_t tag,
|
||||||
|
N2Command_t command, PHmacKey_t hmacKey, unsigned char addr, void *bufOut,
|
||||||
|
unsigned short nOut) {
|
||||||
|
int ret;
|
||||||
|
unsigned short nBytesRead;
|
||||||
|
Sha1Sum_t sha1sum;
|
||||||
|
N2Packet_t packet;
|
||||||
|
|
||||||
|
ZeroMemory(&packet, sizeof packet);
|
||||||
|
unsigned short footerSize =
|
||||||
|
tag == N2_TAG_RQU_COMMAND ? N2_FOOTER_RQU_SIZE : N2_FOOTER_SIGN_SIZE;
|
||||||
|
ret = mxkN2CmdReadData(addr, &packet, nOut + N2_HEADER_SIZE + footerSize, &nBytesRead);
|
||||||
|
if (ret != 0) {
|
||||||
|
amiDebugLog("Error: Data read failed. ErrorCode %d.", ret);
|
||||||
|
return -7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mxkN2CmdIsValidOutParam(
|
||||||
|
&packet, tag == N2_TAG_RQU_COMMAND ? N2_TAG_RSP_COMMAND : N2_TAG_RSP_AUTH_COMMAND,
|
||||||
|
nBytesRead)) {
|
||||||
|
amiDebugLog("Error: Invalid output parameter.");
|
||||||
|
return -9;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned short fixedCommand = _byteswap_ushort(command);
|
||||||
|
|
||||||
|
mxkN2UtilSha1Many(&sha1sum, 3, &packet, N2_HEADER_SIZE, &fixedCommand, sizeof fixedCommand,
|
||||||
|
packet.m_Body, nOut);
|
||||||
|
|
||||||
|
N2PacketFooter_t *footer = (N2PacketFooter_t *)(packet.m_Body + nOut);
|
||||||
|
|
||||||
|
if (tag == N2_TAG_RQU_COMMAND) {
|
||||||
|
if (memcmp(footer->rqu.m_ShaSum, sha1sum, sizeof sha1sum) != 0) {
|
||||||
|
amiDebugLog("Error: Invalid hash value.");
|
||||||
|
return -10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (requestNonce == NULL || hmacKey == NULL) return -2;
|
||||||
|
|
||||||
|
HmacSum_t computedHash;
|
||||||
|
mxkN2UtilHmacPacket(&sha1sum, &footer->sign.m_Nonce, requestNonce, hmacKey, &computedHash);
|
||||||
|
if (memcmp(footer->sign.m_Hmac, computedHash, sizeof computedHash) != 0) {
|
||||||
|
amiDebugLog("Error: Invalid hash value.");
|
||||||
|
return -10;
|
||||||
|
}
|
||||||
|
memcpy_s(requestNonce, sizeof *requestNonce, packet.m_Body + nOut, 20);
|
||||||
|
|
||||||
|
if (hmacSalt != NULL)
|
||||||
|
memcpy_s(hmacSalt, sizeof *hmacSalt, &footer->sign.m_Nonce,
|
||||||
|
sizeof footer->sign.m_Nonce);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufOut != NULL && nOut != 0) {
|
||||||
|
memcpy_s(bufOut, nOut, packet.m_Body,
|
||||||
|
((nBytesRead - footerSize) - N2_HEADER_SIZE) & 0xffff);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mxkN2CmdEnableSession(void) {
|
int mxkN2CmdEnableSession(void) {
|
||||||
int ret;
|
N2Nonce_t nonce;
|
||||||
unsigned char local_18[20];
|
|
||||||
|
|
||||||
if (!MXK_N2_INIT) {
|
CheckN2Init;
|
||||||
amiDebugLog("Error: Uninitialized.");
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = mxkN2CmdWriteCommand(NULL, local_18, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL,
|
int err;
|
||||||
|
err = mxkN2CmdWriteCommand(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL,
|
||||||
N2DeviceInfo.m_Addr, NULL, 0);
|
N2DeviceInfo.m_Addr, NULL, 0);
|
||||||
if (ret != 0) return ret;
|
if (err != 0) return err;
|
||||||
|
|
||||||
Sleep(32);
|
Sleep(32);
|
||||||
// TODO: ASAP
|
err = mxkN2CmdReadResponce(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL,
|
||||||
// ret = mxkN2CmdReadResponce(local_18, NULL, N2_TAG_RQU_COMMAND, N2_ORD_ENABLE_SESSION, NULL,
|
N2DeviceInfo.m_Addr, &N2DeviceInfo.m_HmacSalt, 20);
|
||||||
// N2DeviceInfo.m_Addr, N2DeviceInfo.m_HmacOut, 20);
|
if (err != 0) return err;
|
||||||
if (ret != 0) return ret;
|
|
||||||
Sleep(16);
|
Sleep(16);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mxkN2CmdGetErrorCode(unsigned short *errorCode) {
|
||||||
|
N2Nonce_t nonce;
|
||||||
|
|
||||||
|
CheckN2Init;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
err = mxkN2CmdWriteCommand(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_GET_ERROR_CODE, NULL,
|
||||||
|
N2DeviceInfo.m_Addr, NULL, 0);
|
||||||
|
if (err != 0) return err;
|
||||||
|
|
||||||
|
Sleep(32);
|
||||||
|
unsigned short rawErrorCode;
|
||||||
|
err = mxkN2CmdReadResponce(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_GET_ERROR_CODE, NULL,
|
||||||
|
N2DeviceInfo.m_Addr, &rawErrorCode, 2);
|
||||||
|
if (err != 0) return err;
|
||||||
|
|
||||||
|
Sleep(16);
|
||||||
|
*errorCode = _byteswap_ushort(rawErrorCode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mxkN2CmdSetAuthKey(PN2AuthKey_t authKey) {
|
||||||
|
CheckN2Init;
|
||||||
|
|
||||||
|
unsigned char authKeyPt[32];
|
||||||
|
ZeroMemory(authKeyPt, sizeof authKeyPt);
|
||||||
|
unsigned char authKeyCt[32];
|
||||||
|
memcpy_s(authKeyPt, sizeof authKeyPt, authKey, sizeof *authKey);
|
||||||
|
mxkCryptEncryptAes128CBC(N2DeviceInfo.m_AESKey.m_Key, N2DeviceInfo.m_AESKey.m_IV, authKeyCt,
|
||||||
|
authKeyPt, sizeof authKeyPt);
|
||||||
|
|
||||||
|
N2Nonce_t nonce;
|
||||||
|
int err;
|
||||||
|
err = mxkN2CmdWriteCommand(&nonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND,
|
||||||
|
N2_ORD_SET_AUTH_KEY, &N2DeviceInfo.m_HmacKey, N2DeviceInfo.m_Addr,
|
||||||
|
authKeyCt, sizeof authKeyCt);
|
||||||
|
if (err != 0) return err;
|
||||||
|
|
||||||
|
Sleep(96);
|
||||||
|
err = mxkN2CmdReadResponce(&nonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND,
|
||||||
|
N2_ORD_SET_AUTH_KEY, &N2DeviceInfo.m_HmacKey, N2DeviceInfo.m_Addr,
|
||||||
|
NULL, 0);
|
||||||
|
if (err != 0) return err;
|
||||||
|
Sleep(16);
|
||||||
|
memcpy_s(N2DeviceInfo.m_AuthKey, sizeof N2DeviceInfo.m_AuthKey, authKey, sizeof *authKey);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mxkN2CmdSetEncKey(AESKey_t *encKey) {
|
||||||
|
CheckN2Init;
|
||||||
|
|
||||||
|
unsigned char encKeyCt[sizeof *encKey];
|
||||||
|
mxkCryptEncryptAes128CBC(N2DeviceInfo.m_AESKey.m_Key, N2DeviceInfo.m_AESKey.m_IV, encKeyCt,
|
||||||
|
encKey, sizeof encKeyCt);
|
||||||
|
|
||||||
|
N2Nonce_t requestNonce;
|
||||||
|
int err;
|
||||||
|
err = mxkN2CmdWriteCommand(&requestNonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND,
|
||||||
|
N2_ORD_SET_ENC_KEY, &N2DeviceInfo.m_AuthKey, N2DeviceInfo.m_Addr,
|
||||||
|
encKeyCt, sizeof encKeyCt);
|
||||||
|
if (err != 0) return err;
|
||||||
|
|
||||||
|
Sleep(96);
|
||||||
|
err = mxkN2CmdReadResponce(&requestNonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND,
|
||||||
|
N2_ORD_SET_ENC_KEY, &N2DeviceInfo.m_AuthKey, N2DeviceInfo.m_Addr,
|
||||||
|
NULL, 0);
|
||||||
|
if (err != 0) return err;
|
||||||
|
|
||||||
|
Sleep(16);
|
||||||
|
memcpy_s(&N2DeviceInfo.m_EncKey, sizeof N2DeviceInfo.m_EncKey, encKey, sizeof *encKey);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mxkN2CmdGetAuthLevel(unsigned char *authLevel) {
|
||||||
|
CheckN2Init;
|
||||||
|
|
||||||
|
unsigned char rawAuthlevel;
|
||||||
|
N2Nonce_t nonce;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
err = mxkN2CmdWriteCommand(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_GET_AUTH_LEVEL, NULL,
|
||||||
|
N2DeviceInfo.m_Addr, NULL, 0);
|
||||||
|
if (err != 0) return err;
|
||||||
|
Sleep(32);
|
||||||
|
err = mxkN2CmdReadResponce(&nonce, NULL, N2_TAG_RQU_COMMAND, N2_ORD_GET_AUTH_LEVEL, NULL,
|
||||||
|
N2DeviceInfo.m_Addr, &rawAuthlevel, 1);
|
||||||
|
if (err != 0) return err;
|
||||||
|
Sleep(16);
|
||||||
|
err = 0;
|
||||||
|
*authLevel = rawAuthlevel;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mxkN2GetErrorCode(void) {
|
||||||
|
unsigned short errorCode;
|
||||||
|
|
||||||
|
int err = mxkN2CmdGetErrorCode(&errorCode);
|
||||||
|
if (err != 0) {
|
||||||
|
amiDebugLog("Error: mxkN2CmdGetErrorCode(). ErrorCode %d", err);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
amiDebugLog("N2 ErrorCode 0x%04X", errorCode);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int mxkN2CmdReadKeychipID(N2KeychipId_t *lpKeychipId) {
|
||||||
|
CheckN2Init;
|
||||||
|
|
||||||
|
N2Nonce_t nonce;
|
||||||
|
|
||||||
|
unsigned char readData[sizeof *lpKeychipId + 2];
|
||||||
|
|
||||||
|
N2Byte_t request[4];
|
||||||
|
request[0] = 0;
|
||||||
|
request[1] = 0;
|
||||||
|
request[2] = 0;
|
||||||
|
request[3] = sizeof *lpKeychipId;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
err = mxkN2CmdWriteCommand(&nonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND,
|
||||||
|
N2_ORD_READ_KEYCHIP_ID, &N2DeviceInfo.m_AuthKey, N2DeviceInfo.m_Addr,
|
||||||
|
request, sizeof request);
|
||||||
|
if (err != 0) return err;
|
||||||
|
Sleep(128);
|
||||||
|
err = mxkN2CmdReadResponce(&nonce, &N2DeviceInfo.m_HmacSalt, N2_TAG_RQU_AUTH_COMMAND,
|
||||||
|
N2_ORD_READ_KEYCHIP_ID, &N2DeviceInfo.m_AuthKey, N2DeviceInfo.m_Addr,
|
||||||
|
readData, sizeof readData);
|
||||||
|
|
||||||
|
if (err != 0) return err;
|
||||||
|
Sleep(16);
|
||||||
|
|
||||||
|
mxkCryptDecryptAes128CBC(N2DeviceInfo.m_EncKey.m_Key, N2DeviceInfo.m_EncKey.m_IV, readData + 2,
|
||||||
|
(unsigned char *)lpKeychipId, sizeof *lpKeychipId);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int mxkN2Authentication(void) {
|
int mxkN2Authentication(void) {
|
||||||
// TODO: ASAP
|
N2AuthKey_t authKey;
|
||||||
// unsigned char auth_key[20];
|
AESKey_t enc_key;
|
||||||
// unsigned char enc_key[32];
|
|
||||||
|
|
||||||
if (!MXK_HAS_INIT) {
|
if (!MXK_HAS_INIT) {
|
||||||
amiDebugLog("No Init Error!!");
|
amiDebugLog("No Init Error!!");
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ErrorCode;
|
int err;
|
||||||
|
err = mxkN2CmdEnableSession();
|
||||||
ErrorCode = mxkN2CmdEnableSession();
|
if (err != 0) {
|
||||||
if (ErrorCode != 0) {
|
mxkN2GetErrorCode();
|
||||||
// mxkN2GetErrorCode();
|
amiDebugLog("Error: mxkN2CmdEnableSession(). ErrorCode %d", err);
|
||||||
amiDebugLog("Error: mxkN2CmdEnableSession(). ErrorCode %d", ErrorCode);
|
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// _randomBytes(auth_key, sizeof auth_key);
|
unsigned char authLevel;
|
||||||
// ErrorCode = mxkN2CmdSetAuthKey(auth_key);
|
mxkN2CmdGetAuthLevel(&authLevel);
|
||||||
// if (ErrorCode != 0) {
|
printf("Achieved auth level: %d\n", authLevel);
|
||||||
// mxkN2GetErrorCode();
|
|
||||||
// amiDebugLog("Error: mxkN2CmdSetAuthKey(). ErrorCode %d", ErrorCode);
|
|
||||||
// return -5;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// _randomBytes(enc_key, sizeof enc_key);
|
_randomBytes(authKey, sizeof authKey);
|
||||||
// ErrorCode = mxkN2CmdSetEncKey(enc_key);
|
err = mxkN2CmdSetAuthKey(&authKey);
|
||||||
// if (ErrorCode != 0) {
|
if (err != 0) {
|
||||||
// mxkN2GetErrorCode();
|
mxkN2GetErrorCode();
|
||||||
// amiDebugLog("Error: mxkN2CmdSetEncKey().ErrorCode %d", ErrorCode);
|
amiDebugLog("Error: mxkN2CmdSetAuthKey(). ErrorCode %d", err);
|
||||||
// return -5;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// unsigned char auth_level;
|
|
||||||
// ErrorCode = mxkN2CmdGetAuthLevel(&auth_level);
|
|
||||||
// if (ErrorCode == 0 && auth_level == 3) return 0;
|
|
||||||
|
|
||||||
// mxkN2GetErrorCode();
|
|
||||||
// amiDebugLog("Error: mxkN2CmdGetAuthLevel().ErrorCode %d", ErrorCode);
|
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mxkN2CmdGetAuthLevel(&authLevel);
|
||||||
|
printf("Achieved auth level: %d\n", authLevel);
|
||||||
|
|
||||||
|
_randomBytes(&enc_key, sizeof enc_key);
|
||||||
|
err = mxkN2CmdSetEncKey(&enc_key);
|
||||||
|
if (err != 0) {
|
||||||
|
mxkN2GetErrorCode();
|
||||||
|
amiDebugLog("Error: mxkN2CmdSetEncKey().ErrorCode %d", err);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
mxkN2CmdGetAuthLevel(&authLevel);
|
||||||
|
printf("Achieved auth level: %d\n", authLevel);
|
||||||
|
|
||||||
|
// unsigned char authLevel;
|
||||||
|
err = mxkN2CmdGetAuthLevel(&authLevel);
|
||||||
|
if (err == 0 && authLevel == 3) return 0;
|
||||||
|
|
||||||
|
mxkN2GetErrorCode();
|
||||||
|
amiDebugLog("Error: mxkN2CmdGetAuthLevel().ErrorCode %d", err);
|
||||||
|
return -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mxkN2Exit(void) { MXK_N2_INIT = FALSE; }
|
||||||
|
|
||||||
|
int mxkN2Init(void) {
|
||||||
|
int err;
|
||||||
|
err = mxkN2CmdSetDeviceInfo();
|
||||||
|
if (err != 0) return err;
|
||||||
|
|
||||||
|
err = mxkN2Authentication();
|
||||||
|
if (err != 0) {
|
||||||
|
unsigned short errorCode;
|
||||||
|
err = mxkN2CmdGetErrorCode(&errorCode);
|
||||||
|
if (err != 0) {
|
||||||
|
amiDebugLog("Error: mxkN2CmdGetErrorCode(). ErrorCode %d", err);
|
||||||
|
} else {
|
||||||
|
amiDebugLog("N2 ErrorCode 0x%04X", errorCode);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -1,25 +1,72 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <varargs.h>
|
#include <varargs.h>
|
||||||
|
|
||||||
void _randomBytes(unsigned char *buf, int nbytes);
|
#include "mxkCrypt.h"
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
uint32_t m_Crc;
|
||||||
|
uint8_t m_Unk04[12];
|
||||||
|
uint8_t m_KeyId[16];
|
||||||
|
struct {
|
||||||
|
uint32_t m_Crc;
|
||||||
|
uint32_t m_FormatType;
|
||||||
|
uint8_t m_GameId[4];
|
||||||
|
uint8_t m_Region;
|
||||||
|
uint8_t m_ModelType;
|
||||||
|
uint8_t m_SystemFlags;
|
||||||
|
uint8_t Rsv0f;
|
||||||
|
uint8_t m_PlatformId[3];
|
||||||
|
uint8_t m_DvdFlag;
|
||||||
|
uint8_t m_NetworkAddr[4];
|
||||||
|
uint8_t Unk10[88];
|
||||||
|
uint8_t m_Seed[16];
|
||||||
|
} m_AppBoot;
|
||||||
|
} N2KeychipId_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
#define N2_ADDR 0x30
|
||||||
|
|
||||||
|
#define N2_AUTH_KEY_SIZE 20
|
||||||
|
#define N2_NONCE_SIZE 20
|
||||||
|
#define N2_DATA_MAX 506
|
||||||
|
|
||||||
|
#define N2_FOOTER_RQU_SIZE SHA1_SUM_SIZE
|
||||||
|
#define N2_FOOTER_SIGN_SIZE (N2_NONCE_SIZE + HMAC_SUM_SIZE)
|
||||||
|
|
||||||
|
typedef char N2Nonce_t[N2_NONCE_SIZE];
|
||||||
|
typedef char N2AuthKey_t[N2_AUTH_KEY_SIZE];
|
||||||
|
typedef char (*PN2Nonce_t)[N2_NONCE_SIZE];
|
||||||
|
typedef char (*PN2AuthKey_t)[N2_AUTH_KEY_SIZE];
|
||||||
|
|
||||||
|
typedef unsigned short N2Tag_t;
|
||||||
|
typedef unsigned short N2Command_t;
|
||||||
|
typedef unsigned char N2Byte_t;
|
||||||
|
|
||||||
|
void _randomBytes(void *buf, int nbytes);
|
||||||
|
|
||||||
int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numStreams,
|
int mxkN2UtilVCatenateData(unsigned char *out, size_t *count, unsigned int numStreams,
|
||||||
va_list args);
|
va_list args);
|
||||||
void mxkN2UtilCatenateData(unsigned char *concatinated, size_t *count, unsigned int numStreams,
|
void mxkN2UtilCatenateData(unsigned char *concatinated, size_t *count, unsigned int numStreams,
|
||||||
...);
|
...);
|
||||||
|
|
||||||
void mxkN2UtilSha1Many(unsigned char *sum, int numStreams, ...);
|
void mxkN2UtilSha1Many(PSha1Sum_t sum, int numStreams, ...);
|
||||||
int mxkN2UtilHmacPacket(void *val1, unsigned char *sha1, void *nonce, void *key,
|
int mxkN2UtilHmacPacket(PSha1Sum_t packetSha, PHmacSum_t hmacSalt, PN2Nonce_t nonce, PHmacKey_t key,
|
||||||
unsigned char *hash_out);
|
PHmacSum_t computedHash);
|
||||||
|
|
||||||
int mxkN2CmdWriteCommand(unsigned char *param_1, unsigned char *packet, unsigned short tag,
|
int mxkN2CmdWriteCommand(PN2Nonce_t nonce, PHmacSum_t hmacSalt, N2Tag_t tag, N2Command_t command,
|
||||||
unsigned short command, unsigned char *auth_key, unsigned char addr,
|
PHmacKey_t hmacKey, unsigned char addr, N2Byte_t *data,
|
||||||
void *data, size_t nbytes);
|
unsigned short nbytes);
|
||||||
|
|
||||||
int mxkN2CmdEnableSession(void);
|
int mxkN2CmdEnableSession(void);
|
||||||
int mxkN2CmdSetAuthKey(unsigned char* authKey);
|
int mxkN2CmdSetAuthKey(PN2AuthKey_t authKey);
|
||||||
|
|
||||||
int mxkN2CmdInit(void);
|
int mxkN2CmdInit(void);
|
||||||
int mxkN2CmdSetDeviceInfo(void);
|
int mxkN2CmdSetDeviceInfo(void);
|
||||||
int mxkN2Authentication(void);
|
int mxkN2Authentication(void);
|
||||||
|
int mxkN2CmdReadKeychipID(N2KeychipId_t *lpKeychipId);
|
||||||
|
|
||||||
|
int mxkN2Init(void);
|
||||||
|
void mxkN2Exit(void);
|
||||||
|
@ -228,7 +228,7 @@ int mxkSmbusI2CWriteCommand(unsigned char command_code, unsigned char *buffer, s
|
|||||||
return tries == 5 ? -9 : 0;
|
return tries == 5 ? -9 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigned char *buffer,
|
int mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigned char *buffer,
|
||||||
unsigned char nbytes) {
|
unsigned char nbytes) {
|
||||||
DWORD nBytesReturned;
|
DWORD nBytesReturned;
|
||||||
smb_packet packet;
|
smb_packet packet;
|
||||||
@ -244,10 +244,10 @@ bool mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigne
|
|||||||
if (!succ || nBytesReturned != sizeof packet) return false;
|
if (!succ || nBytesReturned != sizeof packet) return false;
|
||||||
if (packet.status == 0) {
|
if (packet.status == 0) {
|
||||||
memcpy(buffer, packet.data, nbytes);
|
memcpy(buffer, packet.data, nbytes);
|
||||||
return true;
|
return 0;
|
||||||
}
|
}
|
||||||
if (packet.status != 24) return false;
|
if (packet.status != 24) return false;
|
||||||
Sleep(16);
|
Sleep(16);
|
||||||
}
|
}
|
||||||
return false;
|
return -8;
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ int mxkSmbusI2CWriteCommand(unsigned char command_code, unsigned char *buffer, s
|
|||||||
|
|
||||||
int mxkSmbusI2CWriteBlock(unsigned char addr, unsigned char command, unsigned char *buffer,
|
int mxkSmbusI2CWriteBlock(unsigned char addr, unsigned char command, unsigned char *buffer,
|
||||||
unsigned char nbytes);
|
unsigned char nbytes);
|
||||||
bool mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigned char *buffer,
|
int mxkSmbusI2CReadBlock(unsigned char smbAddress, unsigned char block, unsigned char *buffer,
|
||||||
unsigned char nbytes);
|
unsigned char nbytes);
|
||||||
|
|
||||||
int mxkSmbusWriteByte(unsigned char v_addr, unsigned char command_code, unsigned char data);
|
int mxkSmbusWriteByte(unsigned char v_addr, unsigned char command_code, unsigned char data);
|
||||||
|
@ -16,7 +16,7 @@ void miceDumpKCPIC() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following sequence is required to avoid SBTR!
|
* The following sequence is required, within 30 seconds, to avoid SBTR!
|
||||||
*
|
*
|
||||||
* amDongleSetupKeychip:
|
* amDongleSetupKeychip:
|
||||||
* keychip.appboot.systemflag=?&cache=0
|
* keychip.appboot.systemflag=?&cache=0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user