From cfb414ebd63e3dc735fcf415117cf06d93385741 Mon Sep 17 00:00:00 2001 From: Dennis Brentjes Date: Tue, 4 Oct 2016 20:01:12 +0200 Subject: adds emulation of a few more instructions. --- emulate/emulator.hpp | 208 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 4 deletions(-) (limited to 'emulate') diff --git a/emulate/emulator.hpp b/emulate/emulator.hpp index e894042..9bb5735 100644 --- a/emulate/emulator.hpp +++ b/emulate/emulator.hpp @@ -7,16 +7,172 @@ #include #include +#include + #include #include class Emulator { public: CpuState cpu; + std::vector memory; std::map> opcode_handlers; + typedef boost::variant RefValueType; + typedef boost::variant ValueType; + std::map> register_getters; + + std::map> interrupt_handlers; + + ValueType extract_immediate_of_size(int size, _DInst inst) { + switch(size) { + case 8: { + return inst.imm.byte; + } + case 16: { + return inst.imm.word; + } + case 32: { + return inst.imm.dword; + } + default: { + throw UnhandledInstruction(); + } + } + } + + struct print : public boost::static_visitor { + template + std::ostream& operator()(T const& t) const { + return std::cout << t; + } + }; + + struct dest_size : public boost::static_visitor { + template + unsigned int operator()(T const&) const { + return sizeof(T)*8; + } + }; + + struct return_visitor : public boost::static_visitor { + template + uint32_t operator()(T const& x) const { + return x; + } + }; + + struct IncompatibleArguments : public std::runtime_error { + IncompatibleArguments() + : std::runtime_error("The two arguments to this instruction are not compatible") + {} + }; + + template + struct binary_op : public boost::static_visitor { + template + Ret operator()(T&, U const&) const { + throw IncompatibleArguments(); + } + }; + + struct and_ : public binary_op { + using binary_op::operator(); + + template + void operator()(T& lh, T const& rh) const { + lh &= rh; + } + }; + + struct mov : public binary_op { + using binary_op::operator(); + + template + void operator()(T& lh, T const& rh) const { + lh = rh; + } + }; + + struct sub : public binary_op { + using binary_op::operator(); + + template + void operator()(T& lh, T const& rh) const { + lh -= rh; + } + }; + template + void handle_binary(_DInst inst) { + std::unique_ptr dest; + ValueType src; + + { + _Operand dest_op = inst.ops[0]; + + switch(dest_op.type) { + case O_REG: { + dest = std::make_unique(register_getters.at(dest_op.index)()); + break; + } + case O_MEM: { + throw UnhandledInstruction(); + break; + } + case O_SMEM: { + throw UnhandledInstruction(); + break; + } + case O_DISP: { + switch(dest_op.size) { + case 8: { + dest = std::make_unique(*reinterpret_cast(&memory[inst.disp])); + break; + } + case 16: { + dest = std::make_unique(*reinterpret_cast(&memory[inst.disp])); + break; + } + case 32: { + dest = std::make_unique(*reinterpret_cast(&memory[inst.disp])); + break; + } + default: { + throw UnhandledInstruction(); + } + } + break; + } + default: { + throw UnhandledInstruction(); + } + } + } + + { + _Operand src_op = inst.ops[1]; + + switch(src_op.type) { + case O_REG: { + auto x = register_getters.at(src_op.index)(); + src = register_getters.at(src_op.index)(); + break; + } + case O_IMM: { + //Do not rely on the imm size as we need to sign extend to dest size. + src = extract_immediate_of_size(boost::apply_visitor(dest_size(), *dest), inst); + break; + } + default: { + throw UnhandledInstruction(); + } + } + } + + boost::apply_visitor(O(), *dest, src); + } void handle_I_JMP(_DInst inst) { if(inst.ops[0].type == O_PC || inst.ops[0].type == O_PTR || inst.ops[0].type == O_DISP) { @@ -33,13 +189,37 @@ public: } void handle_I_AND(_DInst inst) { - std::cout << inst.ops[0].size << std::endl; - //get_op(0, inst) &= get_op(1, inst); + handle_binary(inst); + } + + void handle_I_MOV(_DInst inst) { + handle_binary(inst); + } + + void handle_I_SUB(_DInst inst) { + handle_binary(inst); + } + + void handle_I_INT(_DInst inst) { + _Operand int_op = inst.ops[0]; + + ValueType imm = extract_immediate_of_size(int_op.size, inst); + + interrupt_handlers.at(boost::apply_visitor(return_visitor(), imm))(); + } + + void int_0x21() { + if(cpu.ah() == 0x30) { + cpu.al() = 6; + cpu.ah() = 0; + cpu.bh() = 0; + } } public: - Emulator(binparse::Offset32 init_eip, binparse::Offset32 init_esp) + Emulator(binparse::Offset32 init_eip, binparse::Offset32 init_esp, std::vector memory) : cpu() + , memory(memory) { cpu.eip() = init_eip; cpu.esp() = init_esp; @@ -49,8 +229,28 @@ public: REGISTER_HANDLER(I_JMP); REGISTER_HANDLER(I_STI); REGISTER_HANDLER(I_AND); + REGISTER_HANDLER(I_MOV); + REGISTER_HANDLER(I_SUB); + REGISTER_HANDLER(I_INT); #undef REGISTER_HANDLER + + #define REGISTER_GETTER(REGISTER, R_NAME) register_getters[REGISTER] = [this]{return RefValueType(cpu.R_NAME());} + + REGISTER_GETTER(R_ESP, esp); + REGISTER_GETTER(R_AL , al ); + REGISTER_GETTER(R_AH , ah ); + REGISTER_GETTER(R_AX , ax ); + REGISTER_GETTER(R_EAX, eax); + REGISTER_GETTER(R_EBX, ebx); + + #undef REGISTER_GETTER + + #define REGISTER_INTERRUPT_HANDLER(INT) interrupt_handlers[INT] = [this]{return int_##INT();} + + REGISTER_INTERRUPT_HANDLER(0x21); + + #undef REGISTER_INTERRUPT_HANDLER } struct UnhandledInstruction : public std::runtime_error { @@ -86,7 +286,7 @@ void emulate(std::string file_path) { auto data_object = file.object_table.entries.at(file.le_header.ESP_object); auto initial_esp = data_object.reloc_base_address + file.le_header.ESP; - Emulator emulator(initial_eip, initial_esp); + Emulator emulator(initial_eip, initial_esp, binary); unsigned int decodedInstructionsCount; -- cgit v1.2.3-70-g09d2