diff --git a/IdaHelper.py b/IdaHelper.py index 772bad8..9ba408b 100644 --- a/IdaHelper.py +++ b/IdaHelper.py @@ -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]): @@ -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 @@ -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 @@ -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:])) + + + + + + + diff --git a/main_switcher.py b/main_switcher.py index a11db3b..a938330 100755 --- a/main_switcher.py +++ b/main_switcher.py @@ -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") @@ -39,8 +37,8 @@ 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 = [] @@ -48,73 +46,29 @@ def run(path, start_group, end_group, DEBUG, config): 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)) @@ -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 @@ -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}'\ diff --git a/run.py b/run.py index 6cca2ea..b098a9b 100755 --- a/run.py +++ b/run.py @@ -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' @@ -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) \ No newline at end of file + main_switcher.run(join(path, file)[:-7], int(start_group), int(end_group), DEBUG, config) \ No newline at end of file diff --git a/switcher.py b/switcher.py index e7951ca..5bb2c25 100644 --- a/switcher.py +++ b/switcher.py @@ -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 + + diff --git a/utils.py b/utils.py index 49e5d61..873b658 100755 --- a/utils.py +++ b/utils.py @@ -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