mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-31 16:31:02 +00:00
Comprehensive WOW64 subsystem implementation
This commit is contained in:
@@ -40,7 +40,10 @@ namespace
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto instructions = d.disassemble(instruction_bytes, 1);
|
||||
uint16_t reg_cs = 0;
|
||||
auto& emu_ref = const_cast<emulator&>(emu);
|
||||
emu_ref.read_raw_register(static_cast<int>(x86_register::cs), ®_cs, sizeof(reg_cs));
|
||||
const auto instructions = d.disassemble(emu_ref, reg_cs, instruction_bytes, 1);
|
||||
if (instructions.empty())
|
||||
{
|
||||
return {};
|
||||
@@ -268,26 +271,32 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto instructions = d.disassemble(instruction_bytes, 1);
|
||||
uint16_t reg_cs = 0;
|
||||
auto& emu_ref = const_cast<emulator&>(emu);
|
||||
emu_ref.read_raw_register(static_cast<int>(x86_register::cs), ®_cs, sizeof(reg_cs));
|
||||
const auto instructions = d.disassemble(emu_ref, reg_cs, instruction_bytes, 1);
|
||||
if (instructions.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return cs_insn_group(d.get_handle(), instructions.data(), CS_GRP_RET);
|
||||
const auto handle = d.resolve_handle(emu_ref, reg_cs);
|
||||
return cs_insn_group(handle, instructions.data(), CS_GRP_RET);
|
||||
}
|
||||
|
||||
void record_instruction(analysis_context& c, const uint64_t address)
|
||||
{
|
||||
auto& emu = c.win_emu->emu();
|
||||
std::array<uint8_t, MAX_INSTRUCTION_BYTES> instruction_bytes{};
|
||||
const auto result = c.win_emu->emu().try_read_memory(address, instruction_bytes.data(), instruction_bytes.size());
|
||||
const auto result = emu.try_read_memory(address, instruction_bytes.data(), instruction_bytes.size());
|
||||
if (!result)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const auto reg_cs = emu.reg<uint16_t>(x86_register::cs);
|
||||
disassembler disasm{};
|
||||
const auto instructions = disasm.disassemble(instruction_bytes, 1);
|
||||
const auto instructions = disasm.disassemble(emu, reg_cs, instruction_bytes, 1);
|
||||
if (instructions.empty())
|
||||
{
|
||||
return;
|
||||
@@ -308,8 +317,10 @@ namespace
|
||||
debugger::handle_events(ec);
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto& current_thread = c.win_emu->current_thread();
|
||||
const auto previous_ip = current_thread.previous_ip;
|
||||
[[maybe_unused]] const auto current_ip = current_thread.current_ip;
|
||||
const auto is_main_exe = win_emu.mod_manager.executable->contains(address);
|
||||
const auto is_previous_main_exe = win_emu.mod_manager.executable->contains(previous_ip);
|
||||
|
||||
|
||||
@@ -1,72 +1,125 @@
|
||||
#include "std_include.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include <utils/finally.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
void cse(const cs_err error)
|
||||
{
|
||||
if (error != CS_ERR_OK)
|
||||
{
|
||||
throw std::runtime_error(cs_strerror(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disassembler::disassembler()
|
||||
{
|
||||
auto deleter = utils::finally([&] { this->release(); });
|
||||
|
||||
cse(cs_open(CS_ARCH_X86, CS_MODE_64, &this->handle_));
|
||||
cse(cs_option(this->handle_, CS_OPT_DETAIL, CS_OPT_ON));
|
||||
|
||||
deleter.cancel();
|
||||
}
|
||||
|
||||
disassembler::~disassembler()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
disassembler::disassembler(disassembler&& obj) noexcept
|
||||
{
|
||||
this->operator=(std::move(obj));
|
||||
}
|
||||
|
||||
disassembler& disassembler::operator=(disassembler&& obj) noexcept
|
||||
{
|
||||
if (this != &obj)
|
||||
{
|
||||
this->release();
|
||||
this->handle_ = obj.handle_;
|
||||
obj.handle_ = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void disassembler::release()
|
||||
{
|
||||
if (this->handle_)
|
||||
{
|
||||
cs_close(&this->handle_);
|
||||
this->handle_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
instructions disassembler::disassemble(const std::span<const uint8_t> data, const size_t count) const
|
||||
{
|
||||
cs_insn* insts{};
|
||||
const auto inst_count = cs_disasm(this->handle_, data.data(), data.size(), count, 0, &insts);
|
||||
return instructions{std::span(insts, inst_count)};
|
||||
}
|
||||
|
||||
void instructions::release()
|
||||
{
|
||||
if (!this->instructions_.empty())
|
||||
{
|
||||
cs_free(this->instructions_.data(), this->instructions_.size());
|
||||
}
|
||||
|
||||
this->instructions_ = {};
|
||||
}
|
||||
#include "std_include.hpp"
|
||||
#include "disassembler.hpp"
|
||||
#include "common/segment_utils.hpp"
|
||||
|
||||
#include <utils/finally.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
void cse(const cs_err error)
|
||||
{
|
||||
if (error != CS_ERR_OK)
|
||||
{
|
||||
throw std::runtime_error(cs_strerror(error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disassembler::disassembler()
|
||||
{
|
||||
auto deleter = utils::finally([&] { this->release(); });
|
||||
|
||||
cse(cs_open(CS_ARCH_X86, CS_MODE_64, &this->handle_64_));
|
||||
cse(cs_option(this->handle_64_, CS_OPT_DETAIL, CS_OPT_ON));
|
||||
|
||||
cse(cs_open(CS_ARCH_X86, CS_MODE_32, &this->handle_32_));
|
||||
cse(cs_option(this->handle_32_, CS_OPT_DETAIL, CS_OPT_ON));
|
||||
|
||||
cse(cs_open(CS_ARCH_X86, CS_MODE_16, &this->handle_16_));
|
||||
cse(cs_option(this->handle_16_, CS_OPT_DETAIL, CS_OPT_ON));
|
||||
|
||||
deleter.cancel();
|
||||
}
|
||||
|
||||
disassembler::~disassembler()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
disassembler::disassembler(disassembler&& obj) noexcept
|
||||
{
|
||||
this->operator=(std::move(obj));
|
||||
}
|
||||
|
||||
disassembler& disassembler::operator=(disassembler&& obj) noexcept
|
||||
{
|
||||
if (this != &obj)
|
||||
{
|
||||
this->release();
|
||||
this->handle_64_ = obj.handle_64_;
|
||||
this->handle_32_ = obj.handle_32_;
|
||||
this->handle_16_ = obj.handle_16_;
|
||||
obj.handle_64_ = 0;
|
||||
obj.handle_32_ = 0;
|
||||
obj.handle_16_ = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void disassembler::release()
|
||||
{
|
||||
if (this->handle_64_)
|
||||
{
|
||||
cs_close(&this->handle_64_);
|
||||
this->handle_64_ = 0;
|
||||
}
|
||||
|
||||
if (this->handle_32_)
|
||||
{
|
||||
cs_close(&this->handle_32_);
|
||||
this->handle_32_ = 0;
|
||||
}
|
||||
|
||||
if (this->handle_16_)
|
||||
{
|
||||
cs_close(&this->handle_16_);
|
||||
this->handle_16_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
instructions disassembler::disassemble(emulator& cpu, const uint16_t cs_selector, const std::span<const uint8_t> data,
|
||||
const size_t count) const
|
||||
{
|
||||
// Select the handle by decoding the code segment descriptor as documented in Intel 64 and IA-32 Architectures SDM Vol. 3.
|
||||
const csh handle_to_use = this->resolve_handle(cpu, cs_selector);
|
||||
|
||||
cs_insn* insts{};
|
||||
const auto inst_count = cs_disasm(handle_to_use, data.data(), data.size(), count, 0, &insts);
|
||||
return instructions{std::span(insts, inst_count)};
|
||||
}
|
||||
|
||||
std::optional<disassembler::segment_bitness> disassembler::get_segment_bitness(emulator& cpu, const uint16_t cs_selector)
|
||||
{
|
||||
return segment_utils::get_segment_bitness(cpu, cs_selector);
|
||||
}
|
||||
|
||||
csh disassembler::resolve_handle(emulator& cpu, const uint16_t cs_selector) const
|
||||
{
|
||||
const auto mode = disassembler::get_segment_bitness(cpu, cs_selector);
|
||||
if (!mode)
|
||||
{
|
||||
return this->handle_64_;
|
||||
}
|
||||
|
||||
switch (*mode)
|
||||
{
|
||||
case segment_bitness::bit16:
|
||||
return this->handle_16_;
|
||||
case segment_bitness::bit32:
|
||||
return this->handle_32_;
|
||||
case segment_bitness::bit64:
|
||||
default:
|
||||
return this->handle_64_;
|
||||
}
|
||||
}
|
||||
|
||||
void instructions::release()
|
||||
{
|
||||
if (!this->instructions_.empty())
|
||||
{
|
||||
cs_free(this->instructions_.data(), this->instructions_.size());
|
||||
}
|
||||
|
||||
this->instructions_ = {};
|
||||
}
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <capstone/capstone.h>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
|
||||
#include "common/segment_utils.hpp"
|
||||
|
||||
class emulator;
|
||||
|
||||
class instructions
|
||||
{
|
||||
@@ -90,15 +96,31 @@ class disassembler
|
||||
disassembler(const disassembler& obj) = delete;
|
||||
disassembler& operator=(const disassembler& obj) = delete;
|
||||
|
||||
instructions disassemble(std::span<const uint8_t> data, size_t count) const;
|
||||
using segment_bitness = segment_utils::segment_bitness;
|
||||
|
||||
csh get_handle() const
|
||||
instructions disassemble(emulator& cpu, uint16_t cs_selector, std::span<const uint8_t> data, size_t count) const;
|
||||
static std::optional<segment_bitness> get_segment_bitness(emulator& cpu, uint16_t cs_selector);
|
||||
csh resolve_handle(emulator& cpu, uint16_t cs_selector) const;
|
||||
|
||||
csh get_handle_64() const
|
||||
{
|
||||
return this->handle_;
|
||||
return this->handle_64_;
|
||||
}
|
||||
|
||||
csh get_handle_32() const
|
||||
{
|
||||
return this->handle_32_;
|
||||
}
|
||||
|
||||
csh get_handle_16() const
|
||||
{
|
||||
return this->handle_16_;
|
||||
}
|
||||
|
||||
private:
|
||||
csh handle_{};
|
||||
csh handle_64_{};
|
||||
csh handle_32_{};
|
||||
csh handle_16_{};
|
||||
|
||||
void release();
|
||||
};
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace
|
||||
|
||||
emulator_object<RTL_USER_PROCESS_PARAMETERS64> get_process_params(windows_emulator& win_emu)
|
||||
{
|
||||
const auto peb = win_emu.process.peb.read();
|
||||
const auto peb = win_emu.process.peb64.read();
|
||||
return {win_emu.emu(), peb.ProcessParameters};
|
||||
}
|
||||
|
||||
@@ -189,14 +189,14 @@ namespace
|
||||
(void)concise;
|
||||
|
||||
#if !defined(__GNUC__) || defined(__clang__)
|
||||
watch_object(win_emu, modules, *win_emu.current_thread().teb, verbose);
|
||||
watch_object(win_emu, modules, win_emu.process.peb, verbose);
|
||||
watch_object(win_emu, modules, *win_emu.current_thread().teb64, verbose);
|
||||
watch_object(win_emu, modules, win_emu.process.peb64, verbose);
|
||||
watch_object<KUSER_SHARED_DATA64>(win_emu, modules, kusd_mmio::address(), verbose);
|
||||
|
||||
auto state = std::make_shared<analysis_state>(win_emu, modules, verbose, concise);
|
||||
|
||||
state->params_hook_ = watch_object(win_emu, modules, win_emu.process.process_params, verbose, state->params_state_);
|
||||
state->ldr_hook_ = watch_object<PEB_LDR_DATA64>(win_emu, modules, win_emu.process.peb.read().Ldr, verbose, state->ldr_state_);
|
||||
state->params_hook_ = watch_object(win_emu, modules, win_emu.process.process_params64, verbose, state->params_state_);
|
||||
state->ldr_hook_ = watch_object<PEB_LDR_DATA64>(win_emu, modules, win_emu.process.peb64.read().Ldr, verbose, state->ldr_state_);
|
||||
|
||||
const auto update_env_hook = [state] {
|
||||
state->env_ptr_hook_ = install_env_hook(state); //
|
||||
@@ -204,17 +204,17 @@ namespace
|
||||
|
||||
update_env_hook();
|
||||
|
||||
win_emu.emu().hook_memory_write(win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters), 0x8,
|
||||
win_emu.emu().hook_memory_write(win_emu.process.peb64.value() + offsetof(PEB64, ProcessParameters), 0x8,
|
||||
[state, update_env = std::move(update_env_hook)](const uint64_t, const void*, size_t) {
|
||||
const auto new_ptr = state->win_emu_.process.peb.read().ProcessParameters;
|
||||
const auto new_ptr = state->win_emu_.process.peb64.read().ProcessParameters;
|
||||
state->params_hook_ = watch_object<RTL_USER_PROCESS_PARAMETERS64>(
|
||||
state->win_emu_, state->modules_, new_ptr, state->verbose_, state->params_state_);
|
||||
update_env();
|
||||
});
|
||||
|
||||
win_emu.emu().hook_memory_write(
|
||||
win_emu.process.peb.value() + offsetof(PEB64, Ldr), 0x8, [state](const uint64_t, const void*, size_t) {
|
||||
const auto new_ptr = state->win_emu_.process.peb.read().Ldr;
|
||||
win_emu.process.peb64.value() + offsetof(PEB64, Ldr), 0x8, [state](const uint64_t, const void*, size_t) {
|
||||
const auto new_ptr = state->win_emu_.process.peb64.read().Ldr;
|
||||
state->ldr_hook_ =
|
||||
watch_object<PEB_LDR_DATA64>(state->win_emu_, state->modules_, new_ptr, state->verbose_, state->ldr_state_);
|
||||
});
|
||||
@@ -253,7 +253,11 @@ namespace
|
||||
{
|
||||
for (const auto& instruction : instructions)
|
||||
{
|
||||
const auto* mnemonic = cs_insn_name(c.d.get_handle(), instruction);
|
||||
const auto& e = c.win_emu;
|
||||
auto& emu = e->emu();
|
||||
const auto reg_cs = emu.reg<uint16_t>(x86_register::cs);
|
||||
const auto handle = c.d.resolve_handle(emu, reg_cs);
|
||||
const auto* mnemonic = cs_insn_name(handle, instruction);
|
||||
c.win_emu->log.print(color::white, "%s: %" PRIu64 "\n", mnemonic, count);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user