Skip to content

Commit

Permalink
More exception progress
Browse files Browse the repository at this point in the history
  • Loading branch information
momo5502 committed Sep 5, 2024
1 parent 7960744 commit 7c6e4a2
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 39 deletions.
28 changes: 25 additions & 3 deletions src/emulator/emulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,31 @@ struct emulator_hook;

using memory_operation = memory_permission;

enum class hook_continuation : bool
enum class instruction_hook_continuation : bool
{
run_instruction = false,
skip_instruction = true,
};

using hook_callback = std::function<hook_continuation()>;
enum class memory_violation_continuation : bool
{
stop = false,
resume = true,
};

enum class memory_violation_type : uint8_t
{
unmapped,
protection,
};

using instruction_hook_callback = std::function<instruction_hook_continuation()>;

using interrupt_hook_callback = std::function<void(int interrupt)>;
using simple_memory_hook_callback = std::function<void(uint64_t address, size_t size)>;
using complex_memory_hook_callback = std::function<void(uint64_t address, size_t size, memory_operation operation)>;
using memory_violation_hook_callback = std::function<memory_violation_continuation(uint64_t address, size_t size, memory_operation operation,
memory_violation_type type)>;

class emulator : public memory_manager
{
Expand All @@ -38,14 +52,22 @@ class emulator : public memory_manager
virtual void read_raw_register(int reg, void* value, size_t size) = 0;
virtual void write_raw_register(int reg, const void* value, size_t size) = 0;

virtual emulator_hook* hook_memory_violation(uint64_t address, size_t size,
memory_violation_hook_callback callback) = 0;

virtual emulator_hook* hook_memory_access(uint64_t address, size_t size, memory_operation filter,
complex_memory_hook_callback callback) = 0;
virtual emulator_hook* hook_instruction(int instruction_type, hook_callback callback) = 0;
virtual emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) = 0;

virtual emulator_hook* hook_interrupt(interrupt_hook_callback callback) = 0;

virtual void delete_hook(emulator_hook* hook) = 0;

emulator_hook* hook_memory_violation(memory_violation_hook_callback callback)
{
return this->hook_memory_violation(0, std::numeric_limits<size_t>::max(), std::move(callback));
}

emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback)
{
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read);
Expand Down
21 changes: 19 additions & 2 deletions src/emulator/typed_emulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,30 @@ class typed_emulator : public emulator
return result;
}

emulator_hook* hook_instruction(hookable_instructions instruction_type, hook_callback callback)
void push_stack(const pointer_type& value)
{
const auto sp = this->read_stack_pointer() - pointer_size;
this->reg(stack_pointer, sp);
this->write_memory(sp, &value, sizeof(value));
}

pointer_type pop_stack()
{
pointer_type result{};
const auto sp = this->read_stack_pointer();
this->read_memory(sp, &result, sizeof(result));
this->reg(stack_pointer, sp + pointer_size);

return result;
}

emulator_hook* hook_instruction(hookable_instructions instruction_type, instruction_hook_callback callback)
{
return this->hook_instruction(static_cast<int>(instruction_type), std::move(callback));
}

private:
emulator_hook* hook_instruction(int instruction_type, hook_callback callback) override = 0;
emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override = 0;

void read_raw_register(int reg, void* value, size_t size) override = 0;
void write_raw_register(int reg, const void* value, size_t size) override = 0;
Expand Down
78 changes: 66 additions & 12 deletions src/unicorn_emulator/unicorn_x64_emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,46 @@ namespace unicorn
return UC_X86_INS_RDTSC;
case x64_hookable_instructions::rdtscp:
return UC_X86_INS_RDTSCP;
default:
throw std::runtime_error("Bad instruction for mapping");
}
}

throw std::runtime_error("Bad instruction for mapping");
memory_violation_type map_memory_violation_type(const uc_mem_type mem_type)
{
switch (mem_type)
{
case UC_MEM_READ_PROT:
case UC_MEM_WRITE_PROT:
case UC_MEM_FETCH_PROT:
return memory_violation_type::protection;
case UC_MEM_READ_UNMAPPED:
case UC_MEM_WRITE_UNMAPPED:
case UC_MEM_FETCH_UNMAPPED:
return memory_violation_type::unmapped;
default:
throw std::runtime_error("Memory type does not constitute a violation");
}
}

