mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-19 03:33:56 +00:00
Support for KnownDLLs and Some Refactoring
This commit is contained in:
@@ -6,6 +6,8 @@
|
||||
#include <fstream>
|
||||
#include <system_error>
|
||||
#include <variant>
|
||||
#include <array>
|
||||
#include "../utils/buffer_accessor.hpp"
|
||||
|
||||
// NOLINTBEGIN(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
|
||||
@@ -478,12 +480,75 @@ struct SECTION_IMAGE_INFORMATION
|
||||
|
||||
namespace winpe
|
||||
{
|
||||
struct pe_image_basic_info
|
||||
{
|
||||
uint64_t entry_point_rva{};
|
||||
uint64_t image_base{};
|
||||
uint64_t size_of_stack_reserve{};
|
||||
uint64_t size_of_stack_commit{};
|
||||
uint32_t size_of_code{};
|
||||
uint32_t loader_flags{};
|
||||
uint32_t checksum{};
|
||||
uint16_t machine{};
|
||||
uint16_t subsystem{};
|
||||
uint16_t subsystem_major_version{};
|
||||
uint16_t subsystem_minor_version{};
|
||||
uint16_t image_characteristics{};
|
||||
uint16_t dll_characteristics{};
|
||||
bool has_code{false};
|
||||
std::array<char, 7> _padding{};
|
||||
};
|
||||
|
||||
enum class pe_arch
|
||||
{
|
||||
pe32,
|
||||
pe64
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline uint64_t get_first_section_offset(const PENTHeaders_t<T>& nt_headers, const uint64_t nt_headers_offset)
|
||||
{
|
||||
const auto* nt_headers_addr = reinterpret_cast<const uint8_t*>(&nt_headers);
|
||||
const size_t optional_header_offset =
|
||||
reinterpret_cast<uintptr_t>(&(nt_headers.OptionalHeader)) - reinterpret_cast<uintptr_t>(&nt_headers);
|
||||
const size_t optional_header_size = nt_headers.FileHeader.SizeOfOptionalHeader;
|
||||
const auto* first_section_addr = nt_headers_addr + optional_header_offset + optional_header_size;
|
||||
|
||||
const auto first_section_absolute = reinterpret_cast<uint64_t>(first_section_addr);
|
||||
const auto absolute_base = reinterpret_cast<uint64_t>(&nt_headers);
|
||||
return nt_headers_offset + (first_section_absolute - absolute_base);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline PEDirectory_t2 get_data_directory_by_index(const PENTHeaders_t<T>& nt_headers, uint64_t directory_index)
|
||||
{
|
||||
return nt_headers.OptionalHeader.DataDirectory[directory_index];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
IMAGE_SECTION_HEADER get_section_header_by_rva(const utils::safe_buffer_accessor<const std::byte>& buffer, const PENTHeaders_t<T>& nt_headers,
|
||||
uint64_t nt_headers_offset, uint64_t rva)
|
||||
{
|
||||
IMAGE_SECTION_HEADER section_header = {};
|
||||
|
||||
auto next_section_offset = winpe::get_first_section_offset(nt_headers, nt_headers_offset);
|
||||
for (size_t i = 0; i < nt_headers.FileHeader.NumberOfSections; i++)
|
||||
{
|
||||
const auto section = buffer.as<IMAGE_SECTION_HEADER>(next_section_offset).get();
|
||||
auto section_va_start = section.VirtualAddress;
|
||||
auto section_va_end = section.VirtualAddress + section.Misc.VirtualSize;
|
||||
|
||||
if (section_va_start <= rva && rva <= section_va_end)
|
||||
{
|
||||
section_header = section;
|
||||
break;
|
||||
}
|
||||
|
||||
next_section_offset += sizeof(IMAGE_SECTION_HEADER);
|
||||
}
|
||||
|
||||
return section_header;
|
||||
}
|
||||
|
||||
inline std::variant<pe_arch, std::error_code> get_pe_arch(const std::filesystem::path& file)
|
||||
{
|
||||
@@ -591,6 +656,93 @@ namespace winpe
|
||||
return std::make_error_code(std::errc::executable_format_error);
|
||||
}
|
||||
|
||||
// Helper function to parse PE headers and extract image information
|
||||
template <typename T>
|
||||
inline bool parse_pe_headers(const std::vector<std::byte>& file_data, pe_image_basic_info& info)
|
||||
{
|
||||
if (file_data.size() < sizeof(PEDosHeader_t))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* dos_header = reinterpret_cast<const PEDosHeader_t*>(file_data.data());
|
||||
if (dos_header->e_magic != PEDosHeader_t::k_Magic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// First check if we can read up to the optional header magic
|
||||
if (file_data.size() < dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + sizeof(uint16_t))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the magic number from the optional header
|
||||
const auto* magic_ptr =
|
||||
reinterpret_cast<const uint16_t*>(file_data.data() + dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t));
|
||||
const uint16_t magic = *magic_ptr;
|
||||
|
||||
// Check if the magic matches the expected type
|
||||
constexpr uint16_t expected_magic = (sizeof(T) == sizeof(uint32_t))
|
||||
? static_cast<uint16_t>(PEOptionalHeader_t<std::uint32_t>::k_Magic)
|
||||
: static_cast<uint16_t>(PEOptionalHeader_t<std::uint64_t>::k_Magic);
|
||||
|
||||
if (magic != expected_magic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now check the full NT headers size
|
||||
if (file_data.size() < dos_header->e_lfanew + sizeof(PENTHeaders_t<T>))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* nt_headers = reinterpret_cast<const PENTHeaders_t<T>*>(file_data.data() + dos_header->e_lfanew);
|
||||
if (nt_headers->Signature != PENTHeaders_t<T>::k_Signature)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& file_header = nt_headers->FileHeader;
|
||||
const auto& optional_header = nt_headers->OptionalHeader;
|
||||
|
||||
// Extract information from headers
|
||||
info.machine = static_cast<uint16_t>(file_header.Machine);
|
||||
info.image_characteristics = file_header.Characteristics;
|
||||
|
||||
info.entry_point_rva = optional_header.AddressOfEntryPoint;
|
||||
info.image_base = optional_header.ImageBase;
|
||||
info.subsystem = optional_header.Subsystem;
|
||||
info.subsystem_major_version = optional_header.MajorSubsystemVersion;
|
||||
info.subsystem_minor_version = optional_header.MinorSubsystemVersion;
|
||||
info.dll_characteristics = optional_header.DllCharacteristics;
|
||||
info.size_of_stack_reserve = optional_header.SizeOfStackReserve;
|
||||
info.size_of_stack_commit = optional_header.SizeOfStackCommit;
|
||||
info.size_of_code = optional_header.SizeOfCode;
|
||||
info.loader_flags = optional_header.LoaderFlags;
|
||||
info.checksum = optional_header.CheckSum;
|
||||
|
||||
// Check if image contains code
|
||||
info.has_code = (optional_header.SizeOfCode > 0) || (optional_header.AddressOfEntryPoint != 0);
|
||||
|
||||
// Also check section characteristics for code sections
|
||||
const auto sections_offset = dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + file_header.SizeOfOptionalHeader;
|
||||
if (file_data.size() >= sections_offset + sizeof(IMAGE_SECTION_HEADER) * file_header.NumberOfSections)
|
||||
{
|
||||
const auto* sections = reinterpret_cast<const IMAGE_SECTION_HEADER*>(file_data.data() + sections_offset);
|
||||
for (uint16_t i = 0; i < file_header.NumberOfSections; ++i)
|
||||
{
|
||||
if (sections[i].Characteristics & IMAGE_SCN_CNT_CODE)
|
||||
{
|
||||
info.has_code = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// NOLINTEND(modernize-use-using,cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
|
||||
@@ -52,3 +52,8 @@ constexpr uint64_t page_align_up(const uint64_t value, const uint64_t page_size
|
||||
{
|
||||
return align_up(value, page_size);
|
||||
}
|
||||
|
||||
constexpr uint64_t rva_to_raw(uint64_t va_base, uint64_t raw_base, uint64_t rva)
|
||||
{
|
||||
return rva - (va_base - raw_base);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ int main()
|
||||
printf("EntryOffset: %08lX\n", api_set_map->EntryOffset);
|
||||
printf("HashOffset: %08lX\n", api_set_map->HashOffset);
|
||||
printf("HashFactor: %08lX\n", api_set_map->HashFactor);
|
||||
// print_apiset(apiSetMap);
|
||||
print_apiset(api_set_map);
|
||||
|
||||
// Compress the API-SET binary blob
|
||||
const auto* data_ptr = reinterpret_cast<const std::byte*>(api_set_map);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
|
||||
#include "../emulator_utils.hpp"
|
||||
|
||||
@@ -33,4 +34,4 @@ namespace apiset
|
||||
const API_SET_NAMESPACE& orig_api_set_map);
|
||||
|
||||
emulator_object<API_SET_NAMESPACE> clone(x86_64_emulator& emu, emulator_allocator& allocator, const container& container);
|
||||
}
|
||||
}
|
||||
@@ -4,23 +4,10 @@
|
||||
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/buffer_accessor.hpp>
|
||||
#include <platform/win_pefile.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename T>
|
||||
uint64_t get_first_section_offset(const PENTHeaders_t<T>& nt_headers, const uint64_t nt_headers_offset)
|
||||
{
|
||||
const auto* nt_headers_addr = reinterpret_cast<const uint8_t*>(&nt_headers);
|
||||
const size_t optional_header_offset =
|
||||
reinterpret_cast<uintptr_t>(&(nt_headers.OptionalHeader)) - reinterpret_cast<uintptr_t>(&nt_headers);
|
||||
const size_t optional_header_size = nt_headers.FileHeader.SizeOfOptionalHeader;
|
||||
const auto* first_section_addr = nt_headers_addr + optional_header_offset + optional_header_size;
|
||||
|
||||
const auto first_section_absolute = reinterpret_cast<uint64_t>(first_section_addr);
|
||||
const auto absolute_base = reinterpret_cast<uint64_t>(&nt_headers);
|
||||
return nt_headers_offset + (first_section_absolute - absolute_base);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::vector<std::byte> read_mapped_memory(const memory_manager& memory, const mapped_module& binary)
|
||||
{
|
||||
@@ -210,7 +197,7 @@ namespace
|
||||
void map_sections(memory_manager& memory, mapped_module& binary, const utils::safe_buffer_accessor<const std::byte> buffer,
|
||||
const PENTHeaders_t<T>& nt_headers, const uint64_t nt_headers_offset)
|
||||
{
|
||||
const auto first_section_offset = get_first_section_offset(nt_headers, nt_headers_offset);
|
||||
const auto first_section_offset = winpe::get_first_section_offset(nt_headers, nt_headers_offset);
|
||||
const auto sections = buffer.as<IMAGE_SECTION_HEADER>(static_cast<size_t>(first_section_offset));
|
||||
|
||||
for (size_t i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i)
|
||||
@@ -384,7 +371,7 @@ mapped_module map_module_from_memory(memory_manager& memory, uint64_t base_addre
|
||||
binary.size_of_heap_reserve = optional_header.SizeOfHeapReserve;
|
||||
binary.size_of_heap_commit = optional_header.SizeOfHeapCommit;
|
||||
|
||||
const auto section_offset = get_first_section_offset(nt_headers, nt_headers_offset);
|
||||
const auto section_offset = winpe::get_first_section_offset(nt_headers, nt_headers_offset);
|
||||
const auto sections = buffer.as<IMAGE_SECTION_HEADER>(static_cast<size_t>(section_offset));
|
||||
|
||||
for (size_t i = 0; i < nt_headers.FileHeader.NumberOfSections; ++i)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "emulator_utils.hpp"
|
||||
#include "windows_emulator.hpp"
|
||||
#include "utils/io.hpp"
|
||||
#include "utils/buffer_accessor.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -177,66 +179,170 @@ namespace
|
||||
return env_map;
|
||||
}
|
||||
|
||||
void create_known_dlls_section_objects(std::unordered_map<std::u16string, section>& knowndlls_sections, const file_system& file_system,
|
||||
bool is_wow64)
|
||||
std::unordered_map<std::u16string, std::u16string> get_apiset_namespace_table(const API_SET_NAMESPACE* api_set_map)
|
||||
{
|
||||
windows_path known_dlls_fs_root_path;
|
||||
std::u16string known_dlls_objmgn_root_path;
|
||||
std::unordered_map<std::u16string, std::u16string> apiset;
|
||||
|
||||
for (size_t i = 0; i < api_set_map->Count; i++)
|
||||
{
|
||||
const auto entry = reinterpret_cast<PAPI_SET_NAMESPACE_ENTRY>(reinterpret_cast<ULONG_PTR>(api_set_map) +
|
||||
api_set_map->EntryOffset + i * sizeof(API_SET_NAMESPACE_ENTRY));
|
||||
|
||||
std::u16string name(reinterpret_cast<const char16_t*>(reinterpret_cast<ULONG_PTR>(api_set_map) + entry->NameOffset),
|
||||
entry->NameLength / sizeof(char16_t));
|
||||
|
||||
const auto value = reinterpret_cast<PAPI_SET_VALUE_ENTRY>(reinterpret_cast<ULONG_PTR>(api_set_map) + entry->ValueOffset +
|
||||
(entry->ValueCount - 1) * sizeof(API_SET_VALUE_ENTRY));
|
||||
std::u16string base_name(reinterpret_cast<const char16_t*>(reinterpret_cast<ULONG_PTR>(api_set_map) + value->ValueOffset),
|
||||
value->ValueLength / sizeof(char16_t));
|
||||
|
||||
apiset[name + u".dll"] = base_name;
|
||||
}
|
||||
|
||||
return apiset;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void create_known_dlls_section_objects(
|
||||
std::unordered_map<std::u16string, section>& knowndlls_section_objects,
|
||||
registry_manager& registry,
|
||||
const apiset::container& apiset_container,
|
||||
const file_system& file_system,
|
||||
bool is_wow64)
|
||||
{
|
||||
const auto* api_set_data = reinterpret_cast<const API_SET_NAMESPACE*>(apiset_container.data.data());
|
||||
auto apiset = get_apiset_namespace_table(api_set_data);
|
||||
|
||||
std::unordered_set<std::u16string> visited_dlls;
|
||||
windows_path system_root_path;
|
||||
std::filesystem::path local_system_root_path;
|
||||
|
||||
if (is_wow64)
|
||||
{
|
||||
known_dlls_fs_root_path = "C:\\Windows\\SysWOW64";
|
||||
known_dlls_objmgn_root_path = u"\\KnownDlls32";
|
||||
system_root_path = "C:\\Windows\\SysWOW64";
|
||||
}
|
||||
else
|
||||
{
|
||||
known_dlls_fs_root_path = "C:\\Windows\\System32";
|
||||
known_dlls_objmgn_root_path = u"\\KnownDlls";
|
||||
system_root_path = "C:\\Windows\\System32";
|
||||
}
|
||||
|
||||
std::vector<std::u16string> known_dll_names = {u"advapi32.dll", u"bcrypt.dll", u"bcryptPrimitives.dll",
|
||||
u"cfgmgr32.dll", u"clbcatq.dll", u"combase.dll",
|
||||
u"COMCTL32.dll", u"COMDLG32.dll", u"coml2.dll",
|
||||
u"CRYPT32.dll", u"difxapi.dll", u"gdi32.dll",
|
||||
u"gdi32full.dll", u"gdiplus.dll", u"IMAGEHLP.dll",
|
||||
u"IMM32.dll", u"kernel32.dll", u"kernelbase.dll",
|
||||
u"MSCTF.dll", u"msvcp_win.dll", u"MSVCRT.dll",
|
||||
u"NORMALIZ.dll", u"NSI.dll", u"ntdll.dll",
|
||||
u"ole32.dll", u"OLEAUT32.dll", u"PSAPI.DLL",
|
||||
u"rpcrt4.dll", u"sechost.dll", u"Setupapi.dll",
|
||||
u"SHCORE.dll", u"SHELL32.dll", u"SHLWAPI.dll",
|
||||
u"ucrtbase.dll", u"user32.dll", u"win32u.dll",
|
||||
u"WINTRUST.dll", u"WLDAP32.dll", u"wow64.dll",
|
||||
u"wow64cpu.dll", u"wow64win.dll", u"WS2_32.dll"};
|
||||
|
||||
for (const auto& known_dll_name : known_dll_names)
|
||||
std::optional<registry_key> knowndlls_key = registry.get_key({R"(\Registry\Machine\System\CurrentControlSet\Control\Session Manager\KnownDLLs)"});
|
||||
if (!knowndlls_key)
|
||||
{
|
||||
if (is_wow64 && known_dll_name.starts_with(u"wow64"))
|
||||
return;
|
||||
}
|
||||
|
||||
local_system_root_path = file_system.translate(system_root_path);
|
||||
for (size_t i = 0; const auto value_opt = registry.get_value(*knowndlls_key, i); i++)
|
||||
{
|
||||
const auto& value = *value_opt;
|
||||
|
||||
if (value.type != REG_SZ && value.type != REG_EXPAND_SZ)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
section s{};
|
||||
|
||||
const auto known_dll_fs_path = known_dlls_fs_root_path / known_dll_name;
|
||||
|
||||
auto local_file = file_system.translate(known_dll_fs_path);
|
||||
if (!std::filesystem::exists(local_file))
|
||||
if (value.data.empty() || value.data.size() % 2 != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto known_dll_objmgn_path = known_dlls_objmgn_root_path + u"\\" + known_dll_name;
|
||||
const auto file_size = std::filesystem::file_size(local_file);
|
||||
const auto char_count = value.data.size() / sizeof(char16_t);
|
||||
const auto* data_ptr = reinterpret_cast<const char16_t*>(value.data.data());
|
||||
if (data_ptr[char_count - 1] != u'\0')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
utils::string::to_lower_inplace(known_dll_objmgn_path);
|
||||
s.name = known_dll_objmgn_path;
|
||||
s.file_name = known_dll_fs_path.u16string();
|
||||
s.maximum_size = file_size;
|
||||
s.section_page_protection = PAGE_EXECUTE_READ;
|
||||
s.allocation_attributes = SEC_IMAGE;
|
||||
auto known_dll_name = std::u16string(data_ptr, char_count - 1);
|
||||
auto known_dll_path = local_system_root_path / known_dll_name;
|
||||
|
||||
knowndlls_sections[known_dll_objmgn_path] = s;
|
||||
if (!std::filesystem::exists(known_dll_path))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
utils::string::to_lower_inplace(known_dll_name);
|
||||
if (visited_dlls.contains(known_dll_name))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto file = utils::io::read_file(known_dll_path);
|
||||
{
|
||||
section s;
|
||||
s.file_name = known_dll_path.u16string();
|
||||
s.maximum_size = page_align_up(std::filesystem::file_size(s.file_name));
|
||||
s.allocation_attributes = SEC_IMAGE;
|
||||
s.section_page_protection = PAGE_EXECUTE;
|
||||
s.cache_image_info_from_filedata(file);
|
||||
knowndlls_section_objects[known_dll_name] = s;
|
||||
}
|
||||
|
||||
utils::safe_buffer_accessor<const std::byte> buffer{file};
|
||||
|
||||
const auto dos_header = buffer.as<PEDosHeader_t>(0).get();
|
||||
const auto nt_headers_offset = dos_header.e_lfanew;
|
||||
const auto nt_headers = buffer.as<PENTHeaders_t<T>>(nt_headers_offset).get();
|
||||
|
||||
const auto& import_directory_entry = winpe::get_data_directory_by_index(nt_headers, IMAGE_DIRECTORY_ENTRY_IMPORT);
|
||||
if (!import_directory_entry.VirtualAddress)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto section_with_import_descs = winpe::get_section_header_by_rva(buffer, nt_headers, nt_headers_offset, import_directory_entry.VirtualAddress);
|
||||
auto import_directory_vbase = section_with_import_descs.VirtualAddress;
|
||||
auto import_directory_rbase = section_with_import_descs.PointerToRawData;
|
||||
|
||||
uint64_t import_directory_raw = rva_to_raw(import_directory_vbase, import_directory_rbase, import_directory_entry.VirtualAddress);
|
||||
auto import_descriptors = buffer.as<IMAGE_IMPORT_DESCRIPTOR>(import_directory_raw);
|
||||
for (size_t import_desc_index = 0;; import_desc_index++)
|
||||
{
|
||||
const auto descriptor = import_descriptors.get(import_desc_index);
|
||||
if (!descriptor.Name)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
auto known_dll_dep_name = buffer.as_string(rva_to_raw(import_directory_vbase, import_directory_rbase, descriptor.Name));
|
||||
|
||||
utils::string::to_lower_inplace(known_dll_dep_name);
|
||||
auto known_dll_dep_name_16 = u8_to_u16(known_dll_dep_name);
|
||||
|
||||
if (known_dll_dep_name_16.starts_with(u"api-") || known_dll_dep_name_16.starts_with(u"ext-"))
|
||||
{
|
||||
if (apiset.contains(known_dll_dep_name_16))
|
||||
{
|
||||
known_dll_dep_name_16 = apiset[known_dll_dep_name_16];
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (knowndlls_section_objects.contains(known_dll_dep_name_16))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
auto known_dll_dep_path = local_system_root_path / known_dll_dep_name_16;
|
||||
auto file = utils::io::read_file(known_dll_dep_path);
|
||||
|
||||
section s;
|
||||
s.file_name = known_dll_dep_path.u16string();
|
||||
s.maximum_size = page_align_up(std::filesystem::file_size(s.file_name));
|
||||
s.allocation_attributes = SEC_IMAGE;
|
||||
s.section_page_protection = PAGE_EXECUTE;
|
||||
s.cache_image_info_from_filedata(file);
|
||||
|
||||
knowndlls_section_objects[known_dll_dep_name_16] = s;
|
||||
}
|
||||
}
|
||||
|
||||
visited_dlls.insert(known_dll_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -446,7 +552,14 @@ void process_context::setup(x86_64_emulator& emu, memory_manager& memory, regist
|
||||
}
|
||||
}
|
||||
|
||||
create_known_dlls_section_objects(this->knowndlls_sections, file_system, is_wow64_process);
|
||||
if (is_wow64_process)
|
||||
{
|
||||
create_known_dlls_section_objects<uint32_t>(this->knowndlls_sections, registry, apiset_container, file_system, is_wow64_process);
|
||||
}
|
||||
else
|
||||
{
|
||||
create_known_dlls_section_objects<uint64_t>(this->knowndlls_sections, registry, apiset_container, file_system, is_wow64_process);
|
||||
}
|
||||
|
||||
this->ntdll_image_base = ntdll.image_base;
|
||||
this->ldr_initialize_thunk = ntdll.find_export("LdrInitializeThunk");
|
||||
|
||||
@@ -7,94 +7,6 @@
|
||||
|
||||
namespace syscalls
|
||||
{
|
||||
// Helper function to parse PE headers and extract image information
|
||||
template <typename T>
|
||||
static bool parse_pe_headers(const std::vector<std::byte>& file_data, section::image_info& info)
|
||||
{
|
||||
if (file_data.size() < sizeof(PEDosHeader_t))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* dos_header = reinterpret_cast<const PEDosHeader_t*>(file_data.data());
|
||||
if (dos_header->e_magic != PEDosHeader_t::k_Magic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// First check if we can read up to the optional header magic
|
||||
if (file_data.size() < dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + sizeof(uint16_t))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the magic number from the optional header
|
||||
const auto* magic_ptr =
|
||||
reinterpret_cast<const uint16_t*>(file_data.data() + dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t));
|
||||
const uint16_t magic = *magic_ptr;
|
||||
|
||||
// Check if the magic matches the expected type
|
||||
constexpr uint16_t expected_magic = (sizeof(T) == sizeof(uint32_t))
|
||||
? static_cast<uint16_t>(PEOptionalHeader_t<std::uint32_t>::k_Magic)
|
||||
: static_cast<uint16_t>(PEOptionalHeader_t<std::uint64_t>::k_Magic);
|
||||
|
||||
if (magic != expected_magic)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now check the full NT headers size
|
||||
if (file_data.size() < dos_header->e_lfanew + sizeof(PENTHeaders_t<T>))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto* nt_headers = reinterpret_cast<const PENTHeaders_t<T>*>(file_data.data() + dos_header->e_lfanew);
|
||||
if (nt_headers->Signature != PENTHeaders_t<T>::k_Signature)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& file_header = nt_headers->FileHeader;
|
||||
const auto& optional_header = nt_headers->OptionalHeader;
|
||||
|
||||
// Extract information from headers
|
||||
info.machine = static_cast<uint16_t>(file_header.Machine);
|
||||
info.image_characteristics = file_header.Characteristics;
|
||||
|
||||
info.entry_point_rva = optional_header.AddressOfEntryPoint;
|
||||
info.image_base = optional_header.ImageBase;
|
||||
info.subsystem = optional_header.Subsystem;
|
||||
info.subsystem_major_version = optional_header.MajorSubsystemVersion;
|
||||
info.subsystem_minor_version = optional_header.MinorSubsystemVersion;
|
||||
info.dll_characteristics = optional_header.DllCharacteristics;
|
||||
info.size_of_stack_reserve = optional_header.SizeOfStackReserve;
|
||||
info.size_of_stack_commit = optional_header.SizeOfStackCommit;
|
||||
info.size_of_code = optional_header.SizeOfCode;
|
||||
info.loader_flags = optional_header.LoaderFlags;
|
||||
info.checksum = optional_header.CheckSum;
|
||||
|
||||
// Check if image contains code
|
||||
info.has_code = (optional_header.SizeOfCode > 0) || (optional_header.AddressOfEntryPoint != 0);
|
||||
|
||||
// Also check section characteristics for code sections
|
||||
const auto sections_offset = dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + file_header.SizeOfOptionalHeader;
|
||||
if (file_data.size() >= sections_offset + sizeof(IMAGE_SECTION_HEADER) * file_header.NumberOfSections)
|
||||
{
|
||||
const auto* sections = reinterpret_cast<const IMAGE_SECTION_HEADER*>(file_data.data() + sections_offset);
|
||||
for (uint16_t i = 0; i < file_header.NumberOfSections; ++i)
|
||||
{
|
||||
if (sections[i].Characteristics & IMAGE_SCN_CNT_CODE)
|
||||
{
|
||||
info.has_code = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
NTSTATUS handle_NtCreateSection(const syscall_context& c, const emulator_object<handle> section_handle,
|
||||
const ACCESS_MASK /*desired_access*/,
|
||||
const emulator_object<OBJECT_ATTRIBUTES<EmulatorTraits<Emu64>>> object_attributes,
|
||||
@@ -141,36 +53,7 @@ namespace syscalls
|
||||
std::vector<std::byte> file_data;
|
||||
if (utils::io::read_file(c.win_emu.file_sys.translate(s.file_name), &file_data))
|
||||
{
|
||||
section::image_info info{};
|
||||
|
||||
// Read the PE magic to determine if it's 32-bit or 64-bit
|
||||
bool parsed = false;
|
||||
if (file_data.size() >= sizeof(PEDosHeader_t))
|
||||
{
|
||||
const auto* dos_header = reinterpret_cast<const PEDosHeader_t*>(file_data.data());
|
||||
if (dos_header->e_magic == PEDosHeader_t::k_Magic &&
|
||||
file_data.size() >= dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + sizeof(uint16_t))
|
||||
{
|
||||
const auto* magic_ptr = reinterpret_cast<const uint16_t*>(file_data.data() + dos_header->e_lfanew +
|
||||
sizeof(uint32_t) + sizeof(PEFileHeader_t));
|
||||
const uint16_t magic = *magic_ptr;
|
||||
|
||||
// Parse based on the actual PE type
|
||||
if (magic == PEOptionalHeader_t<std::uint32_t>::k_Magic)
|
||||
{
|
||||
parsed = parse_pe_headers<uint32_t>(file_data, info);
|
||||
}
|
||||
else if (magic == PEOptionalHeader_t<std::uint64_t>::k_Magic)
|
||||
{
|
||||
parsed = parse_pe_headers<uint64_t>(file_data, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed)
|
||||
{
|
||||
s.cached_image_info = info;
|
||||
}
|
||||
s.cache_image_info_from_filedata(file_data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,10 +119,25 @@ namespace syscalls
|
||||
}
|
||||
|
||||
utils::string::to_lower_inplace(filename);
|
||||
|
||||
|
||||
if (is_known_dll)
|
||||
{
|
||||
auto& knowndlls_sections = c.win_emu.process.knowndlls_sections;
|
||||
|
||||
if (filename.starts_with(u"\\knowndlls\\"))
|
||||
{
|
||||
filename = std::u16string_view(filename).substr(11, filename.length() - 11);
|
||||
}
|
||||
else if (filename.starts_with(u"\\knowndlls32\\"))
|
||||
{
|
||||
filename = std::u16string_view(filename).substr(13, filename.length() - 13);
|
||||
}
|
||||
|
||||
if (filename == u"win32u.dll")
|
||||
{
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (!knowndlls_sections.contains(filename))
|
||||
{
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <serialization_helper.hpp>
|
||||
#include <utils/file_handle.hpp>
|
||||
#include <platform/synchronisation.hpp>
|
||||
#include <platform/win_pefile.hpp>
|
||||
|
||||
struct timer : ref_counted_object
|
||||
{
|
||||
@@ -220,33 +221,47 @@ struct section : ref_counted_object
|
||||
uint64_t maximum_size{};
|
||||
uint32_t section_page_protection{};
|
||||
uint32_t allocation_attributes{};
|
||||
|
||||
// Cached PE image information for image sections
|
||||
struct image_info
|
||||
{
|
||||
uint64_t entry_point_rva{};
|
||||
uint64_t image_base{};
|
||||
uint64_t size_of_stack_reserve{};
|
||||
uint64_t size_of_stack_commit{};
|
||||
uint32_t size_of_code{};
|
||||
uint32_t loader_flags{};
|
||||
uint32_t checksum{};
|
||||
uint16_t machine{};
|
||||
uint16_t subsystem{};
|
||||
uint16_t subsystem_major_version{};
|
||||
uint16_t subsystem_minor_version{};
|
||||
uint16_t image_characteristics{};
|
||||
uint16_t dll_characteristics{};
|
||||
bool has_code{false};
|
||||
std::array<char, 7> _padding{};
|
||||
};
|
||||
std::optional<image_info> cached_image_info{};
|
||||
std::optional<winpe::pe_image_basic_info> cached_image_info{};
|
||||
|
||||
bool is_image() const
|
||||
{
|
||||
return this->allocation_attributes & SEC_IMAGE;
|
||||
}
|
||||
|
||||
void cache_image_info_from_filedata(const std::vector<std::byte>& file_data)
|
||||
{
|
||||
winpe::pe_image_basic_info info{};
|
||||
|
||||
// Read the PE magic to determine if it's 32-bit or 64-bit
|
||||
bool parsed = false;
|
||||
if (file_data.size() >= sizeof(PEDosHeader_t))
|
||||
{
|
||||
const auto* dos_header = reinterpret_cast<const PEDosHeader_t*>(file_data.data());
|
||||
if (dos_header->e_magic == PEDosHeader_t::k_Magic &&
|
||||
file_data.size() >= dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t) + sizeof(uint16_t))
|
||||
{
|
||||
const auto* magic_ptr =
|
||||
reinterpret_cast<const uint16_t*>(file_data.data() + dos_header->e_lfanew + sizeof(uint32_t) + sizeof(PEFileHeader_t));
|
||||
const uint16_t magic = *magic_ptr;
|
||||
|
||||
// Parse based on the actual PE type
|
||||
if (magic == PEOptionalHeader_t<std::uint32_t>::k_Magic)
|
||||
{
|
||||
parsed = winpe::parse_pe_headers<uint32_t>(file_data, info);
|
||||
}
|
||||
else if (magic == PEOptionalHeader_t<std::uint64_t>::k_Magic)
|
||||
{
|
||||
parsed = winpe::parse_pe_headers<uint64_t>(file_data, info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (parsed)
|
||||
{
|
||||
this->cached_image_info = info;
|
||||
}
|
||||
}
|
||||
|
||||
void serialize_object(utils::buffer_serializer& buffer) const override
|
||||
{
|
||||
buffer.write(this->name);
|
||||
@@ -254,7 +269,7 @@ struct section : ref_counted_object
|
||||
buffer.write(this->maximum_size);
|
||||
buffer.write(this->section_page_protection);
|
||||
buffer.write(this->allocation_attributes);
|
||||
buffer.write_optional<image_info>(this->cached_image_info);
|
||||
buffer.write_optional<winpe::pe_image_basic_info>(this->cached_image_info);
|
||||
}
|
||||
|
||||
void deserialize_object(utils::buffer_deserializer& buffer) override
|
||||
|
||||
Reference in New Issue
Block a user