From a3a95ec8298ae15b7a51bebe96cf633edf334da6 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Fri, 25 Oct 2024 17:04:45 +0200 Subject: [PATCH] Prepare unittest support --- .gitmodules | 3 ++ deps/CMakeLists.txt | 3 +- deps/googletest | 1 + deps/googletest.cmake | 4 +++ src/CMakeLists.txt | 1 + src/test-sample/test.cpp | 10 +++--- src/windows-emulator-test/CMakeLists.txt | 19 ++++++++++ src/windows-emulator-test/emulation_test.cpp | 27 ++++++++++++++ src/windows-emulator-test/main.cpp | 7 ++++ .../serialization_test.cpp | 33 +++++++++++++++++ src/windows-emulator/process_context.hpp | 5 ++- src/windows-emulator/syscalls.cpp | 35 +++++++++++++------ src/windows-emulator/windows_emulator.cpp | 7 +++- src/windows-emulator/windows_emulator.hpp | 2 ++ 14 files changed, 139 insertions(+), 18 deletions(-) create mode 160000 deps/googletest create mode 100644 deps/googletest.cmake create mode 100644 src/windows-emulator-test/CMakeLists.txt create mode 100644 src/windows-emulator-test/emulation_test.cpp create mode 100644 src/windows-emulator-test/main.cpp create mode 100644 src/windows-emulator-test/serialization_test.cpp diff --git a/.gitmodules b/.gitmodules index 56715e7f..c6814e54 100644 --- a/.gitmodules +++ b/.gitmodules @@ -15,3 +15,6 @@ path = deps/mini-gdbstub url = ../mini-gdbstub.git shallow = true +[submodule "deps/googletest"] + path = deps/googletest + url = https://github.com/google/googletest.git diff --git a/deps/CMakeLists.txt b/deps/CMakeLists.txt index 0e4ca9c4..439293bd 100644 --- a/deps/CMakeLists.txt +++ b/deps/CMakeLists.txt @@ -12,4 +12,5 @@ target_include_directories(reflect INTERFACE ########################################## -include(mini-gdbstub.cmake) \ No newline at end of file +include(mini-gdbstub.cmake) +include(googletest.cmake) \ No newline at end of file diff --git a/deps/googletest b/deps/googletest new file mode 160000 index 00000000..df1544bc --- /dev/null +++ b/deps/googletest @@ -0,0 +1 @@ +Subproject commit df1544bcee0c7ce35cd5ea0b3eb8cc81855a4140 diff --git a/deps/googletest.cmake b/deps/googletest.cmake new file mode 100644 index 00000000..1182c029 --- /dev/null +++ b/deps/googletest.cmake @@ -0,0 +1,4 @@ +option(BUILD_GMOCK OFF) +option(INSTALL_GTEST OFF) + +add_subdirectory(googletest) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e16cc98e..1565e612 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,3 +7,4 @@ add_subdirectory(fuzzing-engine) add_subdirectory(fuzzer) add_subdirectory(bad-sample) add_subdirectory(test-sample) +add_subdirectory(windows-emulator-test) diff --git a/src/test-sample/test.cpp b/src/test-sample/test.cpp index f38350f9..14fe5a47 100644 --- a/src/test-sample/test.cpp +++ b/src/test-sample/test.cpp @@ -87,12 +87,12 @@ bool test_io() return text == buffer; } -#define RUN_TEST(func, name) \ -{ \ +#define RUN_TEST(func, name) \ +{ \ printf("Running test '" name "': "); \ - const auto res = func(); \ - valid &= res; \ - puts(res ? "Sucess" : "Fail"); \ + const auto res = func(); \ + valid &= res; \ + puts(res ? "Sucess" : "Fail"); \ } int main(int /*argc*/, const char* /*argv*/[]) diff --git a/src/windows-emulator-test/CMakeLists.txt b/src/windows-emulator-test/CMakeLists.txt new file mode 100644 index 00000000..6f2d8e4e --- /dev/null +++ b/src/windows-emulator-test/CMakeLists.txt @@ -0,0 +1,19 @@ +file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS + *.cpp + *.hpp + *.rc +) + +list(SORT SRC_FILES) + +add_executable(windows-emulator-test ${SRC_FILES}) + +momo_assign_source_group(${SRC_FILES}) + +target_link_libraries(windows-emulator-test PRIVATE + gtest + common + windows-emulator +) + +add_dependencies(windows-emulator-test test-sample) \ No newline at end of file diff --git a/src/windows-emulator-test/emulation_test.cpp b/src/windows-emulator-test/emulation_test.cpp new file mode 100644 index 00000000..3cf9931e --- /dev/null +++ b/src/windows-emulator-test/emulation_test.cpp @@ -0,0 +1,27 @@ +#include +#include + + +namespace test +{ + TEST(EmulationTest, BasicEmulationWorks) + { + windows_emulator emu{"./test-sample.exe"}; + emu.logger.disable_output(true); + emu.start(); + + ASSERT_TRUE(emu.process().exit_status.has_value()); + ASSERT_EQ(*emu.process().exit_status, 0); + } + + TEST(EmulationTest, CountedEmulationWorks) + { + constexpr auto count = 123; + + windows_emulator emu{ "./test-sample.exe" }; + emu.logger.disable_output(true); + emu.start({}, count); + + ASSERT_EQ(emu.process().executed_instructions, count); + } +} diff --git a/src/windows-emulator-test/main.cpp b/src/windows-emulator-test/main.cpp new file mode 100644 index 00000000..0194ab6e --- /dev/null +++ b/src/windows-emulator-test/main.cpp @@ -0,0 +1,7 @@ +#include + +int main(int argc, char* argv[]) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/src/windows-emulator-test/serialization_test.cpp b/src/windows-emulator-test/serialization_test.cpp new file mode 100644 index 00000000..6a3c14fb --- /dev/null +++ b/src/windows-emulator-test/serialization_test.cpp @@ -0,0 +1,33 @@ +#include +#include + + +namespace test +{ + TEST(SerializationTest, BasicSerializationWorks) + { + windows_emulator emu{"./test-sample.exe"}; + emu.logger.disable_output(true); + emu.start({}, 100); + + utils::buffer_serializer serializer{}; + emu.serialize(serializer); + + utils::buffer_deserializer deserializer{serializer.get_buffer()}; + + windows_emulator new_emu{}; + new_emu.logger.disable_output(true); + new_emu.deserialize(deserializer); + + new_emu.start(); + emu.start(); + + utils::buffer_serializer serializer1{}; + utils::buffer_serializer serializer2{}; + + emu.serialize(serializer1); + new_emu.serialize(serializer2); + + ASSERT_EQ(serializer1.get_buffer(), serializer2.get_buffer()); + } +} diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 664e5d70..130f24c8 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -235,7 +235,7 @@ public: std::wstring name{}; - std::optional exit_status{}; + std::optional exit_status{}; std::optional await_object{}; bool waiting_for_alert{false}; bool alerted{false}; @@ -353,6 +353,7 @@ struct process_context uint64_t previous_ip{0}; std::optional exception_rip{}; + std::optional exit_status{}; emulator_allocator base_allocator; @@ -390,6 +391,7 @@ struct process_context buffer.write(this->current_ip); buffer.write(this->previous_ip); buffer.write_optional(this->exception_rip); + buffer.write_optional(this->exit_status); buffer.write(this->base_allocator); buffer.write(this->peb); buffer.write(this->process_params); @@ -424,6 +426,7 @@ struct process_context buffer.read(this->current_ip); buffer.read(this->previous_ip); buffer.read_optional(this->exception_rip); + buffer.read_optional(this->exit_status); buffer.read(this->base_allocator); buffer.read(this->peb); buffer.read(this->process_params); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 4cce1844..af214467 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -1596,15 +1596,24 @@ namespace } NTSTATUS handle_NtTerminateProcess(const syscall_context& c, const uint64_t process_handle, - NTSTATUS /*exit_status*/) + NTSTATUS exit_status) { if (process_handle == 0) { + for (auto& t : c.proc.threads) + { + if (&t.second != c.proc.active_thread) + { + t.second.exit_status = exit_status; + } + } + return STATUS_SUCCESS; } if (process_handle == ~0ULL) { + c.proc.exit_status = exit_status; c.emu.stop(); return STATUS_SUCCESS; } @@ -2126,16 +2135,8 @@ namespace return STATUS_SUCCESS; } - NTSTATUS handle_NtAlertThreadByThreadIdEx(const syscall_context& c, const uint64_t thread_id, - const emulator_object lock) + NTSTATUS handle_NtAlertThreadByThreadId(const syscall_context& c, const uint64_t thread_id) { - if (lock.value()) - { - puts("NtAlertThreadByThreadIdEx with lock not supported yet!"); - //c.emu.stop(); - //return STATUS_NOT_SUPPORTED; - } - for (auto& t : c.proc.threads) { if (t.second.id == thread_id) @@ -2148,6 +2149,19 @@ namespace return STATUS_INVALID_HANDLE; } + NTSTATUS handle_NtAlertThreadByThreadIdEx(const syscall_context& c, const uint64_t thread_id, + const emulator_object lock) + { + if (lock.value()) + { + puts("NtAlertThreadByThreadIdEx with lock not supported yet!"); + //c.emu.stop(); + //return STATUS_NOT_SUPPORTED; + } + + return handle_NtAlertThreadByThreadId(c, thread_id); + } + NTSTATUS handle_NtWaitForAlertByThreadId(const syscall_context& c, const uint64_t, const emulator_object timeout) { @@ -2247,6 +2261,7 @@ void syscall_dispatcher::add_handlers(std::unordered_mapexit_status.has_value()) + { + return false; + } + if (this->waiting_for_alert) { if (this->alerted) diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index b72cb58e..6651d2c0 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -1,4 +1,6 @@ #pragma once +#include "std_include.hpp" + #include #include "syscall_dispatcher.hpp"