memory_operation map_memory_operation(const uc_mem_type mem_type)
{
switch (mem_type)
{
case UC_MEM_READ:
return memory_permission::read;
case UC_MEM_READ_PROT:
case UC_MEM_READ_UNMAPPED:
return memory_operation::read;
case UC_MEM_WRITE:
return memory_permission::write;
case UC_MEM_WRITE_PROT:
case UC_MEM_WRITE_UNMAPPED:
return memory_operation::write;
case UC_MEM_FETCH:
case UC_MEM_FETCH_PROT:
case UC_MEM_FETCH_UNMAPPED:
return memory_operation::exec;
default:
return memory_permission::none;
return memory_operation::none;
}
}

Expand Down Expand Up @@ -177,7 +202,7 @@ namespace unicorn
size_t result_size = size;
uce(uc_reg_write2(*this, reg, value, &result_size));

if (size != result_size)
if (size < result_size)
{
throw std::runtime_error(
"Register size mismatch: " + std::to_string(size) + " != " + std::to_string(result_size));
Expand All @@ -187,9 +212,10 @@ namespace unicorn
void read_raw_register(const int reg, void* value, const size_t size) override
{
size_t result_size = size;
memset(value, 0, size);
uce(uc_reg_read2(*this, reg, value, &result_size));

if (size != result_size)
if (size < result_size)
{
throw std::runtime_error(
"Register size mismatch: " + std::to_string(size) + " != " + std::to_string(result_size));
Expand Down Expand Up @@ -250,11 +276,11 @@ namespace unicorn
}*/

emulator_hook* hook_instruction(int instruction_type,
hook_callback callback)
instruction_hook_callback callback)
{
function_wrapper<int, uc_engine*> wrapper([c = std::move(callback)](uc_engine*)
{
return (c() == hook_continuation::skip_instruction)
return (c() == instruction_hook_continuation::skip_instruction)
? 1
: 0;
});
Expand Down Expand Up @@ -288,10 +314,11 @@ namespace unicorn

emulator_hook* hook_interrupt(interrupt_hook_callback callback) override
{
function_wrapper<void, uc_engine*, int> wrapper([c = std::move(callback)](uc_engine*, const int interrupt_type)
{
c(interrupt_type);
});
function_wrapper<void, uc_engine*, int> wrapper(
[c = std::move(callback)](uc_engine*, const int interrupt_type)
{
c(interrupt_type);
});

unicorn_hook hook{*this};
auto container = std::make_unique<hook_container>();
Expand All @@ -306,6 +333,33 @@ namespace unicorn
return result;
}

emulator_hook* hook_memory_violation(uint64_t address, size_t size,
memory_violation_hook_callback callback) override
{
function_wrapper<bool, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
[c = std::move(callback)](uc_engine*, const uc_mem_type type,
const uint64_t address, const int size, const int64_t)
{
assert(size >= 0);
const auto operation = map_memory_operation(type);
const auto violation = map_memory_violation_type(type);

return c(address, static_cast<uint64_t>(size), operation, violation) == memory_violation_continuation::resume;
});

unicorn_hook hook{*this};
auto container = std::make_unique<hook_container>();

uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_INVALID, wrapper.get_function(),
wrapper.get_user_data(), address, size));

container->add(std::move(wrapper), std::move(hook));

auto* result = container->as_opaque_hook();
this->hooks_.push_back(std::move(container));
return result;
}

emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter,
complex_memory_hook_callback callback) override
{
Expand Down
74 changes: 54 additions & 20 deletions src/windows_emulator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
#define STACK_ADDRESS (0x80000000000 - STACK_SIZE)
#define KUSD_ADDRESS 0x7ffe0000

bool use_gdb = true;
#define GDT_ADDR 0x30000
#define GDT_LIMIT 0x1000
#define GDT_ENTRY_SIZE 0x8

bool use_gdb = false;

struct breakpoint_key
{
Expand Down Expand Up @@ -274,18 +278,31 @@ namespace
return emulator_allocator{emu, base, size};
}

void setup_gdt(x64_emulator& emu)
{
constexpr uint64_t gdtr[4] = {0, GDT_ADDR, GDT_LIMIT, 0};
emu.write_register(x64_register::gdtr, &gdtr, sizeof(gdtr));
emu.allocate_memory(GDT_ADDR, GDT_LIMIT, memory_permission::read);

emu.write_memory<uint64_t>(GDT_ADDR + 6 * (sizeof(uint64_t)), 0xEFFE000000FFFF);
emu.reg<uint16_t>(x64_register::cs, 0x33);

emu.write_memory<uint64_t>(GDT_ADDR + 5 * (sizeof(uint64_t)), 0xEFF6000000FFFF);
emu.reg<uint16_t>(x64_register::ss, 0x2B);
}

process_context setup_context(x64_emulator& emu)
{
setup_stack(emu, STACK_ADDRESS, STACK_SIZE);
process_context context{};

context.kusd = setup_kusd(emu);
setup_stack(emu, STACK_ADDRESS, STACK_SIZE);
setup_gdt(emu);

context.kusd = setup_kusd(emu);
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 Down Expand Up @@ -348,6 +365,12 @@ namespace
x64_register::r15,
x64_register::rip,
x64_register::rflags,
/*x64_register::cs,
x64_register::ss,
x64_register::ds,
x64_register::es,
x64_register::fs,
x64_register::gs,*/
};

memory_operation map_breakpoint_type(const breakpoint_type type)
Expand Down Expand Up @@ -463,7 +486,7 @@ namespace

try
{
if (regno < 0 || regno >= gdb_registers.size())
if (static_cast<size_t>(regno) >= gdb_registers.size())
{
return true;
}
Expand All @@ -481,7 +504,7 @@ namespace
{
try
{
if (regno < 0 || regno >= gdb_registers.size())
if (static_cast<size_t>(regno) >= gdb_registers.size())
{
return true;
}
Expand Down Expand Up @@ -598,40 +621,51 @@ namespace
emu->hook_instruction(x64_hookable_instructions::syscall, [&]
{
dispatcher.dispatch(*emu, context);
return hook_continuation::skip_instruction;
return instruction_hook_continuation::skip_instruction;
});

emu->hook_instruction(x64_hookable_instructions::rdtsc, [&]
{
emu->reg(x64_register::rax, 0x0011223344556677);
return hook_continuation::skip_instruction;
return instruction_hook_continuation::skip_instruction;
});

emu->hook_instruction(x64_hookable_instructions::invalid, [&]
{
const auto ip = emu->read_instruction_pointer();
printf("Invalid instruction at: %llX\n", ip);
return hook_continuation::skip_instruction;
return instruction_hook_continuation::skip_instruction;
});

emu->hook_interrupt([&](int interrupt)
{
printf("Interrupt: %i\n", interrupt);
if (interrupt == 13)
{
const auto sp = emu->reg(x64_register::rsp);
const auto new_ip = emu->read_memory<uint64_t>(sp);
});

emu->hook_memory_violation([&](const uint64_t address, const size_t size, const memory_operation operation,
const memory_violation_type type)
{
const auto permission = get_permission_string(operation);
const auto ip = emu->read_instruction_pointer();

emu->reg(x64_register::rsp, sp + 8);
emu->reg(x64_register::rip, new_ip);
if (type == memory_violation_type::protection)
{
printf("Protection violation: %llX (%zX) - %s at %llX\n", address, size, permission.c_str(), ip);
}
else if (type == memory_violation_type::unmapped)
{
printf("Mapping violation: %llX (%zX) - %s at %llX\n", address, size, permission.c_str(), ip);
}
});

watch_object(*emu, context.teb);
watch_object(*emu, context.peb);
watch_object(*emu, context.process_params);
watch_object(*emu, context.kusd);
return memory_violation_continuation::stop;
});

/*
watch_object(*emu, context.teb);
watch_object(*emu, context.peb);
watch_object(*emu, context.process_params);
watch_object(*emu, context.kusd);
*/
/*emu->hook_memory_execution(0, std::numeric_limits<size_t>::max(), [&](const uint64_t address, const size_t)
{
if (address == 0x1800D52F4)
Expand Down
2 changes: 1 addition & 1 deletion src/windows_emulator/module_mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ std::optional<mapped_binary> map_file(x64_emulator& emu, const std::filesystem::

auto binary = map_module(emu, data, file.generic_string());

hook_exports(emu, binary, file);
//hook_exports(emu, binary, file);

return binary;
}
2 changes: 1 addition & 1 deletion src/windows_emulator/syscalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1156,7 +1156,7 @@ namespace
{
if (file_handle == STDOUT_HANDLE)
{
std::vector<uint8_t> temp_buffer{};
std::string temp_buffer{};
temp_buffer.resize(length);
c.emu.read_memory(buffer, temp_buffer.data(), temp_buffer.size());

Expand Down

0 comments on commit 7c6e4a2

Please sign in to comment.