Skip to content

Commit

Permalink
Add support for pop {regs, lr} (remove used regs from randomization)
Browse files Browse the repository at this point in the history
  • Loading branch information
DoroninaD committed Nov 1, 2017
1 parent e885db6 commit 7707cb8
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 92 deletions.
85 changes: 76 additions & 9 deletions IdaHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,18 +171,15 @@ def getVars(lines):
varsDict[(addr, name)] = value





def hadleExternalJumps(groups, conditions, funcAddrDict):
have_external_jumps = {}
ext_jumps_list = {}
external_jumps = []

have_not_defined_jumps = []

# убираем b, которые внутри функции
for index, group in enumerate(groups):
containsJumpsPattern = re.compile('\sb('+'|'.join(conditions)+')\s',re.IGNORECASE)
containsJumpsPattern = re.compile('\sb('+'|'.join(conditions)+')?(\.w)?\s',re.IGNORECASE)
#clear = [not group[i][2].startswith('b') for i in range(len(group)) if len(group[i]) > 2]
containsJumps = searchInLines(containsJumpsPattern, group)
#if all([not containsJumpsPattern.search(g.line) for g in group]):
Expand All @@ -204,10 +201,14 @@ def hadleExternalJumps(groups, conditions, funcAddrDict):
# last_addr = int(groups[index+1][0][0],16)
#addr = int(g.addr,16)
addr = g.line[containsJumpsPattern.search(g.line).end():].strip().split(';')[0]
if addr in funcAddrDict:
if addr in funcAddrDict: #а что если функция внешняя?
addr = funcAddrDict[addr]
addr = re.sub('[a-z]+_','0x',addr)
addr = int(addr, 16)
try:
addr = int(addr, 16)
except:
have_not_defined_jumps.append(group)
break
#addr = int(addr.replace('[a-z]+_','0x'), 16)
if addr < first_addr or addr > last_addr:
has_ext_jumps = True
Expand Down Expand Up @@ -285,8 +286,8 @@ def hadleExternalJumps(groups, conditions, funcAddrDict):
for jump in external_jumps_res:
if f==jumpFunc[jump]:
nojumps = False
if nojumps:
groups.append(index)
if nojumps and f not in have_not_defined_jumps:
groups.append(f)
return groups


Expand All @@ -307,5 +308,71 @@ def hadleExternalJumps(groups, conditions, funcAddrDict):
# return groups


def handlePopLr(group, conditions):
pattern = re.compile('(pop|ldmfd).*,\s*lr}',re.IGNORECASE)
popLr = searchInLines(pattern,group)
if len(popLr) == 0:
return []
popLrIndex = group.index(popLr[0])
conditions = '|'.join(conditions)
notUseRegs = []

# jumpsWithoutReturn = re.compile('\sb({0})?(\.w)?\s+'.format(conditions),re.IGNORECASE)
# if len(searchInLines(jumpsWithoutReturn, group)) > 0:
# return ['-1']
# действие до конца функции, т.к. может прыгнуть куда-нибудь вниз (вверх не должна)
# смотрим, есть ли вызов функций
# простые прыжки (b) уже убрали, смотрим на bl
jumpsPattern = re.compile('\sbl?({0})?(\.w)?\s+'.format(conditions),re.IGNORECASE)
jumps = searchInLines(jumpsPattern, group[popLrIndex+1:])
#если есть вызов других функций, то r0-r3 затирать нельзя,
# т.к. они могут быть переданы как входные
if len(jumps) > 0:
notUseRegs.extend(['r0','r1','r2','r3'])

# смотрим, значения каких функций могут быть переданы в r0-r3
# ищем просто все регистры, которые задают где-то значения - до вызова последней функции
#lastFuncIndex = group.index(jumpsWithReturn[-1])
restOfTheGroup = group[popLrIndex+1:]

changePattern = re.compile('\s(mov|mvn|sub|add)s?({0})?\s+r[0-9]+(,\s?r[0-9]+)+'
.format(conditions), re.IGNORECASE)
changeRegsLines = searchPatterns(changePattern, restOfTheGroup)
for l in changeRegsLines:
#print(l.group())
regs = l.group().replace(' ','').lower().split(',')[1:]
notUseRegs.extend([r.strip() for r in regs])

regPattern = re.compile('r[0-9]+',re.IGNORECASE)
ldrPattern = re.compile('\s(ldr|str|cbn?z)({0})?\s'.format(conditions), re.IGNORECASE)
ldrRegLines = searchInLines(ldrPattern, restOfTheGroup)
for l in ldrRegLines:
#print(l.line)
regs = regPattern.findall(l.line.lower().replace(' ','').strip())
if 'ldr' in l.line:
regs = regs[1:]
notUseRegs.extend([r.strip() for r in regs])

cmpPattern = re.compile('\scmp({0})?.*\s'.format(conditions),re.IGNORECASE)
cmpLines = searchInLines(cmpPattern, restOfTheGroup)
for l in cmpLines:
#print(l.line)
regs = re.findall('r[0-9]+',l.line.lower(),re.IGNORECASE)
notUseRegs.extend([r.strip() for r in regs])

