diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp index 8f98041b..360dcfb4 100644 --- a/src/emulator/serialization.hpp +++ b/src/emulator/serialization.hpp @@ -486,19 +486,37 @@ namespace utils this->break_offset_ = break_offset; } - void print_diff(const buffer_serializer& other) const + std::optional get_diff(const buffer_serializer& other) const { auto& b1 = this->get_buffer(); auto& b2 = other.get_buffer(); - for (size_t i = 0; i < b1.size() && i < b2.size(); ++i) + const auto s1 = b1.size(); + const auto s2 = b2.size(); + + for (size_t i = 0; i < s1 && i < s2; ++i) { if (b1.at(i) != b2.at(i)) { - printf("Diff at %zd\n", i); - break; + return i; } } + + if (s1 != s2) + { + return std::min(s1, s2); + } + + return std::nullopt; + } + + void print_diff(const buffer_serializer& other) const + { + const auto diff = this->get_diff(other); + if (diff) + { + printf("Diff at %zd\n", *diff); + } } private: diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index fc483139..18feb1b7 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -62,4 +62,64 @@ namespace test return create_sample_emulator(std::move(settings)); } + + inline void bisect_emulation(windows_emulator& emu) + { + utils::buffer_serializer start_state{}; + emu.serialize(start_state); + + emu.start(); + const auto limit = emu.process().executed_instructions; + + const auto reset_emulator = [&] { + utils::buffer_deserializer deserializer{start_state.get_buffer()}; + emu.deserialize(deserializer); + }; + + const auto get_state_for_count = [&](const size_t count) { + reset_emulator(); + emu.start({}, count); + + utils::buffer_serializer state{}; + emu.serialize(state); + return state; + }; + + const auto has_diff_after_count = [&](const size_t count) { + const auto s1 = get_state_for_count(count); + const auto s2 = get_state_for_count(count); + + return s1.get_diff(s2).has_value(); + }; + + if (!has_diff_after_count(limit)) + { + puts("Emulation has no diff"); + } + + auto lower_bound = 0ULL; + auto upper_bound = limit; + + printf("Bounds: %" PRIx64 " - %" PRIx64 "\n", lower_bound, upper_bound); + + while (lower_bound + 1 < upper_bound) + { + const auto diff = (upper_bound - lower_bound); + const auto pivot = lower_bound + (diff / 2); + + const auto has_diff = has_diff_after_count(pivot); + + auto& bound = has_diff ? upper_bound : lower_bound; + bound = pivot; + + printf("Bounds: %" PRIx64 " - %" PRIx64 "\n", lower_bound, upper_bound); + } + + (void)get_state_for_count(lower_bound); + + const auto rip = emu.emu().read_instruction_pointer(); + + printf("Diff detected after 0x%" PRIx64 " instructions at 0x%" PRIx64 " (%s)\n", lower_bound, rip, + emu.process().mod_manager.find_name(rip)); + } }