add decrypt/encrypt for simple DCv2 executable encryption
This commit is contained in:
@@ -1425,3 +1425,35 @@ EncryptedDCv2Executables encrypt_dp_address_jpn(const string& executable, const
|
|||||||
ret.indexes.at(fixup_steps_offset) = 0;
|
ret.indexes.at(fixup_steps_offset) = 0;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string crypt_dp_address_jpn_simple(const std::string& data, int64_t mask_key) {
|
||||||
|
if (data.size() & 3) {
|
||||||
|
throw runtime_error("size is not a multiple of 4");
|
||||||
|
}
|
||||||
|
|
||||||
|
StringReader r(data);
|
||||||
|
if (mask_key < 0) {
|
||||||
|
unordered_map<uint32_t, size_t> key_freq;
|
||||||
|
while (!r.eof()) {
|
||||||
|
key_freq[r.get_u32l()] += 1;
|
||||||
|
}
|
||||||
|
size_t max_v = 0;
|
||||||
|
for (const auto& it : key_freq) {
|
||||||
|
if (it.second > max_v) {
|
||||||
|
max_v = it.second;
|
||||||
|
mask_key = it.first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mask_key < 0) {
|
||||||
|
throw runtime_error("cannot determine mask key");
|
||||||
|
}
|
||||||
|
log_info("Determined %08" PRIX64 " to be the most likely mask key", mask_key);
|
||||||
|
r.go(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringWriter w;
|
||||||
|
while (!r.eof()) {
|
||||||
|
w.put_u32l(r.get_u32l() ^ mask_key);
|
||||||
|
}
|
||||||
|
return std::move(w.str());
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,3 +32,5 @@ std::string decrypt_dp_address_jpn(
|
|||||||
const std::string& iwashi_sea_data,
|
const std::string& iwashi_sea_data,
|
||||||
const std::string& katsuo_sea_data);
|
const std::string& katsuo_sea_data);
|
||||||
EncryptedDCv2Executables encrypt_dp_address_jpn(const std::string& executable, const std::string& indexes);
|
EncryptedDCv2Executables encrypt_dp_address_jpn(const std::string& executable, const std::string& indexes);
|
||||||
|
|
||||||
|
std::string crypt_dp_address_jpn_simple(const std::string& data, int64_t seed = -1);
|
||||||
|
|||||||
+34
-12
@@ -757,35 +757,57 @@ Action a_encrypt_save_data("encrypt-save-data", nullptr, a_encrypt_decrypt_save_
|
|||||||
Action a_decrypt_dcv2_executable(
|
Action a_decrypt_dcv2_executable(
|
||||||
"decrypt-dcv2-executable", "\
|
"decrypt-dcv2-executable", "\
|
||||||
decrypt-dcv2-executable --executable=EXEC --indexes=INDEXES --values=VALUES\n\
|
decrypt-dcv2-executable --executable=EXEC --indexes=INDEXES --values=VALUES\n\
|
||||||
|
decrypt-dcv2-executable --executable=EXEC --simple [--seed=SEED]\n\
|
||||||
Decrypt a PSO DC v2 executable file. EXEC should be the path to the\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\
|
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\
|
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",
|
(IWASHI.SEA). The output is written to EXEC.dec.\n\
|
||||||
|
If --simple is given, uses the simpler encryption method used in some\n\
|
||||||
|
community modifications of the game. In this case, --seed is not required;\n\
|
||||||
|
if not given, finds the seed automatically, and prints it to stderr so you\n\
|
||||||
|
will be able to use it when re-encrypting.",
|
||||||
+[](Arguments& args) {
|
+[](Arguments& args) {
|
||||||
string executable_filename = args.get<string>("executable", true);
|
string executable_filename = args.get<string>("executable", true);
|
||||||
string values_filename = args.get<string>("values", true);
|
|
||||||
string indexes_filename = args.get<string>("indexes", true);
|
|
||||||
string executable_data = load_file(executable_filename);
|
string executable_data = load_file(executable_filename);
|
||||||
string values_data = load_file(values_filename);
|
string decrypted;
|
||||||
string indexes_data = load_file(indexes_filename);
|
if (args.get<bool>("simple")) {
|
||||||
string decrypted = decrypt_dp_address_jpn(executable_data, values_data, indexes_data);
|
string seed_str = args.get<string>("seed");
|
||||||
|
int64_t seed = seed_str.empty() ? -1 : stoull(seed_str, nullptr, 16);
|
||||||
|
decrypted = crypt_dp_address_jpn_simple(executable_data, seed);
|
||||||
|
} else {
|
||||||
|
string values_filename = args.get<string>("values", true);
|
||||||
|
string indexes_filename = args.get<string>("indexes", true);
|
||||||
|
string values_data = load_file(values_filename);
|
||||||
|
string indexes_data = load_file(indexes_filename);
|
||||||
|
decrypted = decrypt_dp_address_jpn(executable_data, values_data, indexes_data);
|
||||||
|
}
|
||||||
save_file(executable_filename + ".dec", decrypted);
|
save_file(executable_filename + ".dec", decrypted);
|
||||||
});
|
});
|
||||||
Action a_encrypt_dcv2_executable(
|
Action a_encrypt_dcv2_executable(
|
||||||
"encrypt-dcv2-executable", "\
|
"encrypt-dcv2-executable", "\
|
||||||
decrypt-dcv2-executable --executable=EXEC --indexes=INDEXES\n\
|
decrypt-dcv2-executable --executable=EXEC --indexes=INDEXES\n\
|
||||||
|
decrypt-dcv2-executable --executable=EXEC --simple --seed=SEED\n\
|
||||||
Encrypt a PSO DC v2 executable file. EXEC should be the path to the\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\
|
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\
|
fixup table (KATSUO.SEA). The output is written to EXEC.enc and\n\
|
||||||
INDEXES.enc.",
|
INDEXES.enc.\n\
|
||||||
|
If --simple is given, uses the simpler encryption method used in some\n\
|
||||||
|
community modifications of the game. In this case, --seed is required.",
|
||||||
+[](Arguments& args) {
|
+[](Arguments& args) {
|
||||||
string executable_filename = args.get<string>("executable", true);
|
string executable_filename = args.get<string>("executable", true);
|
||||||
string indexes_filename = args.get<string>("indexes", true);
|
|
||||||
string executable_data = load_file(executable_filename);
|
string executable_data = load_file(executable_filename);
|
||||||
string indexes_data = load_file(indexes_filename);
|
string encrypted_executable;
|
||||||
auto encrypted = encrypt_dp_address_jpn(executable_data, indexes_data);
|
if (args.get<bool>("simple")) {
|
||||||
save_file(executable_filename + ".enc", encrypted.executable);
|
int64_t seed = stoull(args.get<string>("seed", true), nullptr, 16);
|
||||||
save_file(indexes_filename + ".enc", encrypted.indexes);
|
encrypted_executable = crypt_dp_address_jpn_simple(executable_data, seed);
|
||||||
|
} else {
|
||||||
|
string indexes_filename = args.get<string>("indexes", true);
|
||||||
|
string indexes_data = load_file(indexes_filename);
|
||||||
|
auto encrypted = encrypt_dp_address_jpn(executable_data, indexes_data);
|
||||||
|
save_file(indexes_filename + ".enc", encrypted.indexes);
|
||||||
|
encrypted_executable = std::move(encrypted.executable);
|
||||||
|
}
|
||||||
|
save_file(executable_filename + ".enc", encrypted_executable);
|
||||||
});
|
});
|
||||||
|
|
||||||
Action a_decode_gci_snapshot(
|
Action a_decode_gci_snapshot(
|
||||||
|
|||||||
Reference in New Issue
Block a user