diff options
Diffstat (limited to 'emulate')
| -rw-r--r-- | emulate/emulator.hpp | 208 |
1 files changed, 204 insertions, 4 deletions
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 <distorm.h> #include <mnemonics.h> +#include <boost/variant.hpp> + #include <fstream> #include <iomanip> class Emulator { public: CpuState cpu; + std::vector<uint8_t> memory; std::map<int, std::function<void(_DInst)>> opcode_handlers; + typedef boost::variant<uint32_t&, uint16_t&, uint8_t&> RefValueType; + typedef boost::variant<uint32_t, uint16_t, uint8_t> ValueType; + std::map<int, std::function<RefValueType()>> register_getters; + + std::map<int, std::function<void()>> 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<std::ostream&> { + template <typename T> + std::ostream& operator()(T const& t) const { + return std::cout << t; + } + }; + + struct dest_size : public boost::static_visitor<unsigned int> { + template<typename T> + unsigned int operator()(T const&) const { + return sizeof(T)*8; + } + }; + + struct return_visitor : public boost::static_visitor<uint32_t> { + template<typename T> + 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 <typename Ret> + struct binary_op : public boost::static_visitor<Ret> { + template <typename T, typename U> + Ret operator()(T&, U const&) const { + throw IncompatibleArguments(); + } + }; + + struct and_ : public binary_op<void> { + using binary_op::operator(); + + template<typename T> + void operator()(T& lh, T const& rh) const { + lh &= rh; + } + }; + + struct mov : public binary_op<void> { + using binary_op::operator(); + + template<typename T> + void operator()(T& lh, T const& rh) const { + lh = rh; + } + }; + + struct sub : public binary_op<void> { + using binary_op::operator(); + + template<typename T> + void operator()(T& lh, T const& rh) const { + lh -= rh; + } + }; + template <typename O> + void handle_binary(_DInst inst) { + std::unique_ptr<RefValueType> dest; + ValueType src; + + { + _Operand dest_op = inst.ops[0]; + + switch(dest_op.type) { + case O_REG: { + dest = std::make_unique<RefValueType>(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<RefValueType>(*reinterpret_cast<uint8_t*>(&memory[inst.disp])); + break; + } + case 16: { + dest = std::make_unique<RefValueType>(*reinterpret_cast<uint16_t*>(&memory[inst.disp])); + break; + } + case 32: { + dest = std::make_unique<RefValueType>(*reinterpret_cast<uint32_t*>(&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<and_>(inst); + } + + void handle_I_MOV(_DInst inst) { + handle_binary<mov>(inst); + } + + void handle_I_SUB(_DInst inst) { + handle_binary<sub>(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<uint8_t> 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; |
