Skip to content

Commit

Permalink
Fix api set map
Browse files Browse the repository at this point in the history
  • Loading branch information
momo5502 committed Aug 31, 2024
1 parent e377bdc commit e320b9c
Showing 1 changed file with 141 additions and 106 deletions.
247 changes: 141 additions & 106 deletions src/windows_emulator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,72 @@ bool use_gdb = true;

namespace
{
template <typename T>
class type_info
{
public:
type_info()
{
this->type_name_ = reflect::type_name<T>();

reflect::for_each<T>([this](auto I)
{
const auto member_name = reflect::member_name<I, T>();
const auto member_offset = reflect::offset_of<I, T>();

this->members_[member_offset] = member_name;
});
}

std::string get_member_name(const size_t offset) const
{
size_t last_offset{};
std::string_view last_member{};

for (const auto& member : this->members_)
{
if (offset == member.first)
{
return member.second;
}

if (offset < member.first)
{
const auto diff = offset - last_offset;
return std::string(last_member) + "+" + std::to_string(diff);
}

last_offset = member.first;
last_member = member.second;
}

return "<N/A>";
}

const std::string& get_type_name() const
{
return this->type_name_;
}

private:
std::string type_name_{};
std::map<size_t, std::string> members_{};
};

template <typename T>
void watch_object(x64_emulator& emu, emulator_object<T> object)
{
const type_info<T> info{};

emu.hook_memory_read(object.value(), object.size(),
[i = std::move(info), object](const uint64_t address, size_t)
{
const auto offset = address - object.value();
printf("%s: %llX (%s)\n", i.get_type_name().c_str(), offset,
i.get_member_name(offset).c_str());
});
}

void setup_stack(x64_emulator& emu, const uint64_t stack_base, const size_t stack_size)
{
emu.allocate_memory(stack_base, stack_size, memory_permission::read_write);
Expand Down Expand Up @@ -81,6 +147,11 @@ namespace
uint64_t copy_string(x64_emulator& emu, emulator_allocator& allocator, const void* base_ptr, const uint64_t offset,
const size_t length)
{
if (!length)
{
return 0;
}

const auto length_to_allocate = length + 2;
const auto str_obj = allocator.reserve(length_to_allocate);
emu.write_memory(str_obj, static_cast<const uint8_t*>(base_ptr) + offset, length);
Expand All @@ -92,49 +163,66 @@ namespace
const void* base_ptr, const uint64_t offset,
const size_t length)
{
return static_cast<ULONG>(copy_string(emu, allocator, base_ptr, offset, length) - result_base);
const auto address = copy_string(emu, allocator, base_ptr, offset, length);
if (!address)
{
return 0;
}

assert(address > result_base);
return static_cast<ULONG>(address - result_base);
}

emulator_object<API_SET_NAMESPACE> clone_api_set_map(x64_emulator& emu, emulator_allocator& allocator,const API_SET_NAMESPACE& orig_api_set_map)
emulator_object<API_SET_NAMESPACE> clone_api_set_map(x64_emulator& emu, emulator_allocator& allocator,
const API_SET_NAMESPACE& orig_api_set_map)
{
const auto api_set_map_obj = allocator.reserve<API_SET_NAMESPACE>();
const auto ns_entries_obj = allocator.reserve<API_SET_NAMESPACE_ENTRY>(orig_api_set_map.Count);
const auto hash_entries_obj = allocator.reserve<API_SET_HASH_ENTRY>(orig_api_set_map.Count);

auto api_set_map = orig_api_set_map;
api_set_map.EntryOffset = static_cast<ULONG>(ns_entries_obj.value() - api_set_map_obj.value());
api_set_map.HashOffset = static_cast<ULONG>(hash_entries_obj.value() - api_set_map_obj.value());

api_set_map_obj.access([&](API_SET_NAMESPACE& api_set)
{
api_set = orig_api_set_map;
api_set.EntryOffset = static_cast<ULONG>(ns_entries_obj.value() - api_set_map_obj.value());
api_set.HashOffset = static_cast<ULONG>(hash_entries_obj.value() - api_set_map_obj.value());
});

const auto orig_ns_entries = offset_pointer<API_SET_NAMESPACE_ENTRY>(
&orig_api_set_map, orig_api_set_map.EntryOffset);
const auto orig_hash_entries = offset_pointer<API_SET_HASH_ENTRY>(
&orig_api_set_map, orig_api_set_map.HashOffset);
const auto orig_ns_entries = offset_pointer<API_SET_NAMESPACE_ENTRY>(&orig_api_set_map,
orig_api_set_map.EntryOffset);
const auto orig_hash_entries = offset_pointer<API_SET_HASH_ENTRY>(&orig_api_set_map,
orig_api_set_map.HashOffset);

for (ULONG i = 0; i < orig_api_set_map.Count; ++i)
{
auto ns_entry = orig_ns_entries[i];
const auto hash_entry = orig_hash_entries[i];

ns_entry.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map,
ns_entry.NameOffset, ns_entry.NameLength);
ns_entry.NameOffset, ns_entry.NameLength);

if (!ns_entry.ValueCount)
{
continue;
}

const auto values_obj = allocator.reserve<API_SET_VALUE_ENTRY>(ns_entry.ValueCount);
const auto orig_values = offset_pointer<API_SET_VALUE_ENTRY>(
&orig_api_set_map, ns_entry.ValueOffset);
const auto orig_values = offset_pointer<API_SET_VALUE_ENTRY>(&orig_api_set_map,
ns_entry.ValueOffset);

ns_entry.ValueOffset = static_cast<ULONG>(values_obj.value() - api_set_map_obj.value());

for (ULONG j = 0; j < ns_entry.ValueCount; ++j)
{
auto value = orig_values[j];

value.ValueOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(), &orig_api_set_map,
value.ValueOffset, value.ValueLength);
value.ValueOffset, value.ValueLength);

if (value.NameLength)
{
value.NameOffset = copy_string_as_relative(emu, allocator, api_set_map_obj.value(),
&orig_api_set_map,
value.NameOffset, value.NameLength);
&orig_api_set_map,
value.NameOffset, value.NameLength);
}

