mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Finish unicorn isolation
This commit is contained in:
@@ -1,15 +1,19 @@
|
||||
#pragma once
|
||||
#include <chrono>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
|
||||
#include "memory_permission.hpp"
|
||||
#include "memory_region.hpp"
|
||||
|
||||
struct memory_region
|
||||
{
|
||||
uint64_t start;
|
||||
size_t length;
|
||||
memory_permission pemissions;
|
||||
};
|
||||
struct emulator_hook;
|
||||
|
||||
using memory_operation = memory_permission;
|
||||
|
||||
using instruction_hook_callback = std::function<void(uint64_t address)>;
|
||||
|
||||
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)>;
|
||||
|
||||
class emulator
|
||||
{
|
||||
@@ -39,54 +43,39 @@ public:
|
||||
virtual void protect_memory(uint64_t address, size_t size, memory_permission permissions) = 0;
|
||||
|
||||
virtual std::vector<memory_region> get_memory_regions() = 0;
|
||||
};
|
||||
|
||||
template <typename PointerType, typename Register, Register StackPointer>
|
||||
class typed_emulator : public emulator
|
||||
{
|
||||
public:
|
||||
using registers = Register;
|
||||
using pointer_type = PointerType;
|
||||
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, instruction_hook_callback callback) = 0;
|
||||
|
||||
static constexpr size_t pointer_size = sizeof(pointer_type);
|
||||
static constexpr registers stack_pointer = StackPointer;
|
||||
virtual void delete_hook(emulator_hook* hook) = 0;
|
||||
|
||||
void write_register(registers reg, const void* value, const size_t size)
|
||||
emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback)
|
||||
{
|
||||
this->write_raw_register(static_cast<int>(reg), value, size);
|
||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read);
|
||||
}
|
||||
|
||||
void read_register(registers reg, void* value, const size_t size)
|
||||
emulator_hook* hook_memory_write(const uint64_t address, const size_t size, simple_memory_hook_callback callback)
|
||||
{
|
||||
this->read_raw_register(static_cast<int>(reg), value, size);
|
||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::write);
|
||||
}
|
||||
|
||||
template <typename T = uint64_t>
|
||||
T reg(const registers regid) const
|
||||
emulator_hook* hook_memory_execution(const uint64_t address, const size_t size,
|
||||
simple_memory_hook_callback callback)
|
||||
{
|
||||
T value{};
|
||||
this->read_register(regid, &value, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T = uint64_t, typename S>
|
||||
void reg(const registers regid, const S& maybe_value) const
|
||||
{
|
||||
T value = static_cast<T>(maybe_value);
|
||||
this->write_register(regid, &value, sizeof(value));
|
||||
}
|
||||
|
||||
pointer_type read_stack(const size_t index) const
|
||||
{
|
||||
uint64_t result{};
|
||||
const auto sp = this->reg(stack_pointer);
|
||||
|
||||
this->read_memory(sp + (index * pointer_size), &result, sizeof(result));
|
||||
|
||||
return result;
|
||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::exec);
|
||||
}
|
||||
|
||||
private:
|
||||
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;
|
||||
emulator_hook* hook_simple_memory_access(const uint64_t address, const size_t size,
|
||||
simple_memory_hook_callback callback, const memory_operation operation)
|
||||
{
|
||||
assert((static_cast<uint8_t>(operation) & (static_cast<uint8_t>(operation) - 1)) == 0);
|
||||
return this->hook_memory_access(address, size, operation,
|
||||
[c = std::move(callback)](const uint64_t a, const size_t s,
|
||||
memory_operation)
|
||||
{
|
||||
c(a, s);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
9
src/emulator/memory_region.hpp
Normal file
9
src/emulator/memory_region.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
#include "memory_permission.hpp"
|
||||
|
||||
struct memory_region
|
||||
{
|
||||
uint64_t start;
|
||||
size_t length;
|
||||
memory_permission pemissions;
|
||||
};
|
||||
75
src/emulator/typed_emulator.hpp
Normal file
75
src/emulator/typed_emulator.hpp
Normal file
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "emulator.hpp"
|
||||
|
||||
using simple_instruction_hook_callback = std::function<void()>;
|
||||
|
||||
template <typename PointerType, typename Register, Register InstructionPointer, Register
|
||||
StackPointer, typename HookableInstructions>
|
||||
class typed_emulator : public emulator
|
||||
{
|
||||
public:
|
||||
using registers = Register;
|
||||
using pointer_type = PointerType;
|
||||
using hookable_instructions = HookableInstructions;
|
||||
|
||||
static constexpr size_t pointer_size = sizeof(pointer_type);
|
||||
static constexpr registers stack_pointer = StackPointer;
|
||||
static constexpr registers instruction_pointer = InstructionPointer;
|
||||
|
||||
void write_register(registers reg, const void* value, const size_t size)
|
||||
{
|
||||
this->write_raw_register(static_cast<int>(reg), value, size);
|
||||
}
|
||||
|
||||
void read_register(registers reg, void* value, const size_t size)
|
||||
{
|
||||
this->read_raw_register(static_cast<int>(reg), value, size);
|
||||
}
|
||||
|
||||
template <typename T = pointer_type>
|
||||
T reg(const registers regid)
|
||||
{
|
||||
T value{};
|
||||
this->read_register(regid, &value, sizeof(value));
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T = pointer_type, typename S>
|
||||
void reg(const registers regid, const S& maybe_value)
|
||||
{
|
||||
T value = static_cast<T>(maybe_value);
|
||||
this->write_register(regid, &value, sizeof(value));
|
||||
}
|
||||
|
||||
pointer_type read_stack(const size_t index)
|
||||
{
|
||||
pointer_type result{};
|
||||
const auto sp = this->reg(stack_pointer);
|
||||
|
||||
this->read_memory(sp + (index * pointer_size), &result, sizeof(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
emulator_hook* hook_instruction(hookable_instructions instruction_type, instruction_hook_callback callback)
|
||||
{
|
||||
return this->hook_instruction(instruction_type, [this, c = std::move(callback)]
|
||||
{
|
||||
const auto ip = static_cast<uint64_t>(this->reg(instruction_pointer));
|
||||
c(ip);
|
||||
});
|
||||
}
|
||||
|
||||
virtual emulator_hook* hook_instruction(hookable_instructions instruction_type,
|
||||
simple_instruction_hook_callback callback) = 0;
|
||||
|
||||
private:
|
||||
emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) override
|
||||
{
|
||||
return this->hook_instruction(static_cast<hookable_instructions>(instruction_type), std::move(callback));
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
@@ -1,248 +1,12 @@
|
||||
#pragma once
|
||||
#include "emulator.hpp"
|
||||
#include "typed_emulator.hpp"
|
||||
#include "x64_register.hpp"
|
||||
|
||||
enum class x64_register
|
||||
enum class x64_hookable_instructions
|
||||
{
|
||||
invalid = 0,
|
||||
ah,
|
||||
al,
|
||||
ax,
|
||||
bh,
|
||||
bl,
|
||||
bp,
|
||||
bpl,
|
||||
bx,
|
||||
ch,
|
||||
cl,
|
||||
cs,
|
||||
cx,
|
||||
dh,
|
||||
di,
|
||||
dil,
|
||||
dl,
|
||||
ds,
|
||||
dx,
|
||||
eax,
|
||||
ebp,
|
||||
ebx,
|
||||
ecx,
|
||||
edi,
|
||||
edx,
|
||||
eflags,
|
||||
eip,
|
||||
es = eip + 2,
|
||||
esi,
|
||||
esp,
|
||||
fpsw,
|
||||
fs,
|
||||
gs,
|
||||
ip,
|
||||
rax,
|
||||
rbp,
|
||||
rbx,
|
||||
rcx,
|
||||
rdi,
|
||||
rdx,
|
||||
rip,
|
||||
rsi = rip + 2,
|
||||
rsp,
|
||||
si,
|
||||
sil,
|
||||
sp,
|
||||
spl,
|
||||
ss,
|
||||
cr0,
|
||||
cr1,
|
||||
cr2,
|
||||
cr3,
|
||||
cr4,
|
||||
cr8 = cr4 + 4,
|
||||
dr0 = cr8 + 8,
|
||||
dr1,
|
||||
dr2,
|
||||
dr3,
|
||||
dr4,
|
||||
dr5,
|
||||
dr6,
|
||||
dr7,
|
||||
fp0 = dr7 + 9,
|
||||
fp1,
|
||||
fp2,
|
||||
fp3,
|
||||
fp4,
|
||||
fp5,
|
||||
fp6,
|
||||
fp7,
|
||||
k0,
|
||||
k1,
|
||||
k2,
|
||||
k3,
|
||||
k4,
|
||||
k5,
|
||||
k6,
|
||||
k7,
|
||||
mm0,
|
||||
mm1,
|
||||
mm2,
|
||||
mm3,
|
||||
mm4,
|
||||
mm5,
|
||||
mm6,
|
||||
mm7,
|
||||
r8,
|
||||
r9,
|
||||
r10,
|
||||
r11,
|
||||
r12,
|
||||
r13,
|
||||
r14,
|
||||
r15,
|
||||
st0,
|
||||
st1,
|
||||
st2,
|
||||
st3,
|
||||
st4,
|
||||
st5,
|
||||
st6,
|
||||
st7,
|
||||
xmm0,
|
||||
xmm1,
|
||||
xmm2,
|
||||
xmm3,
|
||||
xmm4,
|
||||
xmm5,
|
||||
xmm6,
|
||||
xmm7,
|
||||
xmm8,
|
||||
xmm9,
|
||||
xmm10,
|
||||
xmm11,
|
||||
xmm12,
|
||||
xmm13,
|
||||
xmm14,
|
||||
xmm15,
|
||||
xmm16,
|
||||
xmm17,
|
||||
xmm18,
|
||||
xmm19,
|
||||
xmm20,
|
||||
xmm21,
|
||||
xmm22,
|
||||
xmm23,
|
||||
xmm24,
|
||||
xmm25,
|
||||
xmm26,
|
||||
xmm27,
|
||||
xmm28,
|
||||
xmm29,
|
||||
xmm30,
|
||||
xmm31,
|
||||
ymm0,
|
||||
ymm1,
|
||||
ymm2,
|
||||
ymm3,
|
||||
ymm4,
|
||||
ymm5,
|
||||
ymm6,
|
||||
ymm7,
|
||||
ymm8,
|
||||
ymm9,
|
||||
ymm10,
|
||||
ymm11,
|
||||
ymm12,
|
||||
ymm13,
|
||||
ymm14,
|
||||
ymm15,
|
||||
ymm16,
|
||||
ymm17,
|
||||
ymm18,
|
||||
ymm19,
|
||||
ymm20,
|
||||
ymm21,
|
||||
ymm22,
|
||||
ymm23,
|
||||
ymm24,
|
||||
ymm25,
|
||||
ymm26,
|
||||
ymm27,
|
||||
ymm28,
|
||||
ymm29,
|
||||
ymm30,
|
||||
ymm31,
|
||||
zmm0,
|
||||
zmm1,
|
||||
zmm2,
|
||||
zmm3,
|
||||
zmm4,
|
||||
zmm5,
|
||||
zmm6,
|
||||
zmm7,
|
||||
zmm8,
|
||||
zmm9,
|
||||
zmm10,
|
||||
zmm11,
|
||||
zmm12,
|
||||
zmm13,
|
||||
zmm14,
|
||||
zmm15,
|
||||
zmm16,
|
||||
zmm17,
|
||||
zmm18,
|
||||
zmm19,
|
||||
zmm20,
|
||||
zmm21,
|
||||
zmm22,
|
||||
zmm23,
|
||||
zmm24,
|
||||
zmm25,
|
||||
zmm26,
|
||||
zmm27,
|
||||
zmm28,
|
||||
zmm29,
|
||||
zmm30,
|
||||
zmm31,
|
||||
r8b,
|
||||
r9b,
|
||||
r10b,
|
||||
r11b,
|
||||
r12b,
|
||||
r13b,
|
||||
r14b,
|
||||
r15b,
|
||||
r8d,
|
||||
r9d,
|
||||
r10d,
|
||||
r11d,
|
||||
r12d,
|
||||
r13d,
|
||||
r14d,
|
||||
r15d,
|
||||
r8w,
|
||||
r9w,
|
||||
r10w,
|
||||
r11w,
|
||||
r12w,
|
||||
r13w,
|
||||
r14w,
|
||||
r15w,
|
||||
idtr,
|
||||
gdtr,
|
||||
ldtr,
|
||||
tr,
|
||||
fpcw,
|
||||
fptag,
|
||||
msr,
|
||||
mxcsr,
|
||||
fs_base,
|
||||
gs_base,
|
||||
flags,
|
||||
rflags,
|
||||
fip,
|
||||
fcs,
|
||||
fdp,
|
||||
fds,
|
||||
fop,
|
||||
end, // Must be last
|
||||
syscall,
|
||||
cpuid,
|
||||
};
|
||||
|
||||
using x64_emulator = typed_emulator<uint64_t, x64_register, x64_register::rsp>;
|
||||
using x64_emulator = typed_emulator<uint64_t, x64_register, x64_register::rip,
|
||||
x64_register::rsp, x64_hookable_instructions>;
|
||||
|
||||
245
src/emulator/x64_register.hpp
Normal file
245
src/emulator/x64_register.hpp
Normal file
@@ -0,0 +1,245 @@
|
||||
#pragma once
|
||||
|
||||
enum class x64_register
|
||||
{
|
||||
invalid = 0,
|
||||
ah,
|
||||
al,
|
||||
ax,
|
||||
bh,
|
||||
bl,
|
||||
bp,
|
||||
bpl,
|
||||
bx,
|
||||
ch,
|
||||
cl,
|
||||
cs,
|
||||
cx,
|
||||
dh,
|
||||
di,
|
||||
dil,
|
||||
dl,
|
||||
ds,
|
||||
dx,
|
||||
eax,
|
||||
ebp,
|
||||
ebx,
|
||||
ecx,
|
||||
edi,
|
||||
edx,
|
||||
eflags,
|
||||
eip,
|
||||
es = eip + 2,
|
||||
esi,
|
||||
esp,
|
||||
fpsw,
|
||||
fs,
|
||||
gs,
|
||||
ip,
|
||||
rax,
|
||||
rbp,
|
||||
rbx,
|
||||
rcx,
|
||||
rdi,
|
||||
rdx,
|
||||
rip,
|
||||
rsi = rip + 2,
|
||||
rsp,
|
||||
si,
|
||||
sil,
|
||||
sp,
|
||||
spl,
|
||||
ss,
|
||||
cr0,
|
||||
cr1,
|
||||
cr2,
|
||||
cr3,
|
||||
cr4,
|
||||
cr8 = cr4 + 4,
|
||||
dr0 = cr8 + 8,
|
||||
dr1,
|
||||
dr2,
|
||||
dr3,
|
||||
dr4,
|
||||
dr5,
|
||||
dr6,
|
||||
dr7,
|
||||
fp0 = dr7 + 9,
|
||||
fp1,
|
||||
fp2,
|
||||
fp3,
|
||||
fp4,
|
||||
fp5,
|
||||
fp6,
|
||||
fp7,
|
||||
k0,
|
||||
k1,
|
||||
k2,
|
||||
k3,
|
||||
k4,
|
||||
k5,
|
||||
k6,
|
||||
k7,
|
||||
mm0,
|
||||
mm1,
|
||||
mm2,
|
||||
mm3,
|
||||
mm4,
|
||||
mm5,
|
||||
mm6,
|
||||
mm7,
|
||||
r8,
|
||||
r9,
|
||||
r10,
|
||||
r11,
|
||||
r12,
|
||||
r13,
|
||||
r14,
|
||||
r15,
|
||||
st0,
|
||||
st1,
|
||||
st2,
|
||||
st3,
|
||||
st4,
|
||||
st5,
|
||||
st6,
|
||||
st7,
|
||||
xmm0,
|
||||
xmm1,
|
||||
xmm2,
|
||||
xmm3,
|
||||
xmm4,
|
||||
xmm5,
|
||||
xmm6,
|
||||
xmm7,
|
||||
xmm8,
|
||||
xmm9,
|
||||
xmm10,
|
||||
xmm11,
|
||||
xmm12,
|
||||
xmm13,
|
||||
xmm14,
|
||||
xmm15,
|
||||
xmm16,
|
||||
xmm17,
|
||||
xmm18,
|
||||
xmm19,
|
||||
xmm20,
|
||||
xmm21,
|
||||
xmm22,
|
||||
xmm23,
|
||||
xmm24,
|
||||
xmm25,
|
||||
xmm26,
|
||||
xmm27,
|
||||
xmm28,
|
||||
xmm29,
|
||||
xmm30,
|
||||
xmm31,
|
||||
ymm0,
|
||||
ymm1,
|
||||
ymm2,
|
||||
ymm3,
|
||||
ymm4,
|
||||
ymm5,
|
||||
ymm6,
|
||||
ymm7,
|
||||
ymm8,
|
||||
ymm9,
|
||||
ymm10,
|
||||
ymm11,
|
||||
ymm12,
|
||||
ymm13,
|
||||
ymm14,
|
||||
ymm15,
|
||||
ymm16,
|
||||
ymm17,
|
||||
ymm18,
|
||||
ymm19,
|
||||
ymm20,
|
||||
ymm21,
|
||||
ymm22,
|
||||
ymm23,
|
||||
ymm24,
|
||||
ymm25,
|
||||
ymm26,
|
||||
ymm27,
|
||||
ymm28,
|
||||
ymm29,
|
||||
ymm30,
|
||||
ymm31,
|
||||
zmm0,
|
||||
zmm1,
|
||||
zmm2,
|
||||
zmm3,
|
||||
zmm4,
|
||||
zmm5,
|
||||
zmm6,
|
||||
zmm7,
|
||||
zmm8,
|
||||
zmm9,
|
||||
zmm10,
|
||||
zmm11,
|
||||
zmm12,
|
||||
zmm13,
|
||||
zmm14,
|
||||
zmm15,
|
||||
zmm16,
|
||||
zmm17,
|
||||
zmm18,
|
||||
zmm19,
|
||||
zmm20,
|
||||
zmm21,
|
||||
zmm22,
|
||||
zmm23,
|
||||
zmm24,
|
||||
zmm25,
|
||||
zmm26,
|
||||
zmm27,
|
||||
zmm28,
|
||||
zmm29,
|
||||
zmm30,
|
||||
zmm31,
|
||||
r8b,
|
||||
r9b,
|
||||
r10b,
|
||||
r11b,
|
||||
r12b,
|
||||
r13b,
|
||||
r14b,
|
||||
r15b,
|
||||
r8d,
|
||||
r9d,
|
||||
r10d,
|
||||
r11d,
|
||||
r12d,
|
||||
r13d,
|
||||
r14d,
|
||||
r15d,
|
||||
r8w,
|
||||
r9w,
|
||||
r10w,
|
||||
r11w,
|
||||
r12w,
|
||||
r13w,
|
||||
r14w,
|
||||
r15w,
|
||||
idtr,
|
||||
gdtr,
|
||||
ldtr,
|
||||
tr,
|
||||
fpcw,
|
||||
fptag,
|
||||
msr,
|
||||
mxcsr,
|
||||
fs_base,
|
||||
gs_base,
|
||||
flags,
|
||||
rflags,
|
||||
fip,
|
||||
fcs,
|
||||
fdp,
|
||||
fds,
|
||||
fop,
|
||||
end, // Must be last
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
#define UNICORN_EMULATOR_IMPL
|
||||
#include "unicorn_x64_emulator.hpp"
|
||||
|
||||
#define NOMINMAX
|
||||
#include <span>
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
@@ -39,6 +40,32 @@ namespace unicorn
|
||||
throw_if_unicorn_error(error_code);
|
||||
}
|
||||
|
||||
uc_x86_insn map_hookable_instruction(const x64_hookable_instructions instruction)
|
||||
{
|
||||
switch (instruction)
|
||||
{
|
||||
case x64_hookable_instructions::syscall:
|
||||
return UC_X86_INS_SYSCALL;
|
||||
case x64_hookable_instructions::cpuid:
|
||||
return UC_X86_INS_CPUID;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Bad instruction for mapping");
|
||||
}
|
||||
|
||||
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_WRITE:
|
||||
return memory_permission::write;
|
||||
default:
|
||||
return memory_permission::none;
|
||||
}
|
||||
}
|
||||
|
||||
class unicorn_memory_regions
|
||||
{
|
||||
public:
|
||||
@@ -70,6 +97,151 @@ namespace unicorn
|
||||
uc_mem_region* regions_{};
|
||||
};
|
||||
|
||||
struct object
|
||||
{
|
||||
object() = default;
|
||||
virtual ~object() = default;
|
||||
|
||||
object(object&&) = default;
|
||||
object(const object&) = default;
|
||||
object& operator=(object&&) = default;
|
||||
object& operator=(const object&) = default;
|
||||
};
|
||||
|
||||
struct hook_object : object
|
||||
{
|
||||
emulator_hook* as_opaque_hook()
|
||||
{
|
||||
return reinterpret_cast<emulator_hook*>(this);
|
||||
}
|
||||
};
|
||||
|
||||
class unicorn_hook
|
||||
{
|
||||
public:
|
||||
unicorn_hook() = default;
|
||||
|
||||
unicorn_hook(uc_engine* uc)
|
||||
: unicorn_hook(uc, {})
|
||||
{
|
||||
}
|
||||
|
||||
unicorn_hook(uc_engine* uc, const uc_hook hook)
|
||||
: uc_(uc)
|
||||
, hook_(hook)
|
||||
{
|
||||
}
|
||||
|
||||
~unicorn_hook()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
unicorn_hook(const unicorn_hook&) = delete;
|
||||
unicorn_hook& operator=(const unicorn_hook&) = delete;
|
||||
|
||||
|
||||
unicorn_hook(unicorn_hook&& obj) noexcept
|
||||
{
|
||||
this->operator=(std::move(obj));
|
||||
}
|
||||
|
||||
uc_hook* make_reference()
|
||||
{
|
||||
if (!this->uc_)
|
||||
{
|
||||
throw std::runtime_error("Cannot make reference on default constructed hook");
|
||||
}
|
||||
|
||||
this->release();
|
||||
return &this->hook_;
|
||||
}
|
||||
|
||||
unicorn_hook& operator=(unicorn_hook&& obj) noexcept
|
||||
{
|
||||
if (this != &obj)
|
||||
{
|
||||
this->release();
|
||||
|
||||
this->uc_ = obj.uc_;
|
||||
this->hook_ = obj.hook_;
|
||||
obj.uc_ = {};
|
||||
}
|
||||
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (this->hook_ && this->uc_)
|
||||
{
|
||||
uc_hook_del(this->uc_, this->hook_);
|
||||
this->hook_ = {};
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uc_engine* uc_{};
|
||||
uc_hook hook_{};
|
||||
};
|
||||
|
||||
template <typename ReturnType, typename... Args>
|
||||
class function_wrapper : public object
|
||||
{
|
||||
public:
|
||||
using user_data_pointer = void*;
|
||||
using c_function_type = ReturnType(Args..., user_data_pointer);
|
||||
using functor_type = std::function<ReturnType(Args...)>;
|
||||
|
||||
function_wrapper(functor_type functor)
|
||||
: functor_(std::make_unique<functor_type>(std::move(functor)))
|
||||
{
|
||||
}
|
||||
|
||||
c_function_type* get_function()
|
||||
{
|
||||
return +[](Args... args, user_data_pointer user_data) -> ReturnType
|
||||
{
|
||||
return (*static_cast<functor_type*>(user_data))(std::forward<Args>(args)...);
|
||||
};
|
||||
}
|
||||
|
||||
user_data_pointer get_user_data() const
|
||||
{
|
||||
return this->functor_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<functor_type> functor_{};
|
||||
};
|
||||
|
||||
class hook_container : public hook_object
|
||||
{
|
||||
public:
|
||||
template <typename T>
|
||||
requires(std::is_base_of_v<object, T>
|
||||
&& std::is_move_constructible_v<T>)
|
||||
void add(T data, unicorn_hook hook)
|
||||
{
|
||||
hook_entry entry{};
|
||||
|
||||
entry.data = std::make_unique<T>(std::move(data));
|
||||
entry.hook = std::move(hook);
|
||||
|
||||
this->hooks_.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
private:
|
||||
struct hook_entry
|
||||
{
|
||||
std::unique_ptr<object> data{};
|
||||
unicorn_hook hook{};
|
||||
};
|
||||
|
||||
std::vector<hook_entry> hooks_;
|
||||
};
|
||||
|
||||
class unicorn_x64_emulator : public x64_emulator
|
||||
{
|
||||
public:
|
||||
@@ -169,6 +341,121 @@ namespace unicorn
|
||||
return result;
|
||||
}
|
||||
|
||||
emulator_hook* hook_instruction(x64_hookable_instructions instruction_type,
|
||||
simple_instruction_hook_callback callback)
|
||||
{
|
||||
const auto uc_instruction = map_hookable_instruction(instruction_type);
|
||||
|
||||
function_wrapper<void, uc_engine*> wrapper([c = std::move(callback)](uc_engine*)
|
||||
{
|
||||
c();
|
||||
});
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_INSN, wrapper.get_function(),
|
||||
wrapper.get_user_data(), 0, std::numeric_limits<pointer_type>::max(), uc_instruction));
|
||||
|
||||
auto container = std::make_unique<hook_container>();
|
||||
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(uint64_t address, size_t size, memory_operation filter,
|
||||
complex_memory_hook_callback callback) override
|
||||
{
|
||||
if (filter == memory_permission::none)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const auto shared_callback = std::make_shared<complex_memory_hook_callback>(std::move(callback));
|
||||
|
||||
auto container = std::make_unique<hook_container>();
|
||||
|
||||
if ((filter & memory_operation::read) != memory_operation::none)
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
[shared_callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size,
|
||||
const int64_t)
|
||||
{
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none)
|
||||
{
|
||||
(*shared_callback)(address, static_cast<uint64_t>(size), operation);
|
||||
}
|
||||
});
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_READ, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, address + size));
|
||||
|
||||
container->add(std::move(wrapper), std::move(hook));
|
||||
}
|
||||
|
||||
if ((filter & memory_operation::write) != memory_operation::none)
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
[shared_callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size,
|
||||
const int64_t)
|
||||
{
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none)
|
||||
{
|
||||
(*shared_callback)(address, static_cast<uint64_t>(size), operation);
|
||||
}
|
||||
});
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_WRITE, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, address + size));
|
||||
|
||||
container->add(std::move(wrapper), std::move(hook));
|
||||
}
|
||||
|
||||
if ((filter & memory_operation::exec) != memory_operation::none)
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uint64_t, uint32_t> wrapper(
|
||||
[shared_callback](uc_engine*, const uint64_t address, const uint32_t size)
|
||||
{
|
||||
(*shared_callback)(address, static_cast<uint64_t>(size), memory_permission::exec);
|
||||
});
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, 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;
|
||||
}
|
||||
|
||||
void delete_hook(emulator_hook* hook) override
|
||||
{
|
||||
const auto entry = std::ranges::find_if(this->hooks_, [&](const std::unique_ptr<hook_object>& hook_ptr)
|
||||
{
|
||||
return hook_ptr->as_opaque_hook() == hook;
|
||||
});
|
||||
|
||||
if (entry != this->hooks_.end())
|
||||
{
|
||||
this->hooks_.erase(entry);
|
||||
}
|
||||
}
|
||||
|
||||
operator uc_engine*() const
|
||||
{
|
||||
return this->uc_;
|
||||
@@ -176,6 +463,7 @@ namespace unicorn
|
||||
|
||||
private:
|
||||
uc_engine* uc_{};
|
||||
std::vector<std::unique_ptr<hook_object>> hooks_{};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
#include "memory_utils.hpp"
|
||||
|
||||
#include <emulator.hpp>
|
||||
|
||||
template <typename T>
|
||||
class emulator_object
|
||||
{
|
||||
@@ -137,96 +135,3 @@ private:
|
||||
uint64_t size_{};
|
||||
uint64_t active_address_{0};
|
||||
};
|
||||
|
||||
/*
|
||||
class unicorn_hook
|
||||
{
|
||||
public:
|
||||
using function = std::function<void(const unicorn& uc, uint64_t address, uint32_t size)>;
|
||||
|
||||
template <typename... Args>
|
||||
unicorn_hook(const unicorn& uc, const int type, const uint64_t begin, const uint64_t end, function callback,
|
||||
Args... args)
|
||||
: uc_(&uc)
|
||||
{
|
||||
this->function_ = std::make_unique<internal_function>(
|
||||
[c = std::move(callback), &uc](const uint64_t address, const uint32_t size)
|
||||
{
|
||||
c(uc, address, size);
|
||||
});
|
||||
|
||||
void* handler = +[](uc_engine*, const uint64_t address, const uint32_t size,
|
||||
void* user_data)
|
||||
{
|
||||
(*static_cast<internal_function*>(user_data))(address, size);
|
||||
};
|
||||
|
||||
if (type == UC_HOOK_INSN)
|
||||
{
|
||||
handler = +[](uc_engine* uc, void* user_data)
|
||||
{
|
||||
uint64_t rip{};
|
||||
uc_reg_read(uc, UC_X86_REG_RIP, &rip);
|
||||
(*static_cast<internal_function*>(user_data))(rip, 0);
|
||||
};
|
||||
}
|
||||
|
||||
if (type == UC_HOOK_MEM_READ)
|
||||
{
|
||||
handler = +[](uc_engine*, const uc_mem_type, const uint64_t address, const int size,
|
||||
const int64_t, void* user_data)
|
||||
{
|
||||
(*static_cast<internal_function*>(user_data))(address, size);
|
||||
};
|
||||
}
|
||||
uce(uc_hook_add(*this->uc_, &this->hook_, type, handler, this->function_.get(), begin, end, args...));
|
||||
}
|
||||
|
||||
unicorn_hook(const unicorn_hook&) = delete;
|
||||
unicorn_hook& operator=(const unicorn_hook&) = delete;
|
||||
|
||||
unicorn_hook(unicorn_hook&& obj) noexcept
|
||||
{
|
||||
this->operator=(std::move(obj));
|
||||
}
|
||||
|
||||
unicorn_hook& operator=(unicorn_hook&& obj) noexcept
|
||||
{
|
||||
if (this != &obj)
|
||||
{
|
||||
this->remove();
|
||||
|
||||
this->uc_ = obj.uc_;
|
||||
this->hook_ = obj.hook_;
|
||||
this->function_ = std::move(obj.function_);
|
||||
|
||||
obj.hook_ = {};
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~unicorn_hook()
|
||||
{
|
||||
this->remove();
|
||||
}
|
||||
|
||||
void remove()
|
||||
{
|
||||
if (this->hook_)
|
||||
{
|
||||
uc_hook_del(*this->uc_, this->hook_);
|
||||
this->hook_ = {};
|
||||
}
|
||||
|
||||
this->function_ = {};
|
||||
}
|
||||
|
||||
private:
|
||||
using internal_function = std::function<void(uint64_t address, uint32_t size)>;
|
||||
|
||||
const unicorn* uc_{};
|
||||
uc_hook hook_{};
|
||||
std::unique_ptr<internal_function> function_{};
|
||||
};
|
||||
*/
|
||||
@@ -270,24 +270,21 @@ namespace
|
||||
std::map<size_t, std::string> members_{};
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
template <typename T>
|
||||
unicorn_hook watch_object(const unicorn& uc, emulator_object<T> object)
|
||||
void watch_object(x64_emulator& emu, emulator_object<T> object)
|
||||
{
|
||||
type_info<T> info{};
|
||||
|
||||
return {
|
||||
uc, UC_HOOK_MEM_READ, object.value(), object.end(),
|
||||
[i = std::move(info), o = std::move(object)](const unicorn&, const uint64_t address,
|
||||
const uint32_t )
|
||||
{
|
||||
const auto offset = address - o.value();
|
||||
printf("%s: %llX (%s)\n", i.get_type_name().c_str(), offset,
|
||||
i.get_member_name(offset).c_str());
|
||||
}
|
||||
};
|
||||
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 run()
|
||||
{
|
||||
const auto emu = unicorn::create_x64_emulator();
|
||||
@@ -309,10 +306,6 @@ namespace
|
||||
(void)entry1;
|
||||
(void)entry2;
|
||||
|
||||
/*
|
||||
std::vector<unicorn_hook> export_hooks{};
|
||||
|
||||
|
||||
std::unordered_map<uint64_t, std::string> export_remap{};
|
||||
for (const auto& exp : context.ntdll.exports)
|
||||
{
|
||||
@@ -322,53 +315,49 @@ namespace
|
||||
for (const auto& exp : export_remap)
|
||||
{
|
||||
auto name = exp.second;
|
||||
unicorn_hook hook(uc, UC_HOOK_CODE, exp.first, exp.first,
|
||||
[n = std::move(name)](const unicorn& uc, const uint64_t address, const uint32_t)
|
||||
{
|
||||
printf("Executing function: %s (%llX)\n", n.c_str(), address);
|
||||
emu->hook_memory_execution(exp.first, exp.first,
|
||||
[&emu, n = std::move(name)](const uint64_t address, const size_t)
|
||||
{
|
||||
printf("Executing function: %s (%llX)\n", n.c_str(), address);
|
||||
|
||||
if (n == "RtlImageNtHeaderEx")
|
||||
{
|
||||
printf("Base: %llX\n", uc.reg(UC_X86_REG_RDX));
|
||||
}
|
||||
});
|
||||
|
||||
export_hooks.emplace_back(std::move(hook));
|
||||
if (n == "RtlImageNtHeaderEx")
|
||||
{
|
||||
printf("Base: %llX\n", emu->reg(x64_register::rdx));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
unicorn_hook hook(uc, UC_HOOK_INSN, 0, std::numeric_limits<uint64_t>::max(),
|
||||
[&](const unicorn&, const uint64_t, const uint32_t)
|
||||
{
|
||||
handle_syscall(uc, context);
|
||||
}, UC_X86_INS_SYSCALL);
|
||||
emu->hook_instruction(x64_hookable_instructions::syscall, [&]
|
||||
{
|
||||
handle_syscall(*emu, context);
|
||||
});
|
||||
|
||||
//export_hooks.emplace_back(watch_object(uc, context.teb));
|
||||
//export_hooks.emplace_back(watch_object(uc, context.peb));
|
||||
//export_hooks.emplace_back(watch_object(uc, context.process_params));
|
||||
//export_hooks.emplace_back(watch_object(uc, context.kusd));
|
||||
watch_object(*emu, context.teb);
|
||||
watch_object(*emu, context.peb);
|
||||
watch_object(*emu, context.process_params);
|
||||
watch_object(*emu, context.kusd);
|
||||
|
||||
unicorn_hook hook2(uc, UC_HOOK_CODE, 0, std::numeric_limits<uint64_t>::max(),
|
||||
[](const unicorn& uc, const uint64_t address, const uint32_t )
|
||||
{
|
||||
static bool hit = false;
|
||||
// if (address == 0x1800D3C80)
|
||||
if (address == 0x1800D4420)
|
||||
{
|
||||
//hit = true;
|
||||
//uc.stop();
|
||||
}
|
||||
emu->hook_memory_execution(0, std::numeric_limits<size_t>::max(), [&](const uint64_t address, const size_t)
|
||||
{
|
||||
static bool hit = false;
|
||||
// if (address == 0x1800D3C80)
|
||||
if (address == 0x1800D4420)
|
||||
{
|
||||
//hit = true;
|
||||
//uc.stop();
|
||||
}
|
||||
|
||||
if (hit)
|
||||
{
|
||||
printf(
|
||||
"Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX\n",
|
||||
address,
|
||||
emu->reg(x64_register::rax), emu->reg(x64_register::rbx), emu->reg(x64_register::rcx),
|
||||
emu->reg(x64_register::rdx), emu->reg(x64_register::r8), emu->reg(x64_register::r9),
|
||||
emu->reg(x64_register::rdi), emu->reg(x64_register::rsi));
|
||||
}
|
||||
});
|
||||
|
||||
if (hit)
|
||||
{
|
||||
printf(
|
||||
"Inst: %16llX - RAX: %16llX - RBX: %16llX - RCX: %16llX - RDX: %16llX - R8: %16llX - R9: %16llX - RDI: %16llX - RSI: %16llX\n",
|
||||
address,
|
||||
uc.reg(UC_X86_REG_RAX), uc.reg(UC_X86_REG_RBX), uc.reg(UC_X86_REG_RCX),
|
||||
uc.reg(UC_X86_REG_RDX), uc.reg(UC_X86_REG_R8), uc.reg(UC_X86_REG_R9),
|
||||
uc.reg(UC_X86_REG_RDI), uc.reg(UC_X86_REG_RSI));
|
||||
}
|
||||
});
|
||||
*/
|
||||
const auto execution_context = context.gs_segment.reserve<CONTEXT>();
|
||||
|
||||
emu->reg(x64_register::rcx, execution_context.value());
|
||||
|
||||
@@ -59,7 +59,7 @@ inline bool is_memory_allocated(emulator& emu, const uint64_t address)
|
||||
return false;
|
||||
}
|
||||
|
||||
inline memory_permission map_nt_to_unicorn_protection(const uint32_t nt_protection)
|
||||
inline memory_permission map_nt_to_emulator_protection(const uint32_t nt_protection)
|
||||
{
|
||||
switch (nt_protection)
|
||||
{
|
||||
@@ -80,7 +80,7 @@ inline memory_permission map_nt_to_unicorn_protection(const uint32_t nt_protecti
|
||||
}
|
||||
}
|
||||
|
||||
inline uint32_t map_unicorn_to_nt_protection(const memory_permission permission)
|
||||
inline uint32_t map_emulator_to_nt_protection(const memory_permission permission)
|
||||
{
|
||||
const bool has_exec = (permission & memory_permission::exec) != memory_permission::none;
|
||||
const bool has_read = (permission & memory_permission::read) != memory_permission::none;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#include "unicorn_utils.hpp"
|
||||
#include "emulator_utils.hpp"
|
||||
|
||||
struct mapped_binary
|
||||
{
|
||||
|
||||
@@ -56,8 +56,6 @@
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <unicorn/unicorn.h>
|
||||
|
||||
#define NTDDI_WIN11_GE 0
|
||||
#define PHNT_VERSION PHNT_WIN11
|
||||
#include <phnt_windows.h>
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
|
||||
namespace
|
||||
{
|
||||
void handle_NtQueryPerformanceCounter(const unicorn& uc)
|
||||
void handle_NtQueryPerformanceCounter(x64_emulator& emu)
|
||||
{
|
||||
const emulator_object<LARGE_INTEGER> performance_counter{uc, uc.reg(UC_X86_REG_R10)};
|
||||
const emulator_object<LARGE_INTEGER> performance_frequency{uc, uc.reg(UC_X86_REG_RDX)};
|
||||
const emulator_object<LARGE_INTEGER> performance_counter{emu, emu.reg(x64_register::r10)};
|
||||
const emulator_object<LARGE_INTEGER> performance_frequency{emu, emu.reg(x64_register::rdx)};
|
||||
|
||||
try
|
||||
{
|
||||
@@ -26,45 +26,45 @@ namespace
|
||||
});
|
||||
}
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_ACCESS_VIOLATION);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_ACCESS_VIOLATION);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_NtManageHotPatch(const unicorn& uc)
|
||||
void handle_NtManageHotPatch(x64_emulator& emu)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
void handle_NtOpenKey(const unicorn& uc)
|
||||
void handle_NtOpenKey(x64_emulator& emu)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
void handle_NtCreateIoCompletion(const unicorn& uc)
|
||||
void handle_NtCreateIoCompletion(x64_emulator& emu)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
void handle_NtTraceEvent(const unicorn& uc)
|
||||
void handle_NtTraceEvent(x64_emulator& emu)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
void handle_NtCreateEvent(const unicorn& uc, process_context& context)
|
||||
void handle_NtCreateEvent(x64_emulator& emu, process_context& context)
|
||||
{
|
||||
const emulator_object<uint64_t> event_handle{uc, uc.reg(UC_X86_REG_R10)};
|
||||
const auto object_attributes = uc.reg(UC_X86_REG_R8);
|
||||
const auto event_type = uc.reg<EVENT_TYPE>(UC_X86_REG_R9D);
|
||||
const auto initial_state = static_cast<BOOLEAN>(uc.read_stack(5));
|
||||
const emulator_object<uint64_t> event_handle{emu, emu.reg(x64_register::r10)};
|
||||
const auto object_attributes = emu.reg(x64_register::r8);
|
||||
const auto event_type = emu.reg<EVENT_TYPE>(x64_register::r9d);
|
||||
const auto initial_state = static_cast<BOOLEAN>(emu.read_stack(5));
|
||||
|
||||
if (object_attributes)
|
||||
{
|
||||
puts("Unsupported object attributes");
|
||||
uc.stop();
|
||||
emu.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -75,34 +75,34 @@ namespace
|
||||
|
||||
static_assert(sizeof(EVENT_TYPE) == sizeof(uint32_t));
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void handle_NtQueryVirtualMemory(const unicorn& uc, const process_context& context)
|
||||
void handle_NtQueryVirtualMemory(x64_emulator& emu, const process_context& context)
|
||||
{
|
||||
const auto process_handle = uc.reg(UC_X86_REG_R10);
|
||||
const auto base_address = uc.reg(UC_X86_REG_RDX);
|
||||
const auto info_class = uc.reg<uint32_t>(UC_X86_REG_R8D);
|
||||
const auto memory_information = uc.reg(UC_X86_REG_R9);
|
||||
const auto memory_information_length = static_cast<uint32_t>(uc.read_stack(5));
|
||||
const emulator_object<uint32_t> return_length{uc, uc.read_stack(6)};
|
||||
const auto process_handle = emu.reg(x64_register::r10);
|
||||
const auto base_address = emu.reg(x64_register::rdx);
|
||||
const auto info_class = emu.reg<uint32_t>(x64_register::r8d);
|
||||
const auto memory_information = emu.reg(x64_register::r9);
|
||||
const auto memory_information_length = static_cast<uint32_t>(emu.read_stack(5));
|
||||
const emulator_object<uint32_t> return_length{emu, emu.read_stack(6)};
|
||||
|
||||
if (process_handle != ~0ULL)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info_class == MemoryWorkingSetExInformation)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info_class != MemoryImageInformation)
|
||||
{
|
||||
printf("Unsupported memory info class: %X\n", info_class);
|
||||
uc.stop();
|
||||
emu.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -113,18 +113,18 @@ namespace
|
||||
|
||||
if (memory_information_length != sizeof(MEMORY_IMAGE_INFORMATION))
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_BUFFER_OVERFLOW);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_BUFFER_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!is_within_start_and_length(base_address, context.ntdll.image_base, context.ntdll.size_of_image))
|
||||
{
|
||||
puts("Bad image request");
|
||||
uc.stop();
|
||||
emu.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
const emulator_object<MEMORY_IMAGE_INFORMATION> info{uc, memory_information};
|
||||
const emulator_object<MEMORY_IMAGE_INFORMATION> info{emu, memory_information};
|
||||
|
||||
info.access([&](MEMORY_IMAGE_INFORMATION& image_info)
|
||||
{
|
||||
@@ -132,20 +132,20 @@ namespace
|
||||
image_info.SizeOfImage = context.ntdll.size_of_image;
|
||||
});
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void handle_NtQuerySystemInformation(const unicorn& uc)
|
||||
void handle_NtQuerySystemInformation(x64_emulator& emu)
|
||||
{
|
||||
const auto info_class = uc.reg<uint32_t>(UC_X86_REG_R10D);
|
||||
const auto system_information = uc.reg(UC_X86_REG_RDX);
|
||||
const auto system_information_length = uc.reg<uint32_t>(UC_X86_REG_R8D);
|
||||
const emulator_object<uint32_t> return_length{uc, uc.reg(UC_X86_REG_R9)};
|
||||
const auto info_class = emu.reg<uint32_t>(x64_register::r10d);
|
||||
const auto system_information = emu.reg(x64_register::rdx);
|
||||
const auto system_information_length = emu.reg<uint32_t>(x64_register::r8d);
|
||||
const emulator_object<uint32_t> return_length{emu, emu.reg(x64_register::r9)};
|
||||
|
||||
if (info_class == SystemFlushInformation
|
||||
|| info_class == SystemHypervisorSharedPageInformation)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,11 +158,11 @@ namespace
|
||||
|
||||
if (system_information_length != sizeof(SYSTEM_NUMA_INFORMATION))
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_BUFFER_TOO_SMALL);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_BUFFER_TOO_SMALL);
|
||||
return;
|
||||
}
|
||||
|
||||
const emulator_object<SYSTEM_NUMA_INFORMATION> info_obj{uc, system_information};
|
||||
const emulator_object<SYSTEM_NUMA_INFORMATION> info_obj{emu, system_information};
|
||||
|
||||
info_obj.access([&](SYSTEM_NUMA_INFORMATION& info)
|
||||
{
|
||||
@@ -172,14 +172,14 @@ namespace
|
||||
info.Pad[0] = 0xFFF;
|
||||
});
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation)
|
||||
{
|
||||
printf("Unsupported system info class: %X\n", info_class);
|
||||
uc.stop();
|
||||
emu.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -190,11 +190,11 @@ namespace
|
||||
|
||||
if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION))
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_BUFFER_TOO_SMALL);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_BUFFER_TOO_SMALL);
|
||||
return;
|
||||
}
|
||||
|
||||
const emulator_object<SYSTEM_BASIC_INFORMATION> info{uc, system_information};
|
||||
const emulator_object<SYSTEM_BASIC_INFORMATION> info{emu, system_information};
|
||||
|
||||
info.access([&](SYSTEM_BASIC_INFORMATION& basic_info)
|
||||
{
|
||||
@@ -210,23 +210,23 @@ namespace
|
||||
basic_info.NumberOfProcessors = 1;
|
||||
});
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void handle_NtQuerySystemInformationEx(const unicorn& uc)
|
||||
void handle_NtQuerySystemInformationEx(x64_emulator& emu)
|
||||
{
|
||||
const auto info_class = uc.reg<uint32_t>(UC_X86_REG_R10D);
|
||||
const auto input_buffer = uc.reg(UC_X86_REG_RDX);
|
||||
const auto input_buffer_length = uc.reg<uint32_t>(UC_X86_REG_R8D);
|
||||
const auto system_information = uc.reg(UC_X86_REG_R9);
|
||||
const auto system_information_length = static_cast<uint32_t>(uc.read_stack(5));
|
||||
const emulator_object<uint32_t> return_length{uc, uc.read_stack(6)};
|
||||
const auto info_class = emu.reg<uint32_t>(x64_register::r10d);
|
||||
const auto input_buffer = emu.reg(x64_register::rdx);
|
||||
const auto input_buffer_length = emu.reg<uint32_t>(x64_register::r8d);
|
||||
const auto system_information = emu.reg(x64_register::r9);
|
||||
const auto system_information_length = static_cast<uint32_t>(emu.read_stack(5));
|
||||
const emulator_object<uint32_t> return_length{emu, emu.read_stack(6)};
|
||||
|
||||
if (info_class == SystemFlushInformation
|
||||
|| info_class == SystemFeatureConfigurationInformation
|
||||
|| info_class == SystemFeatureConfigurationSectionInformation)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_SUPPORTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_SUPPORTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace
|
||||
{
|
||||
void* buffer = calloc(1, input_buffer_length);
|
||||
void* res_buff = calloc(1, system_information_length);
|
||||
uc_mem_read(uc, input_buffer, buffer, input_buffer_length);
|
||||
emu.read_memory(input_buffer, buffer, input_buffer_length);
|
||||
|
||||
uint64_t code = 0;
|
||||
|
||||
@@ -247,20 +247,20 @@ namespace
|
||||
|
||||
if (code == 0)
|
||||
{
|
||||
uc_mem_write(uc, system_information, res_buff, return_length.read());
|
||||
emu.write_memory(system_information, res_buff, return_length.read());
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
free(res_buff);
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, code);
|
||||
emu.reg<uint64_t>(x64_register::rax, code);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info_class != SystemBasicInformation && info_class != SystemEmulationBasicInformation)
|
||||
{
|
||||
printf("Unsupported system info ex class: %X\n", info_class);
|
||||
uc.stop();
|
||||
emu.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -271,11 +271,11 @@ namespace
|
||||
|
||||
if (system_information_length != sizeof(SYSTEM_BASIC_INFORMATION))
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_BUFFER_TOO_SMALL);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_BUFFER_TOO_SMALL);
|
||||
return;
|
||||
}
|
||||
|
||||
const emulator_object<SYSTEM_BASIC_INFORMATION> info{uc, system_information};
|
||||
const emulator_object<SYSTEM_BASIC_INFORMATION> info{emu, system_information};
|
||||
|
||||
info.access([&](SYSTEM_BASIC_INFORMATION& basic_info)
|
||||
{
|
||||
@@ -291,27 +291,27 @@ namespace
|
||||
basic_info.NumberOfProcessors = 1;
|
||||
});
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void handle_NtQueryProcessInformation(const unicorn& uc)
|
||||
void handle_NtQueryProcessInformation(x64_emulator& emu)
|
||||
{
|
||||
const auto process_handle = uc.reg<uint64_t>(UC_X86_REG_R10);
|
||||
const auto info_class = uc.reg<uint32_t>(UC_X86_REG_EDX);
|
||||
const auto process_information = uc.reg(UC_X86_REG_R8);
|
||||
const auto process_information_length = uc.reg<uint32_t>(UC_X86_REG_R9D);
|
||||
const emulator_object<uint32_t> return_length{uc, uc.read_stack(5)};
|
||||
const auto process_handle = emu.reg<uint64_t>(x64_register::r10);
|
||||
const auto info_class = emu.reg<uint32_t>(x64_register::edx);
|
||||
const auto process_information = emu.reg(x64_register::r8);
|
||||
const auto process_information_length = emu.reg<uint32_t>(x64_register::r9d);
|
||||
const emulator_object<uint32_t> return_length{emu, emu.read_stack(5)};
|
||||
|
||||
if (process_handle != ~0ULL)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
if (info_class != ProcessCookie)
|
||||
{
|
||||
printf("Unsupported process info class: %X\n", info_class);
|
||||
uc.stop();
|
||||
emu.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -322,27 +322,27 @@ namespace
|
||||
|
||||
if (process_information_length != sizeof(uint32_t))
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_BUFFER_OVERFLOW);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_BUFFER_OVERFLOW);
|
||||
return;
|
||||
}
|
||||
|
||||
const emulator_object<uint32_t> info{uc, process_information};
|
||||
const emulator_object<uint32_t> info{emu, process_information};
|
||||
info.write(0x01234567);
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void handle_NtProtectVirtualMemory(const unicorn& uc)
|
||||
void handle_NtProtectVirtualMemory(x64_emulator& emu)
|
||||
{
|
||||
const auto process_handle = uc.reg(UC_X86_REG_R10);
|
||||
const emulator_object<uint64_t> base_address{uc, uc.reg(UC_X86_REG_RDX)};
|
||||
const emulator_object<uint32_t> bytes_to_protect{uc, uc.reg(UC_X86_REG_R8)};
|
||||
const auto protection = uc.reg<uint32_t>(UC_X86_REG_R9D);
|
||||
const emulator_object<uint32_t> old_protection{uc, uc.read_stack(5)};
|
||||
const auto process_handle = emu.reg(x64_register::r10);
|
||||
const emulator_object<uint64_t> base_address{emu, emu.reg(x64_register::rdx)};
|
||||
const emulator_object<uint32_t> bytes_to_protect{emu, emu.reg(x64_register::r8)};
|
||||
const auto protection = emu.reg<uint32_t>(x64_register::r9d);
|
||||
const emulator_object<uint32_t> old_protection{emu, emu.read_stack(5)};
|
||||
|
||||
if (process_handle != ~0ULL)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -352,27 +352,27 @@ namespace
|
||||
const auto size = page_align_up(bytes_to_protect.read());
|
||||
bytes_to_protect.write(static_cast<uint32_t>(size));
|
||||
|
||||
const auto current_uc_protection = get_memory_protection(uc, address);
|
||||
const auto current_protection = map_unicorn_to_nt_protection(current_uc_protection);
|
||||
const auto current_uc_protection = get_memory_protection(emu, address);
|
||||
const auto current_protection = map_emulator_to_nt_protection(current_uc_protection);
|
||||
old_protection.write(current_protection);
|
||||
|
||||
const auto requested_protection = map_nt_to_unicorn_protection(protection);
|
||||
uce(uc_mem_protect(uc, address, size, requested_protection));
|
||||
const auto requested_protection = map_nt_to_emulator_protection(protection);
|
||||
emu.protect_memory(address, size, requested_protection);
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void handle_NtAllocateVirtualMemory(const unicorn& uc)
|
||||
void handle_NtAllocateVirtualMemory(x64_emulator& emu)
|
||||
{
|
||||
const auto process_handle = uc.reg(UC_X86_REG_R10);
|
||||
const emulator_object<uint64_t> base_address{uc, uc.reg(UC_X86_REG_RDX)};
|
||||
const emulator_object<uint64_t> bytes_to_allocate{uc, uc.reg(UC_X86_REG_R9)};
|
||||
//const auto allocation_type = uc.reg<uint32_t>(UC_X86_REG_R9D);
|
||||
const auto page_protection = static_cast<uint32_t>(uc.read_stack(6));
|
||||
const auto process_handle = emu.reg(x64_register::r10);
|
||||
const emulator_object<uint64_t> base_address{emu, emu.reg(x64_register::rdx)};
|
||||
const emulator_object<uint64_t> bytes_to_allocate{emu, emu.reg(x64_register::r9)};
|
||||
//const auto allocation_type =emu.reg<uint32_t>(x64_register::r9d);
|
||||
const auto page_protection = static_cast<uint32_t>(emu.read_stack(6));
|
||||
|
||||
if (process_handle != ~0ULL)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ namespace
|
||||
//allocation_bytes = align_up(allocation_bytes, allocation_granularity);
|
||||
//bytes_to_allocate.write(allocation_bytes);
|
||||
|
||||
const auto protection = map_nt_to_unicorn_protection(page_protection);
|
||||
const auto protection = map_nt_to_emulator_protection(page_protection);
|
||||
|
||||
auto allocate_anywhere = false;
|
||||
auto allocation_base = base_address.read();
|
||||
@@ -390,9 +390,9 @@ namespace
|
||||
allocate_anywhere = true;
|
||||
allocation_base = allocation_granularity;
|
||||
}
|
||||
else if (is_memory_allocated(uc, allocation_base))
|
||||
else if (is_memory_allocated(emu, allocation_base))
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -400,34 +400,42 @@ namespace
|
||||
|
||||
while (true)
|
||||
{
|
||||
succeeded = uc_mem_map(uc, allocation_base, allocation_bytes, protection) == UC_ERR_OK;
|
||||
if (succeeded || !allocate_anywhere)
|
||||
try
|
||||
{
|
||||
emu.map_memory(allocation_base, allocation_bytes, protection);
|
||||
succeeded = true;
|
||||
break;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
if (!allocate_anywhere)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
allocation_base += allocation_granularity;
|
||||
allocation_base += allocation_granularity;
|
||||
}
|
||||
}
|
||||
|
||||
base_address.write(allocation_base);
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, succeeded
|
||||
? STATUS_SUCCESS
|
||||
: STATUS_NOT_SUPPORTED // No idea what the correct code is
|
||||
emu.reg<uint64_t>(x64_register::rax, succeeded
|
||||
? STATUS_SUCCESS
|
||||
: STATUS_NOT_SUPPORTED // No idea what the correct code is
|
||||
);
|
||||
}
|
||||
|
||||
void handle_NtAllocateVirtualMemoryEx(const unicorn& uc)
|
||||
void handle_NtAllocateVirtualMemoryEx(x64_emulator& emu)
|
||||
{
|
||||
const auto process_handle = uc.reg(UC_X86_REG_R10);
|
||||
const emulator_object<uint64_t> base_address{uc, uc.reg(UC_X86_REG_RDX)};
|
||||
const emulator_object<uint64_t> bytes_to_allocate{uc, uc.reg(UC_X86_REG_R8)};
|
||||
//const auto allocation_type = uc.reg<uint32_t>(UC_X86_REG_R9D);
|
||||
const auto page_protection = static_cast<uint32_t>(uc.read_stack(5));
|
||||
const auto process_handle = emu.reg(x64_register::r10);
|
||||
const emulator_object<uint64_t> base_address{emu, emu.reg(x64_register::rdx)};
|
||||
const emulator_object<uint64_t> bytes_to_allocate{emu, emu.reg(x64_register::r8)};
|
||||
//const auto allocation_type =emu.reg<uint32_t>(x64_register::r9d);
|
||||
const auto page_protection = static_cast<uint32_t>(emu.read_stack(5));
|
||||
|
||||
if (process_handle != ~0ULL)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -436,7 +444,7 @@ namespace
|
||||
//allocation_bytes = align_up(allocation_bytes, allocation_granularity);
|
||||
//bytes_to_allocate.write(allocation_bytes);
|
||||
|
||||
const auto protection = map_nt_to_unicorn_protection(page_protection);
|
||||
const auto protection = map_nt_to_emulator_protection(page_protection);
|
||||
|
||||
auto allocate_anywhere = false;
|
||||
auto allocation_base = base_address.read();
|
||||
@@ -445,9 +453,9 @@ namespace
|
||||
allocate_anywhere = true;
|
||||
allocation_base = allocation_granularity;
|
||||
}
|
||||
else if (is_memory_allocated(uc, allocation_base))
|
||||
else if (is_memory_allocated(emu, allocation_base))
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_SUCCESS);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_SUCCESS);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -455,51 +463,69 @@ namespace
|
||||
|
||||
while (true)
|
||||
{
|
||||
succeeded = uc_mem_map(uc, allocation_base, allocation_bytes, protection) == UC_ERR_OK;
|
||||
if (succeeded || !allocate_anywhere)
|
||||
try
|
||||
{
|
||||
emu.map_memory(allocation_base, allocation_bytes, protection);
|
||||
succeeded = true;
|
||||
break;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
succeeded = false;
|
||||
if (!allocate_anywhere)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
allocation_base += allocation_granularity;
|
||||
allocation_base += allocation_granularity;
|
||||
}
|
||||
}
|
||||
|
||||
base_address.write(allocation_base);
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, succeeded
|
||||
? STATUS_SUCCESS
|
||||
: STATUS_NOT_SUPPORTED // No idea what the correct code is
|
||||
emu.reg<uint64_t>(x64_register::rax, succeeded
|
||||
? STATUS_SUCCESS
|
||||
: STATUS_NOT_SUPPORTED // No idea what the correct code is
|
||||
);
|
||||
}
|
||||
|
||||
void handle_NtFreeVirtualMemory(const unicorn& uc)
|
||||
void handle_NtFreeVirtualMemory(x64_emulator& emu)
|
||||
{
|
||||
const auto process_handle = uc.reg(UC_X86_REG_R10);
|
||||
const emulator_object<uint64_t> base_address{uc, uc.reg(UC_X86_REG_RDX)};
|
||||
const emulator_object<uint64_t> bytes_to_allocate{uc, uc.reg(UC_X86_REG_R8)};
|
||||
const auto process_handle = emu.reg(x64_register::r10);
|
||||
const emulator_object<uint64_t> base_address{emu, emu.reg(x64_register::rdx)};
|
||||
const emulator_object<uint64_t> bytes_to_allocate{emu, emu.reg(x64_register::r8)};
|
||||
|
||||
if (process_handle != ~0ULL)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto allocation_base = base_address.read();
|
||||
const auto allocation_size = bytes_to_allocate.read();
|
||||
|
||||
const auto succeeded = uc_mem_unmap(uc, allocation_base, allocation_size) == UC_ERR_OK;
|
||||
bool succeeded = false;
|
||||
try
|
||||
{
|
||||
emu.unmap_memory(allocation_base, allocation_size);
|
||||
succeeded = true;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
succeeded = false;
|
||||
}
|
||||
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, succeeded
|
||||
? STATUS_SUCCESS
|
||||
: STATUS_NOT_SUPPORTED // No idea what the correct code is
|
||||
emu.reg<uint64_t>(x64_register::rax, succeeded
|
||||
? STATUS_SUCCESS
|
||||
: STATUS_NOT_SUPPORTED // No idea what the correct code is
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void handle_syscall(x64_emulator& emu, process_context& context)
|
||||
{
|
||||
const auto address = uc.reg(UC_X86_REG_RIP);
|
||||
const auto syscall_id = uc.reg<uint32_t>(UC_X86_REG_EAX);
|
||||
const auto address = emu.reg(x64_register::rip);
|
||||
const auto syscall_id = emu.reg<uint32_t>(x64_register::eax);
|
||||
|
||||
printf("Handling syscall: %X (%llX)\n", syscall_id, address);
|
||||
|
||||
@@ -508,56 +534,56 @@ void handle_syscall(x64_emulator& emu, process_context& context)
|
||||
switch (syscall_id)
|
||||
{
|
||||
case 0x12:
|
||||
handle_NtOpenKey(uc);
|
||||
handle_NtOpenKey(emu);
|
||||
break;
|
||||
case 0x18:
|
||||
handle_NtAllocateVirtualMemory(uc);
|
||||
handle_NtAllocateVirtualMemory(emu);
|
||||
break;
|
||||
case 0x1E:
|
||||
handle_NtFreeVirtualMemory(uc);
|
||||
handle_NtFreeVirtualMemory(emu);
|
||||
break;
|
||||
case 0x19:
|
||||
handle_NtQueryProcessInformation(uc);
|
||||
handle_NtQueryProcessInformation(emu);
|
||||
break;
|
||||
case 0x23:
|
||||
handle_NtQueryVirtualMemory(uc, context);
|
||||
handle_NtQueryVirtualMemory(emu, context);
|
||||
break;
|
||||
case 0x31:
|
||||
handle_NtQueryPerformanceCounter(uc);
|
||||
handle_NtQueryPerformanceCounter(emu);
|
||||
break;
|
||||
case 0x36:
|
||||
handle_NtQuerySystemInformation(uc);
|
||||
handle_NtQuerySystemInformation(emu);
|
||||
break;
|
||||
case 0x48:
|
||||
handle_NtCreateEvent(uc, context);
|
||||
handle_NtCreateEvent(emu, context);
|
||||
break;
|
||||
case 0x50:
|
||||
handle_NtProtectVirtualMemory(uc);
|
||||
handle_NtProtectVirtualMemory(emu);
|
||||
break;
|
||||
case 0x5E:
|
||||
handle_NtTraceEvent(uc);
|
||||
handle_NtTraceEvent(emu);
|
||||
break;
|
||||
case 0x78:
|
||||
handle_NtAllocateVirtualMemoryEx(uc);
|
||||
handle_NtAllocateVirtualMemoryEx(emu);
|
||||
break;
|
||||
case 0xB2:
|
||||
handle_NtCreateIoCompletion(uc);
|
||||
handle_NtCreateIoCompletion(emu);
|
||||
break;
|
||||
case 0x11A:
|
||||
handle_NtManageHotPatch(uc);
|
||||
handle_NtManageHotPatch(emu);
|
||||
break;
|
||||
case 0x16E:
|
||||
handle_NtQuerySystemInformationEx(uc);
|
||||
handle_NtQuerySystemInformationEx(emu);
|
||||
break;
|
||||
default:
|
||||
printf("Unhandled syscall: %X\n", syscall_id);
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_NOT_IMPLEMENTED);
|
||||
uc.stop();
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_NOT_IMPLEMENTED);
|
||||
emu.stop();
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
uc.reg<uint64_t>(UC_X86_REG_RAX, STATUS_UNSUCCESSFUL);
|
||||
emu.reg<uint64_t>(x64_register::rax, STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user