Prepare unittest support

This commit is contained in:
momo5502
2024-10-25 17:04:45 +02:00
parent 2c9718ce3f
commit a3a95ec829
14 changed files with 139 additions and 18 deletions

3
.gitmodules vendored
View File

@@ -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

3
deps/CMakeLists.txt vendored
View File

@@ -12,4 +12,5 @@ target_include_directories(reflect INTERFACE
##########################################
include(mini-gdbstub.cmake)
include(mini-gdbstub.cmake)
include(googletest.cmake)

1
deps/googletest vendored Submodule

Submodule deps/googletest added at df1544bcee

4
deps/googletest.cmake vendored Normal file
View File

@@ -0,0 +1,4 @@
option(BUILD_GMOCK OFF)
option(INSTALL_GTEST OFF)
add_subdirectory(googletest)

View File

@@ -7,3 +7,4 @@ add_subdirectory(fuzzing-engine)
add_subdirectory(fuzzer)
add_subdirectory(bad-sample)
add_subdirectory(test-sample)
add_subdirectory(windows-emulator-test)

View File

@@ -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*/[])

View File

@@ -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)

View File

@@ -0,0 +1,27 @@
#include <gtest/gtest.h>
#include <windows_emulator.hpp>
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);
}
}

View File

@@ -0,0 +1,7 @@
#include <gtest/gtest.h>
int main(int argc, char* argv[])
{
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,33 @@
#include <gtest/gtest.h>
#include <windows_emulator.hpp>
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());
}
}

View File

@@ -235,7 +235,7 @@ public:
std::wstring name{};
std::optional<uint32_t> exit_status{};
std::optional<NTSTATUS> exit_status{};
std::optional<handle> await_object{};
bool waiting_for_alert{false};
bool alerted{false};
@@ -353,6 +353,7 @@ struct process_context
uint64_t previous_ip{0};
std::optional<uint64_t> exception_rip{};
std::optional<NTSTATUS> 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);

View File

@@ -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<RTL_SRWLOCK> 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<RTL_SRWLOCK> 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<LARGE_INTEGER> timeout)
{
@@ -2247,6 +2261,7 @@ void syscall_dispatcher::add_handlers(std::unordered_map<std::string, syscall_ha
add_handler(NtDelayExecution);
add_handler(NtWaitForAlertByThreadId);
add_handler(NtAlertThreadByThreadIdEx);
add_handler(NtAlertThreadByThreadId);
add_handler(NtReadFile);
add_handler(NtSetInformationFile);
add_handler(NtUserRegisterWindowMessage);

View File

@@ -425,7 +425,7 @@ namespace
bool switch_to_thread(const logger& logger, x64_emulator& emu, process_context& context, emulator_thread& thread)
{
if (thread.exit_status.has_value() || !thread.is_thread_ready(context))
if (!thread.is_thread_ready(context))
{
return false;
}
@@ -584,6 +584,11 @@ void emulator_thread::mark_as_ready(const NTSTATUS status)
bool emulator_thread::is_thread_ready(process_context& context)
{
if(this->exit_status.has_value())
{
return false;
}
if (this->waiting_for_alert)
{
if (this->alerted)

View File

@@ -1,4 +1,6 @@
#pragma once
#include "std_include.hpp"
#include <x64_emulator.hpp>
#include "syscall_dispatcher.hpp"