disassemble encrypted send_function_calls on proxy server
This commit is contained in:
+48
-16
@@ -444,25 +444,57 @@ static HandlerResult process_server_88(shared_ptr<ServerState>,
|
|||||||
|
|
||||||
static HandlerResult process_server_B2(shared_ptr<ServerState>,
|
static HandlerResult process_server_B2(shared_ptr<ServerState>,
|
||||||
ProxyServer::LinkedSession& session, uint16_t, uint32_t flag, string& data) {
|
ProxyServer::LinkedSession& session, uint16_t, uint32_t flag, string& data) {
|
||||||
if (session.save_files) {
|
const auto& cmd = check_size_t<S_ExecuteCode_B2>(data, sizeof(S_ExecuteCode_B2), 0xFFFF);
|
||||||
|
|
||||||
|
if (cmd.code_size && session.save_files) {
|
||||||
|
string code = data.substr(sizeof(S_ExecuteCode_B2));
|
||||||
|
|
||||||
|
if (session.newserv_client_config.cfg.flags & Client::Flag::ENCRYPTED_SEND_FUNCTION_CALL) {
|
||||||
|
StringReader r(code);
|
||||||
|
bool is_big_endian = (session.version == GameVersion::GC || session.version == GameVersion::DC);
|
||||||
|
uint32_t decompressed_size = is_big_endian ? r.get_u32b() : r.get_u32l();
|
||||||
|
uint32_t key = is_big_endian ? r.get_u32b() : r.get_u32l();
|
||||||
|
|
||||||
|
PSOV2Encryption crypt(key);
|
||||||
|
string decrypted_data;
|
||||||
|
if (is_big_endian) {
|
||||||
|
StringWriter w;
|
||||||
|
while (!r.eof()) {
|
||||||
|
w.put_u32b(r.get_u32b() ^ crypt.next());
|
||||||
|
}
|
||||||
|
decrypted_data = move(w.str());
|
||||||
|
} else {
|
||||||
|
decrypted_data = r.read(r.remaining());
|
||||||
|
crypt.decrypt(decrypted_data.data(), decrypted_data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
code = prs_decompress(decrypted_data);
|
||||||
|
if (decompressed_size < code.size()) {
|
||||||
|
code.resize(decompressed_size);
|
||||||
|
} else if (decompressed_size > code.size()) {
|
||||||
|
throw runtime_error("decompressed code smaller than expected");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
code = data.substr(sizeof(S_ExecuteCode_B2));
|
||||||
|
if (code.size() < cmd.code_size) {
|
||||||
|
code.resize(cmd.code_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string output_filename = string_printf("code.%" PRId64 ".bin", now());
|
string output_filename = string_printf("code.%" PRId64 ".bin", now());
|
||||||
save_file(output_filename, data);
|
save_file(output_filename, data);
|
||||||
session.log.info("Wrote code from server to file %s", output_filename.c_str());
|
session.log.info("Wrote code from server to file %s", output_filename.c_str());
|
||||||
|
|
||||||
#ifdef HAVE_RESOURCE_FILE
|
#ifdef HAVE_RESOURCE_FILE
|
||||||
try {
|
try {
|
||||||
// Note: we copy header here because we might modify data later, which
|
if (code.size() < sizeof(S_ExecuteCode_Footer_GC_B2)) {
|
||||||
// would break the reference
|
throw runtime_error("code section is too small");
|
||||||
auto header = StringReader(data).get<S_ExecuteCode_B2>();
|
|
||||||
|
|
||||||
size_t footer_end_offset = header.code_size;
|
|
||||||
size_t footer_offset = footer_end_offset - sizeof(S_ExecuteCode_Footer_GC_B2);
|
|
||||||
size_t orig_size = data.size() - sizeof(header);
|
|
||||||
if (data.size() < (sizeof(header) + footer_end_offset)) {
|
|
||||||
data.resize((sizeof(header) + footer_end_offset), '\0');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringReader r(data.data() + sizeof(header), data.size() - sizeof(header));
|
size_t footer_offset = code.size() - sizeof(S_ExecuteCode_Footer_GC_B2);
|
||||||
|
|
||||||
|
StringReader r(code.data(), code.size());
|
||||||
const auto& footer = r.pget<S_ExecuteCode_Footer_GC_B2>(footer_offset);
|
const auto& footer = r.pget<S_ExecuteCode_Footer_GC_B2>(footer_offset);
|
||||||
|
|
||||||
multimap<uint32_t, string> labels;
|
multimap<uint32_t, string> labels;
|
||||||
@@ -477,17 +509,17 @@ static HandlerResult process_server_B2(shared_ptr<ServerState>,
|
|||||||
labels.emplace(r.pget_u32b(footer.entrypoint_addr_offset), "start");
|
labels.emplace(r.pget_u32b(footer.entrypoint_addr_offset), "start");
|
||||||
|
|
||||||
string disassembly = PPC32Emulator::disassemble(
|
string disassembly = PPC32Emulator::disassemble(
|
||||||
&r.pget<uint8_t>(0, orig_size),
|
&r.pget<uint8_t>(0, code.size()),
|
||||||
orig_size,
|
code.size(),
|
||||||
0,
|
0,
|
||||||
&labels);
|
&labels);
|
||||||
|
|
||||||
output_filename = string_printf("code.%" PRId64 ".txt", now());
|
output_filename = string_printf("code.%" PRId64 ".txt", now());
|
||||||
{
|
{
|
||||||
auto f = fopen_unique(output_filename, "wt");
|
auto f = fopen_unique(output_filename, "wt");
|
||||||
fprintf(f.get(), "// code_size = 0x%" PRIX32 "\n", header.code_size.load());
|
fprintf(f.get(), "// code_size = 0x%" PRIX32 "\n", cmd.code_size.load());
|
||||||
fprintf(f.get(), "// checksum_addr = 0x%" PRIX32 "\n", header.checksum_start.load());
|
fprintf(f.get(), "// checksum_addr = 0x%" PRIX32 "\n", cmd.checksum_start.load());
|
||||||
fprintf(f.get(), "// checksum_size = 0x%" PRIX32 "\n", header.checksum_size.load());
|
fprintf(f.get(), "// checksum_size = 0x%" PRIX32 "\n", cmd.checksum_size.load());
|
||||||
fwritex(f.get(), disassembly);
|
fwritex(f.get(), disassembly);
|
||||||
}
|
}
|
||||||
session.log.info("Wrote disassembly to file %s", output_filename.c_str());
|
session.log.info("Wrote disassembly to file %s", output_filename.c_str());
|
||||||
|
|||||||
+1
-2
@@ -258,11 +258,10 @@ void send_function_call(
|
|||||||
while (!compressed_r.eof()) {
|
while (!compressed_r.eof()) {
|
||||||
w.put_u32b(compressed_r.get_u32b() ^ crypt.next());
|
w.put_u32b(compressed_r.get_u32b() ^ crypt.next());
|
||||||
}
|
}
|
||||||
|
data = move(w.str());
|
||||||
} else {
|
} else {
|
||||||
crypt.encrypt(data.data(), data.size());
|
crypt.encrypt(data.data(), data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
data = move(w.str());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user