Skip to content

Commit

Permalink
Fix sockets and add test (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
momo5502 authored Jan 26, 2025
2 parents d1e7080 + 5387c45 commit 614a7f8
Show file tree
Hide file tree
Showing 8 changed files with 401 additions and 53 deletions.
56 changes: 56 additions & 0 deletions src/emulator/serialization.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ namespace utils
{ a.deserialize(deserializer) } -> std::same_as<void>;
};

template <typename T>
struct is_optional : std::false_type
{
};

template <typename T>
struct is_optional<std::optional<T>> : std::true_type
{
};

namespace detail
{
template <typename, typename = void>
Expand Down Expand Up @@ -349,6 +359,12 @@ namespace utils
const uint64_t old_size = this->buffer_.size();
#endif

if (this->break_offset_ && this->buffer_.size() <= *this->break_offset_ &&
this->buffer_.size() + length > *this->break_offset_)
{
throw std::runtime_error("Break offset reached!");
}

const auto* byte_buffer = static_cast<const std::byte*>(buffer);
this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length);

Expand All @@ -365,6 +381,7 @@ namespace utils
}

template <typename T>
requires(!is_optional<T>::value)
void write(const T& object)
{
constexpr auto is_trivially_copyable = std::is_trivially_copyable_v<T>;
Expand Down Expand Up @@ -475,8 +492,47 @@ namespace utils
return std::move(this->buffer_);
}

void set_break_offset(const size_t break_offset)
{
this->break_offset_ = break_offset;
}

std::optional<size_t> get_diff(const buffer_serializer& other) const
{
auto& b1 = this->get_buffer();
auto& b2 = other.get_buffer();

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))
{
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:
std::vector<std::byte> buffer_{};
std::optional<size_t> break_offset_{};
};

template <>
Expand Down
4 changes: 4 additions & 0 deletions src/samples/test-sample/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ list(SORT SRC_FILES)
add_executable(test-sample ${SRC_FILES})

momo_assign_source_group(${SRC_FILES})

target_link_libraries(test-sample PRIVATE
emulator-common
)
55 changes: 48 additions & 7 deletions src/samples/test-sample/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#include <filesystem>
#include <string_view>

#include <Windows.h>
#include <network/udp_socket.hpp>

using namespace std::literals;

Expand Down Expand Up @@ -195,7 +195,7 @@ std::optional<std::string> read_registry_string(const HKEY root, const char* pat
return "";
}

return {std::string(data, min(length - 1, sizeof(data)))};
return {std::string(data, std::min(static_cast<size_t>(length - 1), sizeof(data)))};
}

bool test_registry()
Expand Down Expand Up @@ -231,6 +231,36 @@ bool test_exceptions()
}
}

bool test_socket()
{
network::udp_socket receiver{AF_INET};
const network::udp_socket sender{AF_INET};
const network::address destination{"127.0.0.1:28970", AF_INET};
constexpr std::string_view send_data = "Hello World";

if (!receiver.bind(destination))
{
puts("Failed to bind socket!");
return false;
}

if (!sender.send(destination, send_data))
{
puts("Failed to send data!");
return false;
}

const auto response = receiver.receive();

if (!response)
{
puts("Failed to recieve data!");
return false;
}

return send_data == response->second;
}

