Skip to content

Commit b5a6de2

Browse files
committed
disasm thumb with capstone
1 parent 27cfcf1 commit b5a6de2

File tree

2 files changed

+28
-18
lines changed

2 files changed

+28
-18
lines changed

pwnlib/asm.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,7 +1014,7 @@ def disasm(data, vma = 0, byte = True, offset = True, instructions = True):
10141014
return re.sub(',([^ ])', r', \1', '\n'.join(lines))
10151015

10161016
@LocalContext
1017-
def get_cs_disassembler():
1017+
def get_cs_disassembler(eabi=None):
10181018
import capstone as cs
10191019
E = {
10201020
'big': cs.CS_MODE_BIG_ENDIAN,
@@ -1023,14 +1023,14 @@ def get_cs_disassembler():
10231023

10241024
B = {16: cs.CS_MODE_16, 32: cs.CS_MODE_32, 64: cs.CS_MODE_64}[context.bits]
10251025

1026-
print("context:", context)
1026+
# print("context:", context)
10271027
params = {
10281028
'i386' : (cs.CS_ARCH_X86, B),
10291029
'amd64' : (cs.CS_ARCH_X86, B),
10301030
'thumb' : (cs.CS_ARCH_ARM, cs.CS_MODE_THUMB + E),
10311031
'arm' : (cs.CS_ARCH_ARM, cs.CS_MODE_ARM + E),
1032-
'aarch64': (cs.CS_ARCH_ARM64, cs.CS_MODE_ARM + E),
1033-
'armhf' : (cs.CS_ARCH_ARM, cs.CS_MODE_ARM + cs.CS_MODE_V8 + cs.CS_MODE_THUMB + E),
1032+
'aarch64': (cs.CS_ARCH_AARCH64, cs.CS_MODE_ARM + E),
1033+
'armhf' : (cs.CS_ARCH_ARM, cs.CS_MODE_ARM + cs.CS_MODE_THUMB + E),
10341034
'mips' : (cs.CS_ARCH_MIPS, cs.CS_MODE_32 + E),
10351035
'mips64' : (cs.CS_ARCH_MIPS, cs.CS_MODE_64 + E),
10361036
'sparc': (cs.CS_ARCH_SPARC, cs.CS_MODE_32 + E),
@@ -1053,10 +1053,13 @@ def get_cs_disassembler():
10531053
#'sh': cs.CS_ARCH_SH,
10541054
}
10551055

1056-
param = params.get(context.arch)
1056+
arch = context.arch
1057+
if arch == 'arm' and eabi == 'hf': arch = 'armhf'
1058+
# print("arch:", arch)
1059+
param = params.get(arch)
10571060
if not param:
10581061
raise Exception(f"unsupported {context.arch} for capstone")
1059-
print("param:", param)
10601062
arch, mode = param
10611063
md = cs.Cs(arch, mode)
1064+
md.detail = True
10621065
return md

pwnlib/elf/elf.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
import re
5555
import subprocess
5656
import tempfile
57+
import capstone as cs
5758

5859
from io import BytesIO
5960

@@ -1143,6 +1144,12 @@ def _populate_kernel_version(self):
11431144

11441145
self.config['version'] = self.version
11451146

1147+
def cs_disasm(self, md: cs.Cs, address, n_bytes):
1148+
if self.arch == 'arm' and address & 1:
1149+
address -= 1
1150+
1151+
return md.disasm(self.read(address, n_bytes), address)
1152+
11461153
@property
11471154
def libc_start_main_return(self):
11481155
""":class:`int`: Address of the return address into __libc_start_main from main.
@@ -1163,21 +1170,20 @@ def libc_start_main_return(self):
11631170
if 'exit' not in self.symbols:
11641171
return 0
11651172

1166-
import capstone as cs
1167-
1173+
eabi = None
11681174
# If there's no delay slot, execution continues on the next instruction after a call.
11691175
call_return_offset = 1
11701176
if self.arch in ['arm', 'thumb']:
1171-
# if b'armhf' in self.linker:
1172-
# self.arch = 'armhf'
1173-
# self.bits = 16
1177+
if b'armhf' in self.linker:
1178+
eabi = 'hf'
1179+
# self.bits = 16
11741180
call_instructions = set([cs.CS_GRP_CALL])
11751181
elif self.arch == 'aarch64':
11761182
call_instructions = set([cs.CS_GRP_CALL])
11771183
elif self.arch in ['mips', 'mips64']:
11781184
# FIXME: `bal` was not included in CS_GRP_CALL. This is fixed on capstone v6.alpha
1179-
call_instructions = set([cs.CS_GRP_CALL, cs.CS_GRP_BRANCH_RELATIVE])
1180-
# call_instructions = set([cs.CS_GRP_CALL])
1185+
#call_instructions = set([cs.CS_GRP_CALL, cs.CS_GRP_BRANCH_RELATIVE])
1186+
call_instructions = set([cs.CS_GRP_CALL])
11811187
# Account for the delay slot.
11821188
call_return_offset = 2
11831189
elif self.arch in ['i386', 'amd64', 'ia64']:
@@ -1186,14 +1192,15 @@ def libc_start_main_return(self):
11861192
call_instructions = set([cs.CS_GRP_CALL])
11871193

11881194
from pwnlib.asm import get_cs_disassembler
1189-
md = get_cs_disassembler(arch=self.arch, endian=self.endian, bits=self.bits)
1190-
md.detail = True
1195+
md = get_cs_disassembler(arch=self.arch, endian=self.endian, bits=self.bits, eabi=eabi)
11911196
func = self.functions['__libc_start_main']
1192-
code = self.read(func.address, func.size)
1193-
dis = list(md.disasm(code, func.address))
1197+
# print("func:", func)
1198+
dis = list(self.cs_disasm(md, func.address, func.size))
11941199
# print("dis:", dis)
11951200

11961201
exit_addr = self.symbols['exit']
1202+
if self.arch == 'arm' and exit_addr & 1: exit_addr -= 1
1203+
# print("exit:", hex(exit_addr))
11971204

11981205
calls = [(i, x) for i, x in enumerate(dis) if call_instructions & set(x.groups)]
11991206
# print("calls:", calls)
@@ -1224,7 +1231,7 @@ def find_ret_main_addr(caller_dis, calls):
12241231
target_addr = op.imm
12251232
# `__libc_start_call_main` is usually smaller than `__libc_start_main`, so
12261233
# we might disassemble a bit too much, but it's a good dynamic estimate.
1227-
callee_dis = list(md.disasm(self.read(target_addr, func.size), target_addr))
1234+
callee_dis = list(self.cs_disasm(md, target_addr, func.size))
12281235
callee_calls = [(i, x) for i, x in enumerate(callee_dis) if call_instructions & set(x.groups)]
12291236
ret_addr = find_ret_main_addr(callee_dis, callee_calls)
12301237
if ret_addr:

0 commit comments

Comments
 (0)