From 6d2f2182d31361fa496bbc8abb92f2ac4f3eea48 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 25 Jan 2025 12:38:40 +0100 Subject: [PATCH 01/12] Add UDP socket test --- src/samples/test-sample/CMakeLists.txt | 4 +++ src/samples/test-sample/test.cpp | 39 +++++++++++++++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/samples/test-sample/CMakeLists.txt b/src/samples/test-sample/CMakeLists.txt index 6a131eff..bd5f2878 100644 --- a/src/samples/test-sample/CMakeLists.txt +++ b/src/samples/test-sample/CMakeLists.txt @@ -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 +) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 83282f81..2e64c255 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include using namespace std::literals; @@ -195,7 +195,7 @@ std::optional 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(length - 1), sizeof(data)))}; } bool test_registry() @@ -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) @@ -256,7 +286,7 @@ bool test_ud2_exception(void* address) { __try { - static_cast(address)(); + reinterpret_cast(address)(); return false; } __except (EXCEPTION_EXECUTE_HANDLER) @@ -301,7 +331,7 @@ 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) { @@ -319,6 +349,7 @@ int main(int argc, const char* argv[]) RUN_TEST(test_exceptions, "Exceptions") RUN_TEST(test_native_exceptions, "Native Exceptions") RUN_TEST(test_tls, "TLS") + RUN_TEST(test_socket, "Socket") return valid ? 0 : 1; } From 0ec2dcaf12ab465b7a9ae4c8f3677c729e595e26 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 25 Jan 2025 17:58:47 +0100 Subject: [PATCH 02/12] Archive more DLLs --- src/tools/create-root.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/create-root.bat b/src/tools/create-root.bat index 5a89a64d..d457c7a8 100644 --- a/src/tools/create-root.bat +++ b/src/tools/create-root.bat @@ -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 From 130367619bd828746091aaf816ce89f8f328ac50 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 25 Jan 2025 20:01:03 +0100 Subject: [PATCH 03/12] Add debugging utils --- src/emulator/serialization.hpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp index 14e2b6af..8f98041b 100644 --- a/src/emulator/serialization.hpp +++ b/src/emulator/serialization.hpp @@ -349,6 +349,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(buffer); this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length); @@ -475,8 +481,29 @@ namespace utils return std::move(this->buffer_); } + void set_break_offset(const size_t break_offset) + { + this->break_offset_ = break_offset; + } + + void print_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) + { + if (b1.at(i) != b2.at(i)) + { + printf("Diff at %zd\n", i); + break; + } + } + } + private: std::vector buffer_{}; + std::optional break_offset_{}; }; template <> From 45d7c542c35dcbbf1189d824d65d3104428c7ac6 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 25 Jan 2025 20:59:10 +0100 Subject: [PATCH 04/12] Prepare emulation bisection --- src/emulator/serialization.hpp | 26 ++++++-- .../emulation_test_utils.hpp | 60 +++++++++++++++++++ 2 files changed, 82 insertions(+), 4 deletions(-) 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)); + } } From 59b82a5e0da9f4f1ec0db2aabae9e53a11c91976 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 26 Jan 2025 08:10:18 +0100 Subject: [PATCH 05/12] Fix compilation --- src/windows-emulator-test/emulation_test_utils.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index 18feb1b7..d1f3a4a0 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -109,8 +109,8 @@ namespace test const auto has_diff = has_diff_after_count(pivot); - auto& bound = has_diff ? upper_bound : lower_bound; - bound = pivot; + auto* bound = has_diff ? &upper_bound : &lower_bound; + *bound = pivot; printf("Bounds: %" PRIx64 " - %" PRIx64 "\n", lower_bound, upper_bound); } From 454c9a267b4b59d6983205e180112ff866392daf Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 26 Jan 2025 09:56:55 +0100 Subject: [PATCH 06/12] Fix afd device serialization --- src/emulator/serialization.hpp | 11 +++++++++++ src/windows-emulator/devices/afd_endpoint.cpp | 16 ++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp index 360dcfb4..4693ce3e 100644 --- a/src/emulator/serialization.hpp +++ b/src/emulator/serialization.hpp @@ -22,6 +22,16 @@ namespace utils { a.deserialize(deserializer) } -> std::same_as; }; + template + struct is_optional : std::false_type + { + }; + + template + struct is_optional> : std::true_type + { + }; + namespace detail { template @@ -371,6 +381,7 @@ namespace utils } template + requires(!is_optional::value) void write(const T& object) { constexpr auto is_trivially_copyable = std::is_trivially_copyable_v; diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 1a364eb4..48d43c08 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -290,20 +290,20 @@ namespace void deserialize(utils::buffer_deserializer& buffer) override { - buffer.read(this->creation_data); + buffer.read_optional(this->creation_data); this->setup(); - buffer.read(this->require_poll_); - buffer.read(this->delayed_ioctl_); - buffer.read(this->timeout_); + buffer.read_optional(this->require_poll_); + buffer.read_optional(this->delayed_ioctl_); + buffer.read_optional(this->timeout_); } void serialize(utils::buffer_serializer& buffer) const override { - buffer.write(this->creation_data); - buffer.write(this->require_poll_); - buffer.write(this->delayed_ioctl_); - buffer.write(this->timeout_); + buffer.write_optional(this->creation_data); + buffer.write_optional(this->require_poll_); + buffer.write_optional(this->delayed_ioctl_); + buffer.write_optional(this->timeout_); } NTSTATUS io_control(windows_emulator& win_emu, const io_device_context& c) override From 8c70ef5af205e41f4c4524144e57d4f32634cfd7 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 26 Jan 2025 10:00:19 +0100 Subject: [PATCH 07/12] Fix compilation --- src/windows-emulator-test/emulation_test_utils.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index d1f3a4a0..1b5c9ef9 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -97,8 +97,8 @@ namespace test puts("Emulation has no diff"); } - auto lower_bound = 0ULL; auto upper_bound = limit; + decltype(upper_bound) lower_bound = 0; printf("Bounds: %" PRIx64 " - %" PRIx64 "\n", lower_bound, upper_bound); From 72a312330356257b176ad4db27e7add6d9f5a1f1 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 26 Jan 2025 11:03:19 +0100 Subject: [PATCH 08/12] Respect reproducibility --- src/samples/test-sample/test.cpp | 18 ++++++++++++++---- .../emulation_test_utils.hpp | 14 ++++++++++---- .../serialization_test.cpp | 10 +++++----- src/windows-emulator-test/time_test.cpp | 2 +- 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 2e64c255..d358bcf5 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -333,10 +333,16 @@ void print_time() 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; @@ -349,7 +355,11 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_exceptions, "Exceptions") RUN_TEST(test_native_exceptions, "Native Exceptions") RUN_TEST(test_tls, "TLS") - RUN_TEST(test_socket, "Socket") + + if (!reproducible) + { + RUN_TEST(test_socket, "Socket") + } return valid ? 0 : 1; } diff --git a/src/windows-emulator-test/emulation_test_utils.hpp b/src/windows-emulator-test/emulation_test_utils.hpp index 1b5c9ef9..72028a01 100644 --- a/src/windows-emulator-test/emulation_test_utils.hpp +++ b/src/windows-emulator-test/emulation_test_utils.hpp @@ -38,14 +38,20 @@ 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"; @@ -53,14 +59,14 @@ namespace test 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) diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp index 95461785..990e48f8 100644 --- a/src/windows-emulator-test/serialization_test.cpp +++ b/src/windows-emulator-test/serialization_test.cpp @@ -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); @@ -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); @@ -55,7 +55,7 @@ namespace test TEST(SerializationTest, EmulationIsReproducible) { - auto emu1 = create_sample_emulator(); + auto emu1 = create_sample_emulator(true); emu1.start(); ASSERT_TERMINATED_SUCCESSFULLY(emu1); @@ -63,7 +63,7 @@ namespace test utils::buffer_serializer serializer1{}; emu1.serialize(serializer1); - auto emu2 = create_sample_emulator(); + auto emu2 = create_sample_emulator(true); emu2.start(); ASSERT_TERMINATED_SUCCESSFULLY(emu2); @@ -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{}; diff --git a/src/windows-emulator-test/time_test.cpp b/src/windows-emulator-test/time_test.cpp index 38555971..bb4b1e01 100644 --- a/src/windows-emulator-test/time_test.cpp +++ b/src/windows-emulator-test/time_test.cpp @@ -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; From a6362b06dc0bac5716c3647a791e07cd31ba351b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 26 Jan 2025 11:52:43 +0100 Subject: [PATCH 09/12] Translate socket values --- src/windows-emulator/devices/afd_endpoint.cpp | 101 ++++++++++++++++-- 1 file changed, 91 insertions(+), 10 deletions(-) diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 48d43c08..558e714a 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -22,6 +22,73 @@ namespace // ... }; + const std::map address_family_map{ + {0, AF_UNSPEC}, // + {2, AF_INET}, // + {23, AF_INET6}, // + }; + + const std::map socket_type_map{ + {0, 0}, // + {1, SOCK_STREAM}, // + {2, SOCK_DGRAM}, // + {3, SOCK_RAW}, // + {4, SOCK_RDM}, // + }; + + const std::map socket_protocol_map{ + {0, 0}, // + {6, IPPROTO_TCP}, // + {17, IPPROTO_UDP}, // + {255, IPPROTO_RAW}, // + }; + + int translate_host_to_win_address_family(const int host_af) + { + for (auto& entry : address_family_map) + { + if (entry.second == host_af) + { + return entry.first; + } + } + + throw std::runtime_error("Unknown host address family: " + std::to_string(host_af)); + } + + int translate_address_family(const int win_af) + { + const auto entry = address_family_map.find(win_af); + if (entry != address_family_map.end()) + { + return entry->second; + } + + throw std::runtime_error("Unknown address family: " + std::to_string(win_af)); + } + + int translate_type(const int win_type) + { + const auto entry = socket_type_map.find(win_type); + if (entry != socket_type_map.end()) + { + return entry->second; + } + + throw std::runtime_error("Unknown socket type: " + std::to_string(win_type)); + } + + int translate_protocol(const int win_protocol) + { + const auto entry = socket_protocol_map.find(win_protocol); + if (entry != socket_protocol_map.end()) + { + return entry->second; + } + + throw std::runtime_error("Unknown socket protocol: " + std::to_string(win_protocol)); + } + afd_creation_data get_creation_data(windows_emulator& win_emu, const io_device_creation_data& data) { if (!data.buffer || data.length < sizeof(afd_creation_data)) @@ -216,8 +283,11 @@ namespace const auto& data = *this->creation_data; - // TODO: values map to windows values; might not be the case for other platforms - const auto sock = socket(data.address_family, data.type, data.protocol); + const auto af = translate_address_family(data.address_family); + const auto type = translate_type(data.type); + const auto protocol = translate_protocol(data.protocol); + + const auto sock = socket(af, type, protocol); if (sock == INVALID_SOCKET) { throw std::runtime_error("Failed to create socket!"); @@ -339,7 +409,7 @@ namespace NTSTATUS ioctl_bind(windows_emulator& win_emu, const io_device_context& c) const { - const auto data = win_emu.emu().read_memory(c.input_buffer, c.input_buffer_length); + auto data = win_emu.emu().read_memory(c.input_buffer, c.input_buffer_length); constexpr auto address_offset = 4; @@ -348,9 +418,12 @@ namespace return STATUS_BUFFER_TOO_SMALL; } - const auto* address = reinterpret_cast(data.data() + address_offset); + auto* address = reinterpret_cast(data.data() + address_offset); const auto address_size = static_cast(data.size() - address_offset); + address->sa_family = + static_castsa_family)>(translate_address_family(address->sa_family)); + const network::address addr(address, address_size); if (bind(*this->s_, &addr.get_addr(), addr.get_size()) == SOCKET_ERROR) @@ -451,8 +524,10 @@ namespace std::vector data{}; data.resize(buffer.len); - const auto recevied_data = recvfrom(*this->s_, data.data(), static_cast(data.size()), 0, - reinterpret_cast(address.data()), &fromlength); + auto* sender = reinterpret_cast(address.data()); + + const auto recevied_data = + recvfrom(*this->s_, data.data(), static_cast(data.size()), 0, sender, &fromlength); if (recevied_data < 0) { @@ -466,6 +541,10 @@ namespace return STATUS_UNSUCCESSFUL; } + // TODO: Translate rest of address struct? + sender->sa_family = + static_castsa_family)>(translate_host_to_win_address_family(sender->sa_family)); + const auto data_size = std::min(data.size(), static_cast(recevied_data)); emu.write_memory(buffer.buf, data.data(), data_size); @@ -497,11 +576,13 @@ namespace const auto send_info = emu.read_memory>>(c.input_buffer); const auto buffer = emu.read_memory>>(send_info.BufferArray); - const auto address = emu.read_memory(send_info.TdiConnInfo.RemoteAddress, - static_cast(send_info.TdiConnInfo.RemoteAddressLength)); + auto address_buffer = emu.read_memory(send_info.TdiConnInfo.RemoteAddress, + static_cast(send_info.TdiConnInfo.RemoteAddressLength)); + auto* address = reinterpret_cast(address_buffer.data()); + address->sa_family = + static_castsa_family)>(translate_address_family(address->sa_family)); - const network::address target(reinterpret_cast(address.data()), - static_cast(address.size())); + const network::address target(address, static_cast(address_buffer.size())); const auto data = emu.read_memory(buffer.buf, buffer.len); From 5d9ecc4c01cafe858eab089b951b6c820e2f10b8 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 26 Jan 2025 15:45:37 +0100 Subject: [PATCH 10/12] Assert socket struct equality --- src/windows-emulator/devices/afd_endpoint.cpp | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 558e714a..c6e27460 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -22,6 +22,65 @@ namespace // ... }; + struct win_sockaddr + { + int16_t sa_family; + uint8_t sa_data[14]; + }; + + struct win_sockaddr_in + { + int16_t sin_family; + uint16_t sin_port; + in_addr sin_addr; + uint8_t sin_zero[8]; + }; + + struct win_sockaddr_in6 + { + int16_t sin6_family; + uint16_t sin6_port; + uint32_t sin6_flowinfo; + in6_addr sin6_addr; + uint32_t sin6_scope_id; + }; + + static_assert(sizeof(win_sockaddr) == 16); + static_assert(sizeof(win_sockaddr_in) == 16); + static_assert(sizeof(win_sockaddr_in6) == 28); + + static_assert(sizeof(win_sockaddr) == sizeof(sockaddr)); + static_assert(sizeof(win_sockaddr_in) == sizeof(sockaddr_in)); + static_assert(sizeof(win_sockaddr_in6) == sizeof(sockaddr_in6)); + + static_assert(offsetof(win_sockaddr, sa_family) == offsetof(sockaddr, sa_family)); + static_assert(offsetof(win_sockaddr, sa_data) == offsetof(sockaddr, sa_data)); + + static_assert(sizeof(win_sockaddr::sa_family) == sizeof(sockaddr::sa_family)); + static_assert(sizeof(win_sockaddr::sa_data) == sizeof(sockaddr::sa_data)); + + static_assert(offsetof(win_sockaddr_in, sin_family) == offsetof(sockaddr_in, sin_family)); + static_assert(offsetof(win_sockaddr_in, sin_port) == offsetof(sockaddr_in, sin_port)); + static_assert(offsetof(win_sockaddr_in, sin_addr) == offsetof(sockaddr_in, sin_addr)); + static_assert(offsetof(win_sockaddr_in, sin_zero) == offsetof(sockaddr_in, sin_zero)); + + static_assert(sizeof(win_sockaddr_in::sin_family) == sizeof(sockaddr_in::sin_family)); + static_assert(sizeof(win_sockaddr_in::sin_port) == sizeof(sockaddr_in::sin_port)); + static_assert(sizeof(win_sockaddr_in::sin_addr) == sizeof(sockaddr_in::sin_addr)); + static_assert(sizeof(win_sockaddr_in::sin_zero) == sizeof(sockaddr_in::sin_zero)); + + static_assert(offsetof(win_sockaddr_in6, sin6_family) == offsetof(sockaddr_in6, sin6_family)); + static_assert(offsetof(win_sockaddr_in6, sin6_port) == offsetof(sockaddr_in6, sin6_port)); + static_assert(offsetof(win_sockaddr_in6, sin6_flowinfo) == offsetof(sockaddr_in6, sin6_flowinfo)); + static_assert(offsetof(win_sockaddr_in6, sin6_addr) == offsetof(sockaddr_in6, sin6_addr)); + static_assert(offsetof(win_sockaddr_in6, sin6_scope_id) == offsetof(sockaddr_in6, sin6_scope_id)); + + static_assert(sizeof(win_sockaddr_in6::sin6_family) == sizeof(sockaddr_in6::sin6_family)); + static_assert(sizeof(win_sockaddr_in6::sin6_port) == sizeof(sockaddr_in6::sin6_port)); + static_assert(sizeof(win_sockaddr_in6::sin6_flowinfo) == sizeof(sockaddr_in6::sin6_flowinfo)); + static_assert(sizeof(win_sockaddr_in6::sin6_addr) == sizeof(sockaddr_in6::sin6_addr)); + static_assert(sizeof(win_sockaddr_in6::sin6_scope_id) == sizeof(sockaddr_in6::sin6_scope_id)); + const std::map address_family_map{ {0, AF_UNSPEC}, // {2, AF_INET}, // From b3d4d32fbdb66c8239799130bc6253c84094a781 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 26 Jan 2025 16:12:08 +0100 Subject: [PATCH 11/12] Assert relevant field equality --- src/windows-emulator/devices/afd_endpoint.cpp | 29 +------------------ 1 file changed, 1 insertion(+), 28 deletions(-) diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index c6e27460..05f15e9c 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -49,36 +49,9 @@ namespace static_assert(sizeof(win_sockaddr_in) == 16); static_assert(sizeof(win_sockaddr_in6) == 28); - static_assert(sizeof(win_sockaddr) == sizeof(sockaddr)); - static_assert(sizeof(win_sockaddr_in) == sizeof(sockaddr_in)); - static_assert(sizeof(win_sockaddr_in6) == sizeof(sockaddr_in6)); - - static_assert(offsetof(win_sockaddr, sa_family) == offsetof(sockaddr, sa_family)); - static_assert(offsetof(win_sockaddr, sa_data) == offsetof(sockaddr, sa_data)); - - static_assert(sizeof(win_sockaddr::sa_family) == sizeof(sockaddr::sa_family)); - static_assert(sizeof(win_sockaddr::sa_data) == sizeof(sockaddr::sa_data)); - - static_assert(offsetof(win_sockaddr_in, sin_family) == offsetof(sockaddr_in, sin_family)); - static_assert(offsetof(win_sockaddr_in, sin_port) == offsetof(sockaddr_in, sin_port)); - static_assert(offsetof(win_sockaddr_in, sin_addr) == offsetof(sockaddr_in, sin_addr)); - static_assert(offsetof(win_sockaddr_in, sin_zero) == offsetof(sockaddr_in, sin_zero)); - - static_assert(sizeof(win_sockaddr_in::sin_family) == sizeof(sockaddr_in::sin_family)); - static_assert(sizeof(win_sockaddr_in::sin_port) == sizeof(sockaddr_in::sin_port)); static_assert(sizeof(win_sockaddr_in::sin_addr) == sizeof(sockaddr_in::sin_addr)); - static_assert(sizeof(win_sockaddr_in::sin_zero) == sizeof(sockaddr_in::sin_zero)); - - static_assert(offsetof(win_sockaddr_in6, sin6_family) == offsetof(sockaddr_in6, sin6_family)); - static_assert(offsetof(win_sockaddr_in6, sin6_port) == offsetof(sockaddr_in6, sin6_port)); - static_assert(offsetof(win_sockaddr_in6, sin6_flowinfo) == offsetof(sockaddr_in6, sin6_flowinfo)); - static_assert(offsetof(win_sockaddr_in6, sin6_addr) == offsetof(sockaddr_in6, sin6_addr)); - static_assert(offsetof(win_sockaddr_in6, sin6_scope_id) == offsetof(sockaddr_in6, sin6_scope_id)); - - static_assert(sizeof(win_sockaddr_in6::sin6_family) == sizeof(sockaddr_in6::sin6_family)); - static_assert(sizeof(win_sockaddr_in6::sin6_port) == sizeof(sockaddr_in6::sin6_port)); - static_assert(sizeof(win_sockaddr_in6::sin6_flowinfo) == sizeof(sockaddr_in6::sin6_flowinfo)); static_assert(sizeof(win_sockaddr_in6::sin6_addr) == sizeof(sockaddr_in6::sin6_addr)); + static_assert(sizeof(win_sockaddr_in6::sin6_flowinfo) == sizeof(sockaddr_in6::sin6_flowinfo)); static_assert(sizeof(win_sockaddr_in6::sin6_scope_id) == sizeof(sockaddr_in6::sin6_scope_id)); const std::map address_family_map{ From 5387c45da2a6759a6470309636af1e4042fc8a5b Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 26 Jan 2025 16:34:07 +0100 Subject: [PATCH 12/12] Convert socket addresses --- src/windows-emulator/devices/afd_endpoint.cpp | 154 +++++++++++++----- 1 file changed, 110 insertions(+), 44 deletions(-) diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 05f15e9c..0068561b 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -49,8 +49,8 @@ namespace static_assert(sizeof(win_sockaddr_in) == 16); static_assert(sizeof(win_sockaddr_in6) == 28); - static_assert(sizeof(win_sockaddr_in::sin_addr) == sizeof(sockaddr_in::sin_addr)); - static_assert(sizeof(win_sockaddr_in6::sin6_addr) == sizeof(sockaddr_in6::sin6_addr)); + static_assert(sizeof(win_sockaddr_in::sin_addr) == 4); + static_assert(sizeof(win_sockaddr_in6::sin6_addr) == 16); static_assert(sizeof(win_sockaddr_in6::sin6_flowinfo) == sizeof(sockaddr_in6::sin6_flowinfo)); static_assert(sizeof(win_sockaddr_in6::sin6_scope_id) == sizeof(sockaddr_in6::sin6_scope_id)); @@ -75,20 +75,20 @@ namespace {255, IPPROTO_RAW}, // }; - int translate_host_to_win_address_family(const int host_af) + int16_t translate_host_to_win_address_family(const int host_af) { for (auto& entry : address_family_map) { if (entry.second == host_af) { - return entry.first; + return static_cast(entry.first); } } throw std::runtime_error("Unknown host address family: " + std::to_string(host_af)); } - int translate_address_family(const int win_af) + int translate_win_to_host_address_family(const int win_af) { const auto entry = address_family_map.find(win_af); if (entry != address_family_map.end()) @@ -99,7 +99,7 @@ namespace throw std::runtime_error("Unknown address family: " + std::to_string(win_af)); } - int translate_type(const int win_type) + int translate_win_to_host_type(const int win_type) { const auto entry = socket_type_map.find(win_type); if (entry != socket_type_map.end()) @@ -110,7 +110,7 @@ namespace throw std::runtime_error("Unknown socket type: " + std::to_string(win_type)); } - int translate_protocol(const int win_protocol) + int translate_win_to_host_protocol(const int win_protocol) { const auto entry = socket_protocol_map.find(win_protocol); if (entry != socket_protocol_map.end()) @@ -121,6 +121,90 @@ namespace throw std::runtime_error("Unknown socket protocol: " + std::to_string(win_protocol)); } + std::vector convert_to_win_address(const network::address& a) + { + if (a.is_ipv4()) + { + win_sockaddr_in win_addr{}; + win_addr.sin_family = translate_host_to_win_address_family(a.get_family()); + win_addr.sin_port = htons(a.get_port()); + memcpy(&win_addr.sin_addr, &a.get_in_addr().sin_addr, sizeof(win_addr.sin_addr)); + + const auto ptr = reinterpret_cast(&win_addr); + return {ptr, ptr + sizeof(win_addr)}; + } + + if (a.is_ipv6()) + { + win_sockaddr_in6 win_addr{}; + win_addr.sin6_family = translate_host_to_win_address_family(a.get_family()); + win_addr.sin6_port = htons(a.get_port()); + + auto& addr = a.get_in6_addr(); + memcpy(&win_addr.sin6_addr, &addr.sin6_addr, sizeof(win_addr.sin6_addr)); + win_addr.sin6_flowinfo = addr.sin6_flowinfo; + win_addr.sin6_scope_id = addr.sin6_scope_id; + + const auto ptr = reinterpret_cast(&win_addr); + return {ptr, ptr + sizeof(win_addr)}; + } + + throw std::runtime_error("Unsupported host address family for conversion: " + std::to_string(a.get_family())); + } + + network::address convert_to_host_address(const std::span data) + { + if (data.size() < sizeof(win_sockaddr)) + { + throw std::runtime_error("Bad address size"); + } + + win_sockaddr win_addr{}; + memcpy(&win_addr, data.data(), sizeof(win_addr)); + + const auto family = translate_win_to_host_address_family(win_addr.sa_family); + + network::address a{}; + + if (family == AF_INET) + { + if (data.size() < sizeof(win_sockaddr_in)) + { + throw std::runtime_error("Bad IPv4 address size"); + } + + win_sockaddr_in win_addr4{}; + memcpy(&win_addr4, data.data(), sizeof(win_addr4)); + + a.set_ipv4(win_addr4.sin_addr); + a.set_port(ntohs(win_addr4.sin_port)); + + return a; + } + + if (family == AF_INET6) + { + if (data.size() < sizeof(win_sockaddr_in6)) + { + throw std::runtime_error("Bad IPv6 address size"); + } + + win_sockaddr_in6 win_addr6{}; + memcpy(&win_addr6, data.data(), sizeof(win_addr6)); + + a.set_ipv6(win_addr6.sin6_addr); + a.set_port(ntohs(win_addr6.sin6_port)); + + auto& addr = a.get_in6_addr(); + addr.sin6_flowinfo = win_addr6.sin6_flowinfo; + addr.sin6_scope_id = win_addr6.sin6_scope_id; + + return a; + } + + throw std::runtime_error("Unsupported win address family for conversion: " + std::to_string(family)); + } + afd_creation_data get_creation_data(windows_emulator& win_emu, const io_device_creation_data& data) { if (!data.buffer || data.length < sizeof(afd_creation_data)) @@ -315,9 +399,9 @@ namespace const auto& data = *this->creation_data; - const auto af = translate_address_family(data.address_family); - const auto type = translate_type(data.type); - const auto protocol = translate_protocol(data.protocol); + const auto af = translate_win_to_host_address_family(data.address_family); + const auto type = translate_win_to_host_type(data.type); + const auto protocol = translate_win_to_host_protocol(data.protocol); const auto sock = socket(af, type, protocol); if (sock == INVALID_SOCKET) @@ -450,13 +534,7 @@ namespace return STATUS_BUFFER_TOO_SMALL; } - auto* address = reinterpret_cast(data.data() + address_offset); - const auto address_size = static_cast(data.size() - address_offset); - - address->sa_family = - static_castsa_family)>(translate_address_family(address->sa_family)); - - const network::address addr(address, address_size); + const auto addr = convert_to_host_address(std::span(data).subspan(address_offset)); if (bind(*this->s_, &addr.get_addr(), addr.get_size()) == SOCKET_ERROR) { @@ -536,30 +614,19 @@ namespace const auto receive_info = emu.read_memory>>(c.input_buffer); const auto buffer = emu.read_memory>>(receive_info.BufferArray); - std::vector address{}; - - unsigned long address_length = 0x1000; - if (receive_info.AddressLength) - { - address_length = emu.read_memory(receive_info.AddressLength); - } - - address.resize(std::clamp(address_length, 1UL, 0x1000UL)); - if (!buffer.len || buffer.len > 0x10000 || !buffer.buf) { return STATUS_INVALID_PARAMETER; } - auto fromlength = static_cast(address.size()); + network::address from{}; + auto from_length = from.get_max_size(); std::vector data{}; data.resize(buffer.len); - auto* sender = reinterpret_cast(address.data()); - - const auto recevied_data = - recvfrom(*this->s_, data.data(), static_cast(data.size()), 0, sender, &fromlength); + const auto recevied_data = recvfrom(*this->s_, data.data(), static_cast(data.size()), 0, + &from.get_addr(), &from_length); if (recevied_data < 0) { @@ -573,17 +640,20 @@ namespace return STATUS_UNSUCCESSFUL; } - // TODO: Translate rest of address struct? - sender->sa_family = - static_castsa_family)>(translate_host_to_win_address_family(sender->sa_family)); + assert(from.get_size() == from_length); const auto data_size = std::min(data.size(), static_cast(recevied_data)); emu.write_memory(buffer.buf, data.data(), data_size); - if (receive_info.Address && address_length) + const auto win_from = convert_to_win_address(from); + + if (receive_info.Address && receive_info.AddressLength) { - const auto address_size = std::min(address.size(), static_cast(address_length)); - emu.write_memory(receive_info.Address, address.data(), address_size); + const emulator_object address_length{emu, receive_info.AddressLength}; + const auto address_size = std::min(win_from.size(), static_cast(address_length.read())); + + emu.write_memory(receive_info.Address, win_from.data(), address_size); + address_length.write(static_cast(address_size)); } if (c.io_status_block) @@ -610,17 +680,13 @@ namespace auto address_buffer = emu.read_memory(send_info.TdiConnInfo.RemoteAddress, static_cast(send_info.TdiConnInfo.RemoteAddressLength)); - auto* address = reinterpret_cast(address_buffer.data()); - address->sa_family = - static_castsa_family)>(translate_address_family(address->sa_family)); - - const network::address target(address, static_cast(address_buffer.size())); + const auto target = convert_to_host_address(address_buffer); const auto data = emu.read_memory(buffer.buf, buffer.len); const auto sent_data = sendto(*this->s_, reinterpret_cast(data.data()), static_cast(data.size()), - 0 /* ? */, &target.get_addr(), target.get_size()); + 0 /* TODO */, &target.get_addr(), target.get_size()); if (sent_data < 0) {