add actions for generating and parsing pcv2 registry files
This commit is contained in:
+98
-1
@@ -187,7 +187,7 @@ string read_input_data(phosg::Arguments& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool is_text_extension(const char* extension) {
|
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) {
|
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");
|
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(
|
Action a_encrypt_challenge_data(
|
||||||
"encrypt-challenge-data", nullptr, +[](phosg::Arguments& args) {
|
"encrypt-challenge-data", nullptr, +[](phosg::Arguments& args) {
|
||||||
string data = read_input_data(args);
|
string data = read_input_data(args);
|
||||||
|
|||||||
@@ -300,6 +300,10 @@ check_struct_size(ChallengeTimeBE, 4);
|
|||||||
|
|
||||||
std::string decrypt_v2_registry_value(const void* data, size_t size);
|
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 {
|
struct DecryptedPR2 {
|
||||||
std::string compressed_data;
|
std::string compressed_data;
|
||||||
size_t decompressed_size;
|
size_t decompressed_size;
|
||||||
|
|||||||
Reference in New Issue
Block a user