diff --git a/src/DCSerialNumbers.cc b/src/DCSerialNumbers.cc index 0ada1767..4610cb59 100644 --- a/src/DCSerialNumbers.cc +++ b/src/DCSerialNumbers.cc @@ -1386,3 +1386,42 @@ void dc_serial_number_speed_test(uint64_t seed) { fprintf(stderr, "Fast vs. slow speedup: %zux\n", static_cast(time_slow / time_fast)); fprintf(stderr, "Disagreements: %zu\n", num_disagreements); } + +string decrypt_dp_address_jpn( + const string& executable, + const string& values, + const string& indexes) { + StringReader values_r(values); + StringReader indexes_r(indexes); + + size_t fixup_values_offset = values_r.pget_u32l(0x3FFC) - 0x8C004000; + size_t fixup_steps_offset = indexes_r.pget_u32l(0x3BFC) - 0x8C008400; + StringReader fixup_values_r = values_r.sub(fixup_values_offset); + StringReader fixup_steps_r = indexes_r.sub(fixup_steps_offset); + + auto decrypted = decrypt_pr2_data(executable); + size_t fixup_offset = 0; + while (fixup_steps_r.get_u8(false)) { + fixup_offset += (fixup_steps_r.get_u8() << 2); + fixup_steps_r.skip(1); + if (fixup_offset + 4 > decrypted.compressed_data.size()) { + throw runtime_error("fixup beyond end of compressed data"); + } + *reinterpret_cast(decrypted.compressed_data.data() + fixup_offset) = fixup_values_r.get_u32l(); + } + + return prs_decompress(decrypted.compressed_data); +} + +EncryptedDCv2Executables encrypt_dp_address_jpn(const string& executable, const string& indexes) { + EncryptedDCv2Executables ret; + + string compressed = prs_compress(executable); + ret.executable = encrypt_pr2_data(compressed, executable.size(), random_object() & 0x7FFFFF7F); + + StringReader indexes_r(indexes); + size_t fixup_steps_offset = indexes_r.pget_u32l(0x3BFC) - 0x8C008400; + ret.indexes = indexes; + ret.indexes.at(fixup_steps_offset) = 0; + return ret; +} diff --git a/src/DCSerialNumbers.hh b/src/DCSerialNumbers.hh index 1a619cf2..4bbef752 100644 --- a/src/DCSerialNumbers.hh +++ b/src/DCSerialNumbers.hh @@ -21,3 +21,14 @@ std::string generate_dc_serial_number(uint8_t domain, uint8_t subdomain = 0xFF); std::unordered_map generate_all_dc_serial_numbers(uint8_t domain = 0xFF, uint8_t subdomain = 0xFF); void dc_serial_number_speed_test(uint64_t seed = 0xFFFFFFFFFFFFFFFF); + +struct EncryptedDCv2Executables { + std::string executable; + std::string indexes; +}; + +std::string decrypt_dp_address_jpn( + const std::string& dp_address_jpn_data, + const std::string& iwashi_sea_data, + const std::string& katsuo_sea_data); +EncryptedDCv2Executables encrypt_dp_address_jpn(const std::string& executable, const std::string& indexes); diff --git a/src/Main.cc b/src/Main.cc index 8763ab92..c347c543 100644 --- a/src/Main.cc +++ b/src/Main.cc @@ -754,6 +754,40 @@ static void a_encrypt_decrypt_save_data_fn(Arguments& args) { Action a_decrypt_save_data("decrypt-save-data", nullptr, a_encrypt_decrypt_save_data_fn); Action a_encrypt_save_data("encrypt-save-data", nullptr, a_encrypt_decrypt_save_data_fn); +Action a_decrypt_dcv2_executable( + "decrypt-dcv2-executable", "\ + decrypt-dcv2-executable --executable=EXEC --indexes=INDEXES --values=VALUES\n\ + Decrypt a PSO DC v2 executable file. EXEC should be the path to the\n\ + executable (DP_ADDRESS.JPN), INDEXES should be the path to the index fixup\n\ + table (KATSUO.SEA), and VALUES should be the path to the value fixup table\n\ + (IWASHI.SEA). The output is written to EXEC.dec.\n", + +[](Arguments& args) { + string executable_filename = args.get("executable", true); + string values_filename = args.get("values", true); + string indexes_filename = args.get("indexes", true); + string executable_data = load_file(executable_filename); + string values_data = load_file(values_filename); + string indexes_data = load_file(indexes_filename); + string decrypted = decrypt_dp_address_jpn(executable_data, values_data, indexes_data); + save_file(executable_filename + ".dec", decrypted); + }); +Action a_encrypt_dcv2_executable( + "encrypt-dcv2-executable", "\ + decrypt-dcv2-executable --executable=EXEC --indexes=INDEXES\n\ + Encrypt a PSO DC v2 executable file. EXEC should be the path to the\n\ + executable (DP_ADDRESS.JPN) and INDEXES should be the path to the index\n\ + fixup table (KATSUO.SEA). The output is written to EXEC.enc and\n\ + INDEXES.enc.", + +[](Arguments& args) { + string executable_filename = args.get("executable", true); + string indexes_filename = args.get("indexes", true); + string executable_data = load_file(executable_filename); + string indexes_data = load_file(indexes_filename); + auto encrypted = encrypt_dp_address_jpn(executable_data, indexes_data); + save_file(executable_filename + ".enc", encrypted.executable); + save_file(indexes_filename + ".enc", encrypted.indexes); + }); + Action a_decode_gci_snapshot( "decode-gci-snapshot", "\ decode-gci-snapshot [INPUT-FILENAME [OUTPUT-FILENAME]]\n\