Start off with Anton Vorobyov's (DarkFenX) Python 3 scanner.

This commit is contained in:
rocky
2015-12-13 03:41:57 -05:00
parent d71164df7f
commit 24c301c489
2 changed files with 495 additions and 628 deletions

View File

@@ -118,7 +118,7 @@ class Scanner(object):
print('%i\t%s\t' % (i, self.opc.opname[op])) print('%i\t%s\t' % (i, self.opc.opname[op]))
def first_instr(self, start, end, instr, target=None, exact=True): def first_instr(self, start, end, instr, target=None, exact=True):
''' """
Find the first <instr> in the block from start to end. Find the first <instr> in the block from start to end.
<instr> is any python bytecode instruction or a list of opcodes <instr> is any python bytecode instruction or a list of opcodes
If <instr> is an opcode with a target (like a jump), a target If <instr> is an opcode with a target (like a jump), a target
@@ -127,32 +127,34 @@ class Scanner(object):
closest to <target> will be returned. closest to <target> will be returned.
Return index to it or None if not found. Return index to it or None if not found.
''' """
code = self.code code = self.code
assert(start>=0 and end<=len(code)) assert(start >= 0 and end <= len(code))
try: None in instr try:
except: instr = [instr] None in instr
except:
instr = [instr]
pos = None result_offset = None
distance = len(code) current_distance = len(code)
for i in self.op_range(start, end): for offset in self.op_range(start, end):
op = code[i] op = code[offset]
if op in instr: if op in instr:
if target is None: if target is None:
return i return offset
dest = self.get_target(i, op) dest = self.get_target(offset)
if dest == target: if dest == target:
return i return offset
elif not exact: elif not exact:
_distance = abs(target - dest) new_distance = abs(target - dest)
if _distance < distance: if new_distance < current_distance:
distance = _distance current_distance = new_distance
pos = i result_offset = offset
return pos return result_offset
def last_instr(self, start, end, instr, target=None, exact=True): def last_instr(self, start, end, instr, target=None, exact=True):
''' """
Find the last <instr> in the block from start to end. Find the last <instr> in the block from start to end.
<instr> is any python bytecode instruction or a list of opcodes <instr> is any python bytecode instruction or a list of opcodes
If <instr> is an opcode with a target (like a jump), a target If <instr> is an opcode with a target (like a jump), a target
@@ -161,65 +163,74 @@ class Scanner(object):
closest to <target> will be returned. closest to <target> will be returned.
Return index to it or None if not found. Return index to it or None if not found.
''' """
code = self.code code = self.code
# Make sure requested positions do not go out of
# code bounds
if not (start>=0 and end<=len(code)): if not (start>=0 and end<=len(code)):
return None return None
try: None in instr try:
except: instr = [instr] None in instr
except:
instr = [instr]
pos = None result_offset = None
distance = len(code) current_distance = len(code)
for i in self.op_range(start, end): for offset in self.op_range(start, end):
op = code[i] op = code[offset]
if op in instr: if op in instr:
if target is None: if target is None:
pos = i result_offset = offset
else: else:
dest = self.get_target(i, op) dest = self.get_target(offset)
if dest == target: if dest == target:
distance = 0 current_distance = 0
pos = i result_offset = offset
elif not exact: elif not exact:
_distance = abs(target - dest) new_distance = abs(target - dest)
if _distance <= distance: if new_distance <= current_distance:
distance = _distance current_distance = new_distance
pos = i result_offset = offset
return pos return result_offset
def all_instr(self, start, end, instr, target=None, include_beyond_target=False): def all_instr(self, start, end, instr, target=None, include_beyond_target=False):
''' """
Find all <instr> in the block from start to end. Find all <instr> in the block from start to end.
<instr> is any python bytecode instruction or a list of opcodes <instr> is any python bytecode instruction or a list of opcodes
If <instr> is an opcode with a target (like a jump), a target If <instr> is an opcode with a target (like a jump), a target
destination can be specified which must match precisely. destination can be specified which must match precisely.
Return a list with indexes to them or [] if none found. Return a list with indexes to them or [] if none found.
''' """
code = self.code code = self.code
assert(start>=0 and end<=len(code)) assert(start >= 0 and end <= len(code))
try: None in instr try:
except: instr = [instr] None in instr
except:
instr = [instr]
result = [] result = []
for i in self.op_range(start, end): for offset in self.op_range(start, end):
op = code[i] op = code[offset]
if op in instr: if op in instr:
if target is None: if target is None:
result.append(i) result.append(offset)
else: else:
t = self.get_target(i, op) t = self.get_target(offset)
if include_beyond_target and t >= target: if include_beyond_target and t >= target:
result.append(i) result.append(offset)
elif t == target: elif t == target:
result.append(i) result.append(offset)
return result return result
def op_size(self, op): def op_size(self, op):
"""
Return size of operator with its arguments
for given opcode <op>.
"""
if op < self.opc.HAVE_ARGUMENT and op not in self.opc.hasArgumentExtended: if op < self.opc.HAVE_ARGUMENT and op not in self.opc.hasArgumentExtended:
return 1 return 1
else: else:
@@ -229,6 +240,10 @@ class Scanner(object):
return self.op_size(op) > 1 return self.op_size(op) > 1
def op_range(self, start, end): def op_range(self, start, end):
"""
Iterate through positions of opcodes, skipping
arguments.
"""
while start < end: while start < end:
yield start yield start
start += self.op_size(self.code[start]) start += self.op_size(self.code[start])
@@ -243,14 +258,14 @@ class Scanner(object):
return filtered return filtered
def rem_or(self, start, end, instr, target=None, include_beyond_target=False): def rem_or(self, start, end, instr, target=None, include_beyond_target=False):
''' """
Find all <instr> in the block from start to end. Find all <instr> in the block from start to end.
<instr> is any python bytecode instruction or a list of opcodes <instr> is any python bytecode instruction or a list of opcodes
If <instr> is an opcode with a target (like a jump), a target If <instr> is an opcode with a target (like a jump), a target
destination can be specified which must match precisely. destination can be specified which must match precisely.
Return a list with indexes to them or [] if none found. Return a list with indexes to them or [] if none found.
''' """
code = self.code code = self.code
assert(start>=0 and end<=len(code)) assert(start>=0 and end<=len(code))

File diff suppressed because it is too large Load Diff