diff --git a/README.md b/README.md
index cab3e67..5a3c671 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,7 @@ Installation on Windows typically requires installing PyQt5.
---
#### Packaging a Function
+##### Binary Ninja
From within Binary Ninja, right click anywhere inside of a function and select `[ripr] Package Function`.
@@ -43,6 +44,10 @@ After packaging, a table will appear listing all of the "packages" you have crea
+##### Radare2
+If you've followed step 3 in the installation instructions, run `.(ripr 0x1234)` (with 0x1234 replaced by the address of the function).
+Otherwise, you can manually invoke ripr with `#!pipe python /absolute/path/to/ripr/r2pipe_run.py 0x1234`.
+
#### Packaging Specific Basic Blocks
You can also choose to only package specific basic blocks rather than the entire function.
diff --git a/__init__.py b/__init__.py
index 4291997..2beb12e 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,6 +1,10 @@
import sys
+
if (sys.platform == 'win32'):
- sys.path.append("C:\\Python27\\lib\\site-packages\\PyQt5")
+ if sys.version_info[0] >= 3:
+ sys.path.append("C:\\Python37\\lib\\site-packages\\PyQt5")
+ else:
+ sys.path.append("C:\\Python27\\lib\\site-packages\\PyQt5")
try:
from binaryninja import *
@@ -9,10 +13,10 @@
raise ImportError
# ripr imports
- from analysis_engine import *
- from codegen import *
- from packager import *
- import gui
+ from .analysis_engine import *
+ from .codegen import *
+ from .packager import *
+ from .gui import *
ui = gui.riprWidget()
@@ -22,19 +26,19 @@ def packageFunction(view, fobj):
pkg.package_function()
def packageRegion(view, start, length):
- print "[ripr] Packaging 0x%x - 0x%x" % (start, start+length)
+ print ("[ripr] Packaging 0x%x - 0x%x" % (start, start+length))
engine = get_engine(view)
pkg = Packager(isFunc=False, address=start, engine=engine, length=length, ui=ui)
pkg.package_region()
def packageBasicBlock(view, addr):
- print "[ripr] Adding Basic Block containing %x " % addr
+ print ("[ripr] Adding Basic Block containing %x " % addr)
engine = get_engine(view)
pkg = Packager(isFunc=False, address=addr, engine=engine, ui=ui)
pkg.package_bb()
def generate_basicBlocks(view, fobj):
- print "[ripr] Generating code from currently selected basic blocks"
+ print ("[ripr] Generating code from currently selected basic blocks")
engine = get_engine(view)
pkg = Packager(isFunc=False, address=fobj.start, engine=engine, ui=ui)
pkg.generate_bb_code()
diff --git a/analysis_engine.py b/analysis_engine.py
index 59e30d5..878aeec 100644
--- a/analysis_engine.py
+++ b/analysis_engine.py
@@ -7,17 +7,17 @@
try:
from binaryninja import *
except:
- print "[!!] Not running in Binary Ninja"
+ print ("[!!] Not running in Binary Ninja")
try:
import r2pipe
except:
- print "[!!] Not running in Radare2"
+ print ("[!!] Not running in Radare2")
import json
import re
import sys
-import codegen
+from .codegen import *
from binascii import unhexlify
def get_engine(*args):
@@ -31,7 +31,7 @@ def get_engine(*args):
return bn_engine(args[0])
- raise ValueError, "No analysis engine found!"
+ raise (ValueError, "No analysis engine found!")
@@ -54,6 +54,7 @@ def get_arch(self):
'x86'
'x64'
'arm'
+ 'arm64'
'mips'
'''
pass
@@ -160,18 +161,20 @@ def get_arch(self):
These can be different from Binary Ninja names, so they are explicitly mapped
into the ripr names, even if they are the same in some cases.
'''
- print self.bv.arch.name
+ print (self.bv.arch.name)
if (self.bv.arch.name == 'x86'):
return 'x86'
elif (self.bv.arch.name == 'x86_64'):
return 'x64'
elif (self.bv.arch.name == 'armv7'):
return 'arm'
+ elif (self.bv.arch.name == 'aarch64'):
+ return 'arm64'
def mark_gathered_basic_block(self, address):
fobj = self.bv.get_functions_containing(address)[0]
if (fobj == None):
- print "FOBJ IS NONE"
+ print ("FOBJ IS NONE")
bb = fobj.get_basic_block_at(address)
bb.highlight = HighlightStandardColor.BlackHighlightColor
@@ -187,25 +190,30 @@ def clean_gathered_basic_block(self, address):
def get_basic_block_bytes(self, address):
bb = self.bv.get_basic_blocks_at(address)
if len(bb) != 1:
- print "[ripr] Address belongs to more than one basic block!"
+ print ("[ripr] Address belongs to more than one basic block!")
bb = bb[0]
- return {bb.start: codegen.codeSlice(self.read_bytes(bb.start, bb.end-bb.start), bb.start)}
+ return {bb.start: codeSlice(self.read_bytes(bb.start, bb.end-bb.start), bb.start)}
def get_function_bytes(self, address=None, name=None):
'''
Binary Ninja does not seem to assume Functions are contiguous; rather they
are treated as a collection of basic blocks.
'''
- print "[ripr] Inside get_function_bytes()"
+ print ("[ripr] Inside get_function_bytes()")
if (address != None):
fobj = self.bv.get_function_at(address)
elif (name != None):
- print "[ripr] TODO"
+ print ("[ripr] TODO")
return
else:
- print "[ripr] No arguments supplied to get_function_bytes"
+ print ("[ripr] No arguments supplied to get_function_bytes")
return None
+
+ if self.bv.get_function_at(address)==None:
+ print ("[ripr] Couldn't get function binary view. Maybe code arch is thumb2?")
+ return None
+
# Sort the basic blocks in ascending order
bblist = sorted(fobj.basic_blocks, key=lambda x: x.start)
map(lambda bb: bb.set_user_highlight(HighlightStandardColor.BlackHighlightColor), bblist)
@@ -218,10 +226,10 @@ def get_function_bytes(self, address=None, name=None):
clist.append([bb])
# Print out the list if the function is not contiguous
if (len(clist) > 1):
- print clist
+ print (clist)
# Create a return list in the expected format from the contiguous units.
- retdir = {unit[0].start : codegen.codeSlice(self.read_bytes(unit[0].start, unit[-1].start - unit[0].start + unit[-1].length), unit[0].start) for unit in clist}
+ retdir = {unit[0].start : codeSlice(self.read_bytes(unit[0].start, unit[-1].start - unit[0].start + unit[-1].length), unit[0].start) for unit in clist}
return retdir
def get_page_bytes(self, address):
@@ -264,7 +272,7 @@ def get_instruction_length(self, address):
def find_llil_block_from_addr(self, address):
fobj = self.bv.get_functions_containing(address)
if len(fobj) > 1:
- print "[ripr] Multiple Functions contain this address!!"
+ print ("[ripr] Multiple Functions contain this address!!")
return None
fobj = fobj[0]
bbindex = fobj.get_basic_block_at(address).index
@@ -273,7 +281,7 @@ def find_llil_block_from_addr(self, address):
def find_mlil_block_from_addr(self, address):
fobj = self.bv.get_functions_containing(address)
if len(fobj) > 1:
- print "[ripr] Multiple Functions contain this address!!"
+ print ("[ripr] Multiple Functions contain this address!!")
return None
fobj = fobj[0]
bbindex = fobj.get_basic_block_at(address).index
@@ -297,6 +305,9 @@ def branches_from_block(self, block, callCallback, branchCallback):
def branches_from_func(self, address, callCallback, branchCallback):
fobj = self.bv.get_function_at(address)
+ if (fobj==None):
+ return
+
for block in fobj.low_level_il:
self.branches_from_block(block, callCallback, branchCallback)
@@ -316,6 +327,8 @@ def get_refs_to(self, address):
def function_contains_addr(self, func_addr, testAddr):
fobj = self.bv.get_function_at(func_addr)
+ if (fobj==None):
+ return False
return (fobj.get_basic_block_at(testAddr) != None)
def scan_potential_pointers_bb(self, il_block, fobj):
@@ -381,7 +394,7 @@ def highlight_instr(self, func_addr, instrAddr, color):
elif color == "orange":
bn_color = HighlightStandardColor.OrangeHighlightColor
else:
- raise ValueError, "Unsupported color"
+ raise (ValueError, "Unsupported color")
fobj.set_user_instr_highlight(instrAddr, bn_color)
def add_comment(self, func_addr, instrAddr, comment):
@@ -442,29 +455,35 @@ def get_arch(self):
elif arch == "x86" and bits == 64:
return 'x64'
else:
- raise NotImplementedError, "Only tested witn x86 & x86_64"
+ raise (NotImplementedError, "Only tested with x86 & x86_64")
+ '''
+ elif arch == "arm" and bits == 32:
+ return 'arm'
+ elif arch == "arm" and bits == 64:
+ return 'arm64'
+ '''
def get_function_bytes(self, address=None, name=None):
if (address != None):
funcInfo = self.r2.cmd("afij {}".format(hex(address)))
elif (name != None):
- print "[ripr] TODO"
+ print ("[ripr] TODO")
return
else:
- print "[ripr] No arguments supplied to get_function_bytes"
+ print ("[ripr] No arguments supplied to get_function_bytes")
return None
if funcInfo.strip() == "":
- raise ValueError, "Function not found at {}".format(address)
+ raise (ValueError, "Function not found at {}".format(address))
funcInfo = json.loads(funcInfo, strict=False)
if len(funcInfo) == 0:
- raise ValueError, "Function not found at {}".format(address)
- print funcInfo
+ raise (ValueError, "Function not found at {}".format(address))
+ print (funcInfo)
offset = funcInfo[0]["offset"]
size = funcInfo[0]["size"]
bytes = self.read_bytes(offset, size)
- retdir = {offset: codegen.codeSlice(bytes, offset)}
+ retdir = {offset: codeSlice(bytes, offset)}
return retdir
def get_page_bytes(self, address):
@@ -560,7 +579,7 @@ def highlight_instr(self, func_addr, instrAddr, color):
def add_comment(self, func_addr, instrAddr, comment):
if not re.compile("^[a-z0-9 !\\-\\_]+$", re.IGNORECASE).match(comment):
# Don't send arbitrary contents to radare pipe
- print "Ignoring malformed comment: {}".format(comment)
+ print ("Ignoring malformed comment: {}".format(comment))
else:
self.r2.cmd("CC [ripr] {} @{}".format(comment, hex(instrAddr)))
diff --git a/cli_ui.py b/cli_ui.py
index 39900ac..6255ab6 100644
--- a/cli_ui.py
+++ b/cli_ui.py
@@ -23,7 +23,7 @@ def text_input_box(self, promptText):
def impCallsOptions(self):
options = ["nop", "hook", "cancel"]
- print "Code contains calls to imported functions. How should this be handled?",
+ print ("Code contains calls to imported functions. How should this be handled?")
while True:
selection = raw_input("({})?".format(", ".join(options))).strip()
if selection in options:
diff --git a/codegen.py b/codegen.py
index 07f12ae..04d4e4f 100644
--- a/codegen.py
+++ b/codegen.py
@@ -3,11 +3,16 @@
'''
import sys
import os
+import binascii
+
+python2=False
+if sys.version_info[0] < 3:
+ python2=True
try:
from binaryninja import *
except:
- print "[+] Not running in BinaryNinja"
+ print ("[+] Not running in BinaryNinja")
class callConv(object):
def __init__(self, name, arch):
@@ -17,15 +22,26 @@ def __init__(self, name, arch):
def gen_arg_number(self, argno):
pass
+ def genPointer(self, arg, regs, indent):
+ pass
+
+ def dumpContext(self, indent):
+ pass
+
class x64callConv(callConv):
# TODO Stack based arguments
def __init__(self, name, arch):
self.name = name
self.arch = arch
self.platform = ''
-
+ self.regs = ["UC_X86_REG_RAX", "UC_X86_REG_RBP", "UC_X86_REG_RBX", "UC_X86_REG_RCX",\
+ "UC_X86_REG_RDI", "UC_X86_REG_RDX", "UC_X86_REG_RSI", "UC_X86_REG_RSP",\
+ "UC_X86_REG_RIP", "UC_X86_REG_R8", "UC_X86_REG_R9", "UC_X86_REG_R10",\
+ "UC_X86_REG_R11", "UC_X86_REG_R12", "UC_X86_REG_R13", "UC_X86_REG_R14",\
+ "UC_X86_REG_R15"]
+
def gen_arg_number(self, argno, indent=1):
- print "X64"
+ print ("X64")
if self.platform == "win":
return self.msft(argno, indent)
return self.systemV(argno, indent)
@@ -52,10 +68,19 @@ def systemV(self, arg, indent):
return ' ' * (indent*4) + "self.mu.reg_write(%s, arg_%x)\n" % (regs[arg.num], arg.num)
return self.genPointer(arg, regs, indent)
+ def dumpContext(self, indent):
+ ret = ' ' * (indent * 4) + ("print ('[!] Exception occured - Emulator state (x64):')\n")
+ for r in self.regs:
+ ret += ' ' * (indent * 4) + ("print (\"%s : %%016X\" %% (self.mu.reg_read(%s)))\n" % (r,r))
+ return ret
+
class x86callConv(callConv):
def __init__(self, name, arch):
self.name = name
self.arch = arch
+ self.regs = ["UC_X86_REG_EAX", "UC_X86_REG_EBP", "UC_X86_REG_EBX", "UC_X86_REG_ECX",\
+ "UC_X86_REG_EDI", "UC_X86_REG_EDX", "UC_X86_REG_ESI", "UC_X86_REG_ESP",\
+ "UC_X86_REG_EIP"]
def genPointer(self, arg, indent):
ret = ' ' * (indent * 4) + "argAddr_%x = (%d * 0x1000)\n" % (arg.num, arg.num + 1)
@@ -70,10 +95,20 @@ def gen_arg_number(self, arg, indent):
return ' ' * (indent * 4) + "self.mu.mem_write(self.mu.reg_read(UC_X86_REG_ESP) + %d, struct.pack(' 1:
return ' ' * (indent *4 ) + "self.mu.reg_write(%s, arg_%x)\n" % (regs[arg.num], arg.num)
return self.genPointer(arg, regs, indent)
-
+
+ def dumpContext(self, indent):
+ ret = ' ' * (indent * 4) + ("print ('[!] Exception occured - Emulator state (arm):')\n")
+ for r in self.regs:
+ ret += ' ' * (indent * 4) + ("print (\"%s : %%X\" %% (self.mu.reg_read(%s)))\n" % (r,r))
+ return ret
+
+class arm64callConv(callConv):
+ def __init__(self, name, arch):
+ self.name = name
+ self.arch = arch
+ self.regs = ["UC_ARM64_REG_X0", "UC_ARM64_REG_X1", "UC_ARM64_REG_X2", "UC_ARM64_REG_X3",\
+ "UC_ARM64_REG_X4", "UC_ARM64_REG_X5", "UC_ARM64_REG_X6", "UC_ARM64_REG_X7",\
+ "UC_ARM64_REG_X8", "UC_ARM64_REG_X9", "UC_ARM64_REG_X10", "UC_ARM64_REG_X11",\
+ "UC_ARM64_REG_X12", "UC_ARM64_REG_X13", "UC_ARM64_REG_X14", "UC_ARM64_REG_X15",\
+ "UC_ARM64_REG_X16", "UC_ARM64_REG_X17", "UC_ARM64_REG_X18", "UC_ARM64_REG_X19",\
+ "UC_ARM64_REG_X20", "UC_ARM64_REG_X21", "UC_ARM64_REG_X22", "UC_ARM64_REG_X23",\
+ "UC_ARM64_REG_X24", "UC_ARM64_REG_X25", "UC_ARM64_REG_X26", "UC_ARM64_REG_X27",\
+ "UC_ARM64_REG_X28", "UC_ARM64_REG_X29", "UC_ARM64_REG_X30"]
+
+ def genPointer(self, arg, regs, indent):
+ ret = ' ' * (indent * 4) + "argAddr_%x = (%d * 0x1000)\n" % (arg.num, arg.num+1)
+ ret += ' ' * (indent * 4) + "self.mu.mem_write(argAddr_%x, arg_%x)\n" % (arg.num, arg.num)
+ ret += ' ' * (indent * 4) + "self.mu.reg_write(%s, argAddr_%x)\n" % (regs[arg.num], arg.num)
+ return ret
+
+ def gen_arg_number(self, arg, indent):
+ regs = ["UC_ARM64_REG_X0", "UC_ARM64_REG_X1", "UC_ARM64_REG_X2", "UC_ARM64_REG_X3"]
+ if arg.num < len(regs):
+ if arg.pointerDepth == 0 or arg.pointerDepth > 1:
+ return ' ' * (indent *4 ) + "self.mu.reg_write(%s, arg_%x)\n" % (regs[arg.num], arg.num)
+ return self.genPointer(arg, regs, indent)
+
+ def dumpContext(self, indent):
+ ret = ' ' * (indent * 4) + ("print ('[!] Exception occured - Emulator state (arm64):')\n")
+ for r in self.regs:
+ ret += ' ' * (indent * 4) + ("print (\"%s : %%X\" %% (self.mu.reg_read(%s)))\n" % (r,r))
+ return ret
class codeSlice(object):
'''
@@ -150,6 +222,17 @@ def __init__(self, name, isFunc=True):
self.isFunc = isFunc
+ def setArch(self,a):
+ self.arch=a
+ if self.arch == 'x64':
+ self.callConv = x64callConv("linux", "x64")
+ elif self.arch == 'x86':
+ self.callConv = x86callConv("linux", "x86")
+ elif self.arch == 'arm':
+ self.callConv =armcallConv("linux", "arm")
+ elif self.arch == 'arm64':
+ self.callConv =armcallConv("linux", "arm64")
+
def data_saved(self, addr):
return any(lowaddr <= addr <= highaddr for (lowaddr, highaddr) in self.saved_ranges)
@@ -159,14 +242,14 @@ def add_mmap(self, addr, len=0x4000):
def add_data(self, data, addr):
if (self.data_saved(addr)):
- print "[Warning] Trying to map data twice!"
+ print ("[Warning] Trying to map data twice!")
return
self.data.append((addr, data))
self.saved_ranges.append((addr, addr + len(data)))
def add_code(self, cSlice):
if (self.data_saved(cSlice.address)):
- print "[Warning] Trying to map data twice"
+ print ("[Warning] Trying to map data twice")
self.code.append(cSlice)
self.saved_ranges.append((cSlice.address, cSlice.address + len(cSlice.code_bytes)))
@@ -199,16 +282,26 @@ def generate_mmap(self, indent = 1):
return out
def generate_data_vars(self, indent = 1):
+ global python2
out = ''
for i in range(0, len(self.data)):
- out += ' ' * (indent * 4) + "self.data_%s = '%s'.decode('hex') \n" % (str(i), self.data[i][1].encode('hex'))
+ if python2==True:
+ cc=binascii.hexlify(self.data[i][1])
+ else:
+ cc=binascii.hexlify(self.data[i][1]).decode('utf-8')
+ out += ' ' * (indent * 4) + "self.data_%s = binascii.unhexlify('%s') \n" % (str(i), cc)
return out
def generate_code_vars(self, indent = 1):
+ global python2
out = ''
i = 0
for cSlice in self.code:
- out += ' ' * (indent * 4) + "self.code_%s = '%s'.decode('hex') \n" % (str(i), cSlice.code_bytes.encode('hex'))
+ if python2==True:
+ cc=binascii.hexlify(cSlice.code_bytes)
+ else:
+ cc=binascii.hexlify(cSlice.code_bytes).decode('utf-8')
+ out += ' ' * (indent * 4) + "self.code_%s = binascii.unhexlify('%s') \n" % (str(i), cc)
i += 1
return out
@@ -225,9 +318,14 @@ def generate_stack_initialization(self, indent = 1):
elif self.arch == 'arm':
self.add_mmap(0x7ffff000, 1024*1024 * 2)
out = ' ' * (indent * 4) + "self.mu.reg_write(UC_ARM_REG_SP, 0x7fffff00)\n"
+
+ elif self.arch == 'arm64':
+ self.add_mmap(0x7ffff000, 1024*1024 * 2)
+ out = ' ' * (indent * 4) + "self.mu.reg_write(UC_ARM64_REG_SP, 0x7fffff00)\n"
+
## TODO Add support for other architectures supported by Unicorn and Binja
else:
- print "[ripr] Error, Unsupported Architecture"
+ print ("[ripr] Error, Unsupported Architecture")
return out
@@ -274,7 +372,7 @@ def generate_start_unicorn_func(self, indent = 1):
'''
decl = ' ' * (indent * 4) + 'def _start_unicorn(self, startaddr):\n'
body = self.generate_emustart(indent=2)
- return decl+body
+ return decl+body+"\n"
def generate_return_guard_marker(self, indent=1):
'''
@@ -287,8 +385,10 @@ def generate_return_guard_marker(self, indent=1):
out += ' ' * (indent *4) + "self.mu.mem_write(0x7fffff00, '\\x01\\x00\\x00\\x00')\n"
elif self.arch == 'arm':
out += ' ' * (indent *4) + "self.mu.reg_write(UC_ARM_REG_LR, 0x4)\n"
+ elif self.arch == 'arm64':
+ out += ' ' * (indent *4) + "self.mu.reg_write(UC_ARM64_REG_LR, 0x4)\n"
else:
- print "Unsupported Arch"
+ print ("Unsupported Arch")
return out
def generate_restore_exec(self, indent=1):
@@ -306,8 +406,11 @@ def generate_restore_exec(self, indent=1):
elif self.arch == 'arm':
out += ' ' * (indent * 4) + "self._start_unicorn(retAddr)\n"
pass
+ elif self.arch == 'arm64':
+ out += ' ' * (indent * 4) + "self._start_unicorn(retAddr)\n"
+ pass
else:
- print "Unsupported Arch"
+ print ("Unsupported Arch")
return out
@@ -318,9 +421,11 @@ def generate_hook_lookup(self, indent=1):
retAddr = ' ' * (indent * 4) + "retAddr = struct.unpack(\" 1:
@@ -58,7 +66,7 @@ def argIdent(self, addr, isFunc):
def uninit_vars(self, bbs):
for bb in bbs:
- mlb = self.engine.find_mlil_block_from_addr(bb.keys()[0])
+ mlb = self.engine.find_mlil_block_from_addr(list(bb.keys())[0])
if mlb == None:
continue
set_vars = []
@@ -72,6 +80,6 @@ def uninit_vars(self, bbs):
unset_vars = set(unset_vars)
for uVar in unset_vars:
- self.engine.highlight_instr(bb.keys()[0], uVar.mil.address, "orange")
+ self.engine.highlight_instr(list(bb.keys())[0], uVar.mil.address, "orange")
return unset_vars
diff --git a/defunct/.widgets.py.swp b/defunct/.widgets.py.swp
deleted file mode 100644
index b03c295..0000000
Binary files a/defunct/.widgets.py.swp and /dev/null differ
diff --git a/dependency.py b/dependency.py
index 25ea443..7f26b46 100644
--- a/dependency.py
+++ b/dependency.py
@@ -4,8 +4,17 @@
properly.
'''
-import analysis_engine as ae
-from binaryninja import *
+from .analysis_engine import aengine as ae
+# Try to import stuff.
+try:
+ from binaryninja import *
+except:
+ print ("[!!] Not running in Binary Ninja")
+try:
+ import r2pipe
+except:
+ print ("[!!] Not running in Radare2")
+
class ImportedCall(object):
'''
@@ -71,7 +80,7 @@ def branchScan(self, address, isFunc=True):
Function is responsible for mapping calls and jumps
that are outside the current selection's bounds, if possible.
'''
- print "[ripr] Inside branchScan"
+ print ("[ripr] Inside branchScan")
def callCallback(dest, instr_addr):
if type(dest) != int:
try:
@@ -79,17 +88,17 @@ def callCallback(dest, instr_addr):
except:
return
if (dest in self.imports):
- print "[ripr] Found imported Call target..."
+ print ("[ripr] Found imported Call target...")
self._mark_imported_call(address, instr_addr, dest)
elif (self.codeobj.data_saved(dest) == False):
- print "[ripr] Found LLIL CALL instruction"
+ print ("[ripr] Found LLIL CALL instruction")
self._mark_additional_branch(address, instr_addr, dest, "call")
else:
- print "[ripr] Target address already mapped"
+ print ("[ripr] Target address already mapped")
def jumpCallback(dest, instr_addr):
- print "[ripr] JUMP TARGET: %s" % (dest)
+ print ("[ripr] JUMP TARGET: %s" % (dest))
if isFunc:
self.engine.branches_from_func(address, callCallback, jumpCallback)
@@ -109,7 +118,7 @@ def _find_stringRefs(self, address):
for stringStart,stringLength in self.engine.get_strings():
for refAddress in self.engine.get_refs_to(stringStart): # Ignored the length
if (self.engine.function_contains_addr(address, refAddress)):
- print "[ripr] Found string reference: 0x%x" % (refAddress)
+ print ("[ripr] Found string reference: 0x%x" % (refAddress))
self._mark_identified_data(address, refAddress)
dref = riprDataRef(stringStart, stringLength, 'str')
self.dataRefs.append(dref)
@@ -124,7 +133,7 @@ def _find_symbolRefs(self, address):
for symStart in symbols:
for refAddress in self.engine.get_refs_to(symStart):
if self.engine.function_contains_addr(address, refAddress):
- print "[ripr] Found Symbol Reference: 0x%x references 0x%x" % (refAddress, symStart)
+ print ("[ripr] Found Symbol Reference: 0x%x references 0x%x" % (refAddress, symStart))
self._mark_identified_data(address, refAddress)
dref = riprDataRef(symStart, -1, 'sym')
self.dataRefs.append(dref)
@@ -142,7 +151,7 @@ def dataScan(self, address):
Function is responsible for finding data the target code
needs in order to run correctly.
'''
- print "[ripr] Inside dataScan"
+ print ("[ripr] Inside dataScan")
ret = []
# Find the low-hanging fruit
@@ -151,7 +160,7 @@ def dataScan(self, address):
# Iterate over all instructions for potential pointers
for target, instrAddr in self.engine.scan_potential_pointers(address):
if self.engine.is_plausible_pointer(target):
- print "Found Potential Pointer: %s instaddr %s" % (hex(target), hex(instrAddr))
+ print ("Found Potential Pointer: %s instaddr %s" % (hex(target), hex(instrAddr)))
self._mark_identified_data(address, instrAddr)
dref = riprDataRef(target, -1, 'ptr')
self.dataRefs.append(dref)
diff --git a/gui.py b/gui.py
index bf88ce2..d623dc4 100644
--- a/gui.py
+++ b/gui.py
@@ -3,12 +3,15 @@
'''
import sys
if (sys.platform == 'win32'):
- sys.path.append("C:\\Python27\\lib\\site-packages")
+ if sys.version_info[0] >= 3:
+ sys.path.append("C:\\Python37\\lib\\site-packages\\PyQt5")
+ else:
+ sys.path.append("C:\\Python27\\lib\\site-packages\\PyQt5")
try:
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtCore import Qt
- from defunct.widgets import BinjaWidget
- import defunct.widgets
+ from .defunct.widgets import BinjaWidget
+ from .defunct.widgets import *
qtAvailable = True
except:
qtAvailable = False
@@ -42,7 +45,7 @@ def _get_selected_codeobj(self):
# Find the Class name from the index
name = self.item(item.row(), item.column()).text()
# Open the Editor
- print "Selected Codeobj: %s" % name
+ print ("Selected Codeobj: %s" % name)
return self.emuchunks[name]
def contextMenuEvent(self, event):
@@ -183,7 +186,10 @@ def yes_no_box(self, msg):
if choice == enums.MessageBoxButtonResult.YesButton:
return True
return False
-
+
+ def msgBox(self, msg):
+ interaction.show_message_box("Binary Ninja - ripr", msg, enums.MessageBoxButtonSet.OKButtonSet)
+
def text_input_box(self,msg):
text = interaction.get_text_line_input(msg, "Binary Ninja - ripr")
return text
diff --git a/packager.py b/packager.py
index 5a6e5fa..f9a059d 100644
--- a/packager.py
+++ b/packager.py
@@ -1,11 +1,11 @@
-from codegen import *
-import analysis_engine as ae
-import dependency as dep
-import conScan as con
+from .codegen import *
+from .analysis_engine import aengine as ae
+from .dependency import depScanner
+from .conScan import convenienceScanner
### Global for listing all chunks of code for which we have tried to create a python wrapper.
emuchunks = {}
-
+
# List of basic block chunks to package for BB mode
bbChunks = []
class Packager(object):
@@ -26,7 +26,7 @@ def __init__(self, isFunc, address, engine, ui = None, length=None):
self.codeobj = genwrapper('', isFunc)
self.arch = self.engine.get_arch()
- self.codeobj.arch = self.arch
+ self.codeobj.setArch(self.arch)
self.impCallStrategy = None
self.dataStrategy = None
@@ -40,7 +40,7 @@ def convenience_passes(self):
This function is a wrapper for determining which convenience features can
be enabled during code generation.
'''
- c = con.convenienceScanner(self.engine)
+ c = convenienceScanner(self.engine)
if (self.isFunc == True and self.codeobj.arch in ['x64', 'x86', 'arm']):
self.codeobj.conPass['ret'] = True
@@ -63,14 +63,17 @@ def minimal_package_function(self, address=None):
address = self.address
# Get the code to be emulated
localCode = self.engine.get_function_bytes(address=address)
-
+ if (localCode == None):
+ self.ui.msgBox("[ripr] Couldn't get function binary view. Maybe code arch is thumb2?")
+ return False
# Add each contiguous chunk of code to codeobj and make sure
# it will be mapped.
- for startAddr in localCode.keys():
+ for startAddr in list(localCode.keys()):
self.codeobj.add_mmap(startAddr)
self.targetCode.append(localCode)
-
+ return True
+
def minimal_package_region(self):
targetCode = self.engine.get_region_bytes(address=self.address)
self.codeobj.add_data(targetCode[0], targetCode[1])
@@ -94,7 +97,8 @@ def package_function(self):
if not self.codeobj.name:
return
# Get the bare minimum required information.
- self.minimal_package_function()
+ if (self.minimal_package_function()==False):
+ return
# Try to find dependencies of our code.
self.resolve_dependencies()
@@ -132,7 +136,7 @@ def generate_bb_code(self):
if not self.codeobj.name:
return
# Set starting address to first basic block selected
- self.codeobj.startaddr = bbChunks[0].keys()[0]
+ self.codeobj.startaddr = list(bbChunks[0].keys())[0]
self.targetCode = bbChunks
@@ -154,7 +158,7 @@ def generate_bb_code(self):
def cleanup_basic_blocks(self):
global bbChunks
for bb in bbChunks:
- self.engine.clean_gathered_basic_block(bb.keys()[0])
+ self.engine.clean_gathered_basic_block(list(bb.keys())[0])
def package_region(self):
@@ -176,14 +180,14 @@ def _find_code_unit(self, faddr):
def _nop_impFunc(self, impCalls):
for impCall in impCalls:
- print "[ripr] Nopping out Imported Call: 0x%x" % (impCall.address)
+ print ("[ripr] Nopping out Imported Call: 0x%x" % (impCall.address))
cSlice = self._find_code_unit(impCall.address)
codeLen = len(cSlice.code_bytes)
nop = self.engine.get_nop_opcode()
if (impCall.inst_len % len(nop) != 0):
- print "[ripr] Cannot NOP out instruction..."
+ print ("[ripr] Cannot NOP out instruction...")
return
# Create string of NOP opcodes and calculate where to place it
@@ -200,15 +204,15 @@ def update_codeobj(self):
# in the case of others being automatically mapped as dependencies
localCode = self.targetCode[0]
- print self.targetCode
- self.codeobj.codelen = sum([len(localCode[x].code_bytes) for x in localCode.keys()])
+ print (self.targetCode)
+ self.codeobj.codelen = sum([len(localCode[x].code_bytes) for x in list(localCode.keys())])
for found_code in self.targetCode:
for addr in found_code:
self.codeobj.add_code(found_code[addr])
def resolve_imported_calls(self, resolv):
- print "[ripr] Selection includes calls to imported Functions!"
+ print ("[ripr] Selection includes calls to imported Functions!")
if self.impCallStrategy == None:
self.impCallStrategy = self.ui.impCallsOptions()
@@ -236,12 +240,15 @@ def map_dependent_sections(self, dataRefs):
'''
Map any sections the target code touches.
'''
- print "Mapping Sections"
+ print ("Mapping Sections")
pagesize = self.engine.get_page_size()
secs = []
- for ref in dataRefs:
- sections = [self.engine.find_section(ref.address)]
- secs += sections
+
+ for ref in dataRefs:
+ section=self.engine.find_section(ref.address)
+ if section!=-1:
+ secs += [section]
+
for sec_start, sec_end, sec_name in secs:
self.codeobj.add_data(self.engine.read_bytes(sec_start, sec_end - sec_start), sec_start)
self.codeobj.add_mmap(sec_start)
@@ -269,23 +276,24 @@ def resolve_data_dependencies(self, dataRefs):
def resolve_codeRefs(self, coderefs):
for ref in coderefs:
- print "Found CodeRef: %x::%s" % (ref.address, ref.type)
+ print ("Found CodeRef: %x::%s" % (ref.address, ref.type))
if (ref.type == 'call'):
- self.minimal_package_function(address=ref.address)
+ if (self.minimal_package_function(address=ref.address)==False):
+ continue
self.resolve_dependencies(address=ref.address, isFunc=True)
def resolve_dependencies(self, address=None, isFunc=None):
'''
This method is a high-level wrapper for finding data our target code depends on.
'''
- resolv = dep.depScanner(self.engine, self.codeobj)
+ resolv = depScanner(self.engine, self.codeobj)
if (address == None):
address = self.address
if (isFunc == None):
isFunc = self.isFunc
- print "Resolving Dependencies for %x" % address
+ print ("Resolving Dependencies for %x" % address)
if isFunc:
coderefs = resolv.branchScan(address, self.isFunc)
datarefs = resolv.dataScan(address)
@@ -293,22 +301,22 @@ def resolve_dependencies(self, address=None, isFunc=None):
datarefs = resolv.dataScan(address)
coderefs = []
for bb in bbChunks:
- coderefs += resolv.branchScan(bb.keys()[0], self.isFunc)
+ coderefs += resolv.branchScan(list(bb.keys())[0], self.isFunc)
if (resolv.impCalls != []):
self.resolve_imported_calls(resolv)
if (coderefs != []):
if (self.ui.yes_no_box("Target code may depend on outside code, attempt to map automatically?") == True):
- print "[ripr] Performing analysis on code dependencies..."
+ print ("[ripr] Performing analysis on code dependencies...")
self.resolve_codeRefs(coderefs)
else:
pass
if (resolv.dataRefs != []):
# Try to map these automatically
- print "[ripr] Found these potential Data References"
+ print ("[ripr] Found these potential Data References")
for ref in resolv.dataRefs:
- print "Data Referenced: 0x%x" % (ref.address)
+ print ("Data Referenced: 0x%x" % (ref.address))
self.resolve_data_dependencies(resolv.dataRefs)
pass
diff --git a/r2pipe_run.py b/r2pipe_run.py
index 762e3e0..376e64a 100644
--- a/r2pipe_run.py
+++ b/r2pipe_run.py
@@ -1,13 +1,13 @@
import sys
# ripr imports
-from analysis_engine import *
-from codegen import *
-from packager import *
-import cli_ui
+from .analysis_engine import *
+from .codegen import *
+from .packager import *
+from .cli_ui import *
def packageFunction(addr):
- print "[ripr] Packaging function {}".format(hex(addr))
+ print ("[ripr] Packaging function {}".format(hex(addr)))
engine = get_engine(addr)
ui = cli_ui.cli_ui()
pkg = Packager(isFunc=True, address=addr, engine=engine, ui=ui)
diff --git a/sample/impCall/ripr_arm_impCall.py b/sample/impCall/ripr_arm_impCall.py
index 34e6021..e250473 100644
--- a/sample/impCall/ripr_arm_impCall.py
+++ b/sample/impCall/ripr_arm_impCall.py
@@ -17,15 +17,15 @@ def __init__(self):
self.hookdict = {66688L: 'hook_puts', 66696L: 'hook_puts', 66704L: 'hook_malloc'}
def hook_puts(self):
- print "===========In Puts=========="
+ print ("===========In Puts==========")
arg = self.mu.reg_read(UC_ARM_REG_R0)
mem = self.mu.mem_read(arg, 0x200)
- print "Puts would have Printed: %s" % (mem.split("\x00")[0])
- print "===========Leaving Puts=========="
+ print ("Puts would have Printed: %s" % (mem.split("\x00")[0]))
+ print ("===========Leaving Puts==========")
def hook_malloc(self):
- print "===========In Malloc=========="
- print "===========Leaving Malloc==========="
+ print ("===========In Malloc==========")
+ print ("===========Leaving Malloc===========")
def _start_unicorn(self, startaddr):
try:
@@ -46,4 +46,4 @@ def run(self):
return self.mu.reg_read(UC_ARM_REG_R0)
x = arm_test()
-print x.run()
+print (x.run())
diff --git a/sample/impCall/ripr_x64_impCall.py b/sample/impCall/ripr_x64_impCall.py
index ead6eba..685208b 100644
--- a/sample/impCall/ripr_x64_impCall.py
+++ b/sample/impCall/ripr_x64_impCall.py
@@ -18,15 +18,15 @@ def __init__(self):
self.hookdict = {4195721L: 'hook_puts', 4195731L: 'hook_malloc', 4195711L: 'hook_puts'}
# Do whatever we want in hooked functions
def hook_puts(self):
- print "===========In Puts=========="
+ print ("===========In Puts==========")
arg = self.mu.reg_read(UC_X86_REG_RDI)
mem = self.mu.mem_read(arg, 0x200)
- print "Puts would have Printed: %s" % (mem.split("\x00")[0])
- print "===========Leaving Puts=========="
+ print ("Puts would have Printed: %s" % (mem.split("\x00")[0]))
+ print ("===========Leaving Puts==========")
def hook_malloc(self):
- print "===========In Malloc=========="
- print "===========Leaving Malloc==========="
+ print ("===========In Malloc==========")
+ print ("===========Leaving Malloc===========")
def _start_unicorn(self, startaddr):
@@ -49,4 +49,4 @@ def run(self):
return self.mu.reg_read(UC_X86_REG_RAX)
x = x64_test()
-print x.run()
+print (x.run())
diff --git a/sample/impCall/ripr_x86_impCall.py b/sample/impCall/ripr_x86_impCall.py
index 18d3218..07138be 100644
--- a/sample/impCall/ripr_x86_impCall.py
+++ b/sample/impCall/ripr_x86_impCall.py
@@ -17,17 +17,17 @@ def __init__(self):
self.hookdict = {134513753L: 'hook_puts', 134513782L: 'hook_malloc', 134513769L: 'hook_puts'}
def hook_puts(self):
- print "===========In Puts=========="
+ print ("===========In Puts==========")
arg = self.mu.reg_read(UC_X86_REG_ESP)
arg2 = self.mu.mem_read(arg+4, 0x4)
arg2 = struct.unpack(" " % (sys.argv[0])
+ print ("Usage: %s " % (sys.argv[0]))
exit()
key=sys.argv[1]
@@ -137,4 +137,4 @@ def run(self, arg_0, arg_1):
ksa=KSA()
S=str(ksa.run(key,S))
prga=PRGA()
-print str(prga.run(S,plain)).encode('hex')
+print (str(prga.run(S,plain)).encode('hex'))
diff --git a/sample/rc4/tester.py b/sample/rc4/tester.py
index 155195e..4258014 100755
--- a/sample/rc4/tester.py
+++ b/sample/rc4/tester.py
@@ -12,7 +12,7 @@
if args.seed != None:
random.seed(args.seed)
-print "Running %d testcases..." % (args.num)
+print ("Running %d testcases..." % (args.num))
for i in xrange(0,args.num):
key_len = random.randint(1,16)
@@ -22,7 +22,7 @@
ripr = subprocess.check_output(["python", "myrc4.py", key, plain]).strip().upper()
orig = subprocess.check_output(["./a.out", key, plain]).strip().upper()
if ripr != orig:
- print "FAIL:\n'%s' vs. '%s'" % (orig, ripr)
- print "Key: %s\nPlain:\n'%s'" % (key, plain)
+ print ("FAIL:\n'%s' vs. '%s'" % (orig, ripr))
+ print ("Key: %s\nPlain:\n'%s'" % (key, plain))
exit()
print "Everything is OK!"