Skip to content

Commit

Permalink
Init for SUB SP
Browse files Browse the repository at this point in the history
  • Loading branch information
DoroninaD committed Nov 6, 2017
1 parent 309456b commit 25f27a2
Show file tree
Hide file tree
Showing 5 changed files with 211 additions and 6 deletions.
8 changes: 6 additions & 2 deletions IdaHelper.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,8 @@ def checkTheSameRegsForPushAndPops(group):
pushpops = dict((g.addr,re.search(pushPatter.pattern+'|'+popPattern.pattern,g.line))
for g in group)
pushpops = dict((addr, line.group()) for addr, line in pushpops.items() if line)

if len(pushpops)==0:
return False
# parse regs
regsSampler = None
for addr, line in pushpops.items():
Expand Down Expand Up @@ -163,8 +164,11 @@ def getVars(lines):
vars = [l for l in lines if pattern.search(l)]
for var in vars:
items = ' '.join(var.split(' ')[1:])
name = re.search('[a-z]+_?[0-9a-fr]*\s', items,re.IGNORECASE)\
try:
name = re.search('[a-z]+_?[0-9a-fr]*\s*', items,re.IGNORECASE)\
.group().strip()
except:
aaa=1
addr = getAddress(var)
value = re.search('=\s*-?(0x)?[a-f0-9]+\s',items,re.IGNORECASE)\
.group().replace('=',' ').strip()
Expand Down
7 changes: 7 additions & 0 deletions arm_translate.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ def code(old_code, mask, s, is_thumb):
return c
return c[4:] + c[:4]

def changeSubSp(old_code, offset, thumb):
#new = code(old_code, '11110000', new_offset, thumb)
c = hex(int(old_code, 16)+offset)[2:].upper()
if thumb:
return c
return c[4:] + c[:4]

def makeLdrOrStrInner(old_instr, old_code, rx, ry, a, is_thumb, l): # ldr rx, [ry + a]
old_instr = old_instr.lower()
s = a
Expand Down
26 changes: 23 additions & 3 deletions main_switcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
conditions_pattern = '|'.join(conditions)

NEW = True
RETURN_TYPES = True
RETURN_TYPES = False

# def findSpSubbed(groups):
# containSpSubbedPattern = re.compile('\ssub\s+sp,',re.IGNORECASE)
Expand Down Expand Up @@ -54,7 +54,16 @@ def run(path, start_group, end_group, DEBUG, config):

# check only one push
# the same regs for push and pops

a = list(filter(None,[switcher.checkOnlyOnePush(g) for g in groups]))
print("Only one push:", len(a))

a = list(filter(None,[switcher.checkTheSameRegsForPushAndPops(g) for g in groups]))
print("The same regs for push and pop:", len(a))


groups = list(filter(None,[switcher.checkSuitable(g) for g in groups]))
print("Suitable groups (push and pop with the same registers, only one push):", len(groups))


groups = switcher.handleExternalJumps(groups, conditions, funcAddrDict)
Expand Down Expand Up @@ -92,7 +101,7 @@ def run(path, start_group, end_group, DEBUG, config):
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')
#print(','.join(restrictedRegs),'Next')

new_registers, table = utils.addRegistersToStartAndEnd\
(push.regs, push.bytes, return_size, restrictedRegs)
Expand Down Expand Up @@ -126,7 +135,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 All @@ -145,6 +154,17 @@ def run(path, start_group, end_group, DEBUG, config):
.format(len(onlyForContainsSub), len(onlyWithPushes), len(handledGroups) - len(onlyWithPushes))
colored.printColored(output, colored.BOLD)

l = []
handled = 0
for item in onlyForContainsSub:
res = parse.getAllSpLinesForSub(item)
if res!=-1 and len(res) > 0:
handled+=1
l.extend(res)
print ('Handled with SUB SP (only sub sp lines):', handled)
to_write.extend(l)



#переписываем файл
f = open(path+'_old.so', 'br')
Expand Down
167 changes: 166 additions & 1 deletion parse.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import re, arm_translate, utils, switcher
import re, arm_translate, utils, switcher, random
conditions = ['eq','ne','cs','hs','cc','lo','mi','pl','vs','vc','hi','ls','ge','lt','gt','le','al']