values_obj.write(value, j);
Expand All @@ -144,7 +232,7 @@ namespace
hash_entries_obj.write(hash_entry, i);
}

api_set_map_obj.write(api_set_map);
//watch_object(emu, api_set_map_obj);

return api_set_map_obj;
}
Expand All @@ -155,6 +243,14 @@ namespace
return clone_api_set_map(emu, allocator, orig_api_set_map);
}

emulator_allocator create_allocator(emulator& emu, const size_t size)
{
const auto base = emu.find_free_allocation_base(size);
emu.allocate_memory(base, size, memory_permission::read_write);

return emulator_allocator{emu, base, size};
}

process_context setup_context(x64_emulator& emu)
{
setup_stack(emu, STACK_ADDRESS, STACK_SIZE);
Expand All @@ -164,6 +260,9 @@ namespace

context.gs_segment = setup_gs_segment(emu, GS_SEGMENT_ADDR, GS_SEGMENT_SIZE);

auto allocator = create_allocator(emu, 1 << 20);


auto& gs = context.gs_segment;

context.teb = gs.reserve<TEB>();
Expand All @@ -181,93 +280,26 @@ namespace
});

context.process_params.access([&](RTL_USER_PROCESS_PARAMETERS& proc_params)
{
proc_params.Length = sizeof(proc_params);
proc_params.Flags = 0x6001;
gs.make_unicode_string(proc_params.CurrentDirectory.DosPath, L"C:\\Users\\mauri\\Desktop");
gs.make_unicode_string(proc_params.ImagePathName, L"C:\\Users\\mauri\\Desktop\\ConsoleApplication6.exe");
gs.make_unicode_string(proc_params.CommandLine, L"C:\\Users\\mauri\\Desktop\\ConsoleApplication6.exe");
});
{
proc_params.Length = sizeof(proc_params);
proc_params.Flags = 0x6001;
gs.make_unicode_string(proc_params.CurrentDirectory.DosPath, L"C:\\Users\\mauri\\Desktop");
gs.make_unicode_string(proc_params.ImagePathName, L"C:\\Users\\mauri\\Desktop\\ConsoleApplication6.exe");
gs.make_unicode_string(proc_params.CommandLine, L"C:\\Users\\mauri\\Desktop\\ConsoleApplication6.exe");
});

