From ef91ab7f3b648051b72fd06dd05eff3c57fa7f65 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Fri, 23 Feb 2018 14:54:44 -0500 Subject: Add APIs for subclassing or hooking an existing architecture in C/C++ --- examples/x86_extension/src/x86_extension.cpp | 585 +-------------------------- 1 file changed, 21 insertions(+), 564 deletions(-) (limited to 'examples/x86_extension') diff --git a/examples/x86_extension/src/x86_extension.cpp b/examples/x86_extension/src/x86_extension.cpp index a2ba4c9c..87f2c2cb 100644 --- a/examples/x86_extension/src/x86_extension.cpp +++ b/examples/x86_extension/src/x86_extension.cpp @@ -10,572 +10,37 @@ using namespace std; using namespace asmx86; -#define IL_FLAG_C 0 -#define IL_FLAG_P 2 -#define IL_FLAG_A 4 -#define IL_FLAG_Z 6 -#define IL_FLAG_S 7 -#define IL_FLAG_D 10 -#define IL_FLAG_O 11 - -#define IL_FLAGWRITE_ALL 1 -#define IL_FLAGWRITE_NOCARRY 2 -#define IL_FLAGWRITE_CO 3 - -#define REG_FSBASE 0x100 -#define REG_GSBASE 0x101 - -#define TRAP_DIV 0 -#define TRAP_ICEBP 1 -#define TRAP_NMI 2 -#define TRAP_BP 3 -#define TRAP_OVERFLOW 4 -#define TRAP_BOUND 5 -#define TRAP_ILL 6 -#define TRAP_NOT_AVAIL 7 -#define TRAP_DOUBLE 8 -#define TRAP_TSS 10 -#define TRAP_NO_SEG 11 -#define TRAP_STACK 12 -#define TRAP_GPF 13 -#define TRAP_PAGE 14 -#define TRAP_FPU 16 -#define TRAP_ALIGN 17 -#define TRAP_MCE 18 -#define TRAP_SIMD 19 - -static uint8_t GetShiftCountForScale(uint8_t scale) -{ - switch (scale) - { - case 2: - return 1; - case 4: - return 2; - case 8: - return 3; - default: - return 0; - } -} - - -static uint32_t GetStackPointer(size_t addrSize) -{ - switch (addrSize) - { - case 2: - return REG_SP; - case 4: - return REG_ESP; - default: - return REG_RSP; - } -} - - -static uint32_t GetFramePointer(size_t addrSize) -{ - switch (addrSize) - { - case 2: - return REG_BP; - case 4: - return REG_EBP; - default: - return REG_RBP; - } -} - - -static uint32_t GetCountRegister(size_t addrSize) -{ - switch (addrSize) - { - case 2: - return REG_CX; - case 4: - return REG_ECX; - default: - return REG_RCX; - } -} - - -static size_t GetILOperandMemoryAddress(LowLevelILFunction& il, InstructionOperand& operand, size_t i, size_t addrSize) -{ - size_t offset; - if (operand.operand != MEM) - offset = il.Operand(i, il.Undefined()); - else if ((operand.components[0] == NONE) && (operand.components[1] == NONE) && operand.relative) - offset = il.Operand(i, il.ConstPointer(addrSize, operand.immediate)); - else if ((operand.components[0] == NONE) && (operand.components[1] == NONE)) - offset = il.Operand(i, il.Const(addrSize, operand.immediate)); - else if ((operand.components[1] == NONE) && (operand.immediate == 0)) - offset = il.Operand(i, il.Register(addrSize, operand.components[0])); - else if (operand.components[1] == NONE) - { - offset = il.Operand(i, il.Add(addrSize, il.Register(addrSize, operand.components[0]), - il.Const(addrSize, operand.immediate))); - } - else if ((operand.components[0] == NONE) && (operand.scale == 1) && (operand.immediate == 0)) - offset = il.Operand(i, il.Register(addrSize, operand.components[1])); - else if ((operand.components[0] == NONE) && (operand.scale == 1)) - { - offset = il.Operand(i, il.Add(addrSize, il.Register(addrSize, operand.components[1]), - il.Const(addrSize, operand.immediate))); - } - else if ((operand.components[0] == NONE) && (operand.immediate == 0)) - { - offset = il.Operand(i, il.ShiftLeft(addrSize, il.Register(addrSize, operand.components[1]), - il.Const(1, GetShiftCountForScale(operand.scale)))); - } - else if (operand.components[0] == NONE) - { - offset = il.Operand(i, il.Add(addrSize, il.ShiftLeft(addrSize, il.Register(addrSize, operand.components[1]), - il.Const(1, GetShiftCountForScale(operand.scale))), il.Const(addrSize, operand.immediate))); - } - else if ((operand.scale == 1) && (operand.immediate == 0)) - { - offset = il.Operand(i, il.Add(addrSize, il.Register(addrSize, operand.components[0]), - il.Register(addrSize, operand.components[1]))); - } - else if (operand.scale == 1) - { - offset = il.Operand(i, il.Add(addrSize, il.Add(addrSize, il.Register(addrSize, operand.components[0]), - il.Register(addrSize, operand.components[1])), il.Const(addrSize, operand.immediate))); - } - else if (operand.immediate == 0) - { - offset = il.Operand(i, il.Add(addrSize, il.Register(addrSize, operand.components[0]), - il.ShiftLeft(addrSize, il.Register(addrSize, operand.components[1]), - il.Const(1, GetShiftCountForScale(operand.scale))))); - } - else - { - offset = il.Operand(i, il.Add(addrSize, il.Add(addrSize, il.Register(addrSize, operand.components[0]), - il.ShiftLeft(addrSize, il.Register(addrSize, operand.components[1]), - il.Const(1, GetShiftCountForScale(operand.scale)))), il.Const(addrSize, operand.immediate))); - } - - if (operand.segment == SEG_FS) - return il.Operand(i, il.Add(addrSize, il.Register(addrSize, REG_FSBASE), offset)); - if (operand.segment == SEG_GS) - return il.Operand(i, il.Add(addrSize, il.Register(addrSize, REG_GSBASE), offset)); - return offset; -} - - -static size_t ReadILOperand(LowLevelILFunction& il, Instruction& instr, size_t i, size_t addrSize, bool isAddress = false) -{ - InstructionOperand& operand = instr.operands[i]; - switch (operand.operand) - { - case NONE: - return il.Undefined(); - case IMM: - if (isAddress) - return il.Operand(i, il.ConstPointer(operand.size, operand.immediate)); - else - return il.Operand(i, il.Const(operand.size, operand.immediate)); - case MEM: - return il.Operand(i, il.Load(operand.size, GetILOperandMemoryAddress(il, operand, i, addrSize))); - default: - return il.Operand(i, il.Register(operand.size, operand.operand)); - } -} - - -static size_t WriteILOperand(LowLevelILFunction& il, Instruction& instr, size_t i, size_t addrSize, size_t value) -{ - InstructionOperand& operand = instr.operands[i]; - switch (operand.operand) - { - case NONE: - case IMM: - return il.Undefined(); - case MEM: - return il.Operand(i, il.Store(operand.size, GetILOperandMemoryAddress(il, operand, i, addrSize), value)); - default: - return il.Operand(i, il.SetRegister(operand.size, operand.operand, value)); - } -} - - -static size_t DirectJump(Architecture* arch, LowLevelILFunction& il, uint64_t target, size_t addrSize) -{ - BNLowLevelILLabel* label = il.GetLabelForAddress(arch, target); - if (label) - return il.Goto(*label); - else - return il.Jump(il.ConstPointer(addrSize, target)); -} - - -static void ConditionalJump(Architecture* arch, LowLevelILFunction& il, size_t cond, size_t addrSize, uint64_t t, uint64_t f) -{ - BNLowLevelILLabel* trueLabel = il.GetLabelForAddress(arch, t); - BNLowLevelILLabel* falseLabel = il.GetLabelForAddress(arch, f); - - if (trueLabel && falseLabel) - { - il.AddInstruction(il.If(cond, *trueLabel, *falseLabel)); - return; - } - - LowLevelILLabel trueCode, falseCode; - - if (trueLabel) - { - il.AddInstruction(il.If(cond, *trueLabel, falseCode)); - il.MarkLabel(falseCode); - il.AddInstruction(il.Jump(il.ConstPointer(addrSize, f))); - return; - } - - if (falseLabel) - { - il.AddInstruction(il.If(cond, trueCode, *falseLabel)); - il.MarkLabel(trueCode); - il.AddInstruction(il.Jump(il.ConstPointer(addrSize, t))); - return; - } - - il.AddInstruction(il.If(cond, trueCode, falseCode)); - il.MarkLabel(trueCode); - il.AddInstruction(il.Jump(il.ConstPointer(addrSize, t))); - il.MarkLabel(falseCode); - il.AddInstruction(il.Jump(il.ConstPointer(addrSize, f))); -} - - -static void DirFlagIf(size_t addrSize, - LowLevelILFunction& il, - std::function addPreTestIl, - std::function addDirFlagSetIl, - std::function addDirFlagClearIl) -{ - LowLevelILLabel dirFlagSet, dirFlagClear, dirFlagDone; - - addPreTestIl(addrSize, il); - - il.AddInstruction(il.If(il.Flag(IL_FLAG_D), dirFlagSet, dirFlagClear)); - il.MarkLabel(dirFlagSet); - - addDirFlagSetIl(addrSize, il); - - il.AddInstruction(il.Goto(dirFlagDone)); - il.MarkLabel(dirFlagClear); - - addDirFlagClearIl(addrSize, il); - - il.AddInstruction(il.Goto(dirFlagDone)); - il.MarkLabel(dirFlagDone); -} - - -static void Repeat(size_t addrSize, - Instruction& instr, - LowLevelILFunction& il, - std::function addil) -{ - LowLevelILLabel trueLabel, falseLabel, doneLabel; - if (instr.flags & X86_FLAG_ANY_REP) - { - il.AddInstruction(il.Goto(trueLabel)); - il.MarkLabel(trueLabel); - il.AddInstruction(il.If(il.CompareEqual(addrSize, il.Register(addrSize, GetCountRegister(addrSize)), - il.Const(addrSize, 0)), doneLabel, falseLabel)); - il.MarkLabel(falseLabel); - } - - addil(addrSize, il); - - if (instr.flags & X86_FLAG_ANY_REP) - { - il.AddInstruction(il.SetRegister(addrSize, GetCountRegister(addrSize), - il.Sub(addrSize, il.Register(addrSize, GetCountRegister(addrSize)), - il.Const(addrSize, 1)))); - if (instr.flags & X86_FLAG_REPE) - il.AddInstruction(il.If(il.FlagCondition(LLFC_E), trueLabel, doneLabel)); - else if (instr.flags & X86_FLAG_REPNE) - il.AddInstruction(il.If(il.FlagCondition(LLFC_NE), trueLabel, doneLabel)); - else - il.AddInstruction(il.Goto(trueLabel)); - il.MarkLabel(doneLabel); - } -} - - // This is a wrapper for the x86 architecture. Its useful for extending and improving // the existing core x86 architecture. -class x86ArchitectureExtension: public Architecture +class x86ArchitectureExtension: public ArchitectureHook { - Architecture* m_arch; public: - x86ArchitectureExtension() : Architecture("x86_extension") - { - m_arch = new CoreArchitecture(BNGetArchitectureByName("x86")); - } - - virtual size_t GetAddressSize() const override - { - return 4; - } - - virtual BNEndianness GetEndianness() const override + x86ArchitectureExtension(Architecture* x86) : ArchitectureHook(x86) { - return LittleEndian; - } - - virtual size_t GetInstructionAlignment() const override - { - return 1; - } - - virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) override - { - return m_arch->GetInstructionInfo(data, addr, maxLen, result); - } - - virtual bool GetInstructionText(const uint8_t* data, uint64_t addr, size_t& len, vector& result) override - { - return m_arch->GetInstructionText(data, addr, len, result); } virtual bool GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override { Instruction instr; - if (!asmx86::Disassemble32(data, addr, len, &instr)) + if (asmx86::Disassemble32(data, addr, len, &instr)) { - il.AddInstruction(il.Undefined()); - return false; + switch (instr.operation) + { + case CPUID: + // The default implementation of CPUID doesn't set registers to constant values + // Here we'll emulate a Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz with _eax set to 1 + il.AddInstruction(il.Register(4, REG_EAX)); // Reference the register so we know it is read + il.AddInstruction(il.SetRegister(4, REG_EAX, il.Const(4, 0x000406e3))); + il.AddInstruction(il.SetRegister(4, REG_EBX, il.Const(4, 0x03100800))); + il.AddInstruction(il.SetRegister(4, REG_ECX, il.Const(4, 0x7ffafbbf))); + il.AddInstruction(il.SetRegister(4, REG_EDX, il.Const(4, 0xbfebfbff))); + len = instr.length; + return true; + default: + break; + } } - - size_t addrSize = 4; - switch (instr.operation) - { - case CPUID: - // The default implementation of CPUID doesn't set registers to constant values - // Here we'll emulate a Intel(R) Core(TM) i5-6267U CPU @ 2.90GHz with _eax set to 1 - il.AddInstruction(il.Register(4, REG_EAX)); // Reference the register so we know it is read - il.AddInstruction(il.SetRegister(4, REG_EAX, il.Const(4, 0x000406e3))); - il.AddInstruction(il.SetRegister(4, REG_EBX, il.Const(4, 0x03100800))); - il.AddInstruction(il.SetRegister(4, REG_ECX, il.Const(4, 0x7ffafbbf))); - il.AddInstruction(il.SetRegister(4, REG_EDX, il.Const(4, 0xbfebfbff))); - len = instr.length; - return true; - - case JMP: - if (instr.operands[0].operand == IMM) - il.AddInstruction(DirectJump(this, il, instr.operands[0].immediate, addrSize)); - else - il.AddInstruction(il.Jump(ReadILOperand(il, instr, 0, addrSize, true))); - return false; - - case JO: - ConditionalJump(this, il, il.FlagCondition(LLFC_O), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JNO: - ConditionalJump(this, il, il.FlagCondition(LLFC_NO), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JB: - ConditionalJump(this, il, il.FlagCondition(LLFC_ULT), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JAE: - ConditionalJump(this, il, il.FlagCondition(LLFC_UGE), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JE: - ConditionalJump(this, il, il.FlagCondition(LLFC_E), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JNE: - ConditionalJump(this, il, il.FlagCondition(LLFC_NE), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JBE: - ConditionalJump(this, il, il.FlagCondition(LLFC_ULE), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JA: - ConditionalJump(this, il, il.FlagCondition(LLFC_UGT), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JS: - ConditionalJump(this, il, il.FlagCondition(LLFC_NEG), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JNS: - ConditionalJump(this, il, il.FlagCondition(LLFC_POS), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JPE: - ConditionalJump(this, il, il.Not(0, il.Flag(IL_FLAG_P)), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JPO: - ConditionalJump(this, il, il.Flag(IL_FLAG_P), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JL: - ConditionalJump(this, il, il.FlagCondition(LLFC_SLT), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JGE: - ConditionalJump(this, il, il.FlagCondition(LLFC_SGE), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JLE: - ConditionalJump(this, il, il.FlagCondition(LLFC_SLE), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JG: - ConditionalJump(this, il, il.FlagCondition(LLFC_SGT), addrSize, instr.operands[0].immediate, addr + instr.length); - return false; - - case JCXZ: - ConditionalJump(this, il, il.CompareEqual(2, il.Register(2, REG_CX), il.Const(2, 0)), addrSize, - instr.operands[0].immediate, addr + instr.length); - return false; - - case JECXZ: - ConditionalJump(this, il, il.CompareEqual(4, il.Register(4, REG_ECX), il.Const(4, 0)), addrSize, - instr.operands[0].immediate, addr + instr.length); - return false; - - case JRCXZ: - ConditionalJump(this, il, il.CompareEqual(8, il.Register(8, REG_RCX), il.Const(8, 0)), addrSize, - instr.operands[0].immediate, addr + instr.length); - return false; - - default: - return m_arch->GetInstructionLowLevelIL(data, addr, len, il); - } - } - - virtual size_t GetFlagWriteLowLevelIL(BNLowLevelILOperation op, size_t size, uint32_t flagWriteType, - uint32_t flag, BNRegisterOrConstant* operands, size_t operandCount, LowLevelILFunction& il) override - { - return m_arch->GetFlagWriteLowLevelIL(op,size, flagWriteType, flag, operands, operandCount, il); - } - - virtual string GetRegisterName(uint32_t reg) override - { - return m_arch->GetRegisterName(reg); - } - - virtual string GetFlagName(uint32_t flag) override - { - return m_arch->GetFlagName(flag); - } - - virtual vector GetAllFlags() override - { - return m_arch->GetAllFlags(); - } - - virtual string GetFlagWriteTypeName(uint32_t flags) override - { - return m_arch->GetFlagWriteTypeName(flags); - } - - virtual vector GetAllFlagWriteTypes() override - { - return m_arch->GetAllFlagWriteTypes(); - } - - virtual BNFlagRole GetFlagRole(uint32_t flag) override - { - return m_arch->GetFlagRole(flag); - } - - virtual vector GetFlagsRequiredForFlagCondition(BNLowLevelILFlagCondition cond) override - { - return m_arch->GetFlagsRequiredForFlagCondition(cond); - } - - virtual vector GetFlagsWrittenByFlagWriteType(uint32_t writeType) override - { - return m_arch->GetFlagsWrittenByFlagWriteType(writeType); - } - - virtual bool IsNeverBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override - { - return m_arch->IsNeverBranchPatchAvailable(data, addr, len); - } - - virtual bool IsAlwaysBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override - { - return m_arch->IsAlwaysBranchPatchAvailable(data, addr, len); - } - - virtual bool IsInvertBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override - { - return m_arch->IsInvertBranchPatchAvailable(data, addr, len); - } - - virtual bool IsSkipAndReturnZeroPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override - { - return m_arch->IsSkipAndReturnZeroPatchAvailable(data, addr, len); - } - - virtual bool IsSkipAndReturnValuePatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override - { - return m_arch->IsSkipAndReturnValuePatchAvailable(data, addr, len); - } - - virtual bool ConvertToNop(uint8_t* data, uint64_t addr, size_t len) override - { - return m_arch->ConvertToNop(data, addr, len); - } - - virtual bool AlwaysBranch(uint8_t* data, uint64_t addr, size_t len) override - { - return m_arch->AlwaysBranch(data, addr, len); - } - - virtual bool InvertBranch(uint8_t* data, uint64_t addr, size_t len) override - { - return m_arch->InvertBranch(data, addr, len); - } - - virtual bool SkipAndReturnValue(uint8_t* data, uint64_t addr, size_t len, uint64_t value) override - { - return m_arch->SkipAndReturnValue(data, addr, len, value); - } - - virtual vector GetFullWidthRegisters() override - { - return m_arch->GetFullWidthRegisters(); - } - - virtual vector GetGlobalRegisters() override - { - return m_arch->GetGlobalRegisters(); - } - - virtual vector GetAllRegisters() override - { - return m_arch->GetAllRegisters(); - } - - virtual BNRegisterInfo GetRegisterInfo(uint32_t reg) override - { - return m_arch->GetRegisterInfo(reg); - } - - virtual uint32_t GetStackPointerRegister() override - { - return m_arch->GetStackPointerRegister(); - } - - virtual bool Assemble(const string& code, uint64_t addr, DataBuffer& result, string& errors) override - { - return m_arch->Assemble(code, addr, result, errors); + return ArchitectureHook::GetInstructionLowLevelIL(data, addr, len, il); } }; @@ -585,21 +50,13 @@ extern "C" BINARYNINJAPLUGIN void CorePluginDependencies() { // Make sure we load after the original x86 plugin loads - SetCurrentPluginLoadOrder(LatePluginLoadOrder); + AddRequiredPluginDependency("arch_x86"); } BINARYNINJAPLUGIN bool CorePluginInit() { - Architecture* x86ext = new x86ArchitectureExtension(); + Architecture* x86ext = new x86ArchitectureExtension(Architecture::GetByName("x86")); Architecture::Register(x86ext); - - // Register the architectures with the binary format parsers so that they know when to use - // these architectures for disassembling an executable file - BinaryViewType::RegisterArchitecture("ELF", 3, LittleEndian, x86ext); - BinaryViewType::RegisterArchitecture("PE", 0x14c, LittleEndian, x86ext); - BinaryViewType::RegisterArchitecture("Mach-O", 0x00000007, LittleEndian, x86ext); - x86ext->SetBinaryViewTypeConstant("ELF", "R_COPY", 5); - x86ext->SetBinaryViewTypeConstant("ELF", "R_JUMP_SLOT", 7); return true; } } -- cgit v1.3.1