Expand Down Expand Up @@ -294,3 +294,168 @@ def changeOffset(offset, cur, table): # offset - общее смещение
if offset > max_key: # и новых смещений
return cur + table[max_key]
return table[offset//4*4]

def getAllSpLinesForSub(lines):
to_write = []

# ldr/str/... rx, [sp], ry - не знаем значение ry, не можем сделать правильное смещение => не обрабатываем такие функции
register_relative = switcher.getRelativeRegs(lines)
if len(register_relative) > 0:
return -1

addSubPattern = re.compile('.*(add|sub)(.w)?\s*sp(,\s?sp)?,\s?#[0-9]+', re.IGNORECASE)
sub_add_sp_lines = switcher.searchInLines(addSubPattern, lines)

subSpLine = sub_add_sp_lines[0]
if len(sub_add_sp_lines) != 0:
sub_ind = lines.index(subSpLine)
a = switcher.getNumber(subSpLine)
if a is None:
return -1
else:
a = 0
sub_ind = 0

spOffset = random.randint(1, 100)
# меняем сдвиг sub sp, #4 -> sub sp, #4+spOffset
newSupSP = arm_translate.changeSubSp(subSpLine.bytes, spOffset, subSpLine.thumb)
to_write.append((subSpLine.addr,
len(subSpLine.bytes) // 2, utils.toLittleEndian(newSupSP)))
# ищем строки вида [sp, #b] - но только после вычитания (sub_ind)
# от всех отнимаем spOffset
# use_sp_lines = list(filter(None,[re.search('.*(ldr|str)(b|h|sb|sh|d)?(.w)?.*\[sp, #[0-9]+\].*', line) for line in lines]))
useSpPattern = re.compile('.*(ldr|str)(b|h|sb|sh|d)?(.w)?.*\[sp,\s?#-?(0x)?[0-9a-f]+.*\].*', re.IGNORECASE)
use_sp_lines = switcher.searchInLines(useSpPattern, lines[sub_ind:])

for l in use_sp_lines:
LdrStrPattern = re.compile('v?(ldr|str)(b|h|sb|sh|d)?(.w)?', re.IGNORECASE)
instr = switcher.searchPattern(LdrStrPattern, l).group().lower()
b = switcher.getNumber(l)
if b is None:
return -1

pattern = re.compile \
('(\s+r10|r11|r12|sp|lr|pc|r[0-9]|((d|s)(([1-2][0-9])|3[0-1]|[0-9]))),', re.IGNORECASE)
rx = switcher.searchPattern(pattern, l).group().strip().replace(',', '')
# code, is_thumb = utils.getCodeFromLine(l.group())
offset = b+spOffset
new_instr_code = arm_translate. \
makeLdrOrStr(instr, l.bytes, rx.lower(), 'sp', offset, l.thumb, l.line)
# to_write ... [sp, #b + new_regs_count*4]
to_write.append((l.addr,
len(l.bytes) // 2, utils.toLittleEndian(new_instr_code)))

# ищем строки вида add rx, sp, (#c) - должна быть одна ? todo
# add_sp_to_reg = list(filter(None, [re.search('.*(add(.w)?|mov)\s*(r[0-9]|r10|r11|r12), sp(, #[1-9]+)?.*', line) for line in lines]))
addSpToRegPattern = re.compile \
('.*(add(.w)?|mov)\s*(r[0-9]|r10|r11|r12),\s?sp(,\s?#[1-9]+)?.*', re.IGNORECASE)
add_sp_to_reg = switcher.searchInLines(addSpToRegPattern, lines)
# todo
if any(['!' in l.line for l in add_sp_to_reg]):
return -1

if len(add_sp_to_reg) > 0:
for l in add_sp_to_reg:
new = getRxLinesForSubSp(lines, l, a, sub_ind, spOffset)
if new == -1:
return -1
to_write.extend(new)

return to_write


def getRxLinesForSubSp(lines, line, sp_subbed, sub_ind, spOffset):
llll = []

def getJumpIndex(line):
try:
jmpAddr = tmp[commonJMPPattern.search(line).end():].strip().split(';')[0]
except:
aaa = 1
jmpAddr = re.sub('[a-z]+_', '0x', jmpAddr).lower()
try:
int(jmpAddr, 16)
except:
return None
try_ind = [l for l in lines if l.addr == jmpAddr]
if len(try_ind) == 0:
return None
return lines.index(try_ind[0])

def handleLine(index, line):
llll.append((index, line))

c = switcher.getNumber(line)
if c is None:
return -1
regsPattern = re.compile('r11|r10|r12|r[0-9]', re.IGNORECASE)
reg = switcher.searchPattern(regsPattern, line).group()
useRegPattern = re.compile \
('.*(ldr|str)(b|h|sb|sh|sw|d)?(.w)?.*\[{0}(,\s?#\-?(0x)?[0-9a-f]+.*\])?'.format(reg),
re.IGNORECASE)
clearRegPattern = re.compile \
('.*(mov(eq|ne)?|(v)?ldr(b|h|sb|sh|sw)?|add)(.w)?\s{0},\s?.*'.format(reg),
re.IGNORECASE)
simpleJMPPattern = re.compile('\sbl?s?(\.w)?\s', re.IGNORECASE)
regJumpPattern = re.compile('\sbl?x\s', re.IGNORECASE)
conditionJumpPattern = re.compile('\s((cbz)|(b(l)?({0})))\s'.format('|'.join(conditions)), re.IGNORECASE)
commonJMPPattern = re.compile('\s((cbn?z)|(bl?s?({0})?))(\.w)?\s'.format('|'.join(conditions)), re.IGNORECASE)
# определяем строку, с которой будем искать строки вида [reg, #d]
start_ind = list(lines).index(line)

ways, old_ways = [start_ind], [start_ind]
while (len(ways) > 0):
i = ways[0]
end_reg = switcher.searchInLines(clearRegPattern, lines[i + 1:])
# определяем строку, ДО которой будем искать строки вида [reg, #d] (mov затирает sp)
end_ind = list(lines).index(end_reg[0].group()) if len(end_reg) > 0 else len(lines)
for l in lines[i:end_ind]:
tmp = l.line
if useRegPattern.search(tmp):
handleLine(i, l)
if simpleJMPPattern.search(tmp):
index = getJumpIndex(tmp)
if index is not None and index not in old_ways:
old_ways.append(index)
ways.append(index)
break
if conditionJumpPattern.search(tmp):
try:
index = getJumpIndex(tmp)
except:
index = getJumpIndex(tmp)
if index is None:
break
if index not in old_ways:
old_ways.append(index)
ways.append(index)
ways.remove(i)

# предполагаем, что изменение sp происходит только в начале и конце функции todo
# если sp еще не отнят, тогда не нужно учитывать a

to_write = []

# todo если будет str rx, [sp, #] и уже добавлен в to_write по sp, будет перезаписано?
for item in llll:
start_ind, l = item[0], item[1]
if start_ind < sub_ind:
sp_subbed = 0
pattern = re.compile('v?(ldr|str)(b|h|sb|sh|d)?(.w)?', re.IGNORECASE)
instr = switcher.searchPattern(pattern, l).group()
d = switcher.getNumber(l)
if d is None:
return -1
pattern = re.compile('(\s+r10|r11|r12|sp|lr|pc|r[0-9]|((d|s)(([1-2][0-9])|3[0-1]|[0-9]))),', re.IGNORECASE)
rx = switcher.searchPattern(pattern, l).group().strip().replace(',', '')
offset = d+spOffset
new_instr_code = arm_translate.makeLdrOrStr(instr, l.bytes, rx, reg, offset, l.thumb, l.line)
to_write.append((l.addr, len(l.bytes) // 2, utils.toLittleEndian(new_instr_code)))

# str rx, [...]
strRegPattern = re.compile('.*str(b|h|sb|sh|sw|d)?(.w)?\s{0}.*'.format(reg), re.IGNORECASE)
str_reg = switcher.searchInLines(strRegPattern, lines[start_ind:end_ind])
if len(str_reg) > 0:
return -1
return to_write

9 changes: 9 additions & 0 deletions switcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@ def getPops(group):
return IdaHelper.getPops(group)


def checkOnlyOnePush(group):
if isIDA:
return IdaHelper.checkOnlyOnePush(group)

def checkTheSameRegsForPushAndPops(groups):
if isIDA:
return IdaHelper.checkTheSameRegsForPushAndPops(groups)


def checkSuitable(group):
if isIDA:
if not IdaHelper.checkOnlyOnePush(group):
Expand Down

0 comments on commit 25f27a2

Please sign in to comment.