diff options
| author | Rusty Wagner <rusty@vector35.com> | 2018-02-23 14:54:44 -0500 |
|---|---|---|
| committer | Rusty Wagner <rusty@vector35.com> | 2018-02-23 15:00:43 -0500 |
| commit | ef91ab7f3b648051b72fd06dd05eff3c57fa7f65 (patch) | |
| tree | d8f6c12a846414e09eb8c5fcb24f45f8260fdb1f | |
| parent | 76f691d065332fabe7ee9aa6370e3fedef217f02 (diff) | |
Add APIs for subclassing or hooking an existing architecture in C/C++
| -rw-r--r-- | architecture.cpp | 378 | ||||
| -rw-r--r-- | binaryninjaapi.h | 89 | ||||
| -rw-r--r-- | binaryninjacore.h | 4 | ||||
| -rw-r--r-- | examples/x86_extension/src/x86_extension.cpp | 585 |
4 files changed, 490 insertions, 566 deletions
diff --git a/architecture.cpp b/architecture.cpp index 90f8e622..a1aaca2d 100644 --- a/architecture.cpp +++ b/architecture.cpp @@ -640,6 +640,13 @@ bool Architecture::SkipAndReturnValueCallback(void* ctxt, uint8_t* data, uint64_ } +void Architecture::Register(BNCustomArchitecture* callbacks) +{ + AddRefForRegistration(); + BNRegisterArchitecture(m_nameForRegister.c_str(), callbacks); +} + + void Architecture::Register(Architecture* arch) { BNCustomArchitecture callbacks; @@ -701,8 +708,7 @@ void Architecture::Register(Architecture* arch) callbacks.alwaysBranch = AlwaysBranchCallback; callbacks.invertBranch = InvertBranchCallback; callbacks.skipAndReturnValue = SkipAndReturnValueCallback; - arch->AddRefForRegistration(); - BNRegisterArchitecture(arch->m_nameForRegister.c_str(), &callbacks); + arch->Register(&callbacks); } @@ -1228,6 +1234,12 @@ Ref<Platform> Architecture::GetStandalonePlatform() } +void Architecture::AddArchitectureRedirection(Architecture* from, Architecture* to) +{ + BNAddArchitectureRedirection(m_object, from->GetObject(), to->GetObject()); +} + + CoreArchitecture::CoreArchitecture(BNArchitecture* arch): Architecture(arch) { } @@ -1712,3 +1724,365 @@ bool CoreArchitecture::SkipAndReturnValue(uint8_t* data, uint64_t addr, size_t l { return BNArchitectureSkipAndReturnValue(m_object, data, addr, len, value); } + + +ArchitectureExtension::ArchitectureExtension(const string& name, Architecture* base): Architecture(name), m_base(base) +{ +} + + +void ArchitectureExtension::Register(BNCustomArchitecture* callbacks) +{ + AddRefForRegistration(); + BNRegisterArchitectureExtension(m_nameForRegister.c_str(), m_base->GetObject(), callbacks); +} + + +BNEndianness ArchitectureExtension::GetEndianness() const +{ + return m_base->GetEndianness(); +} + + +size_t ArchitectureExtension::GetAddressSize() const +{ + return m_base->GetAddressSize(); +} + + +size_t ArchitectureExtension::GetDefaultIntegerSize() const +{ + return m_base->GetDefaultIntegerSize(); +} + + +size_t ArchitectureExtension::GetInstructionAlignment() const +{ + return m_base->GetInstructionAlignment(); +} + + +size_t ArchitectureExtension::GetMaxInstructionLength() const +{ + return m_base->GetMaxInstructionLength(); +} + + +size_t ArchitectureExtension::GetOpcodeDisplayLength() const +{ + return m_base->GetOpcodeDisplayLength(); +} + + +Ref<Architecture> ArchitectureExtension::GetAssociatedArchitectureByAddress(uint64_t& addr) +{ + Ref<Architecture> result = m_base->GetAssociatedArchitectureByAddress(addr); + if (result == m_base) + return this; + return result; +} + + +bool ArchitectureExtension::GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) +{ + return m_base->GetInstructionInfo(data, addr, maxLen, result); +} + + +bool ArchitectureExtension::GetInstructionText(const uint8_t* data, uint64_t addr, size_t& len, + vector<InstructionTextToken>& result) +{ + return m_base->GetInstructionText(data, addr, len, result); +} + + +bool ArchitectureExtension::GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) +{ + return m_base->GetInstructionLowLevelIL(data, addr, len, il); +} + + +string ArchitectureExtension::GetRegisterName(uint32_t reg) +{ + return m_base->GetRegisterName(reg); +} + + +string ArchitectureExtension::GetFlagName(uint32_t flag) +{ + return m_base->GetFlagName(flag); +} + + +string ArchitectureExtension::GetFlagWriteTypeName(uint32_t flags) +{ + return m_base->GetFlagWriteTypeName(flags); +} + + +string ArchitectureExtension::GetSemanticFlagClassName(uint32_t semClass) +{ + return m_base->GetSemanticFlagClassName(semClass); +} + + +string ArchitectureExtension::GetSemanticFlagGroupName(uint32_t semGroup) +{ + return m_base->GetSemanticFlagGroupName(semGroup); +} + + +vector<uint32_t> ArchitectureExtension::GetFullWidthRegisters() +{ + return m_base->GetFullWidthRegisters(); +} + + +vector<uint32_t> ArchitectureExtension::GetAllRegisters() +{ + return m_base->GetAllRegisters(); +} + + +vector<uint32_t> ArchitectureExtension::GetAllFlags() +{ + return m_base->GetAllFlags(); +} + + +vector<uint32_t> ArchitectureExtension::GetAllFlagWriteTypes() +{ + return m_base->GetAllFlagWriteTypes(); +} + + +vector<uint32_t> ArchitectureExtension::GetAllSemanticFlagClasses() +{ + return m_base->GetAllSemanticFlagClasses(); +} + + +vector<uint32_t> ArchitectureExtension::GetAllSemanticFlagGroups() +{ + return m_base->GetAllSemanticFlagGroups(); +} + + +BNFlagRole ArchitectureExtension::GetFlagRole(uint32_t flag, uint32_t semClass) +{ + return m_base->GetFlagRole(flag, semClass); +} + + +vector<uint32_t> ArchitectureExtension::GetFlagsRequiredForFlagCondition(BNLowLevelILFlagCondition cond, + uint32_t semClass) +{ + return m_base->GetFlagsRequiredForFlagCondition(cond, semClass); +} + + +vector<uint32_t> ArchitectureExtension::GetFlagsRequiredForSemanticFlagGroup(uint32_t semGroup) +{ + return m_base->GetFlagsRequiredForSemanticFlagGroup(semGroup); +} + + +map<uint32_t, BNLowLevelILFlagCondition> ArchitectureExtension::GetFlagConditionsForSemanticFlagGroup(uint32_t semGroup) +{ + return m_base->GetFlagConditionsForSemanticFlagGroup(semGroup); +} + + +vector<uint32_t> ArchitectureExtension::GetFlagsWrittenByFlagWriteType(uint32_t writeType) +{ + return m_base->GetFlagsWrittenByFlagWriteType(writeType); +} + + +uint32_t ArchitectureExtension::GetSemanticClassForFlagWriteType(uint32_t writeType) +{ + return m_base->GetSemanticClassForFlagWriteType(writeType); +} + + +ExprId ArchitectureExtension::GetFlagWriteLowLevelIL(BNLowLevelILOperation op, size_t size, uint32_t flagWriteType, + uint32_t flag, BNRegisterOrConstant* operands, size_t operandCount, LowLevelILFunction& il) +{ + return m_base->GetFlagWriteLowLevelIL(op, size, flagWriteType, flag, operands, operandCount, il); +} + + +ExprId ArchitectureExtension::GetFlagConditionLowLevelIL(BNLowLevelILFlagCondition cond, + uint32_t semClass, LowLevelILFunction& il) +{ + return m_base->GetFlagConditionLowLevelIL(cond, semClass, il); +} + + +ExprId ArchitectureExtension::GetSemanticFlagGroupLowLevelIL(uint32_t semGroup, LowLevelILFunction& il) +{ + return m_base->GetSemanticFlagGroupLowLevelIL(semGroup, il); +} + + +BNRegisterInfo ArchitectureExtension::GetRegisterInfo(uint32_t reg) +{ + return m_base->GetRegisterInfo(reg); +} + + +uint32_t ArchitectureExtension::GetStackPointerRegister() +{ + return m_base->GetStackPointerRegister(); +} + + +uint32_t ArchitectureExtension::GetLinkRegister() +{ + return m_base->GetLinkRegister(); +} + + +vector<uint32_t> ArchitectureExtension::GetGlobalRegisters() +{ + return m_base->GetGlobalRegisters(); +} + + +string ArchitectureExtension::GetRegisterStackName(uint32_t regStack) +{ + return m_base->GetRegisterStackName(regStack); +} + + +vector<uint32_t> ArchitectureExtension::GetAllRegisterStacks() +{ + return m_base->GetAllRegisterStacks(); +} + + +BNRegisterStackInfo ArchitectureExtension::GetRegisterStackInfo(uint32_t regStack) +{ + return m_base->GetRegisterStackInfo(regStack); +} + + +string ArchitectureExtension::GetIntrinsicName(uint32_t intrinsic) +{ + return m_base->GetIntrinsicName(intrinsic); +} + + +vector<uint32_t> ArchitectureExtension::GetAllIntrinsics() +{ + return m_base->GetAllIntrinsics(); +} + + +vector<NameAndType> ArchitectureExtension::GetIntrinsicInputs(uint32_t intrinsic) +{ + return m_base->GetIntrinsicInputs(intrinsic); +} + + +vector<Confidence<Ref<Type>>> ArchitectureExtension::GetIntrinsicOutputs(uint32_t intrinsic) +{ + return m_base->GetIntrinsicOutputs(intrinsic); +} + + +bool ArchitectureExtension::Assemble(const string& code, uint64_t addr, DataBuffer& result, string& errors) +{ + return m_base->Assemble(code, addr, result, errors); +} + + +bool ArchitectureExtension::IsNeverBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) +{ + return m_base->IsNeverBranchPatchAvailable(data, addr, len); +} + + +bool ArchitectureExtension::IsAlwaysBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) +{ + return m_base->IsAlwaysBranchPatchAvailable(data, addr, len); +} + + +bool ArchitectureExtension::IsInvertBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) +{ + return m_base->IsInvertBranchPatchAvailable(data, addr, len); +} + + +bool ArchitectureExtension::IsSkipAndReturnZeroPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) +{ + return m_base->IsSkipAndReturnValuePatchAvailable(data, addr, len); +} + + +bool ArchitectureExtension::IsSkipAndReturnValuePatchAvailable(const uint8_t* data, uint64_t addr, size_t len) +{ + return m_base->IsSkipAndReturnValuePatchAvailable(data, addr, len); +} + + +bool ArchitectureExtension::ConvertToNop(uint8_t* data, uint64_t addr, size_t len) +{ + return m_base->ConvertToNop(data, addr, len); +} + + +bool ArchitectureExtension::AlwaysBranch(uint8_t* data, uint64_t addr, size_t len) +{ + return m_base->AlwaysBranch(data, addr, len); +} + + +bool ArchitectureExtension::InvertBranch(uint8_t* data, uint64_t addr, size_t len) +{ + return m_base->InvertBranch(data, addr, len); +} + + +bool ArchitectureExtension::SkipAndReturnValue(uint8_t* data, uint64_t addr, size_t len, uint64_t value) +{ + return m_base->SkipAndReturnValue(data, addr, len, value); +} + + +ArchitectureHook::ArchitectureHook(Architecture* base): CoreArchitecture(nullptr), m_base(base) +{ + // Architecture hooks allow existing architecture implementations to be extended without creating + // a new Architecture object for the changes. By deriving from the ArchitectureHook class and passing + // the original Architecture object of the architecture to be extended, any reimplemented functions + // will be called first before the original architecture's implementation. You MUST call the base + // class method to call the original implementation's version of the function, as calling the + // same function on the original Architecture object will call your implementation again. + + // Example of a hook to modify the lifting process: + + // class ArchitectureHookExample: public ArchitectureHook + // { + // public: + // ArchitectureHookExample(Architecture* existingArch) : ArchitectureHook(existingArch) + // { + // } + // + // virtual bool GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, + // LowLevelILFunction& il) override + // { + // // Perform extra lifting here + // // ... + // // For unhandled cases, call the original architecture's implementation + // return ArchitectureHook::GetInstructionLowLevelIL(data, addr, len, il); + // } + // }; +} + + +void ArchitectureHook::Register(BNCustomArchitecture* callbacks) +{ + AddRefForRegistration(); + m_object = BNRegisterArchitectureHook(m_base->GetObject(), callbacks); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 91162af7..89eba009 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1668,6 +1668,8 @@ namespace BinaryNinja static bool InvertBranchCallback(void* ctxt, uint8_t* data, uint64_t addr, size_t len); static bool SkipAndReturnValueCallback(void* ctxt, uint8_t* data, uint64_t addr, size_t len, uint64_t value); + virtual void Register(BNCustomArchitecture* callbacks); + public: Architecture(const std::string& name); @@ -1832,6 +1834,8 @@ namespace BinaryNinja Ref<CallingConvention> GetStdcallCallingConvention(); Ref<CallingConvention> GetFastcallCallingConvention(); Ref<Platform> GetStandalonePlatform(); + + void AddArchitectureRedirection(Architecture* from, Architecture* to); }; class CoreArchitecture: public Architecture @@ -1900,6 +1904,91 @@ namespace BinaryNinja virtual bool SkipAndReturnValue(uint8_t* data, uint64_t addr, size_t len, uint64_t value) override; }; + class ArchitectureExtension: public Architecture + { + protected: + Ref<Architecture> m_base; + + virtual void Register(BNCustomArchitecture* callbacks) override; + + public: + ArchitectureExtension(const std::string& name, Architecture* base); + + Ref<Architecture> GetBaseArchitecture() const { return m_base; } + + virtual BNEndianness GetEndianness() const override; + virtual size_t GetAddressSize() const override; + virtual size_t GetDefaultIntegerSize() const override; + virtual size_t GetInstructionAlignment() const override; + virtual size_t GetMaxInstructionLength() const override; + virtual size_t GetOpcodeDisplayLength() const override; + virtual Ref<Architecture> GetAssociatedArchitectureByAddress(uint64_t& addr) override; + virtual bool GetInstructionInfo(const uint8_t* data, uint64_t addr, size_t maxLen, InstructionInfo& result) override; + virtual bool GetInstructionText(const uint8_t* data, uint64_t addr, size_t& len, + std::vector<InstructionTextToken>& result) override; + virtual bool GetInstructionLowLevelIL(const uint8_t* data, uint64_t addr, size_t& len, LowLevelILFunction& il) override; + virtual std::string GetRegisterName(uint32_t reg) override; + virtual std::string GetFlagName(uint32_t flag) override; + virtual std::string GetFlagWriteTypeName(uint32_t flags) override; + virtual std::string GetSemanticFlagClassName(uint32_t semClass) override; + virtual std::string GetSemanticFlagGroupName(uint32_t semGroup) override; + virtual std::vector<uint32_t> GetFullWidthRegisters() override; + virtual std::vector<uint32_t> GetAllRegisters() override; + virtual std::vector<uint32_t> GetAllFlags() override; + virtual std::vector<uint32_t> GetAllFlagWriteTypes() override; + virtual std::vector<uint32_t> GetAllSemanticFlagClasses() override; + virtual std::vector<uint32_t> GetAllSemanticFlagGroups() override; + virtual BNFlagRole GetFlagRole(uint32_t flag, uint32_t semClass = 0) override; + virtual std::vector<uint32_t> GetFlagsRequiredForFlagCondition(BNLowLevelILFlagCondition cond, + uint32_t semClass = 0) override; + virtual std::vector<uint32_t> GetFlagsRequiredForSemanticFlagGroup(uint32_t semGroup) override; + virtual std::map<uint32_t, BNLowLevelILFlagCondition> GetFlagConditionsForSemanticFlagGroup(uint32_t semGroup) override; + virtual std::vector<uint32_t> GetFlagsWrittenByFlagWriteType(uint32_t writeType) override; + virtual uint32_t GetSemanticClassForFlagWriteType(uint32_t writeType) override; + virtual ExprId GetFlagWriteLowLevelIL(BNLowLevelILOperation op, size_t size, uint32_t flagWriteType, + uint32_t flag, BNRegisterOrConstant* operands, size_t operandCount, LowLevelILFunction& il) override; + virtual ExprId GetFlagConditionLowLevelIL(BNLowLevelILFlagCondition cond, + uint32_t semClass, LowLevelILFunction& il) override; + virtual ExprId GetSemanticFlagGroupLowLevelIL(uint32_t semGroup, LowLevelILFunction& il) override; + virtual BNRegisterInfo GetRegisterInfo(uint32_t reg) override; + virtual uint32_t GetStackPointerRegister() override; + virtual uint32_t GetLinkRegister() override; + virtual std::vector<uint32_t> GetGlobalRegisters() override; + + virtual std::string GetRegisterStackName(uint32_t regStack) override; + virtual std::vector<uint32_t> GetAllRegisterStacks() override; + virtual BNRegisterStackInfo GetRegisterStackInfo(uint32_t regStack) override; + + virtual std::string GetIntrinsicName(uint32_t intrinsic) override; + virtual std::vector<uint32_t> GetAllIntrinsics() override; + virtual std::vector<NameAndType> GetIntrinsicInputs(uint32_t intrinsic) override; + virtual std::vector<Confidence<Ref<Type>>> GetIntrinsicOutputs(uint32_t intrinsic) override; + + virtual bool Assemble(const std::string& code, uint64_t addr, DataBuffer& result, std::string& errors) override; + + virtual bool IsNeverBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override; + virtual bool IsAlwaysBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override; + virtual bool IsInvertBranchPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override; + virtual bool IsSkipAndReturnZeroPatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override; + virtual bool IsSkipAndReturnValuePatchAvailable(const uint8_t* data, uint64_t addr, size_t len) override; + + virtual bool ConvertToNop(uint8_t* data, uint64_t addr, size_t len) override; + virtual bool AlwaysBranch(uint8_t* data, uint64_t addr, size_t len) override; + virtual bool InvertBranch(uint8_t* data, uint64_t addr, size_t len) override; + virtual bool SkipAndReturnValue(uint8_t* data, uint64_t addr, size_t len, uint64_t value) override; + }; + + class ArchitectureHook: public CoreArchitecture + { + protected: + Ref<Architecture> m_base; + + virtual void Register(BNCustomArchitecture* callbacks) override; + + public: + ArchitectureHook(Architecture* base); + }; + class Structure; class NamedTypeReference; class Enumeration; diff --git a/binaryninjacore.h b/binaryninjacore.h index fa7a818a..5329a1d9 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -2085,6 +2085,10 @@ extern "C" BINARYNINJACOREAPI BNArchitecture** BNGetArchitectureList(size_t* count); BINARYNINJACOREAPI void BNFreeArchitectureList(BNArchitecture** archs); BINARYNINJACOREAPI BNArchitecture* BNRegisterArchitecture(const char* name, BNCustomArchitecture* arch); + BINARYNINJACOREAPI BNArchitecture* BNRegisterArchitectureExtension(const char* name, + BNArchitecture* base, BNCustomArchitecture* arch); + BINARYNINJACOREAPI void BNAddArchitectureRedirection(BNArchitecture* arch, BNArchitecture* from, BNArchitecture* to); + BINARYNINJACOREAPI BNArchitecture* BNRegisterArchitectureHook(BNArchitecture* base, BNCustomArchitecture* arch); BINARYNINJACOREAPI char* BNGetArchitectureName(BNArchitecture* arch); BINARYNINJACOREAPI BNEndianness BNGetArchitectureEndianness(BNArchitecture* arch); 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<void (size_t addrSize, LowLevelILFunction& il)> addPreTestIl, - std::function<void (size_t addrSize, LowLevelILFunction& il)> addDirFlagSetIl, - std::function<void (size_t addrSize, LowLevelILFunction& il)> 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<void (size_t addrSize, LowLevelILFunction& il)> 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<InstructionTextToken>& 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<uint32_t> GetAllFlags() override - { - return m_arch->GetAllFlags(); - } - - virtual string GetFlagWriteTypeName(uint32_t flags) override - { - return m_arch->GetFlagWriteTypeName(flags); - } - - virtual vector<uint32_t> GetAllFlagWriteTypes() override - { - return m_arch->GetAllFlagWriteTypes(); - } - - virtual BNFlagRole GetFlagRole(uint32_t flag) override - { - return m_arch->GetFlagRole(flag); - } - - virtual vector<uint32_t> GetFlagsRequiredForFlagCondition(BNLowLevelILFlagCondition cond) override - { - return m_arch->GetFlagsRequiredForFlagCondition(cond); - } - - virtual vector<uint32_t> 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<uint32_t> GetFullWidthRegisters() override - { - return m_arch->GetFullWidthRegisters(); - } - - virtual vector<uint32_t> GetGlobalRegisters() override - { - return m_arch->GetGlobalRegisters(); - } - - virtual vector<uint32_t> 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; } } |
