diff --git a/src/sample/main.cpp b/src/sample/main.cpp index d4d52a2..1d5e932 100644 --- a/src/sample/main.cpp +++ b/src/sample/main.cpp @@ -34,19 +34,8 @@ namespace }); } - - void run() + void run_emulation(windows_emulator& win_emu) { - windows_emulator win_emu { - R"(C:\Users\mauri\source\repos\ConsoleApplication6\x64\Release\ConsoleApplication6.exe)", - { - L"Hello", - L"World", - } - }; - - watch_system_objects(win_emu); - try { if (use_gdb) @@ -69,6 +58,52 @@ namespace printf("Emulation done.\n"); } + + void run() + { + windows_emulator win_emu{ + R"(C:\Users\mauri\Desktop\Desktop\qiling-sample\lul.exe)", + { + L"Hello", + L"World", + } + }; + + watch_system_objects(win_emu); + + + const auto& exe = *win_emu.process().executable; + + const auto text_start = exe.image_base + 0x1000; + const auto text_end = exe.image_base + 0x52000; + const auto scan_size = 0x1000; + + win_emu.emu().hook_memory_read(text_start, scan_size, [&](uint64_t address, size_t, uint64_t) + { + const auto rip = win_emu.emu().read_instruction_pointer(); + if (rip >= text_start && rip < text_end) + { + win_emu.logger.print(color::green, "Reading from executable .text: 0x%llX at 0x%llX\n", address, rip); + } + }); + + win_emu.add_syscall_hook([&] + { + const auto rip = win_emu.emu().read_instruction_pointer(); + if (rip >= text_start && rip < text_end) + { + const auto syscall_id = win_emu.emu().reg(x64_register::eax); + const auto syscall_name = win_emu.dispatcher().get_syscall_name(syscall_id); + + win_emu.logger.print(color::blue, "Executing inline syscall: %s (0x%X) at 0x%llX\n", syscall_name.c_str(), + syscall_id, rip); + } + + return instruction_hook_continuation::run_instruction; + }); + + run_emulation(win_emu); + } } int main(int /*argc*/, char** /*argv*/) diff --git a/src/sample/object_watching.hpp b/src/sample/object_watching.hpp index db2bfac..44b40c7 100644 --- a/src/sample/object_watching.hpp +++ b/src/sample/object_watching.hpp @@ -13,8 +13,9 @@ emulator_hook* watch_object(windows_emulator& emu, emulator_object object) const auto rip = emu.emu().read_instruction_pointer(); const auto offset = address - object.value(); - printf("%s: %llX (%s) at %llX (%s)\n", i.get_type_name().c_str(), offset, - i.get_member_name(offset).c_str(), rip, - emu.process().module_manager.find_name(rip)); + emu.logger.log("Object access: %s - %llX (%s) at %llX (%s)\n", i.get_type_name().c_str(), + offset, + i.get_member_name(offset).c_str(), rip, + emu.process().module_manager.find_name(rip)); }); } diff --git a/src/windows_emulator/logger.cpp b/src/windows_emulator/logger.cpp new file mode 100644 index 0000000..481d6f5 --- /dev/null +++ b/src/windows_emulator/logger.cpp @@ -0,0 +1,94 @@ +#include "std_include.hpp" +#include "logger.hpp" + +#include + +namespace +{ +#ifdef _WIN32 +#define COLOR(win, posix) win + using color_type = WORD; +#else +#define COLOR(win, posix) posix + using color_type = const char*; +#endif + + color_type get_reset_color() + { + return COLOR(7, "\033[0m"); + } + + color_type get_color_type(const color c) + { + using enum color; + + switch (c) + { + case black: return COLOR(0x8, "\033[0;90m"); + case red: return COLOR(0xC, "\033[0;91m"); + case green: return COLOR(0xA, "\033[0;92m"); + case yellow: return COLOR(0xE, "\033[0;93m"); + case blue: return COLOR(0x9, "\033[0;94m"); + case cyan: return COLOR(0xB, "\033[0;96m"); + case pink: return COLOR(0xD, "\033[0;95m"); + case white: return COLOR(0xF, "\033[0;97m"); + case gray: + default: return get_reset_color(); + } + } + +#ifdef _WIN32 + HANDLE get_console_handle() + { + return GetStdHandle(STD_OUTPUT_HANDLE); + } +#endif + + void set_color(const color_type color) + { +#ifdef _WIN32 + SetConsoleTextAttribute(get_console_handle(), color); +#else + printf("%s", color); +#endif + } + + void reset_color() + { + (void)fflush(stdout); + set_color(get_reset_color()); + (void)fflush(stdout); + } + + std::string_view format(va_list* ap, const char* message) + { + thread_local char buffer[0x1000]; + +#ifdef _WIN32 + const int count = _vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer), message, *ap); +#else + const int count = vsnprintf(buffer, sizeof(buffer), message, *ap); +#endif + + if (count < 0) return {}; + return {buffer, static_cast(count)}; + } + + void print_colored(const std::string_view& line, const color_type base_color) + { + const auto _ = utils::finally(&reset_color); + set_color(base_color); + (void)fwrite(line.data(), 1, line.size(), stdout); + } +} + +void logger::print(const color c, const char* message, ...) const +{ + va_list ap; + va_start(ap, message); + + const auto data = format(&ap, message); + print_colored(data, get_color_type(c)); + + va_end(ap); +} diff --git a/src/windows_emulator/logger.hpp b/src/windows_emulator/logger.hpp new file mode 100644 index 0000000..3cbab67 --- /dev/null +++ b/src/windows_emulator/logger.hpp @@ -0,0 +1,50 @@ +#pragma once + +enum class color +{ + black, + red, + green, + yellow, + blue, + cyan, + pink, + white, + gray, +}; + +class logger +{ +public: + void print(color c, const char* message, ...) const; + + template + void info(const char* message, Args... args) + { + this->print(color::cyan, message, args...); + } + + template + void warn(const char* message, Args... args) + { + this->print(color::yellow, message, args...); + } + + template + void error(const char* message, Args... args) + { + this->print(color::red, message, args...); + } + + template + void success(const char* message, Args... args) + { + this->print(color::green, message, args...); + } + + template + void log(const char* message, Args... args) + { + this->print(color::gray, message, args...); + } +}; diff --git a/src/windows_emulator/syscalls.hpp b/src/windows_emulator/syscalls.hpp index b8b2a3e..466361d 100644 --- a/src/windows_emulator/syscalls.hpp +++ b/src/windows_emulator/syscalls.hpp @@ -26,6 +26,11 @@ class syscall_dispatcher void setup(const exported_symbols& ntdll_exports, const exported_symbols& win32u_exports); + std::string get_syscall_name(const uint64_t id) + { + return this->handlers_.at(id).name; + } + private: std::unordered_map handlers_{}; diff --git a/src/windows_emulator/windows_emulator.cpp b/src/windows_emulator/windows_emulator.cpp index e0d88d0..09b1a21 100644 --- a/src/windows_emulator/windows_emulator.cpp +++ b/src/windows_emulator/windows_emulator.cpp @@ -535,6 +535,14 @@ void windows_emulator::setup_hooks() { this->emu().hook_instruction(x64_hookable_instructions::syscall, [&] { + for (const auto& hook : this->syscall_hooks_) + { + if (hook() == instruction_hook_continuation::skip_instruction) + { + return instruction_hook_continuation::skip_instruction; + } + } + this->dispatcher_.dispatch(this->emu(), this->process()); return instruction_hook_continuation::skip_instruction; }); diff --git a/src/windows_emulator/windows_emulator.hpp b/src/windows_emulator/windows_emulator.hpp index 0b79ba6..3505374 100644 --- a/src/windows_emulator/windows_emulator.hpp +++ b/src/windows_emulator/windows_emulator.hpp @@ -3,6 +3,7 @@ #include "syscalls.hpp" #include "process_context.hpp" +#include "logger.hpp" std::unique_ptr create_default_x64_emulator(); @@ -38,6 +39,16 @@ class windows_emulator return this->process_; } + syscall_dispatcher& dispatcher() + { + return this->dispatcher_; + } + + const syscall_dispatcher& dispatcher() const + { + return this->dispatcher_; + } + void serialize(utils::buffer_serializer& buffer) const; void deserialize(utils::buffer_deserializer& buffer); @@ -49,10 +60,19 @@ class windows_emulator this->verbose_ = verbose; } + void add_syscall_hook(instruction_hook_callback callback) + { + this->syscall_hooks_.push_back(std::move(callback)); + } + + logger logger{}; + private: bool verbose_{false}; std::unique_ptr emu_{}; + std::vector syscall_hooks_{}; + process_context process_; syscall_dispatcher dispatcher_;