context.peb.access([&](PEB& peb)
{
peb.ImageBaseAddress = nullptr;
peb.ProcessHeap = nullptr;
peb.ProcessHeaps = nullptr;
peb.ProcessParameters = context.process_params.ptr();
peb.ApiSetMap = build_api_set_map(emu, gs).ptr();
peb.ApiSetMap = build_api_set_map(emu, allocator).ptr();
});

return context;
}

template <typename T>
class type_info
{
public:
type_info()
{
this->type_name_ = reflect::type_name<T>();

reflect::for_each<T>([this](auto I)
{
const auto member_name = reflect::member_name<I, T>();
const auto member_offset = reflect::offset_of<I, T>();

this->members_[member_offset] = member_name;
});
}

std::string get_member_name(const size_t offset) const
{
size_t last_offset{};
std::string_view last_member{};

for (const auto& member : this->members_)
{
if (offset == member.first)
{
return member.second;
}

if (offset < member.first)
{
const auto diff = offset - last_offset;
return std::string(last_member) + "+" + std::to_string(diff);
}

last_offset = member.first;
last_member = member.second;
}

return "<N/A>";
}

const std::string& get_type_name() const
{
return this->type_name_;
}

private:
std::string type_name_{};
std::map<size_t, std::string> members_{};
};


template <typename T>
void watch_object(x64_emulator& emu, emulator_object<T> object)
{
const type_info<T> info{};

emu.hook_memory_read(object.value(), object.size(),
[i = std::move(info), object](const uint64_t address, size_t)
{
const auto offset = address - object.value();
printf("%s: %llX (%s)\n", i.get_type_name().c_str(), offset,
i.get_member_name(offset).c_str());
});
}

enum class gdb_registers
{
rax = 0,
Expand Down Expand Up @@ -405,15 +437,21 @@ namespace

bool read_reg(const int regno, size_t* value) override
{
*value = 0;

try
{
const auto mapped_register = register_map.at(static_cast<gdb_registers>(regno));
this->emu_->read_register(mapped_register, value, sizeof(*value));
const auto entry = register_map.find(static_cast<gdb_registers>(regno));
if (entry == register_map.end())
{
return true;
}

this->emu_->read_register(entry->second, value, sizeof(*value));
return true;
}
catch (...)
{
*value = 0;
return true;
}
}
Expand All @@ -422,8 +460,13 @@ namespace
{
try
{
const auto mapped_register = register_map.at(static_cast<gdb_registers>(regno));
this->emu_->write_register(mapped_register, &value, sizeof(value));
const auto entry = register_map.find(static_cast<gdb_registers>(regno));
if (entry == register_map.end())
{
return false;
}

this->emu_->write_register(entry->second, &value, sizeof(value));
return true;
}
catch (...)
Expand All @@ -434,15 +477,7 @@ namespace

bool read_mem(const size_t addr, const size_t len, void* val) override
{
try
{
this->emu_->read_memory(addr, val, len);
return true;
}
catch (...)
{
return false;
}
return this->emu_->try_read_memory(addr, val, len);
}

bool write_mem(const size_t addr, const size_t len, void* val) override
Expand Down

0 comments on commit e320b9c

Please sign in to comment.