From 105fb2549bd8fc0e19907fefff1168322dee3bb3 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 26 Feb 2018 22:37:19 -0500 Subject: Architecture plugins no longer need to override the perform_* methods (you can now override get_instruction_info, not perform_get_instruction_info). The perform_* methods are now deprecated but will still function as expected. Added architecture hooks to Python API using this new style. --- python/basicblock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python/basicblock.py') diff --git a/python/basicblock.py b/python/basicblock.py index 8e64c1c1..c93d0b2c 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -100,7 +100,7 @@ class BasicBlock(object): arch = core.BNGetBasicBlockArchitecture(self.handle) if arch is None: return None - self._arch = architecture.Architecture(arch) + self._arch = architecture.CoreArchitecture(arch) return self._arch @property -- cgit v1.3.1 From 5f07bf18df013860c9d9870a4ad0fba78379b0f1 Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Tue, 20 Mar 2018 09:53:59 -0400 Subject: Cache all created CoreArchitecture objects --- python/architecture.py | 18 +++++++++++++----- python/basicblock.py | 2 +- python/binaryview.py | 6 +++--- python/callingconvention.py | 2 +- python/function.py | 8 ++++---- python/platform.py | 2 +- 6 files changed, 23 insertions(+), 15 deletions(-) (limited to 'python/basicblock.py') diff --git a/python/architecture.py b/python/architecture.py index 781edcfd..c5f87ec6 100644 --- a/python/architecture.py +++ b/python/architecture.py @@ -44,7 +44,7 @@ class _ArchitectureMetaClass(type): archs = core.BNGetArchitectureList(count) result = [] for i in xrange(0, count.value): - result.append(CoreArchitecture(archs[i])) + result.append(CoreArchitecture._from_cache(archs[i])) core.BNFreeArchitectureList(archs) return result @@ -54,7 +54,7 @@ class _ArchitectureMetaClass(type): archs = core.BNGetArchitectureList(count) try: for i in xrange(0, count.value): - yield CoreArchitecture(archs[i]) + yield CoreArchitecture._from_cache(archs[i]) finally: core.BNFreeArchitectureList(archs) @@ -63,7 +63,7 @@ class _ArchitectureMetaClass(type): arch = core.BNGetArchitectureByName(name) if arch is None: raise KeyError("'%s' is not a valid architecture" % str(name)) - return CoreArchitecture(arch) + return CoreArchitecture._from_cache(arch) def register(cls): startup._init_plugins() @@ -2037,6 +2037,7 @@ class Architecture(object): core.BNRegisterCallingConvention(self.handle, cc.handle) +_architecture_cache = {} class CoreArchitecture(Architecture): def __init__(self, handle): super(CoreArchitecture, self).__init__() @@ -2256,12 +2257,19 @@ class CoreArchitecture(Architecture): self._intrinsics[name] = intrinsics[i] self._intrinsics_by_index[intrinsics[i]] = (name, self.intrinsics[name]) core.BNFreeRegisterList(intrinsics) + global _architecture_cache + _architecture_cache[ctypes.addressof(handle.contents)] = self + + @classmethod + def _from_cache(cls, handle): + global _architecture_cache + return _architecture_cache.get(ctypes.addressof(handle.contents)) or cls(handle) def get_associated_arch_by_address(self, addr): new_addr = ctypes.c_ulonglong() new_addr.value = addr result = core.BNGetAssociatedArchitectureByAddress(self.handle, new_addr) - return CoreArchitecture(handle = result), new_addr.value + return CoreArchitecture._from_cache(handle = result), new_addr.value def get_instruction_info(self, data, addr): """ @@ -2289,7 +2297,7 @@ class CoreArchitecture(Architecture): for i in xrange(0, info.branchCount): target = info.branchTarget[i] if info.branchArch[i]: - arch = CoreArchitecture(info.branchArch[i]) + arch = CoreArchitecture._from_cache(info.branchArch[i]) else: arch = None result.add_branch(BranchType(info.branchType[i]), target, arch) diff --git a/python/basicblock.py b/python/basicblock.py index c93d0b2c..1d932c5e 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -100,7 +100,7 @@ class BasicBlock(object): arch = core.BNGetBasicBlockArchitecture(self.handle) if arch is None: return None - self._arch = architecture.CoreArchitecture(arch) + self._arch = architecture.CoreArchitecture._from_cache(arch) return self._arch @property diff --git a/python/binaryview.py b/python/binaryview.py index 3af0ee50..0cf25e70 100644 --- a/python/binaryview.py +++ b/python/binaryview.py @@ -411,7 +411,7 @@ class BinaryViewType(object): arch = core.BNGetArchitectureForViewType(self.handle, ident, endian) if arch is None: return None - return architecture.CoreArchitecture(arch) + return architecture.CoreArchitecture._from_cache(arch) def register_platform(self, ident, arch, plat): core.BNRegisterPlatformForViewType(self.handle, ident, arch.handle, plat.handle) @@ -823,7 +823,7 @@ class BinaryView(object): arch = core.BNGetDefaultArchitecture(self.handle) if arch is None: return None - return architecture.CoreArchitecture(handle=arch) + return architecture.CoreArchitecture._from_cache(handle=arch) @arch.setter def arch(self, value): @@ -2211,7 +2211,7 @@ class BinaryView(object): else: func = None if refs[i].arch: - arch = architecture.CoreArchitecture(refs[i].arch) + arch = architecture.CoreArchitecture._from_cache(refs[i].arch) else: arch = None addr = refs[i].addr diff --git a/python/callingconvention.py b/python/callingconvention.py index 49ef7666..e3ec7261 100644 --- a/python/callingconvention.py +++ b/python/callingconvention.py @@ -75,7 +75,7 @@ class CallingConvention(object): self.__class__._registered_calling_conventions.append(self) else: self.handle = handle - self.arch = architecture.CoreArchitecture(core.BNGetCallingConventionArchitecture(self.handle)) + self.arch = architecture.CoreArchitecture._from_cache(core.BNGetCallingConventionArchitecture(self.handle)) self.__dict__["name"] = core.BNGetCallingConventionName(self.handle) self.__dict__["arg_regs_share_index"] = core.BNAreArgumentRegistersSharedIndex(self.handle) self.__dict__["stack_reserved_for_arg_regs"] = core.BNIsStackReservedForArgumentRegisters(self.handle) diff --git a/python/function.py b/python/function.py index 0d796d98..8c4b7765 100644 --- a/python/function.py +++ b/python/function.py @@ -420,7 +420,7 @@ class Function(object): arch = core.BNGetFunctionArchitecture(self.handle) if arch is None: return None - self._arch = architecture.CoreArchitecture(arch) + self._arch = architecture.CoreArchitecture._from_cache(arch) return self._arch @property @@ -558,7 +558,7 @@ class Function(object): branches = core.BNGetIndirectBranches(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.CoreArchitecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -1142,7 +1142,7 @@ class Function(object): branches = core.BNGetIndirectBranchesAt(self.handle, arch.handle, addr, count) result = [] for i in xrange(0, count.value): - result.append(IndirectBranchInfo(architecture.CoreArchitecture(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) + result.append(IndirectBranchInfo(architecture.CoreArchitecture._from_cache(branches[i].sourceArch), branches[i].sourceAddr, architecture.Architecture(branches[i].destArch), branches[i].destAddr, branches[i].autoDefined)) core.BNFreeIndirectBranchList(branches) return result @@ -1660,7 +1660,7 @@ class FunctionGraphBlock(object): arch = core.BNGetFunctionGraphBlockArchitecture(self.handle) if arch is None: return None - return architecture.CoreArchitecture(arch) + return architecture.CoreArchitecture._from_cache(arch) @property def start(self): diff --git a/python/platform.py b/python/platform.py index 09670bac..a79e3b9a 100644 --- a/python/platform.py +++ b/python/platform.py @@ -105,7 +105,7 @@ class Platform(object): else: self.handle = handle self.__dict__["name"] = core.BNGetPlatformName(self.handle) - self.arch = architecture.CoreArchitecture(core.BNGetPlatformArchitecture(self.handle)) + self.arch = architecture.CoreArchitecture._from_cache(core.BNGetPlatformArchitecture(self.handle)) def __del__(self): core.BNFreePlatform(self.handle) -- cgit v1.3.1 From fa716fe2da53a4f136380b1f60197bd197b2793a Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 2 Apr 2018 23:30:56 -0400 Subject: Add plugin commands for LLIL and MLIL --- basicblock.cpp | 37 +++++++++ binaryninjaapi.h | 101 ++++++++++++++++++++--- binaryninjacore.h | 69 ++++++++++++---- binaryview.cpp | 2 + function.cpp | 1 + functiongraph.cpp | 36 ++++++++ functiongraphblock.cpp | 1 + plugin.cpp | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ python/basicblock.py | 21 ++++- python/function.py | 71 +++++++++++++--- python/plugin.py | 219 +++++++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 736 insertions(+), 40 deletions(-) (limited to 'python/basicblock.py') diff --git a/basicblock.cpp b/basicblock.cpp index d42a1038..33f57d40 100644 --- a/basicblock.cpp +++ b/basicblock.cpp @@ -276,6 +276,7 @@ vector BasicBlock::GetDisassemblyText(DisassemblySettings* { DisassemblyTextLine line; line.addr = lines[i].addr; + line.instrIndex = lines[i].instrIndex; line.tokens.reserve(lines[i].count); for (size_t j = 0; j < lines[i].count; j++) { @@ -417,3 +418,39 @@ bool BasicBlock::IsBackEdge(BasicBlock* source, BasicBlock* target) } return false; } + + +bool BasicBlock::IsILBlock() const +{ + return BNIsILBasicBlock(m_object); +} + + +bool BasicBlock::IsLowLevelILBlock() const +{ + return BNIsLowLevelILBasicBlock(m_object); +} + + +bool BasicBlock::IsMediumLevelILBlock() const +{ + return BNIsMediumLevelILBasicBlock(m_object); +} + + +Ref BasicBlock::GetLowLevelILFunction() const +{ + BNLowLevelILFunction* func = BNGetBasicBlockLowLevelILFunction(m_object); + if (!func) + return nullptr; + return new LowLevelILFunction(func); +} + + +Ref BasicBlock::GetMediumLevelILFunction() const +{ + BNMediumLevelILFunction* func = BNGetBasicBlockMediumLevelILFunction(m_object); + if (!func) + return nullptr; + return new MediumLevelILFunction(func); +} diff --git a/binaryninjaapi.h b/binaryninjaapi.h index d0c19e7a..81b5105d 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -986,6 +986,7 @@ namespace BinaryNinja struct DisassemblyTextLine { uint64_t addr; + size_t instrIndex; std::vector tokens; }; @@ -1590,6 +1591,7 @@ namespace BinaryNinja }; class LowLevelILFunction; + class MediumLevelILFunction; class FunctionRecognizer; class CallingConvention; @@ -2254,6 +2256,12 @@ namespace BinaryNinja void SetUserBasicBlockHighlight(uint8_t r, uint8_t g, uint8_t b, uint8_t alpha = 255); static bool IsBackEdge(BasicBlock* source, BasicBlock* target); + + bool IsILBlock() const; + bool IsLowLevelILBlock() const; + bool IsMediumLevelILBlock() const; + Ref GetLowLevelILFunction() const; + Ref GetMediumLevelILFunction() const; }; struct VariableNameAndType @@ -2570,6 +2578,12 @@ namespace BinaryNinja bool IsOptionSet(BNDisassemblyOption option) const; void SetOption(BNDisassemblyOption option, bool state = true); + + bool IsILGraph() const; + bool IsLowLevelILGraph() const; + bool IsMediumLevelILGraph() const; + Ref GetLowLevelILFunction() const; + Ref GetMediumLevelILFunction() const; }; struct LowLevelILLabel: public BNLowLevelILLabel @@ -3312,7 +3326,10 @@ namespace BinaryNinja { Ref view; uint64_t address, length; + size_t instrIndex; Ref function; + Ref lowLevelILFunction; + Ref mediumLevelILFunction; PluginCommandContext(); }; @@ -3345,15 +3362,55 @@ namespace BinaryNinja std::function isValid; }; + struct RegisteredLowLevelILFunctionCommand + { + std::function action; + std::function isValid; + }; + + struct RegisteredLowLevelILInstructionCommand + { + std::function action; + std::function isValid; + }; + + struct RegisteredMediumLevelILFunctionCommand + { + std::function action; + std::function isValid; + }; + + struct RegisteredMediumLevelILInstructionCommand + { + std::function action; + std::function isValid; + }; + static void DefaultPluginCommandActionCallback(void* ctxt, BNBinaryView* view); static void AddressPluginCommandActionCallback(void* ctxt, BNBinaryView* view, uint64_t addr); static void RangePluginCommandActionCallback(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len); static void FunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, BNFunction* func); + static void LowLevelILFunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func); + static void LowLevelILInstructionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr); + static void MediumLevelILFunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func); + static void MediumLevelILInstructionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr); static bool DefaultPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view); static bool AddressPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, uint64_t addr); static bool RangePluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len); static bool FunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, BNFunction* func); + static bool LowLevelILFunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func); + static bool LowLevelILInstructionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr); + static bool MediumLevelILFunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func); + static bool MediumLevelILInstructionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr); public: PluginCommand(const BNPluginCommand& cmd); @@ -3363,25 +3420,45 @@ namespace BinaryNinja PluginCommand& operator=(const PluginCommand& cmd); static void Register(const std::string& name, const std::string& description, - const std::function& action); + const std::function& action); static void Register(const std::string& name, const std::string& description, - const std::function& action, - const std::function& isValid); + const std::function& action, + const std::function& isValid); static void RegisterForAddress(const std::string& name, const std::string& description, - const std::function& action); + const std::function& action); static void RegisterForAddress(const std::string& name, const std::string& description, - const std::function& action, - const std::function& isValid); + const std::function& action, + const std::function& isValid); static void RegisterForRange(const std::string& name, const std::string& description, - const std::function& action); + const std::function& action); static void RegisterForRange(const std::string& name, const std::string& description, - const std::function& action, - const std::function& isValid); + const std::function& action, + const std::function& isValid); static void RegisterForFunction(const std::string& name, const std::string& description, - const std::function& action); + const std::function& action); static void RegisterForFunction(const std::string& name, const std::string& description, - const std::function& action, - const std::function& isValid); + const std::function& action, + const std::function& isValid); + static void RegisterForLowLevelILFunction(const std::string& name, const std::string& description, + const std::function& action); + static void RegisterForLowLevelILFunction(const std::string& name, const std::string& description, + const std::function& action, + const std::function& isValid); + static void RegisterForLowLevelILInstruction(const std::string& name, const std::string& description, + const std::function& action); + static void RegisterForLowLevelILInstruction(const std::string& name, const std::string& description, + const std::function& action, + const std::function& isValid); + static void RegisterForMediumLevelILFunction(const std::string& name, const std::string& description, + const std::function& action); + static void RegisterForMediumLevelILFunction(const std::string& name, const std::string& description, + const std::function& action, + const std::function& isValid); + static void RegisterForMediumLevelILInstruction(const std::string& name, const std::string& description, + const std::function& action); + static void RegisterForMediumLevelILInstruction(const std::string& name, const std::string& description, + const std::function& action, + const std::function& isValid); static std::vector GetList(); static std::vector GetValidList(const PluginCommandContext& ctxt); diff --git a/binaryninjacore.h b/binaryninjacore.h index cb4b9eb9..69c5e61b 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -1205,6 +1205,7 @@ extern "C" struct BNDisassemblyTextLine { uint64_t addr; + size_t instrIndex; BNInstructionTextToken* tokens; size_t count; }; @@ -1365,7 +1366,11 @@ extern "C" DefaultPluginCommand, AddressPluginCommand, RangePluginCommand, - FunctionPluginCommand + FunctionPluginCommand, + LowLevelILFunctionPluginCommand, + LowLevelILInstructionPluginCommand, + MediumLevelILFunctionPluginCommand, + MediumLevelILInstructionPluginCommand }; struct BNPluginCommand @@ -1379,11 +1384,19 @@ extern "C" void (*addressCommand)(void* ctxt, BNBinaryView* view, uint64_t addr); void (*rangeCommand)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len); void (*functionCommand)(void* ctxt, BNBinaryView* view, BNFunction* func); + void (*lowLevelILFunctionCommand)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func); + void (*lowLevelILInstructionCommand)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr); + void (*mediumLevelILFunctionCommand)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func); + void (*mediumLevelILInstructionCommand)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr); bool (*defaultIsValid)(void* ctxt, BNBinaryView* view); bool (*addressIsValid)(void* ctxt, BNBinaryView* view, uint64_t addr); bool (*rangeIsValid)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len); bool (*functionIsValid)(void* ctxt, BNBinaryView* view, BNFunction* func); + bool (*lowLevelILFunctionIsValid)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func); + bool (*lowLevelILInstructionIsValid)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr); + bool (*mediumLevelILFunctionIsValid)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func); + bool (*mediumLevelILInstructionIsValid)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr); }; struct BNCustomCallingConvention @@ -2347,6 +2360,11 @@ extern "C" BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlockDominanceFrontier(BNBasicBlock* block, size_t* count); BINARYNINJACOREAPI BNBasicBlock** BNGetBasicBlockIteratedDominanceFrontier(BNBasicBlock** blocks, size_t incomingCount, size_t* outputCount); + BINARYNINJACOREAPI bool BNIsILBasicBlock(BNBasicBlock* block); + BINARYNINJACOREAPI bool BNIsLowLevelILBasicBlock(BNBasicBlock* block); + BINARYNINJACOREAPI bool BNIsMediumLevelILBasicBlock(BNBasicBlock* block); + BINARYNINJACOREAPI BNLowLevelILFunction* BNGetBasicBlockLowLevelILFunction(BNBasicBlock* block); + BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetBasicBlockMediumLevelILFunction(BNBasicBlock* block); BINARYNINJACOREAPI BNDisassemblyTextLine* BNGetBasicBlockDisassemblyText(BNBasicBlock* block, BNDisassemblySettings* settings, size_t* count); @@ -2547,6 +2565,11 @@ extern "C" BINARYNINJACOREAPI void BNSetFunctionGraphCompleteCallback(BNFunctionGraph* graph, void* ctxt, void (*func)(void* ctxt)); BINARYNINJACOREAPI void BNAbortFunctionGraph(BNFunctionGraph* graph); BINARYNINJACOREAPI BNFunctionGraphType BNGetFunctionGraphType(BNFunctionGraph* graph); + BINARYNINJACOREAPI bool BNIsILFunctionGraph(BNFunctionGraph* graph); + BINARYNINJACOREAPI bool BNIsLowLevelILFunctionGraph(BNFunctionGraph* graph); + BINARYNINJACOREAPI bool BNIsMediumLevelILFunctionGraph(BNFunctionGraph* graph); + BINARYNINJACOREAPI BNLowLevelILFunction* BNGetFunctionGraphLowLevelILFunction(BNFunctionGraph* graph); + BINARYNINJACOREAPI BNMediumLevelILFunction* BNGetFunctionGraphMediumLevelILFunction(BNFunctionGraph* graph); BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocks(BNFunctionGraph* graph, size_t* count); BINARYNINJACOREAPI BNFunctionGraphBlock** BNGetFunctionGraphBlocksInRegion( @@ -3017,29 +3040,45 @@ extern "C" // Plugin commands BINARYNINJACOREAPI void BNRegisterPluginCommand(const char* name, const char* description, - void (*action)(void* ctxt, BNBinaryView* view), - bool (*isValid)(void* ctxt, BNBinaryView* view), void* context); + void (*action)(void* ctxt, BNBinaryView* view), bool (*isValid)(void* ctxt, BNBinaryView* view), void* context); BINARYNINJACOREAPI void BNRegisterPluginCommandForAddress(const char* name, const char* description, - void (*action)(void* ctxt, BNBinaryView* view, uint64_t addr), - bool (*isValid)(void* ctxt, BNBinaryView* view, uint64_t addr), - void* context); + void (*action)(void* ctxt, BNBinaryView* view, uint64_t addr), + bool (*isValid)(void* ctxt, BNBinaryView* view, uint64_t addr), void* context); BINARYNINJACOREAPI void BNRegisterPluginCommandForRange(const char* name, const char* description, - void (*action)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len), - bool (*isValid)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len), - void* context); + void (*action)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len), + bool (*isValid)(void* ctxt, BNBinaryView* view, uint64_t addr, uint64_t len), void* context); BINARYNINJACOREAPI void BNRegisterPluginCommandForFunction(const char* name, const char* description, - void (*action)(void* ctxt, BNBinaryView* view, BNFunction* func), - bool (*isValid)(void* ctxt, BNBinaryView* view, BNFunction* func), - void* context); + void (*action)(void* ctxt, BNBinaryView* view, BNFunction* func), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNFunction* func), void* context); + BINARYNINJACOREAPI void BNRegisterPluginCommandForLowLevelILFunction(const char* name, const char* description, + void (*action)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func), void* context); + BINARYNINJACOREAPI void BNRegisterPluginCommandForLowLevelILInstruction(const char* name, const char* description, + void (*action)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNLowLevelILFunction* func, size_t instr), void* context); + BINARYNINJACOREAPI void BNRegisterPluginCommandForMediumLevelILFunction(const char* name, const char* description, + void (*action)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func), void* context); + BINARYNINJACOREAPI void BNRegisterPluginCommandForMediumLevelILInstruction(const char* name, const char* description, + void (*action)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr), + bool (*isValid)(void* ctxt, BNBinaryView* view, BNMediumLevelILFunction* func, size_t instr), void* context); BINARYNINJACOREAPI BNPluginCommand* BNGetAllPluginCommands(size_t* count); BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommands(BNBinaryView* view, size_t* count); BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForAddress(BNBinaryView* view, uint64_t addr, - size_t* count); + size_t* count); BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForRange(BNBinaryView* view, uint64_t addr, - uint64_t len, size_t* count); + uint64_t len, size_t* count); BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForFunction(BNBinaryView* view, BNFunction* func, - size_t* count); + size_t* count); + BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForLowLevelILFunction(BNBinaryView* view, + BNLowLevelILFunction* func, size_t* count); + BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForLowLevelILInstruction(BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr, size_t* count); + BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForMediumLevelILFunction(BNBinaryView* view, + BNMediumLevelILFunction* func, size_t* count); + BINARYNINJACOREAPI BNPluginCommand* BNGetValidPluginCommandsForMediumLevelILInstruction(BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr, size_t* count); BINARYNINJACOREAPI void BNFreePluginCommandList(BNPluginCommand* commands); // Calling conventions diff --git a/binaryview.cpp b/binaryview.cpp index 8dcae40f..0a9a7118 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1459,6 +1459,7 @@ vector BinaryView::GetPreviousLinearDisassemblyLines(Line line.block = lines[i].block ? new BasicBlock(BNNewBasicBlockReference(lines[i].block)) : nullptr; line.lineOffset = lines[i].lineOffset; line.contents.addr = lines[i].contents.addr; + line.contents.instrIndex = lines[i].contents.instrIndex; line.contents.tokens.reserve(lines[i].contents.count); for (size_t j = 0; j < lines[i].contents.count; j++) { @@ -1507,6 +1508,7 @@ vector BinaryView::GetNextLinearDisassemblyLines(LinearDi line.block = lines[i].block ? new BasicBlock(BNNewBasicBlockReference(lines[i].block)) : nullptr; line.lineOffset = lines[i].lineOffset; line.contents.addr = lines[i].contents.addr; + line.contents.instrIndex = lines[i].contents.instrIndex; line.contents.tokens.reserve(lines[i].contents.count); for (size_t j = 0; j < lines[i].contents.count; j++) { diff --git a/function.cpp b/function.cpp index 1e91f8f3..835ab144 100644 --- a/function.cpp +++ b/function.cpp @@ -1337,6 +1337,7 @@ vector Function::GetTypeTokens(DisassemblySettings* setting { DisassemblyTextLine line; line.addr = lines[i].addr; + line.instrIndex = lines[i].instrIndex; line.tokens.reserve(lines[i].count); for (size_t j = 0; j < lines[i].count; j++) { diff --git a/functiongraph.cpp b/functiongraph.cpp index a743254e..9948d70e 100644 --- a/functiongraph.cpp +++ b/functiongraph.cpp @@ -186,3 +186,39 @@ void FunctionGraph::SetOption(BNDisassemblyOption option, bool state) { BNSetFunctionGraphOption(m_graph, option, state); } + + +bool FunctionGraph::IsILGraph() const +{ + return BNIsILFunctionGraph(m_graph); +} + + +bool FunctionGraph::IsLowLevelILGraph() const +{ + return BNIsLowLevelILFunctionGraph(m_graph); +} + + +bool FunctionGraph::IsMediumLevelILGraph() const +{ + return BNIsMediumLevelILFunctionGraph(m_graph); +} + + +Ref FunctionGraph::GetLowLevelILFunction() const +{ + BNLowLevelILFunction* func = BNGetFunctionGraphLowLevelILFunction(m_graph); + if (!func) + return nullptr; + return new LowLevelILFunction(func); +} + + +Ref FunctionGraph::GetMediumLevelILFunction() const +{ + BNMediumLevelILFunction* func = BNGetFunctionGraphMediumLevelILFunction(m_graph); + if (!func) + return nullptr; + return new MediumLevelILFunction(func); +} diff --git a/functiongraphblock.cpp b/functiongraphblock.cpp index 06a35eee..469fb175 100644 --- a/functiongraphblock.cpp +++ b/functiongraphblock.cpp @@ -94,6 +94,7 @@ const vector& FunctionGraphBlock::GetLines() { DisassemblyTextLine line; line.addr = lines[i].addr; + line.instrIndex = lines[i].instrIndex; line.tokens.reserve(lines[i].count); for (size_t j = 0; j < lines[i].count; j++) { diff --git a/plugin.cpp b/plugin.cpp index 972ce28b..22befd65 100644 --- a/plugin.cpp +++ b/plugin.cpp @@ -19,6 +19,8 @@ // IN THE SOFTWARE. #include "binaryninjaapi.h" +#include "lowlevelilinstruction.h" +#include "mediumlevelilinstruction.h" using namespace BinaryNinja; using namespace std; @@ -27,6 +29,7 @@ using namespace std; PluginCommandContext::PluginCommandContext() { address = length = 0; + instrIndex = BN_INVALID_EXPR; } @@ -97,6 +100,48 @@ void PluginCommand::FunctionPluginCommandActionCallback(void* ctxt, BNBinaryView } +void PluginCommand::LowLevelILFunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func) +{ + RegisteredLowLevelILFunctionCommand* cmd = (RegisteredLowLevelILFunctionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func)); + cmd->action(viewObject, funcObject); +} + + +void PluginCommand::LowLevelILInstructionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr) +{ + RegisteredLowLevelILInstructionCommand* cmd = (RegisteredLowLevelILInstructionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func)); + LowLevelILInstruction instrObject = funcObject->GetInstruction(instr); + cmd->action(viewObject, instrObject); +} + + +void PluginCommand::MediumLevelILFunctionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func) +{ + RegisteredMediumLevelILFunctionCommand* cmd = (RegisteredMediumLevelILFunctionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func)); + cmd->action(viewObject, funcObject); +} + + +void PluginCommand::MediumLevelILInstructionPluginCommandActionCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr) +{ + RegisteredMediumLevelILInstructionCommand* cmd = (RegisteredMediumLevelILInstructionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func)); + MediumLevelILInstruction instrObject = funcObject->GetInstruction(instr); + cmd->action(viewObject, instrObject); +} + + bool PluginCommand::DefaultPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view) { RegisteredDefaultCommand* cmd = (RegisteredDefaultCommand*)ctxt; @@ -130,6 +175,48 @@ bool PluginCommand::FunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryVie } +bool PluginCommand::LowLevelILFunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func) +{ + RegisteredLowLevelILFunctionCommand* cmd = (RegisteredLowLevelILFunctionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func)); + return cmd->isValid(viewObject, funcObject); +} + + +bool PluginCommand::LowLevelILInstructionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNLowLevelILFunction* func, size_t instr) +{ + RegisteredLowLevelILInstructionCommand* cmd = (RegisteredLowLevelILInstructionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new LowLevelILFunction(BNNewLowLevelILFunctionReference(func)); + LowLevelILInstruction instrObject = funcObject->GetInstruction(instr); + return cmd->isValid(viewObject, instrObject); +} + + +bool PluginCommand::MediumLevelILFunctionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func) +{ + RegisteredMediumLevelILFunctionCommand* cmd = (RegisteredMediumLevelILFunctionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func)); + return cmd->isValid(viewObject, funcObject); +} + + +bool PluginCommand::MediumLevelILInstructionPluginCommandIsValidCallback(void* ctxt, BNBinaryView* view, + BNMediumLevelILFunction* func, size_t instr) +{ + RegisteredMediumLevelILInstructionCommand* cmd = (RegisteredMediumLevelILInstructionCommand*)ctxt; + Ref viewObject = new BinaryView(BNNewViewReference(view)); + Ref funcObject = new MediumLevelILFunction(BNNewMediumLevelILFunctionReference(func)); + MediumLevelILInstruction instrObject = funcObject->GetInstruction(instr); + return cmd->isValid(viewObject, instrObject); +} + + void PluginCommand::Register(const string& name, const string& description, const function& action) { @@ -206,6 +293,89 @@ void PluginCommand::RegisterForFunction(const string& name, const string& descri } +void PluginCommand::RegisterForLowLevelILFunction(const string& name, const string& description, + const function& action) +{ + RegisterForLowLevelILFunction(name, description, action, [](BinaryView*, LowLevelILFunction*) { return true; }); +} + + +void PluginCommand::RegisterForLowLevelILFunction(const string& name, const string& description, + const function& action, + const function& isValid) +{ + RegisteredLowLevelILFunctionCommand* cmd = new RegisteredLowLevelILFunctionCommand; + cmd->action = action; + cmd->isValid = isValid; + BNRegisterPluginCommandForLowLevelILFunction(name.c_str(), description.c_str(), + LowLevelILFunctionPluginCommandActionCallback, + LowLevelILFunctionPluginCommandIsValidCallback, cmd); +} + + +void PluginCommand::RegisterForLowLevelILInstruction(const string& name, const string& description, + const function& action) +{ + RegisterForLowLevelILInstruction(name, description, action, + [](BinaryView*, const LowLevelILInstruction&) { return true; }); +} + + +void PluginCommand::RegisterForLowLevelILInstruction(const string& name, const string& description, + const function& action, + const function& isValid) +{ + RegisteredLowLevelILInstructionCommand* cmd = new RegisteredLowLevelILInstructionCommand; + cmd->action = action; + cmd->isValid = isValid; + BNRegisterPluginCommandForLowLevelILInstruction(name.c_str(), description.c_str(), + LowLevelILInstructionPluginCommandActionCallback, + LowLevelILInstructionPluginCommandIsValidCallback, cmd); +} + + +void PluginCommand::RegisterForMediumLevelILFunction(const string& name, const string& description, + const function& action) +{ + RegisterForMediumLevelILFunction(name, description, action, + [](BinaryView*, MediumLevelILFunction*) { return true; }); +} + + +void PluginCommand::RegisterForMediumLevelILFunction(const string& name, const string& description, + const function& action, + const function& isValid) +{ + RegisteredMediumLevelILFunctionCommand* cmd = new RegisteredMediumLevelILFunctionCommand; + cmd->action = action; + cmd->isValid = isValid; + BNRegisterPluginCommandForMediumLevelILFunction(name.c_str(), description.c_str(), + MediumLevelILFunctionPluginCommandActionCallback, + MediumLevelILFunctionPluginCommandIsValidCallback, cmd); +} + + +void PluginCommand::RegisterForMediumLevelILInstruction(const string& name, const string& description, + const function& action) +{ + RegisterForMediumLevelILInstruction(name, description, action, + [](BinaryView*, const MediumLevelILInstruction&) { return true; }); +} + + +void PluginCommand::RegisterForMediumLevelILInstruction(const string& name, const string& description, + const function& action, + const function& isValid) +{ + RegisteredMediumLevelILInstructionCommand* cmd = new RegisteredMediumLevelILInstructionCommand; + cmd->action = action; + cmd->isValid = isValid; + BNRegisterPluginCommandForMediumLevelILInstruction(name.c_str(), description.c_str(), + MediumLevelILInstructionPluginCommandActionCallback, + MediumLevelILInstructionPluginCommandIsValidCallback, cmd); +} + + vector PluginCommand::GetList() { vector result; @@ -259,6 +429,38 @@ bool PluginCommand::IsValid(const PluginCommandContext& ctxt) const if (!m_command.functionIsValid) return true; return m_command.functionIsValid(m_command.context, ctxt.view->GetObject(), ctxt.function->GetObject()); + case LowLevelILFunctionPluginCommand: + if (!ctxt.lowLevelILFunction) + return false; + if (!m_command.lowLevelILFunctionIsValid) + return true; + return m_command.lowLevelILFunctionIsValid(m_command.context, ctxt.view->GetObject(), + ctxt.lowLevelILFunction->GetObject()); + case LowLevelILInstructionPluginCommand: + if (!ctxt.lowLevelILFunction) + return false; + if (ctxt.instrIndex == BN_INVALID_EXPR) + return false; + if (!m_command.lowLevelILInstructionIsValid) + return true; + return m_command.lowLevelILInstructionIsValid(m_command.context, ctxt.view->GetObject(), + ctxt.lowLevelILFunction->GetObject(), ctxt.instrIndex); + case MediumLevelILFunctionPluginCommand: + if (!ctxt.mediumLevelILFunction) + return false; + if (!m_command.mediumLevelILFunctionIsValid) + return true; + return m_command.mediumLevelILFunctionIsValid(m_command.context, ctxt.view->GetObject(), + ctxt.mediumLevelILFunction->GetObject()); + case MediumLevelILInstructionPluginCommand: + if (!ctxt.mediumLevelILFunction) + return false; + if (ctxt.instrIndex == BN_INVALID_EXPR) + return false; + if (!m_command.mediumLevelILInstructionIsValid) + return true; + return m_command.mediumLevelILInstructionIsValid(m_command.context, ctxt.view->GetObject(), + ctxt.mediumLevelILFunction->GetObject(), ctxt.instrIndex); default: return false; } @@ -284,6 +486,22 @@ void PluginCommand::Execute(const PluginCommandContext& ctxt) const case FunctionPluginCommand: m_command.functionCommand(m_command.context, ctxt.view->GetObject(), ctxt.function->GetObject()); break; + case LowLevelILFunctionPluginCommand: + m_command.lowLevelILFunctionCommand(m_command.context, ctxt.view->GetObject(), + ctxt.lowLevelILFunction->GetObject()); + break; + case LowLevelILInstructionPluginCommand: + m_command.lowLevelILInstructionCommand(m_command.context, ctxt.view->GetObject(), + ctxt.lowLevelILFunction->GetObject(), ctxt.instrIndex); + break; + case MediumLevelILFunctionPluginCommand: + m_command.mediumLevelILFunctionCommand(m_command.context, ctxt.view->GetObject(), + ctxt.mediumLevelILFunction->GetObject()); + break; + case MediumLevelILInstructionPluginCommand: + m_command.mediumLevelILInstructionCommand(m_command.context, ctxt.view->GetObject(), + ctxt.mediumLevelILFunction->GetObject(), ctxt.instrIndex); + break; default: break; } diff --git a/python/basicblock.py b/python/basicblock.py index 1d932c5e..4dc783c3 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -256,6 +256,21 @@ class BasicBlock(object): def highlight(self, value): self.set_user_highlight(value) + @property + def is_il(self): + """Whether the basic block contains IL""" + return core.BNIsILBasicBlock(self.handle) + + @property + def is_low_level_il(self): + """Whether the basic block contains Low Level IL""" + return core.BNIsLowLevelILBasicBlock(self.handle) + + @property + def is_medium_level_il(self): + """Whether the basic block contains Medium Level IL""" + return core.BNIsMediumLevelILBasicBlock(self.handle) + @classmethod def get_iterated_dominance_frontier(self, blocks): if len(blocks) == 0: @@ -322,6 +337,10 @@ class BasicBlock(object): result = [] for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(self, 'il_function'): + il_instr = self.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -333,7 +352,7 @@ class BasicBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(function.InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(function.DisassemblyTextLine(addr, tokens)) + result.append(function.DisassemblyTextLine(addr, tokens, il_instr)) core.BNFreeDisassemblyTextLines(lines, count.value) return result diff --git a/python/function.py b/python/function.py index 1cc4dcac..6db44e6d 100644 --- a/python/function.py +++ b/python/function.py @@ -1598,9 +1598,10 @@ class AdvancedFunctionAnalysisDataRequestor(object): class DisassemblyTextLine(object): - def __init__(self, addr, tokens): + def __init__(self, addr, tokens, il_instr = None): self.address = addr self.tokens = tokens + self.il_instruction = il_instr def __str__(self): result = "" @@ -1625,8 +1626,9 @@ class FunctionGraphEdge(object): class FunctionGraphBlock(object): - def __init__(self, handle): + def __init__(self, handle, graph): self.handle = handle + self.graph = graph def __del__(self): core.BNFreeFunctionGraphBlock(self.handle) @@ -1645,13 +1647,22 @@ class FunctionGraphBlock(object): def basic_block(self): """Basic block associated with this part of the function graph (read-only)""" block = core.BNGetFunctionGraphBasicBlock(self.handle) - func = core.BNGetBasicBlockFunction(block) - if func is None: + func_handle = core.BNGetBasicBlockFunction(block) + if func_handle is None: core.BNFreeBasicBlock(block) - block = None + return None + + view = binaryview.BinaryView(handle = core.BNGetFunctionData(func_handle)) + func = Function(view, func_handle) + + if core.BNIsLowLevelILBasicBlock(block): + block = lowlevelil.LowLevelILBasicBlock(view, block, + lowlevelil.LowLevelILFunction(func.arch, core.BNGetBasicBlockLowLevelILFunction(block), func)) + elif core.BNIsMediumLevelILBasicBlock(block): + block = mediumlevelil.MediumLevelILBasicBlock(view, block, + mediumlevelil.MediumLevelILFunction(func.arch, core.BNGetBasicBlockMediumLevelILFunction(block), func)) else: - block = basicblock.BasicBlock(binaryview.BinaryView(handle = core.BNGetFunctionData(func)), block) - core.BNFreeFunction(func) + block = basicblock.BasicBlock(view, block) return block @property @@ -1697,9 +1708,14 @@ class FunctionGraphBlock(object): """Function graph block list of lines (read-only)""" count = ctypes.c_ulonglong() lines = core.BNGetFunctionGraphBlockLines(self.handle, count) + block = self.basic_block result = [] for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'): + il_instr = block.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -1711,7 +1727,7 @@ class FunctionGraphBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - result.append(DisassemblyTextLine(addr, tokens)) + result.append(DisassemblyTextLine(addr, tokens, il_instr)) core.BNFreeDisassemblyTextLines(lines, count.value) return result @@ -1756,9 +1772,14 @@ class FunctionGraphBlock(object): def __iter__(self): count = ctypes.c_ulonglong() lines = core.BNGetFunctionGraphBlockLines(self.handle, count) + block = self.basic_block try: for i in xrange(0, count.value): addr = lines[i].addr + if (lines[i].instrIndex != 0xffffffffffffffff) and hasattr(block, 'il_function'): + il_instr = block.il_function[lines[i].instrIndex] + else: + il_instr = None tokens = [] for j in xrange(0, lines[i].count): token_type = InstructionTextTokenType(lines[i].tokens[j].type) @@ -1770,7 +1791,7 @@ class FunctionGraphBlock(object): confidence = lines[i].tokens[j].confidence address = lines[i].tokens[j].address tokens.append(InstructionTextToken(token_type, text, value, size, operand, context, address, confidence)) - yield DisassemblyTextLine(addr, tokens) + yield DisassemblyTextLine(addr, tokens, il_instr) finally: core.BNFreeDisassemblyTextLines(lines, count.value) @@ -1858,7 +1879,7 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocks(self.handle, count) result = [] for i in xrange(0, count.value): - result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]))) + result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)) core.BNFreeFunctionGraphBlockList(blocks, count.value) return result @@ -1897,6 +1918,32 @@ class FunctionGraph(object): def settings(self): return DisassemblySettings(core.BNGetFunctionGraphSettings(self.handle)) + @property + def is_il(self): + return core.BNIsILFunctionGraph(self.handle) + + @property + def is_low_level_il(self): + return core.BNIsLowLevelILFunctionGraph(self.handle) + + @property + def is_medium_level_il(self): + return core.BNIsMediumLevelILFunctionGraph(self.handle) + + @property + def il_function(self): + if self.is_low_level_il: + il_func = core.BNGetFunctionGraphLowLevelILFunction(self.handle) + if not il_func: + return None + return lowlevelil.LowLevelILFunction(self.function.arch, il_func, self.function) + if self.is_medium_level_il: + il_func = core.BNGetFunctionGraphMediumLevelILFunction(self.handle) + if not il_func: + return None + return mediumlevelil.MediumLevelILFunction(self.function.arch, il_func, self.function) + return None + def __setattr__(self, name, value): try: object.__setattr__(self, name, value) @@ -1911,7 +1958,7 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocks(self.handle, count) try: for i in xrange(0, count.value): - yield FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i])) + yield FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self) finally: core.BNFreeFunctionGraphBlockList(blocks, count.value) @@ -1954,7 +2001,7 @@ class FunctionGraph(object): blocks = core.BNGetFunctionGraphBlocksInRegion(self.handle, left, top, right, bottom, count) result = [] for i in xrange(0, count.value): - result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]))) + result.append(FunctionGraphBlock(core.BNNewFunctionGraphBlockReference(blocks[i]), self)) core.BNFreeFunctionGraphBlockList(blocks, count.value) return result diff --git a/python/plugin.py b/python/plugin.py index e0054d86..c6cd9fc0 100644 --- a/python/plugin.py +++ b/python/plugin.py @@ -30,6 +30,8 @@ import filemetadata import binaryview import function import log +import lowlevelil +import mediumlevelil class PluginCommandContext(object): @@ -38,6 +40,7 @@ class PluginCommandContext(object): self.address = 0 self.length = 0 self.function = None + self.instruction = None class _PluginCommandMetaClass(type): @@ -117,6 +120,50 @@ class PluginCommand(object): except: log.log_error(traceback.format_exc()) + @classmethod + def _low_level_il_function_action(cls, view, func, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + action(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _low_level_il_instruction_action(cls, view, func, instr, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + action(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _medium_level_il_function_action(cls, view, func, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + action(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + + @classmethod + def _medium_level_il_instruction_action(cls, view, func, instr, action): + try: + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + action(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + @classmethod def _default_is_valid(cls, view, is_valid): try: @@ -166,6 +213,62 @@ class PluginCommand(object): log.log_error(traceback.format_exc()) return False + @classmethod + def _low_level_il_function_is_valid(cls, view, func, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _low_level_il_instruction_is_valid(cls, view, func, instr, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetLowLevelILOwnerFunction(func)) + func_obj = lowlevelil.LowLevelILFunction(owner.arch, core.BNNewLowLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _medium_level_il_function_is_valid(cls, view, func, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj) + except: + log.log_error(traceback.format_exc()) + return False + + @classmethod + def _medium_level_il_instruction_is_valid(cls, view, func, instr, is_valid): + try: + if is_valid is None: + return True + file_metadata = filemetadata.FileMetadata(handle = core.BNGetFileForView(view)) + view_obj = binaryview.BinaryView(file_metadata = file_metadata, handle = core.BNNewViewReference(view)) + owner = function.Function(view_obj, core.BNGetMediumLevelILOwnerFunction(func)) + func_obj = mediumlevelil.MediumLevelILFunction(owner.arch, core.BNNewMediumLevelILFunctionReference(func), owner) + return is_valid(view_obj, func_obj[instr]) + except: + log.log_error(traceback.format_exc()) + return False + @classmethod def register(cls, name, description, action, is_valid = None): """ @@ -242,6 +345,82 @@ class PluginCommand(object): cls._registered_commands.append((action_obj, is_valid_obj)) core.BNRegisterPluginCommandForFunction(name, description, action_obj, is_valid_obj, None) + @classmethod + def register_for_low_level_il_function(cls, name, description, action, is_valid = None): + """ + ``register_for_low_level_il_function`` Register a plugin to be called with a low level IL function argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``LowLevelILFunction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_low_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_action(view, func, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction))(lambda ctxt, view, func: cls._low_level_il_function_is_valid(view, func, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForLowLevelILFunction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_low_level_il_instruction(cls, name, description, action, is_valid = None): + """ + ``register_for_low_level_il_instruction`` Register a plugin to be called with a low level IL instruction argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``LowLevelILInstruction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_low_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_action(view, func, instr, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNLowLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._low_level_il_instruction_is_valid(view, func, instr, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForLowLevelILInstruction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_medium_level_il_function(cls, name, description, action, is_valid = None): + """ + ``register_for_medium_level_il_function`` Register a plugin to be called with a medium level IL function argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``MediumLevelILFunction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_medium_level_il_function`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_action(view, func, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction))(lambda ctxt, view, func: cls._medium_level_il_function_is_valid(view, func, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForMediumLevelILFunction(name, description, action_obj, is_valid_obj, None) + + @classmethod + def register_for_medium_level_il_instruction(cls, name, description, action, is_valid = None): + """ + ``register_for_medium_level_il_instruction`` Register a plugin to be called with a medium level IL instruction argument + + :param str name: name of the plugin + :param str description: description of the plugin + :param action: function to call with the ``BinaryView`` and a ``MediumLevelILInstruction`` as arguments + :param is_valid: optional argument of a function passed a ``BinaryView`` to determine whether the plugin should be enabled for that view + :rtype: None + + .. warning:: Calling ``register_for_medium_level_il_instruction`` with the same function name will replace the existing function but will leak the memory of the original plugin. + """ + startup._init_plugins() + action_obj = ctypes.CFUNCTYPE(None, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_action(view, func, instr, action)) + is_valid_obj = ctypes.CFUNCTYPE(ctypes.c_bool, ctypes.c_void_p, ctypes.POINTER(core.BNBinaryView), ctypes.POINTER(core.BNMediumLevelILFunction), ctypes.c_ulonglong)(lambda ctxt, view, func, instr: cls._medium_level_il_instruction_is_valid(view, func, instr, is_valid)) + cls._registered_commands.append((action_obj, is_valid_obj)) + core.BNRegisterPluginCommandForMediumLevelILInstruction(name, description, action_obj, is_valid_obj, None) + @classmethod def get_valid_list(cls, context): """Dict of registered plugins""" @@ -275,6 +454,36 @@ class PluginCommand(object): if not self.command.functionIsValid: return True return self.command.functionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILFunctionPluginCommand: + if context.function is None: + return False + if not self.command.lowLevelILFunctionIsValid: + return True + return self.command.lowLevelILFunctionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILInstructionPluginCommand: + if context.instruction is None: + return False + if not isinstance(context.instruction, lowlevelil.LowLevelILInstruction): + return False + if not self.command.lowLevelILInstructionIsValid: + return True + return self.command.lowLevelILInstructionIsValid(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) + elif self.command.type == PluginCommandType.MediumLevelILFunctionPluginCommand: + if context.function is None: + return False + if not self.command.mediumLevelILFunctionIsValid: + return True + return self.command.mediumLevelILFunctionIsValid(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.MediumLevelILInstructionPluginCommand: + if context.instruction is None: + return False + if not isinstance(context.instruction, mediumlevelil.MediumLevelILInstruction): + return False + if not self.command.mediumLevelILInstructionIsValid: + return True + return self.command.mediumLevelILInstructionIsValid(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) return False def execute(self, context): @@ -288,6 +497,16 @@ class PluginCommand(object): self.command.rangeCommand(self.command.context, context.view.handle, context.address, context.length) elif self.command.type == PluginCommandType.FunctionPluginCommand: self.command.functionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILFunctionPluginCommand: + self.command.lowLevelILFunctionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.LowLevelILInstructionPluginCommand: + self.command.lowLevelILInstructionCommand(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) + elif self.command.type == PluginCommandType.MediumLevelILFunctionPluginCommand: + self.command.mediumLevelILFunctionCommand(self.command.context, context.view.handle, context.function.handle) + elif self.command.type == PluginCommandType.MediumLevelILInstructionPluginCommand: + self.command.mediumLevelILInstructionCommand(self.command.context, context.view.handle, + context.instruction.function.handle, context.instruction.instr_index) def __repr__(self): return "" % self.name -- cgit v1.3.1 From 16368c3b9864d5ba635264eea1365c400c563646 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Wed, 11 Apr 2018 17:34:43 -0400 Subject: fix for #1015, thanks josh --- python/basicblock.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python/basicblock.py') diff --git a/python/basicblock.py b/python/basicblock.py index 4dc783c3..c55e15f0 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -308,7 +308,7 @@ class BasicBlock(object): idx = start while idx < end: - data = self.view.read(idx, 16) + data = self.view.read(idx, self.arch.max_instr_length) inst_info = self.arch.get_instruction_info(data, idx) inst_text = self.arch.get_instruction_text(data, idx) -- cgit v1.3.1 From bbc3116e82e8d92084a0e667e6f5222fc1455999 Mon Sep 17 00:00:00 2001 From: Ryan Snyder Date: Fri, 6 Jul 2018 11:10:04 -0400 Subject: python: fix BasicBlock iteration for invalid instructions --- python/basicblock.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'python/basicblock.py') diff --git a/python/basicblock.py b/python/basicblock.py index c55e15f0..a79b53ad 100644 --- a/python/basicblock.py +++ b/python/basicblock.py @@ -312,6 +312,8 @@ class BasicBlock(object): inst_info = self.arch.get_instruction_info(data, idx) inst_text = self.arch.get_instruction_text(data, idx) + if inst_info is None: + break yield inst_text idx += inst_info.length -- cgit v1.3.1