diff --git a/src/analyzer/main.cpp b/src/analyzer/main.cpp index e647bc6b..ca39a6fb 100644 --- a/src/analyzer/main.cpp +++ b/src/analyzer/main.cpp @@ -4,9 +4,8 @@ #include #include "object_watching.hpp" +#include "snapshot.hpp" -#include -#include #include #include @@ -26,67 +25,6 @@ namespace std::unordered_map path_mappings{}; }; - std::vector build_dump_data(const windows_emulator& win_emu) - { - utils::buffer_serializer serializer{}; - win_emu.serialize(serializer); - - auto compressed_data = utils::compression::zlib::compress(serializer.get_buffer()); - - // TODO: Add version - compressed_data.insert(compressed_data.begin(), {'E', 'D', 'M', 'P'}); - - return compressed_data; - } - - std::string get_main_executable_name(const windows_emulator& win_emu) - { - const auto* exe = win_emu.mod_manager.executable; - if (exe) - { - return std::filesystem::path(exe->name).stem().string(); - } - - return "process"; - } - - void generate_dump(const windows_emulator& win_emu) - { - std::filesystem::path dump = get_main_executable_name(win_emu) + "-" + std::to_string(time(nullptr)) + ".edmp"; - win_emu.log.log("Writing to %s...\n", dump.string().c_str()); - - const auto data = build_dump_data(win_emu); - utils::io::write_file(dump, data); - } - - void load_dump_data(windows_emulator& win_emu, const std::span data) - { - if (data.size() < 4 || memcmp(data.data(), "EDMP", 4) != 0) - { - throw std::runtime_error("Invalid dump"); - } - - const auto plain_data = utils::compression::zlib::decompress(data.subspan(4)); - if (plain_data.empty()) - { - throw std::runtime_error("Failed to decompress dump"); - } - - utils::buffer_deserializer deserializer{plain_data, true}; - win_emu.deserialize(deserializer); - } - - void load_dump(windows_emulator& win_emu, const std::filesystem::path& dump) - { - std::vector data{}; - if (!utils::io::read_file(dump, &data)) - { - throw std::runtime_error("Failed to read dump file: " + dump.string()); - } - - load_dump_data(win_emu, data); - } - void watch_system_objects(windows_emulator& win_emu, const std::set>& modules, const bool cache_logging) { @@ -119,6 +57,23 @@ namespace #endif } + bool read_yes_no_answer() + { + while (true) + { + const auto chr = static_cast(getchar()); + if (chr == 'y') + { + return true; + } + + if (chr == 'n') + { + return false; + } + } + } + bool run_emulation(windows_emulator& win_emu, const analysis_options& options) { std::atomic_uint32_t signals_received{0}; @@ -153,20 +108,12 @@ namespace if (signals_received > 0) { - win_emu.log.log("Do you want to create a dump? (y/n)\n"); + win_emu.log.log("Do you want to create a snapshot? (y/n)\n"); + const auto write_snapshot = read_yes_no_answer(); - bool write_dump = false; - - char res{}; - while (res != 'n' && res != 'y') + if (write_snapshot) { - res = static_cast(getchar()); - write_dump = res == 'y'; - } - - if (write_dump) - { - generate_dump(win_emu); + snapshot::write_emulator_snapshot(win_emu); } } } @@ -254,7 +201,7 @@ namespace } auto win_emu = create_empty_emulator(options); - load_dump(*win_emu, options.dump); + snapshot::load_emulator_snapshot(*win_emu, options.dump); return win_emu; } diff --git a/src/analyzer/snapshot.cpp b/src/analyzer/snapshot.cpp new file mode 100644 index 00000000..2b04848b --- /dev/null +++ b/src/analyzer/snapshot.cpp @@ -0,0 +1,123 @@ +#include "snapshot.hpp" + +#include +#include + +namespace snapshot +{ + namespace + { + struct snapshot_header + { + // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) + char magic[4] = {'S', 'N', 'A', 'P'}; + uint32_t version{1}; + }; + + static_assert(sizeof(snapshot_header) == 8); + + std::span validate_header(const std::span snapshot) + { + snapshot_header default_header; + snapshot_header header{}; + + if (snapshot.size() < sizeof(header)) + { + throw std::runtime_error("Snapshot is too small"); + } + + memcpy(&header, snapshot.data(), sizeof(header)); + + if (memcmp(default_header.magic, header.magic, sizeof(header.magic)) != 0) + { + throw std::runtime_error("Invalid snapshot"); + } + + if (default_header.version != header.version) + { + throw std::runtime_error("Unsupported snapshot version: " + std::to_string(header.version) + + "(needed: " + std::to_string(default_header.version) + ")"); + } + + return snapshot.subspan(sizeof(header)); + } + + std::vector get_compressed_emulator_state(const windows_emulator& win_emu) + { + utils::buffer_serializer serializer{}; + win_emu.serialize(serializer); + + return utils::compression::zlib::compress(serializer.get_buffer()); + } + + std::vector get_decompressed_emulator_state(const std::span snapshot) + { + const auto data = validate_header(snapshot); + return utils::compression::zlib::decompress(data); + } + + std::string get_main_executable_name(const windows_emulator& win_emu) + { + const auto* exe = win_emu.mod_manager.executable; + if (exe) + { + return std::filesystem::path(exe->name).stem().string(); + } + + return "process"; + } + } + + std::vector create_emulator_snapshot(const windows_emulator& win_emu) + { + const auto state = get_compressed_emulator_state(win_emu); + + snapshot_header header{}; + std::span header_span(reinterpret_cast(&header), sizeof(header)); + + std::vector snapshot{}; + snapshot.reserve(header_span.size() + state.size()); + snapshot.assign(header_span.begin(), header_span.end()); + snapshot.insert(snapshot.end(), state.begin(), state.end()); + + return snapshot; + } + + std::filesystem::path write_emulator_snapshot(const windows_emulator& win_emu, const bool log) + { + std::filesystem::path snapshot_file = + get_main_executable_name(win_emu) + "-" + std::to_string(time(nullptr)) + ".snap"; + + if (log) + { + win_emu.log.log("Writing snapshot to %s...\n", snapshot_file.string().c_str()); + } + + const auto snapshot = create_emulator_snapshot(win_emu); + if (!utils::io::write_file(snapshot_file, snapshot)) + { + throw std::runtime_error("Failed to write snapshot!"); + } + + return snapshot_file; + } + + void load_emulator_snapshot(windows_emulator& win_emu, const std::span snapshot) + { + const auto data = get_decompressed_emulator_state(snapshot); + + utils::buffer_deserializer deserializer{data}; + win_emu.deserialize(deserializer); + } + + void load_emulator_snapshot(windows_emulator& win_emu, const std::filesystem::path& snapshot_file) + { + std::vector data{}; + if (!utils::io::read_file(snapshot_file, &data)) + { + throw std::runtime_error("Failed to read snapshot file: " + snapshot_file.string()); + } + + load_emulator_snapshot(win_emu, data); + } +} diff --git a/src/analyzer/snapshot.hpp b/src/analyzer/snapshot.hpp new file mode 100644 index 00000000..8b5fbba4 --- /dev/null +++ b/src/analyzer/snapshot.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +namespace snapshot +{ + std::vector create_emulator_snapshot(const windows_emulator& win_emu); + std::filesystem::path write_emulator_snapshot(const windows_emulator& win_emu, bool log = true); + + void load_emulator_snapshot(windows_emulator& win_emu, std::span snapshot); + void load_emulator_snapshot(windows_emulator& win_emu, const std::filesystem::path& snapshot_file); +} diff --git a/src/common/utils/buffer_accessor.hpp b/src/common/utils/buffer_accessor.hpp index 67646c29..73d0ca2e 100644 --- a/src/common/utils/buffer_accessor.hpp +++ b/src/common/utils/buffer_accessor.hpp @@ -5,12 +5,13 @@ namespace utils { - template - requires(std::is_trivially_copyable_v && std::is_same_v>) + template + requires(std::is_trivially_copyable_v && (std::is_same_v> || + std::is_same_v>)) class safe_object_accessor { public: - safe_object_accessor(const std::span buffer, const size_t offset) + safe_object_accessor(const std::span buffer, const size_t offset) : buffer_(buffer), offset_(offset) { @@ -21,25 +22,25 @@ namespace utils * are respected ****************************************************************************/ - T get(const size_t element_index = 0) const + Type get(const size_t element_index = 0) const { - T value{}; + Type value{}; memcpy(&value, get_valid_pointer(element_index), size); return value; } - void set(const T value, const size_t element_index = 0) const + void set(const Type value, const size_t element_index = 0) const { memcpy(get_valid_pointer(element_index), &value, size); } private: - static constexpr auto size = sizeof(T); + static constexpr auto size = sizeof(Type); - std::span buffer_{}; + std::span buffer_{}; size_t offset_{}; - S* get_valid_pointer(const size_t element_index) const + SpanElement* get_valid_pointer(const size_t element_index) const { const auto start_offset = offset_ + (size * element_index); const auto end_offset = start_offset + size; @@ -52,29 +53,31 @@ namespace utils } }; - template - requires(std::is_same_v>) + template + requires(std::is_same_v> || + std::is_same_v>) class safe_buffer_accessor { public: - safe_buffer_accessor(const std::span buffer) + safe_buffer_accessor(const std::span buffer) : buffer_(buffer) { } - template - safe_buffer_accessor(const safe_buffer_accessor& obj) + template + requires(std::is_same_v, std::remove_cv_t>) + safe_buffer_accessor(const safe_buffer_accessor& obj) : buffer_(obj.get_buffer()) { } - template - safe_object_accessor as(const size_t offset) const + template + safe_object_accessor as(const size_t offset) const { return {this->buffer_, offset}; } - T* get_pointer_for_range(const size_t offset, const size_t size) const + SpanElement* get_pointer_for_range(const size_t offset, const size_t size) const { this->validate(offset, size); return this->buffer_.data() + offset; @@ -89,11 +92,11 @@ namespace utils } } - template - std::basic_string as_string(const size_t offset) const + template + std::basic_string as_string(const size_t offset) const { - safe_object_accessor string_accessor{this->buffer_, offset}; - std::basic_string result{}; + safe_object_accessor string_accessor{this->buffer_, offset}; + std::basic_string result{}; while (true) { @@ -107,12 +110,12 @@ namespace utils } } - std::span get_buffer() const + std::span get_buffer() const { return this->buffer_; } private: - const std::span buffer_{}; + const std::span buffer_{}; }; } diff --git a/src/common/utils/compression.cpp b/src/common/utils/compression.cpp index 17c6da8c..3f6465b1 100644 --- a/src/common/utils/compression.cpp +++ b/src/common/utils/compression.cpp @@ -2,6 +2,7 @@ #include #include +#include #include namespace utils::compression @@ -48,16 +49,16 @@ namespace utils::compression }; } - std::vector decompress(const std::span data) + std::vector decompress(const std::span data) { - std::vector buffer{}; + std::vector buffer{}; zlib_stream stream_container{}; if (!stream_container.is_valid()) { return {}; } - static thread_local std::array dest{}; + static thread_local std::array dest{}; auto& stream = stream_container.get(); stream.avail_in = static_cast(data.size()); @@ -66,7 +67,7 @@ namespace utils::compression do { stream.avail_out = static_cast(dest.size()); - stream.next_out = dest.data(); + stream.next_out = reinterpret_cast(dest.data()); const auto ret = inflate(&stream, Z_FINISH); if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_STREAM_END) @@ -80,14 +81,9 @@ namespace utils::compression return buffer; } - std::vector decompress(const std::span& data) + std::vector compress(const std::span data) { - return decompress(std::span(reinterpret_cast(data.data()), data.size())); - } - - std::vector compress(const std::span data) - { - std::vector result{}; + std::vector result{}; auto length = compressBound(static_cast(data.size())); result.resize(length); @@ -100,10 +96,5 @@ namespace utils::compression result.resize(length); return result; } - - std::vector compress(const std::span data) - { - return compress(std::span(reinterpret_cast(data.data()), data.size())); - } } } diff --git a/src/common/utils/compression.hpp b/src/common/utils/compression.hpp index 70ded9f7..cc20810a 100644 --- a/src/common/utils/compression.hpp +++ b/src/common/utils/compression.hpp @@ -2,16 +2,13 @@ #include #include -#include namespace utils::compression { namespace zlib { constexpr unsigned int ZCHUNK_SIZE = 16384u; - std::vector compress(std::span data); - std::vector compress(std::span data); - std::vector decompress(std::span data); - std::vector decompress(std::span data); + std::vector compress(std::span data); + std::vector decompress(std::span data); } -}; +} diff --git a/src/common/utils/io.cpp b/src/common/utils/io.cpp index a43190f8..5c96a607 100644 --- a/src/common/utils/io.cpp +++ b/src/common/utils/io.cpp @@ -21,7 +21,7 @@ namespace utils::io return std::ifstream(file).good(); } - bool write_file(const std::filesystem::path& file, const std::span data, const bool append) + bool write_file(const std::filesystem::path& file, const std::span data, const bool append) { if (file.has_parent_path()) { @@ -41,34 +41,42 @@ namespace utils::io return false; } - bool write_file(const std::filesystem::path& file, const std::span data, const bool append) + std::vector read_file(const std::filesystem::path& file) { - return write_file(file, std::span(reinterpret_cast(data.data()), data.size()), append); - } - - std::vector read_file(const std::filesystem::path& file) - { - std::vector data; + std::vector data{}; read_file(file, &data); return data; } - bool read_file(const std::filesystem::path& file, std::vector* data) + bool read_file(const std::filesystem::path& file, std::vector* data) { if (!data) { return false; } - data->clear(); + *data = {}; - std::ifstream stream(file, std::ios::binary); - if (!stream) + std::ifstream file_stream(file, std::ios::binary); + if (!file_stream) { return false; } - *data = std::vector{(std::istreambuf_iterator(stream)), std::istreambuf_iterator()}; + std::vector temp_buffer(0x1000); + + while (file_stream) + { + file_stream.read(temp_buffer.data(), static_cast(temp_buffer.size())); + const auto bytes_read = file_stream.gcount(); + + if (bytes_read > 0) + { + const auto* buffer = reinterpret_cast(temp_buffer.data()); + data->insert(data->end(), buffer, buffer + bytes_read); + } + } + return true; } diff --git a/src/common/utils/io.hpp b/src/common/utils/io.hpp index 69bdb975..3e553520 100644 --- a/src/common/utils/io.hpp +++ b/src/common/utils/io.hpp @@ -9,10 +9,9 @@ namespace utils::io bool remove_file(const std::filesystem::path& file); bool move_file(const std::filesystem::path& src, const std::filesystem::path& target); bool file_exists(const std::filesystem::path& file); - bool write_file(const std::filesystem::path& file, std::span data, bool append = false); bool write_file(const std::filesystem::path& file, std::span data, bool append = false); - bool read_file(const std::filesystem::path& file, std::vector* data); - std::vector read_file(const std::filesystem::path& file); + bool read_file(const std::filesystem::path& file, std::vector* data); + std::vector read_file(const std::filesystem::path& file); size_t file_size(const std::filesystem::path& file); bool create_directory(const std::filesystem::path& directory); bool directory_exists(const std::filesystem::path& directory); diff --git a/src/emulator/serialization.hpp b/src/emulator/serialization.hpp index ae84ed9a..981d3b51 100644 --- a/src/emulator/serialization.hpp +++ b/src/emulator/serialization.hpp @@ -72,23 +72,20 @@ namespace utils void write(const void* buffer, const size_t length) { -#ifndef NDEBUG - const uint64_t old_size = this->buffer_.size(); -#endif + const auto old_size_remainder = static_cast(length); + constexpr auto check_size = sizeof(old_size_remainder); if (this->break_offset_ && this->buffer_.size() <= *this->break_offset_ && - this->buffer_.size() + length > *this->break_offset_) + this->buffer_.size() + length + check_size > *this->break_offset_) { throw std::runtime_error("Break offset reached!"); } + const auto* security_buffer = reinterpret_cast(&old_size_remainder); + this->buffer_.insert(this->buffer_.end(), security_buffer, security_buffer + check_size); + const auto* byte_buffer = static_cast(buffer); this->buffer_.insert(this->buffer_.end(), byte_buffer, byte_buffer + length); - -#ifndef NDEBUG - const auto* security_buffer = reinterpret_cast(&old_size); - this->buffer_.insert(this->buffer_.end(), security_buffer, security_buffer + sizeof(old_size)); -#endif } void write(const buffer_serializer& object) @@ -256,60 +253,43 @@ namespace utils { public: template - buffer_deserializer(const std::span buffer, const bool no_debugging = false) - : no_debugging_(no_debugging), - buffer_(reinterpret_cast(buffer.data()), buffer.size() * sizeof(T)) + buffer_deserializer(const std::span buffer) + : buffer_(reinterpret_cast(buffer.data()), buffer.size() * sizeof(T)) { static_assert(std::is_trivially_copyable_v, "Type must be trivially copyable"); } template - buffer_deserializer(const std::vector& buffer, const bool no_debugging = false) - : buffer_deserializer(std::span(buffer), no_debugging) + buffer_deserializer(const std::vector& buffer) + : buffer_deserializer(std::span(buffer)) { } - buffer_deserializer(const buffer_serializer& serializer, const bool no_debugging = false) - : buffer_deserializer(serializer.get_buffer(), no_debugging) + buffer_deserializer(const buffer_serializer& serializer) + : buffer_deserializer(serializer.get_buffer()) { } std::span read_data(const size_t length) { -#ifndef NDEBUG - const uint64_t real_old_size = this->offset_; - (void)real_old_size; -#endif + const auto length_rest = static_cast(length); + constexpr auto check_size = sizeof(length_rest); - if (this->offset_ + length > this->buffer_.size()) + if (this->offset_ + (length + check_size) > this->buffer_.size()) { throw std::runtime_error("Out of bounds read from byte buffer"); } + if (static_cast(this->buffer_[this->offset_]) != length_rest) + { + throw std::runtime_error("Reading from serialized buffer mismatches written data!"); + } + + this->offset_ += check_size; + const std::span result(this->buffer_.data() + this->offset_, length); this->offset_ += length; - (void)this->no_debugging_; - -#ifndef NDEBUG - if (!this->no_debugging_) - { - uint64_t old_size{}; - if (this->offset_ + sizeof(old_size) > this->buffer_.size()) - { - throw std::runtime_error("Out of bounds read from byte buffer"); - } - - memcpy(&old_size, this->buffer_.data() + this->offset_, sizeof(old_size)); - if (old_size != real_old_size) - { - throw std::runtime_error("Reading from serialized buffer mismatches written data!"); - } - - this->offset_ += sizeof(old_size); - } -#endif - return result; } @@ -506,7 +486,6 @@ namespace utils } private: - bool no_debugging_{false}; size_t offset_{0}; std::span buffer_{}; std::unordered_map> factories_{}; diff --git a/src/tools/dump-apiset/dump-apiset.cpp b/src/tools/dump-apiset/dump-apiset.cpp index 5811a73b..548e0bec 100644 --- a/src/tools/dump-apiset/dump-apiset.cpp +++ b/src/tools/dump-apiset/dump-apiset.cpp @@ -35,8 +35,8 @@ int main() // print_apiset(apiSetMap); // Compress the API-SET binary blob - const auto* data_ptr = reinterpret_cast(api_set_map); - const std::vector buffer(data_ptr, data_ptr + api_set_map->Size); + const auto* data_ptr = reinterpret_cast(api_set_map); + const std::span buffer(data_ptr, data_ptr + api_set_map->Size); const auto compressed = utils::compression::zlib::compress(buffer); if (compressed.empty()) { diff --git a/src/windows-emulator/apiset/apiset.cpp b/src/windows-emulator/apiset/apiset.cpp index 6d6679b1..d0b32c7e 100644 --- a/src/windows-emulator/apiset/apiset.cpp +++ b/src/windows-emulator/apiset/apiset.cpp @@ -42,7 +42,7 @@ namespace apiset return static_cast(address - result_base); } - std::vector decompress_apiset(const std::vector& apiset) + std::vector decompress_apiset(const std::vector& apiset) { auto buffer = utils::compression::zlib::decompress(apiset); if (buffer.empty()) @@ -53,7 +53,7 @@ namespace apiset return buffer; } - std::vector obtain_data(const location location, const std::filesystem::path& root) + std::vector obtain_data(const location location, const std::filesystem::path& root) { switch (location) { @@ -61,7 +61,7 @@ namespace apiset case location::host: { const auto apiSetMap = reinterpret_cast(NtCurrentTeb64()->ProcessEnvironmentBlock->ApiSetMap); - const auto* dataPtr = reinterpret_cast(apiSetMap); + const auto* dataPtr = reinterpret_cast(apiSetMap); return {dataPtr, dataPtr + apiSetMap->Size}; } #else @@ -78,11 +78,13 @@ namespace apiset return decompress_apiset(apiset); } case location::default_windows_10: { - const std::vector apiset{apiset_w10, apiset_w10 + sizeof(apiset_w10)}; + const auto* byte_apiset = reinterpret_cast(apiset_w10); + const std::vector apiset{byte_apiset, byte_apiset + sizeof(apiset_w10)}; return decompress_apiset(apiset); } case location::default_windows_11: { - const std::vector apiset{apiset_w11, apiset_w11 + sizeof(apiset_w11)}; + const auto* byte_apiset = reinterpret_cast(apiset_w11); + const std::vector apiset{byte_apiset, byte_apiset + sizeof(apiset_w11)}; return decompress_apiset(apiset); } default: diff --git a/src/windows-emulator/apiset/apiset.hpp b/src/windows-emulator/apiset/apiset.hpp index d0097da1..55deda12 100644 --- a/src/windows-emulator/apiset/apiset.hpp +++ b/src/windows-emulator/apiset/apiset.hpp @@ -18,7 +18,7 @@ namespace apiset struct container { - std::vector data{}; + std::vector data{}; const API_SET_NAMESPACE& get() const { diff --git a/src/windows-emulator/module/module_mapping.cpp b/src/windows-emulator/module/module_mapping.cpp index 17cc4857..2e20e6e9 100644 --- a/src/windows-emulator/module/module_mapping.cpp +++ b/src/windows-emulator/module/module_mapping.cpp @@ -20,16 +20,16 @@ namespace return nt_headers_offset + (first_section_absolute - absolute_base); } - std::vector read_mapped_memory(const memory_manager& memory, const mapped_module& binary) + std::vector read_mapped_memory(const memory_manager& memory, const mapped_module& binary) { - std::vector mem{}; + std::vector mem{}; mem.resize(binary.size_of_image); memory.read_memory(binary.image_base, mem.data(), mem.size()); return mem; } - void collect_exports(mapped_module& binary, const utils::safe_buffer_accessor buffer, + void collect_exports(mapped_module& binary, const utils::safe_buffer_accessor buffer, const PEOptionalHeader_t& optional_header) { const auto& export_directory_entry = optional_header.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; @@ -70,7 +70,7 @@ namespace template requires(std::is_integral_v) - void apply_relocation(const utils::safe_buffer_accessor buffer, const uint64_t offset, + void apply_relocation(const utils::safe_buffer_accessor buffer, const uint64_t offset, const uint64_t delta) { const auto obj = buffer.as(offset); @@ -79,7 +79,7 @@ namespace obj.set(new_value); } - void apply_relocations(const mapped_module& binary, const utils::safe_buffer_accessor buffer, + void apply_relocations(const mapped_module& binary, const utils::safe_buffer_accessor buffer, const PEOptionalHeader_t& optional_header) { const auto delta = binary.image_base - optional_header.ImageBase; @@ -142,7 +142,7 @@ namespace } void map_sections(memory_manager& memory, mapped_module& binary, - const utils::safe_buffer_accessor buffer, + const utils::safe_buffer_accessor buffer, const PENTHeaders_t& nt_headers, const uint64_t nt_headers_offset) { const auto first_section_offset = get_first_section_offset(nt_headers, nt_headers_offset); @@ -196,7 +196,7 @@ namespace } } -mapped_module map_module_from_data(memory_manager& memory, const std::span data, +mapped_module map_module_from_data(memory_manager& memory, const std::span data, std::filesystem::path file) { mapped_module binary{}; @@ -241,7 +241,7 @@ mapped_module map_module_from_data(memory_manager& memory, const std::span mapped_buffer{mapped_memory}; + utils::safe_buffer_accessor mapped_buffer{mapped_memory}; apply_relocations(binary, mapped_buffer, optional_header); collect_exports(binary, mapped_buffer, optional_header); diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 256945d3..edd49c3f 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -791,7 +791,7 @@ namespace } uint64_t size = section_entry->maximum_size; - std::vector file_data{}; + std::vector file_data{}; if (!section_entry->file_name.empty()) {