Skip to content

Commit f1eaafb

Browse files
committed
add support for ppc64el and s390
1 parent 132f01d commit f1eaafb

File tree

3 files changed

+36
-17
lines changed

3 files changed

+36
-17
lines changed

pwnlib/asm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1037,8 +1037,8 @@ def get_cs_disassembler(eabi=None):
10371037
'ppc': (cs.CS_ARCH_PPC, B + E),
10381038
'powerpc': (cs.CS_ARCH_PPC, E + cs.CS_MODE_32),
10391039
'powerpc64': (cs.CS_ARCH_PPC, E + cs.CS_MODE_64),
1040+
'em_s390': (cs.CS_ARCH_SYSTEMZ, cs.CS_MODE_BIG_ENDIAN + cs.CS_MODE_64),
10401041
#'ia64': None,
1041-
#'sysz': cs.CS_ARCH_SYSZ,
10421042
#'m68k': cs.CS_ARCH_M68K,
10431043
#'xcore': cs.CS_ARCH_XCORE,
10441044
#'tms320c64x': cs.CS_ARCH_TMS320C64X,

pwnlib/context/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ class ContextType(object):
427427
's390': big_32,
428428
'sparc': big_32,
429429
'sparc64': big_64,
430+
'em_s390': big_64,
430431
'thumb': little_32,
431432
'vax': little_32,
432433
'none': {},

pwnlib/elf/elf.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1170,41 +1170,57 @@ def libc_start_main_return(self):
11701170
if 'exit' not in self.symbols:
11711171
return 0
11721172

1173+
func = self.functions['__libc_start_main']
1174+
exit_addr = self.symbols['exit']
11731175
eabi = None
1176+
# `__libc_start_call_main` is usually smaller than `__libc_start_main`,
1177+
# (except for powerpc which uses a bigger `generic_start_main`), so
1178+
# we might disassemble a bit too much, but it's a good dynamic estimate.
1179+
callee_size = func.size
1180+
# most arch's call instruction has the first operands as an intermidiate, except s390
1181+
imm_index = 0
1182+
11741183
# If there's no delay slot, execution continues on the next instruction after a call.
11751184
call_return_offset = 1
1185+
call_instructions = set([cs.CS_GRP_CALL])
11761186
if self.arch in ['arm', 'thumb']:
11771187
if b'armhf' in self.linker:
11781188
eabi = 'hf'
1179-
call_instructions = set([cs.CS_GRP_CALL])
1189+
if exit_addr & 1: exit_addr -= 1
11801190
elif self.arch == 'aarch64':
1181-
call_instructions = set([cs.CS_GRP_CALL])
1191+
pass
11821192
elif self.arch in ['mips', 'mips64']:
11831193
# FIXME: `bal` was not included in CS_GRP_CALL. This is fixed on capstone v6.alpha
1184-
#call_instructions = set([cs.CS_GRP_CALL])
1185-
call_instructions = set([cs.CS_GRP_CALL, cs.CS_GRP_BRANCH_RELATIVE])
1194+
call_instructions = call_instructions.add(cs.CS_GRP_BRANCH_RELATIVE)
11861195
# Account for the delay slot.
11871196
call_return_offset = 2
11881197
elif self.arch in ['i386', 'amd64', 'ia64']:
1189-
call_instructions = set([cs.CS_GRP_CALL])
1198+
pass
1199+
elif self.arch in ['ppc', 'powerpc', 'powerpc64']:
1200+
callee_size *= 2
1201+
if exit_addr & 1 == 0:
1202+
# powepc often jumps to the local entry point after TOC setup
1203+
exit_addr += 8
1204+
pass
1205+
elif self.arch in ['em_s390', 's390']:
1206+
imm_index = 1
1207+
pass
11901208
else:
11911209
log.error('Unsupported architecture %s in ELF.libc_start_main_return', self.arch)
11921210
return 0
11931211

11941212
from pwnlib.asm import get_cs_disassembler
11951213
md = get_cs_disassembler(arch=self.arch, endian=self.endian, bits=self.bits, eabi=eabi)
1196-
func = self.functions['__libc_start_main']
11971214
dis = list(self.cs_disasm(md, func.address, func.size))
11981215

1199-
exit_addr = self.symbols['exit']
1200-
if self.arch == 'arm' and exit_addr & 1: exit_addr -= 1
1201-
1202-
calls = [(i, x) for i, x in enumerate(dis) if call_instructions & set(x.groups)]
1216+
filter_calls = lambda dis: ((i, x) for i, x in enumerate(dis) if call_instructions & set(x.groups))
1217+
calls = list(filter_calls(dis))
12031218

12041219
def find_ret_main_addr(caller_dis, calls):
12051220
call_to_main = -1
12061221
for i, insn in calls:
1207-
if insn.operands[0].imm == exit_addr: break
1222+
if cs.CS_GRP_CALL in insn.groups and insn.operands[imm_index].imm == exit_addr:
1223+
break
12081224
call_to_main = i
12091225
else:
12101226
return 0
@@ -1218,17 +1234,19 @@ def find_ret_main_addr(caller_dis, calls):
12181234
if ret_addr:
12191235
return ret_addr
12201236

1237+
if self.arch in ['ppc', 'powerpc', 'powerpc64']:
1238+
filter_calls = lambda dis: ((i, x) for i, x in enumerate(dis) if set([x.mnemonic]) & set(['bctrl', 'bl']))
1239+
12211240
# `__libc_start_main` -> `__libc_start_call_main` -> `main`
12221241
# Find a direct call which calls `exit` once. That's probably `__libc_start_call_main`.
12231242
for _, insn in calls:
1224-
op = insn.operands[0]
1243+
op = insn.operands[imm_index]
12251244
if op.type != cs.CS_OP_IMM: continue
12261245

12271246
target_addr = op.imm
1228-
# `__libc_start_call_main` is usually smaller than `__libc_start_main`, so
1229-
# we might disassemble a bit too much, but it's a good dynamic estimate.
1230-
callee_dis = list(self.cs_disasm(md, target_addr, func.size))
1231-
callee_calls = [(i, x) for i, x in enumerate(callee_dis) if call_instructions & set(x.groups)]
1247+
callee_dis = list(self.cs_disasm(md, target_addr, callee_size))
1248+
callee_calls = filter_calls(callee_dis)
1249+
12321250
ret_addr = find_ret_main_addr(callee_dis, callee_calls)
12331251
if ret_addr:
12341252
return ret_addr

0 commit comments

Comments
 (0)