bxRegPattern = re.compile('\sbx\s+r[0-9]+\s',re.IGNORECASE)
bxRegLines = searchPatterns(bxRegPattern, restOfTheGroup)
for l in bxRegLines:
#print(l.group())
notUseRegs.append(re.search('r[0-9]+',l.group(),re.IGNORECASE).group().lower().strip())
#print(','.join(notUseRegs))
return sorted(set(notUseRegs),key = lambda x: int(x[1:]))









111 changes: 34 additions & 77 deletions main_switcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,28 @@
conditions_pattern = '|'.join(conditions)

NEW = True
RETURN_TYPES = False
RETURN_TYPES = True

def findSpSubbed(groups):
containSpSubbedPattern = re.compile('\ssub\s+sp,',re.IGNORECASE)
matching_groups = []
for group in groups:
matches = switcher.searchInLines(containSpSubbedPattern,group)
if len(matches)>0:
matching_groups.append(group)
return matching_groups
# def findSpSubbed(groups):
# containSpSubbedPattern = re.compile('\ssub\s+sp,',re.IGNORECASE)
# matching_groups = []
# for group in groups:
# matches = switcher.searchInLines(containSpSubbedPattern,group)
# if len(matches)>0:
# matching_groups.append(group)
# return matching_groups


def findBxLR(groups):
containSpSubbedPattern = re.compile('bx\s+lr',re.IGNORECASE)
def findInGroups(pattern,groups):
#containSpSubbedPattern = re.compile('bx\s+lr',re.IGNORECASE)
matching_groups = []
for group in groups:
matches = switcher.searchInLines(containSpSubbedPattern,group)
matches = switcher.searchInLines(pattern,group)
if len(matches)>0:
matching_groups.append(group)
return matching_groups




def run(path, start_group, end_group, DEBUG, config):
print('DEBUG ', DEBUG)
f = codecs.open(path+'.txt', 'r','utf-8', errors="ignore")
Expand All @@ -39,82 +37,38 @@ def run(path, start_group, end_group, DEBUG, config):

groups, addrFuncDict = switcher.getFunctions(lines)
funcAddrDict = dict(zip(addrFuncDict.values(),addrFuncDict.keys()))

g = switcher.handleExternalJumps(groups, conditions, funcAddrDict)
init_group_len = len(groups)
print('GROUPS:', len(groups))

#находим тип функций
function_types = []
if RETURN_TYPES:
print('FUNCTIONS')
function_types = parse_functions_utils.getFunctionsReturnTypeSize(addrFuncDict, config)
#todo использовать числа при рандомизации
# all_registers = ['r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8', 'r9', 'r10', 'r11']


#ищем push, записываем для него все pop с теми же регистрами, пока не встретим новый push
#или название функции <..>
i = 0
# groups = []
# lst = []
# while i < len(stack_lines)-1:
# if len(stack_lines[i]) == 2:
# #lst.append(stack_lines[i])
# i+=1
# continue
# probably_push = str(stack_lines[i][2])
# if probably_push.startswith('push') or probably_push.startswith('stmdb'):
# #lst = [stack_lines[i]]
# lst.append(stack_lines[i])
# j = i + 1
# while len(stack_lines[j]) > 2 \
# and (str(stack_lines[j][2]).startswith("b") or ((str(stack_lines[j][2]).startswith('pop') or str(stack_lines[j][2]).startswith('ldmia')) \
# and stack_lines[j][3] == stack_lines[i][3])):
# lst.append(stack_lines[j])
# j += 1
# if j >= len(stack_lines):
# break
# if j - i > 1:
# groups.append(lst.copy())
# lst.clear()
# i = j
# lst.clear()
# else:
# i += 1
init_group_len = len(groups)



containSpSubbed = findSpSubbed(groups)
containSpSubbed = findInGroups(re.compile('\ssub\s+sp,',re.IGNORECASE),groups)
print('Groups with subbed sp:', len(containSpSubbed))

#difference = [g for g in groups if g not in f]
containBXLRbefore = findInGroups(re.compile('bx\s+lr',re.IGNORECASE),groups)

#groups = switcher.hadleExternalJumps(groups)

# фильтруем группы - убираем те, в которых последний pop нe pc
print ('GROUPS:', len(groups))
# check only one push
# the same regs for push and pops
groups = list(filter(None,[switcher.checkSuitable(g) for g in groups]))


groups = switcher.handleExternalJumps(groups, conditions, funcAddrDict)
print("Groups after jumps removing", len(groups))

# gr = groups
# groups = []
# for group in gr:
# #if all(g[6]=='pc' for g in group[1:]):
# #берем только те функции, в которых нет pop lr
# #if len(group) > 1 and all(g[6]=='pc' for g in group[1:]):
# if len(group) > 1:
# groups.append(group)
# #if group[-1][6] == 'pc':
# # groups.append(group)
containBXLRbefore = findBxLR(groups)
containBXLR = findInGroups(re.compile('bx\s+lr',re.IGNORECASE),groups)
print('CONTAINS BX LR:',len(containBXLR))
containPOPLR = findInGroups(re.compile('(pop|ldmfd).*,lr}',re.IGNORECASE),groups)
print('CONTAINS POP LR:',len(containPOPLR))