void throw_access_violation()
{
if (do_the_task)
Expand All @@ -256,7 +286,7 @@ bool test_ud2_exception(void* address)
{
__try
{
static_cast<void (*)()>(address)();
reinterpret_cast<void (*)()>(address)();
return false;
}
__except (EXCEPTION_EXECUTE_HANDLER)
Expand Down Expand Up @@ -301,12 +331,18 @@ void print_time()
puts(res ? "Success" : "Fail"); \
}

int main(int argc, const char* argv[])
int main(const int argc, const char* argv[])
{
if (argc == 2 && argv[1] == "-time"sv)
bool reproducible = false;
if (argc == 2)
{
print_time();
return 0;
if (argv[1] == "-time"sv)
{
print_time();
return 0;
}

reproducible = argv[1] == "-reproducible"sv;
}

bool valid = true;
Expand All @@ -320,5 +356,10 @@ int main(int argc, const char* argv[])
RUN_TEST(test_native_exceptions, "Native Exceptions")
RUN_TEST(test_tls, "TLS")

if (!reproducible)
{
RUN_TEST(test_socket, "Socket")
}

return valid ? 0 : 1;
}
2 changes: 2 additions & 0 deletions src/tools/create-root.bat
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ CALL :collect_dll mscms.dll
CALL :collect_dll ktmw32.dll
CALL :collect_dll shcore.dll
CALL :collect_dll diagnosticdatasettings.dll
CALL :collect_dll mswsock.dll
CALL :collect_dll umpdc.dll

CALL :collect_dll locale.nls

Expand Down
74 changes: 70 additions & 4 deletions src/windows-emulator-test/emulation_test_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,94 @@ namespace test
return env;
}

inline windows_emulator create_sample_emulator(emulator_settings settings, emulator_callbacks callbacks = {})
inline windows_emulator create_sample_emulator(emulator_settings settings, const bool reproducible = false,
emulator_callbacks callbacks = {})
{
const auto is_verbose = enable_verbose_logging();

if (is_verbose)
{
settings.disable_logging = false;
settings.verbose_calls = true;
// settings.verbose_calls = true;
}

if (reproducible)
{
settings.arguments = {u"-reproducible"};
}

settings.application = "c:/test-sample.exe";
settings.emulation_root = get_emulator_root();
return windows_emulator{std::move(settings), std::move(callbacks)};
}

inline windows_emulator create_sample_emulator()
inline windows_emulator create_sample_emulator(const bool reproducible = false)
{
emulator_settings settings{
.disable_logging = true,
.use_relative_time = true,
};

return create_sample_emulator(std::move(settings));
return create_sample_emulator(std::move(settings), reproducible);
}

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 upper_bound = limit;
decltype(upper_bound) lower_bound = 0;

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));
}
}
10 changes: 5 additions & 5 deletions src/windows-emulator-test/serialization_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace test
{
TEST(SerializationTest, ResettingEmulatorWorks)
{
auto emu = create_sample_emulator();
auto emu = create_sample_emulator(true);

utils::buffer_serializer start_state{};
emu.serialize(start_state);
Expand All @@ -31,7 +31,7 @@ namespace test

TEST(SerializationTest, SerializedDataIsReproducible)
{
auto emu1 = create_sample_emulator();
auto emu1 = create_sample_emulator(true);
emu1.start();

ASSERT_TERMINATED_SUCCESSFULLY(emu1);
Expand All @@ -55,15 +55,15 @@ namespace test

TEST(SerializationTest, EmulationIsReproducible)
{
auto emu1 = create_sample_emulator();
auto emu1 = create_sample_emulator(true);
emu1.start();

ASSERT_TERMINATED_SUCCESSFULLY(emu1);

utils::buffer_serializer serializer1{};
emu1.serialize(serializer1);

auto emu2 = create_sample_emulator();
auto emu2 = create_sample_emulator(true);
emu2.start();

ASSERT_TERMINATED_SUCCESSFULLY(emu2);
Expand All @@ -76,7 +76,7 @@ namespace test

TEST(SerializationTest, DeserializedEmulatorBehavesLikeSource)
{
auto emu = create_sample_emulator();
auto emu = create_sample_emulator(true);
emu.start({}, 100);

utils::buffer_serializer serializer{};
Expand Down
2 changes: 1 addition & 1 deletion src/windows-emulator-test/time_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace test
.use_relative_time = false,
};

auto emu = create_sample_emulator(settings, callbacks);
auto emu = create_sample_emulator(settings, false, callbacks);
emu.start();

constexpr auto prefix = "Time: "sv;
Expand Down
Loading

0 comments on commit 614a7f8

Please sign in to comment.