From 56d270363e63b45c2032f4e73d02f9e2a92c76c2 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 30 May 2016 04:20:27 -0400 Subject: Add APIs for querying stack variable values and parameters by index --- python/__init__.py | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/__init__.py b/python/__init__.py index 821e3f41..6776ef09 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -2292,7 +2292,7 @@ class Function(object): def get_reg_value_at_low_level_il_instruction(self, i, reg): if isinstance(reg, str): reg = self.arch.regs[reg].index - value = core.BNGetRegisterValueAtInstruction(self.handle, self.arch.handle, i, reg) + value = core.BNGetRegisterValueAtLowLevelILInstruction(self.handle, i, reg) result = RegisterValue(self.arch, value) core.BNFreeRegisterValue(value) return result @@ -2300,7 +2300,55 @@ class Function(object): def get_reg_value_after_low_level_il_instruction(self, i, reg): if isinstance(reg, str): reg = self.arch.regs[reg].index - value = core.BNGetRegisterValueAfterInstruction(self.handle, self.arch.handle, i, reg) + value = core.BNGetRegisterValueAfterLowLevelILInstruction(self.handle, i, reg) + result = RegisterValue(self.arch, value) + core.BNFreeRegisterValue(value) + return result + + def get_stack_contents_at(self, arch, addr, offset, size): + if isinstance(reg, str): + reg = arch.regs[reg].index + value = core.BNGetStackContentsAtInstruction(self.handle, arch.handle, addr, offset, size) + result = RegisterValue(arch, value) + core.BNFreeRegisterValue(value) + return result + + def get_stack_contents_after(self, arch, addr, offset, size): + if isinstance(reg, str): + reg = arch.regs[reg].index + value = core.BNGetStackContentsAfterInstruction(self.handle, arch.handle, addr, reg) + result = RegisterValue(arch, value) + core.BNFreeRegisterValue(value) + return result + + def get_stack_contents_at_low_level_il_instruction(self, i, offset, size): + if isinstance(reg, str): + reg = self.arch.regs[reg].index + value = core.BNGetStackContentsAtLowLevelILInstruction(self.handle, i, offset, size) + result = RegisterValue(self.arch, value) + core.BNFreeRegisterValue(value) + return result + + def get_stack_contents_after_low_level_il_instruction(self, i, offset, size): + if isinstance(reg, str): + reg = self.arch.regs[reg].index + value = core.BNGetStackContentsAfterInstruction(self.handle, i, offset, size) + result = RegisterValue(self.arch, value) + core.BNFreeRegisterValue(value) + return result + + def get_parameter_at(self, arch, addr, func_type, i): + if func_type is not None: + func_type = func_type.handle + value = core.BNGetParameterValueAtInstruction(self.handle, arch.handle, addr, func_type, i) + result = RegisterValue(arch, value) + core.BNFreeRegisterValue(value) + return result + + def get_parameter_at_low_level_il_instruction(self, instr, func_type, i): + if func_type is not None: + func_type = func_type.handle + value = core.BNGetParameterValueAtLowLevelILInstruction(self.handle, instr, func_type, i) result = RegisterValue(self.arch, value) core.BNFreeRegisterValue(value) return result -- cgit v1.3.1 From 4dc7c3041e7c95e373b55dbb27b1861e82976fc0 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Mon, 30 May 2016 22:40:24 -0400 Subject: Add IL instruction to promote bool to int, used for MIPS jump tables --- binaryninjaapi.h | 1 + binaryninjacore.h | 1 + lowlevelil.cpp | 6 ++++++ python/__init__.py | 1 + 4 files changed, 9 insertions(+) (limited to 'python') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 7ece4c4d..72240975 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -1545,6 +1545,7 @@ namespace BinaryNinja ExprId CompareSignedGreaterThan(size_t size, ExprId a, ExprId b); ExprId CompareUnsignedGreaterThan(size_t size, ExprId a, ExprId b); ExprId TestBit(size_t size, ExprId a, ExprId b); + ExprId BoolToInt(size_t size, ExprId a); ExprId SystemCall(); ExprId Breakpoint(); ExprId Trap(uint32_t num); diff --git a/binaryninjacore.h b/binaryninjacore.h index 41388a98..cbbfcfa8 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -245,6 +245,7 @@ extern "C" LLIL_CMP_SGT, LLIL_CMP_UGT, LLIL_TEST_BIT, + LLIL_BOOL_TO_INT, LLIL_SYSCALL, LLIL_BP, LLIL_TRAP, diff --git a/lowlevelil.cpp b/lowlevelil.cpp index d86bb523..550accc2 100644 --- a/lowlevelil.cpp +++ b/lowlevelil.cpp @@ -428,6 +428,12 @@ ExprId LowLevelILFunction::TestBit(size_t size, ExprId a, ExprId b) } +ExprId LowLevelILFunction::BoolToInt(size_t size, ExprId a) +{ + return AddExpr(LLIL_BOOL_TO_INT, size, 0, a); +} + + ExprId LowLevelILFunction::SystemCall() { return AddExpr(LLIL_SYSCALL, 0, 0); diff --git a/python/__init__.py b/python/__init__.py index 6776ef09..75d114cd 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -3987,6 +3987,7 @@ class LowLevelILInstruction(object): core.LLIL_CMP_SGT: [("left", "expr"), ("right", "expr")], core.LLIL_CMP_UGT: [("left", "expr"), ("right", "expr")], core.LLIL_TEST_BIT: [("left", "expr"), ("right", "expr")], + core.LLIL_BOOL_TO_INT: [("src", "expr")], core.LLIL_SYSCALL: [], core.LLIL_BP: [], core.LLIL_TRAP: [("value", "int")], -- cgit v1.3.1 From 16a07a7b7a5fe7acf172c8f5eedd5d9898645e22 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Wed, 1 Jun 2016 04:51:14 -0400 Subject: stylized svg and start of tooltips --- python/examples/export-svg.py | 108 ++++++++++++++++++++++++++++++------------ 1 file changed, 78 insertions(+), 30 deletions(-) (limited to 'python') diff --git a/python/examples/export-svg.py b/python/examples/export-svg.py index e00b651f..ad3a3dd7 100755 --- a/python/examples/export-svg.py +++ b/python/examples/export-svg.py @@ -1,16 +1,34 @@ from binaryninja import * -import os +import os,sys + +escape_table = { + "&": "&", + "'": "'", + ">": ">", + "<": "<", + '"': """, + ' ': " ", +} + +def escape(string): + return ''.join(escape_table.get(i,i) for i in string) def save_svg(bv,function): filename = bv.file.filename.split(os.sep)[-1] - outputfile = os.environ['HOME'] + os.sep + 'binaryninja-{filename}-{function}.svg'.format(filename=filename,function=function.symbol.name) - try: - output = open(outputfile,'w') - output.write(render_svg(function)) - output.close() - except: - print "Unexpected error:", sys.exc_info()[0] - raise + outputfile = os.path.join(os.path.expanduser('~'), 'binaryninja-{filename}-{function}.html'.format(filename=filename,function=function.symbol.name)) + content = render_svg(function) + output = open(outputfile,'w') + output.write(content) + output.close() + #os.system('open %s' % outputfile) + +def instruction_data_flow(function,address): + ''' TODO: Extract data flow information ''' + length = function.view.get_instruction_length(function.arch,address) + bytes = function.view.read(address, length) + hex = bytes.encode('hex') + padded = ' '.join([hex[i:i+2] for i in range(0, len(hex), 2)]) + return 'Opcode: {bytes}'.format(bytes=padded) def render_svg(function): graph = function.create_graph() @@ -19,44 +37,71 @@ def render_svg(function): ratio = 0.54 widthconst = int(heightconst*ratio) - output = ''' - - + output = ''' - + - + - + @@ -74,9 +119,9 @@ def render_svg(function): height = int((block.height) * heightconst) #Render block - output += ' \n' - output += ' Basic Block {i}\n' - output += ' \n'.format(i=i,x=x,y=y,width=width,height=height) + output += ' \n'.format(i=i) + output += ' Basic Block {i}\n'.format(i=i) + output += ' \n'.format(x=x,y=y,width=width,height=height) #Render instructions, unfortunately tspans don't allow copying/pasting more #than one line at a time, need SVG 1.2 textarea tags for that it looks like @@ -84,9 +129,12 @@ def render_svg(function): output += ' \n'.format(x=x,y=y + (i + 1) * heightconst) for i,line in enumerate(block.lines): output += ' '.format(x=x,y=y + (i + 0.7) * heightconst,address=hex(line.address)[:-1]) + hover = instruction_data_flow(function, line.address) + output += '{hover}'.format(hover=hover) for token in line.tokens: - output+='{text}'.format(text=token.text,tokentype=token.type) - output += ' \n' + # TODO: add hover for hex, function, and reg tokens + output+='{text}'.format(text=escape(token.text),tokentype=token.type) + output += '\n' output += ' \n' output += ' \n' @@ -100,7 +148,7 @@ def render_svg(function): edges += ' \n'.format(type=edge.type,points=points) output += ' ' + edges + '\n' output += ' \n' - output += '' + output += '' return output -PluginCommand.register_for_function("Export to SVG", "Exports an SVG to your home folder for the given function", save_svg) +PluginCommand.register_for_function("Export to SVG", "Exports an SVG of the current function to your home folder.", save_svg) -- cgit v1.3.1 From d77bcec46af3b1e08ec1bf26899bef8dae46a528 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Wed, 1 Jun 2016 05:09:05 -0400 Subject: missed a few colors --- python/examples/export-svg.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'python') diff --git a/python/examples/export-svg.py b/python/examples/export-svg.py index ad3a3dd7..5826a546 100755 --- a/python/examples/export-svg.py +++ b/python/examples/export-svg.py @@ -76,24 +76,27 @@ def render_svg(function): .CodeSymbolToken {{ fill: rgb(128, 198, 223); }} - .TextToken {{ + .DataSymbolToken {{ + fill: rgb(142, 230, 237); + }} + .TextToken, .InstructionToken, .BeginMemoryOperandToken, .EndMemoryOperandToken {{ fill: rgb(224, 224, 224); }} - .PossibleAddressToken {{ + .PossibleAddressToken, .IntegerToken {{ fill: rgb(162, 217, 175); }} .RegisterToken {{ fill: rgb(237, 223, 179); }} - .InstructionToken {{ - fill: rgb(224, 224, 224); - }} .AnnotationToken {{ fill: rgb(218, 196, 209); }} .ImportToken {{ fill: rgb(237, 189, 129); }} + .StackVariableToken {{ + fill: rgb(193, 220, 199); + }} ]]> -- cgit v1.3.1 From e397c1c03ddca833bf39cf0bbdb6ce859bb16c7a Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Thu, 2 Jun 2016 00:09:18 -0400 Subject: properly escape higher unicode, use address instead of function in filename, add indirect branch style, split style --- python/examples/export-svg.py | 145 ++++++++++++++++++++++-------------------- 1 file changed, 77 insertions(+), 68 deletions(-) (limited to 'python') diff --git a/python/examples/export-svg.py b/python/examples/export-svg.py index 5826a546..c169337c 100755 --- a/python/examples/export-svg.py +++ b/python/examples/export-svg.py @@ -2,20 +2,21 @@ from binaryninja import * import os,sys escape_table = { - "&": "&", "'": "'", ">": ">", "<": "<", '"': """, - ' ': " ", + ' ': " " } def escape(string): - return ''.join(escape_table.get(i,i) for i in string) + string=string.decode('utf-8').encode('ascii','xmlcharrefreplace') #handle extended unicode + return ''.join(escape_table.get(i,i) for i in string) #still escape the basics def save_svg(bv,function): filename = bv.file.filename.split(os.sep)[-1] - outputfile = os.path.join(os.path.expanduser('~'), 'binaryninja-{filename}-{function}.html'.format(filename=filename,function=function.symbol.name)) + address = hex(function.start).replace('L','') + outputfile = os.path.join(os.path.expanduser('~'), 'binaryninja-{filename}-{function}.html'.format(filename=filename,function=address)) content = render_svg(function) output = open(outputfile,'w') output.write(content) @@ -37,74 +38,82 @@ def render_svg(function): ratio = 0.54 widthconst = int(heightconst*ratio) - output = ''' + output = ''' + + + + +''' + output += ''' - - + - + - + + + + @@ -131,7 +140,7 @@ def render_svg(function): output += ' \n'.format(x=x,y=y + (i + 1) * heightconst) for i,line in enumerate(block.lines): - output += ' '.format(x=x,y=y + (i + 0.7) * heightconst,address=hex(line.address)[:-1]) + output += ' '.format(x=x,y=y + (i + 0.7) * heightconst,address=hex(line.address)[:-1]) hover = instruction_data_flow(function, line.address) output += '{hover}'.format(hover=hover) for token in line.tokens: -- cgit v1.3.1 From 5236ac0f8855e37f905e953254266c95b11d5617 Mon Sep 17 00:00:00 2001 From: plafosse Date: Thu, 2 Jun 2016 17:18:22 -0400 Subject: SVG export fixes for border --- python/examples/export-svg.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'python') diff --git a/python/examples/export-svg.py b/python/examples/export-svg.py index c169337c..1e5e3ca0 100755 --- a/python/examples/export-svg.py +++ b/python/examples/export-svg.py @@ -34,9 +34,9 @@ def instruction_data_flow(function,address): def render_svg(function): graph = function.create_graph() graph.layout_and_wait() - heightconst = 15 - ratio = 0.54 - widthconst = int(heightconst*ratio) + heightconst = 17 + ratio = 0.44 + widthconst = heightconst*ratio output = ''' @@ -117,7 +117,7 @@ def render_svg(function): - '''.format(width=graph.width*widthconst, height=graph.height*heightconst) + '''.format(width=int(graph.width * widthconst + 0.5), height=graph.height * heightconst) output += ''' Function Graph 0 ''' @@ -125,10 +125,10 @@ def render_svg(function): for i,block in enumerate(graph.blocks): #Calculate basic block location and coordinates - x = int((block.x) * widthconst) + x = int(block.x * widthconst + 0.5) y = int((block.y) * heightconst) - width = int((block.width) * widthconst) - height = int((block.height) * heightconst) + width = int(block.width * widthconst + 0.5) + height = block.height * heightconst #Render block output += ' \n'.format(i=i) @@ -138,9 +138,9 @@ def render_svg(function): #Render instructions, unfortunately tspans don't allow copying/pasting more #than one line at a time, need SVG 1.2 textarea tags for that it looks like - output += ' \n'.format(x=x,y=y + (i + 1) * heightconst) + output += ' \n'.format(x=x+3,y=y+5 + (i + 1) * (heightconst - 2)) for i,line in enumerate(block.lines): - output += ' '.format(x=x,y=y + (i + 0.7) * heightconst,address=hex(line.address)[:-1]) + output += ' '.format(x=x+3,y=y + 5 + (i + 0.7) * (heightconst - 2),address=hex(line.address)[:-1]) hover = instruction_data_flow(function, line.address) output += '{hover}'.format(hover=hover) for token in line.tokens: -- cgit v1.3.1 From 01d331415a6db0728c0045d2f77649f73e20d097 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Thu, 2 Jun 2016 19:31:43 -0400 Subject: fix padding bugs, no padding anywhere now but at least its consistent --- python/examples/export-svg.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'python') diff --git a/python/examples/export-svg.py b/python/examples/export-svg.py index 1e5e3ca0..3800edf7 100755 --- a/python/examples/export-svg.py +++ b/python/examples/export-svg.py @@ -34,8 +34,8 @@ def instruction_data_flow(function,address): def render_svg(function): graph = function.create_graph() graph.layout_and_wait() - heightconst = 17 - ratio = 0.44 + heightconst = 15 + ratio = 0.48 widthconst = heightconst*ratio output = ''' @@ -117,7 +117,7 @@ def render_svg(function): - '''.format(width=int(graph.width * widthconst + 0.5), height=graph.height * heightconst) + '''.format(width=graph.width*widthconst, height=graph.height*heightconst) output += ''' Function Graph 0 ''' @@ -125,10 +125,10 @@ def render_svg(function): for i,block in enumerate(graph.blocks): #Calculate basic block location and coordinates - x = int(block.x * widthconst + 0.5) - y = int((block.y) * heightconst) - width = int(block.width * widthconst + 0.5) - height = block.height * heightconst + x = ((block.x) * widthconst) + y = ((block.y) * heightconst) + width = ((block.width) * widthconst) + height = ((block.height) * heightconst) #Render block output += ' \n'.format(i=i) @@ -138,9 +138,9 @@ def render_svg(function): #Render instructions, unfortunately tspans don't allow copying/pasting more #than one line at a time, need SVG 1.2 textarea tags for that it looks like - output += ' \n'.format(x=x+3,y=y+5 + (i + 1) * (heightconst - 2)) + output += ' \n'.format(x=x,y=y + (i + 1) * heightconst) for i,line in enumerate(block.lines): - output += ' '.format(x=x+3,y=y + 5 + (i + 0.7) * (heightconst - 2),address=hex(line.address)[:-1]) + output += ' '.format(x=x,y=y + (i + 0.7) * heightconst,address=hex(line.address)[:-1]) hover = instruction_data_flow(function, line.address) output += '{hover}'.format(hover=hover) for token in line.tokens: -- cgit v1.3.1 From 51b6c971f9c014e2fcd734a5230e09ddc5d70753 Mon Sep 17 00:00:00 2001 From: Ryan Stortz Date: Thu, 2 Jun 2016 21:13:09 -0400 Subject: get_stack_contents_at* referenced an undefined variable --- python/__init__.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'python') diff --git a/python/__init__.py b/python/__init__.py index 75d114cd..8024cae8 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -2306,32 +2306,24 @@ class Function(object): return result def get_stack_contents_at(self, arch, addr, offset, size): - if isinstance(reg, str): - reg = arch.regs[reg].index value = core.BNGetStackContentsAtInstruction(self.handle, arch.handle, addr, offset, size) result = RegisterValue(arch, value) core.BNFreeRegisterValue(value) return result def get_stack_contents_after(self, arch, addr, offset, size): - if isinstance(reg, str): - reg = arch.regs[reg].index - value = core.BNGetStackContentsAfterInstruction(self.handle, arch.handle, addr, reg) + value = core.BNGetStackContentsAfterInstruction(self.handle, arch.handle, addr, offset, size) result = RegisterValue(arch, value) core.BNFreeRegisterValue(value) return result def get_stack_contents_at_low_level_il_instruction(self, i, offset, size): - if isinstance(reg, str): - reg = self.arch.regs[reg].index value = core.BNGetStackContentsAtLowLevelILInstruction(self.handle, i, offset, size) result = RegisterValue(self.arch, value) core.BNFreeRegisterValue(value) return result def get_stack_contents_after_low_level_il_instruction(self, i, offset, size): - if isinstance(reg, str): - reg = self.arch.regs[reg].index value = core.BNGetStackContentsAfterInstruction(self.handle, i, offset, size) result = RegisterValue(self.arch, value) core.BNFreeRegisterValue(value) -- cgit v1.3.1 From 3d7bb5ada00ac4650a916cdb59d3418e5db7f3eb Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Wed, 29 Jun 2016 16:41:36 -0400 Subject: Add analysis completion event and wait API --- binaryninjaapi.h | 16 ++++++++++++++++ binaryninjacore.h | 7 +++++++ binaryview.cpp | 30 ++++++++++++++++++++++++++++++ python/__init__.py | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+) (limited to 'python') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index 72240975..f7d260a1 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -571,6 +571,20 @@ namespace BinaryNinja uint64_t addr; }; + class AnalysisCompletionEvent: public CoreRefCountObject + { + protected: + std::function m_callback; + std::recursive_mutex m_mutex; + + static void CompletionCallback(void* ctxt); + + public: + AnalysisCompletionEvent(BinaryView* view, const std::function& callback); + void Cancel(); + }; + class BinaryView: public CoreRefCountObject { protected: @@ -740,6 +754,8 @@ namespace BinaryNinja std::vector GetStrings(); std::vector GetStrings(uint64_t start, uint64_t len); + + Ref AddAnalysisCompletionEvent(const std::function& callback); }; class BinaryData: public BinaryView diff --git a/binaryninjacore.h b/binaryninjacore.h index cbbfcfa8..20f1b204 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -95,6 +95,7 @@ extern "C" struct BNEnumeration; struct BNCallingConvention; struct BNPlatform; + struct BNAnalysisCompletionEvent; enum BNLogLevel { @@ -1203,6 +1204,12 @@ extern "C" uint64_t addr, size_t* count); BINARYNINJACOREAPI void BNFreeInstructionTextLines(BNInstructionTextLine* lines, size_t count); + BINARYNINJACOREAPI BNAnalysisCompletionEvent* BNAddAnalysisCompletionEvent(BNBinaryView* view, void* ctxt, + void (*callback)(void* ctxt)); + BINARYNINJACOREAPI BNAnalysisCompletionEvent* BNNewAnalysisCompletionEventReference(BNAnalysisCompletionEvent* event); + BINARYNINJACOREAPI void BNFreeAnalysisCompletionEvent(BNAnalysisCompletionEvent* event); + BINARYNINJACOREAPI void BNCancelAnalysisCompletionEvent(BNAnalysisCompletionEvent* event); + // Function graph BINARYNINJACOREAPI BNFunctionGraph* BNCreateFunctionGraph(BNFunction* func); BINARYNINJACOREAPI BNFunctionGraph* BNNewFunctionGraphReference(BNFunctionGraph* graph); diff --git a/binaryview.cpp b/binaryview.cpp index 21a502ba..9a9461a4 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -180,6 +180,30 @@ Ref Symbol::ImportedFunctionFromImportAddressSymbol(Symbol* sym, uint64_ } +AnalysisCompletionEvent::AnalysisCompletionEvent(BinaryView* view, const std::function& callback): + m_callback(callback) +{ + m_object = BNAddAnalysisCompletionEvent(view->GetObject(), this, CompletionCallback); +} + + +void AnalysisCompletionEvent::CompletionCallback(void* ctxt) +{ + AnalysisCompletionEvent* event = (AnalysisCompletionEvent*)ctxt; + + unique_lock lock(event->m_mutex); + event->m_callback(); + event->m_callback = []() {}; +} + + +void AnalysisCompletionEvent::Cancel() +{ + unique_lock lock(m_mutex); + m_callback = []() {}; +} + + BinaryView::BinaryView(const std::string& typeName, FileMetadata* file) { BNCustomBinaryView view; @@ -1064,6 +1088,12 @@ vector BinaryView::GetStrings(uint64_t start, uint64_t len) } +Ref BinaryView::AddAnalysisCompletionEvent(const function& callback) +{ + return new AnalysisCompletionEvent(this, callback); +} + + BinaryData::BinaryData(FileMetadata* file): BinaryView(BNCreateBinaryDataView(file->GetObject())) { } diff --git a/python/__init__.py b/python/__init__.py index 8024cae8..3d2123b3 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -627,6 +627,29 @@ class BinaryViewType(object): except AttributeError: raise AttributeError, "attribute '%s' is read only" % name +class AnalysisCompletionEvent(object): + def __init__(self, view, callback): + self.view = view + self.callback = callback + self._cb = ctypes.CFUNCTYPE(None, ctypes.c_void_p)(self._notify) + self.handle = core.BNAddAnalysisCompletionEvent(self.view.handle, None, self._cb) + + def __del__(self): + core.BNFreeAnalysisCompletionEvent(self.handle) + + def _notify(self, ctxt): + try: + self.callback() + except: + log_error(traceback.format_exc()) + + def _empty_callback(self): + pass + + def cancel(self): + self.callback = self._empty_callback + core.BNCancelAnalysisCompletionEvent(self.handle) + class BinaryView(object): name = None """Binary View name""" @@ -1252,6 +1275,29 @@ class BinaryView(object): def update_analysis(self): core.BNUpdateAnalysis(self.handle) + def update_analysis_and_wait(self): + class WaitEvent: + def __init__(self): + self.cond = threading.Condition() + self.done = False + + def complete(self): + self.cond.acquire() + self.done = True + self.cond.notify() + self.cond.release() + + def wait(self): + self.cond.acquire() + while not self.done: + self.cond.wait() + self.cond.release() + + wait = WaitEvent() + event = AnalysisCompletionEvent(self, lambda: wait.complete()) + core.BNUpdateAnalysis(self.handle) + wait.wait() + def abort_analysis(self): core.BNAbortAnalysis(self.handle) @@ -1428,6 +1474,9 @@ class BinaryView(object): core.BNFreeStringList(strings) return result + def add_analysis_completion_event(self, callback): + return AnalysisCompletionEvent(self, callback) + def __setattr__(self, name, value): try: object.__setattr__(self,name,value) -- cgit v1.3.1 From 32153536526753edc3e80ea43512ad7ab65a3271 Mon Sep 17 00:00:00 2001 From: Jordan Wiens Date: Thu, 30 Jun 2016 13:51:07 -0400 Subject: remove sleep from sample plugins --- python/examples/arm-syscall.py | 5 +---- python/examples/bin-info.py | 5 +---- python/examples/instruction-iterator.py | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) (limited to 'python') diff --git a/python/examples/arm-syscall.py b/python/examples/arm-syscall.py index cbd8f4bf..f94b8531 100644 --- a/python/examples/arm-syscall.py +++ b/python/examples/arm-syscall.py @@ -10,10 +10,7 @@ else: raise ValueError("Missing argument to binary.") bv = binaryninja.BinaryViewType["Mach-O"].open(target) -bv.update_analysis() - -"""Until update_analysis_and_wait is complete, sleep is necessary as the analysis is multi-threaded.""" -time.sleep(5) +bv.update_analysis_and_wait() for func in bv.functions: for il in func.low_level_il: diff --git a/python/examples/bin-info.py b/python/examples/bin-info.py index 6ec00bce..48073894 100644 --- a/python/examples/bin-info.py +++ b/python/examples/bin-info.py @@ -13,10 +13,7 @@ else: target = "/bin/ls" bv = binaryninja.BinaryViewType[bintype].open(target) -bv.update_analysis() - -"""Until update_analysis_and_wait is complete, sleep is necessary as the analysis is multi-threaded.""" -time.sleep(1) +bv.update_analysis_and_wait() print "-------- %s --------" % target print "START: 0x%x" % bv.start diff --git a/python/examples/instruction-iterator.py b/python/examples/instruction-iterator.py index 7b03b095..43bc000e 100644 --- a/python/examples/instruction-iterator.py +++ b/python/examples/instruction-iterator.py @@ -21,10 +21,7 @@ else: target = "/bin/ls" bv = binaryninja.BinaryViewType[bintype].open(target) -bv.update_analysis() - -"""Until update_analysis_and_wait is complete, sleep is necessary as the analysis is multi-threaded.""" -time.sleep(1) +bv.update_analysis_and_wait() print "-------- %s --------" % target print "START: 0x%x" % bv.start -- cgit v1.3.1 From a7eaa72caa4a5e3e7cd7ea7c32236c93b06d1442 Mon Sep 17 00:00:00 2001 From: Rusty Wagner Date: Thu, 30 Jun 2016 17:15:19 -0400 Subject: Add API for analysis progress --- binaryninjaapi.h | 2 ++ binaryninjacore.h | 15 +++++++++++++++ binaryview.cpp | 6 ++++++ python/__init__.py | 22 ++++++++++++++++++++++ 4 files changed, 45 insertions(+) (limited to 'python') diff --git a/binaryninjaapi.h b/binaryninjaapi.h index f0ad784f..3f0b1f4b 100644 --- a/binaryninjaapi.h +++ b/binaryninjaapi.h @@ -809,6 +809,8 @@ namespace BinaryNinja std::vector GetStrings(uint64_t start, uint64_t len); Ref AddAnalysisCompletionEvent(const std::function& callback); + + BNAnalysisProgress GetAnalysisProgress(); }; class BinaryData: public BinaryView diff --git a/binaryninjacore.h b/binaryninjacore.h index 6a1e6a63..048255b1 100644 --- a/binaryninjacore.h +++ b/binaryninjacore.h @@ -735,6 +735,19 @@ extern "C" uint64_t address; }; + enum BNAnalysisState + { + IdleState, + DisassembleState, + AnalyzeState + }; + + struct BNAnalysisProgress + { + BNAnalysisState state; + size_t count, total; + }; + BINARYNINJACOREAPI char* BNAllocString(const char* contents); BINARYNINJACOREAPI void BNFreeString(char* str); @@ -1211,6 +1224,8 @@ extern "C" BINARYNINJACOREAPI void BNFreeAnalysisCompletionEvent(BNAnalysisCompletionEvent* event); BINARYNINJACOREAPI void BNCancelAnalysisCompletionEvent(BNAnalysisCompletionEvent* event); + BINARYNINJACOREAPI BNAnalysisProgress BNGetAnalysisProgress(BNBinaryView* view); + // Function graph BINARYNINJACOREAPI BNFunctionGraph* BNCreateFunctionGraph(BNFunction* func); BINARYNINJACOREAPI BNFunctionGraph* BNNewFunctionGraphReference(BNFunctionGraph* graph); diff --git a/binaryview.cpp b/binaryview.cpp index 9a9461a4..a3abc02a 100644 --- a/binaryview.cpp +++ b/binaryview.cpp @@ -1094,6 +1094,12 @@ Ref BinaryView::AddAnalysisCompletionEvent(const functi } +BNAnalysisProgress BinaryView::GetAnalysisProgress() +{ + return BNGetAnalysisProgress(m_object); +} + + BinaryData::BinaryData(FileMetadata* file): BinaryView(BNCreateBinaryDataView(file->GetObject())) { } diff --git a/python/__init__.py b/python/__init__.py index 3d2123b3..e07bd7c5 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -650,6 +650,22 @@ class AnalysisCompletionEvent(object): self.callback = self._empty_callback core.BNCancelAnalysisCompletionEvent(self.handle) +class AnalysisProgress(object): + def __init__(self, state, count, total): + self.state = state + self.count = count + self.total = total + + def __str__(self): + if self.state == core.DisassembleState: + return "Disassembling (%d/%d)" % (self.count, self.total) + if self.state == core.AnalyzeState: + return "Analyzing (%d/%d)" % (self.count, self.total) + return "Idle" + + def __repr__(self): + return "" % str(self) + class BinaryView(object): name = None """Binary View name""" @@ -928,6 +944,12 @@ class BinaryView(object): def saved(self, value): self.file.saved = value + @property + def analysis_progress(self): + """Status of current analysis (read-only)""" + result = core.BNGetAnalysisProgress(self.handle) + return AnalysisProgress(result.state, result.count, result.total) + def __len__(self): return int(core.BNGetViewLength(self.handle)) -- cgit v1.3.1