# check only one push
# the same regs for push and pops
groups = list(filter(None,[switcher.checkSuitable(g) for g in groups]))
restrictedRegsDict = dict((g[0].addr,switcher.handlePopLr(g, conditions,4)) for g in containPOPLR)
# for key, value in restrictedRegsDict.items():
# print('{0}:{1}'.format(key, ','.join(value)))

containBXLR = findBxLR(groups)
print('CONTAINS BX LR:',len(containBXLR))

#groups = [group for group in groups if group[i][6]=='pc' for i in range(1,len(group))]
print ('Functions with push-pop pairs', len(groups))
Expand All @@ -133,12 +87,15 @@ def run(path, start_group, end_group, DEBUG, config):
#first, last = group[0], group[-1]
push, pops = switcher.getPushes(group)[0], switcher.getPops(group)
l+=1

# добавляем регистры в начало, считает их количество
real_reg_count = len(push.regs)
return_size = function_types[push.addr] if RETURN_TYPES else 4
return_size = function_types[group[0].addr] if RETURN_TYPES else 4
restrictedRegs = restrictedRegsDict[group[0].addr]\
if group[0].addr in restrictedRegsDict else []
print(','.join(restrictedRegs),'Next')

new_registers, table = utils.addRegistersToStartAndEnd\
(push.regs, push.bytes, return_size)
(push.regs, push.bytes, return_size, restrictedRegs)
if new_registers == -1:
full_registers_count+=1
continue
Expand Down Expand Up @@ -169,7 +126,7 @@ def run(path, start_group, end_group, DEBUG, config):
funcAddr = group[0].addr
key = cxxfilt.demangle(addrFuncDict[funcAddr]) \
if addrFuncDict[funcAddr]!='' else push.addr
# print(colored.setColored('{0}: '.format(key), colored.OKGREEN) + 'old {0}, new {1}'.format(push.regs, new_registers))
print(colored.setColored('{0}: '.format(key), colored.OKGREEN) + 'old {0}, new {1}'.format(push.regs, new_registers))
regs_added += len(new_registers) - len(push.regs)
secured = groups_count/init_group_len*100
# output = 'End:{0}, full regs:{1}, secured:{2}%, average randomness:{3}'\
Expand Down
7 changes: 3 additions & 4 deletions run.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from os import listdir
from os.path import isfile, join
import main_insert_border_regs, sys, colored, config_parser
import main_insert_border_regs, sys, colored, config_parser, main_switcher

#path = 'data/com.instagram.android/lib/armeabi-v7a/'
#path = 'data/noassertTel/lib/armeabi-v7a/'
#path = 'apps/telegram/lib/armeabi-v7a/'
#harded_path = 'apps/app-debug/lib/armeabi-v7a/'
harded_path = 'apps/curl/lib/armeabi-v7a/'
harded_path = 'apps/files/lib/armeabi-v7a/'
DEBUG=1
path = sys.argv[1] if len(sys.argv) > 1 else harded_path
config_path = sys.argv[2] if len(sys.argv)>2 else 'config.ini'
Expand All @@ -33,6 +33,5 @@
# start_group = 0
# end_group = 1


colored.printColored (file[:-7], colored.HEADER)
main_insert_border_regs.run(join(path, file)[:-7], int(start_group), int(end_group), DEBUG, config)
main_switcher.run(join(path, file)[:-7], int(start_group), int(end_group), DEBUG, config)
7 changes: 7 additions & 0 deletions switcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,12 @@ def handleExternalJumps(groups, conditions, funcAddrDict):
return IdaHelper.hadleExternalJumps(groups, conditions,funcAddrDict)


def handlePopLr(group, conditions, retSize):
if isIDA:
regs= IdaHelper.handlePopLr(group, conditions)
#print(','.join(regs))
return regs




6 changes: 4 additions & 2 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,14 @@ def addRegistersToEnd(current_registers):

return current_registers + new_registers

def addRegistersToStartAndEnd(current_registers, code, returnValueSize):
def addRegistersToStartAndEnd(current_registers, code, returnValueSize, regsNotToUse):
minreg = returnValueSize
#minreg = 4
start = min(minreg, int(current_registers[0][1:])) if len(current_registers) != 0 else minreg
end = 12 if len(code) > 4 else 8
new_regs = ['r{0}'.format(i) for i in range(start, end) if 'r{0}'.format(i) not in current_registers]
new_regs = ['r{0}'.format(i) for i in range(start, end)
if 'r{0}'.format(i) not in current_registers
and 'r{0}'.format(i) not in regsNotToUse]
if len(new_regs) == 0:
return -1, -1
# todo - uncomment for randomization
Expand Down

0 comments on commit 7707cb8

Please sign in to comment.