add actions for generating and parsing pcv2 registry files

This commit is contained in:
Martin Michelsen
2024-09-25 21:44:10 -07:00
parent e50848b52e
commit c8b8bf43f7
2 changed files with 102 additions and 1 deletions
+98 -1
View File
@@ -187,7 +187,7 @@ string read_input_data(phosg::Arguments& args) {
}
bool is_text_extension(const char* extension) {
return (!strcmp(extension, "txt") || !strcmp(extension, "json"));
return (!strcmp(extension, "txt") || !strcmp(extension, "json") || !strcmp(extension, "reg"));
}
void write_output_data(phosg::Arguments& args, const void* data, size_t size, const char* extension) {
@@ -558,6 +558,103 @@ Action a_decrypt_registry_value(
write_output_data(args, out_data.data(), out_data.size(), "dec");
});
Action a_parse_pc_v2_registry(
"parse-pc-v2-registry", "\
parse-pc-v2-registry [INPUT-FILENAME]\n\
Decrypt and show the encrypted serial number, access key, and email fields\n\
from the given registry export. The input file should be a .reg file\n\
exported from the HKEY_CURRENT_USER\\Software\\SonicTeam\\PSOV2 key.\n",
+[](phosg::Arguments& args) {
string data = read_input_data(args);
if (phosg::starts_with(data, "\xFF\xFE")) {
data = tt_utf16_to_utf8(data.substr(2));
}
data = phosg::str_replace_all(data, "\r", "");
data = phosg::str_replace_all(data, "\\\n", "");
bool in_psov2_section = false;
string serial_data, access_data, email_data;
for (string line : phosg::split(data, '\n')) {
if (phosg::starts_with(line, "[")) {
in_psov2_section = (line == "[HKEY_CURRENT_USER\\Software\\SonicTeam\\PSOV2]");
} else if (!in_psov2_section) {
// Wrong section; skip the line
} else if (phosg::starts_with(line, "\"SERIAL\"=hex:")) {
serial_data = phosg::parse_data_string(line.substr(13));
} else if (phosg::starts_with(line, "\"ACCESS\"=hex:")) {
access_data = phosg::parse_data_string(line.substr(13));
} else if (phosg::starts_with(line, "\"E-MAIL\"=hex:")) {
email_data = phosg::parse_data_string(line.substr(13));
}
}
if (serial_data.size() != 8) {
throw std::runtime_error("serial number data is missing or incorrect size");
}
if (access_data.size() != 8) {
throw std::runtime_error("access key data is missing or incorrect size");
}
if (email_data.size() != 0x40) {
throw std::runtime_error("email data is missing or incorrect size");
}
serial_data = decrypt_v2_registry_value(serial_data);
access_data = decrypt_v2_registry_value(access_data);
email_data = decrypt_v2_registry_value(email_data);
uint32_t serial_number = stoul(serial_data, nullptr, 16);
phosg::strip_trailing_zeroes(access_data);
phosg::strip_trailing_zeroes(email_data);
fprintf(stderr, "Serial number (decimal): %" PRIu32 "\nSerial number (hex): %08" PRIX32 "\nAccess key: %s\nEmail address: %s\n",
serial_number, serial_number, access_data.c_str(), email_data.c_str());
});
// ./newserv generate-pc-v2-registry --serial-number=386248990 --access-key=14575600 --email=mjem@wildblue.net
Action a_generate_pc_v2_registry(
"generate-pc-v2-registry", "\
generate-pc-v2-registry <OPTIONS> [OUTPUT-FILENAME]\n\
Generate a .reg file containing PSO PC v2 credentials suitable for\n\
importing into the Windows registry. The following options are required:\n\
--serial-number=SERIAL-NUMBER (decimal serial number)\n\
--access-key=ACCESS-KEY (access key, 8 characters)\n\
--email=EMAIL (email address)\n",
+[](phosg::Arguments& args) {
auto hex_str_for_data = +[](const string& data) -> string {
if (data.size() == 0) {
return string();
}
string ret = phosg::string_printf("%02hx", data[0]);
for (size_t z = 1; z < data.size(); z++) {
ret += phosg::string_printf(",%02hx", data[z]);
}
return ret;
};
uint32_t serial_number = args.get<uint32_t>("serial-number", 0);
string access_key = args.get<string>("access-key", true);
string email = args.get<string>("email", true);
if (access_key.size() != 8) {
throw std::runtime_error("access key is not exactly 8 characters");
}
if (email.size() > 0x40) {
throw std::runtime_error("email address is too long");
}
email.resize(0x40, '\0');
string serial_data = decrypt_v2_registry_value(phosg::string_printf("%08" PRIX32, serial_number));
string access_data = decrypt_v2_registry_value(access_key);
string email_data = decrypt_v2_registry_value(email);
string serial_hex = hex_str_for_data(serial_data);
string access_hex = hex_str_for_data(access_data);
string email_hex = hex_str_for_data(email_data);
string output_data = phosg::string_printf("Windows Registry Editor Version 5.00\r\n\r\n[HKEY_CURRENT_USER\\Software\\SonicTeam\\PSOV2]\r\n\r\n\"SERIAL\"=hex:%s\r\n\"ACCESS\"=hex:%s\r\n\"E-MAIL\"=hex:%s\r\n",
serial_hex.c_str(), access_hex.c_str(), email_hex.c_str());
write_output_data(args, output_data.data(), output_data.size(), "reg");
});
Action a_encrypt_challenge_data(
"encrypt-challenge-data", nullptr, +[](phosg::Arguments& args) {
string data = read_input_data(args);
+4
View File
@@ -300,6 +300,10 @@ check_struct_size(ChallengeTimeBE, 4);
std::string decrypt_v2_registry_value(const void* data, size_t size);
inline std::string decrypt_v2_registry_value(const std::string& s) {
return decrypt_v2_registry_value(s.data(), s.size());
}
struct DecryptedPR2 {
std::string compressed_data;
size_t decompressed_size;