Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@amtal
Last active June 23, 2023 04:03
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save amtal/c457176af7f8770e0ad519aadc86013c to your computer and use it in GitHub Desktop.
Save amtal/c457176af7f8770e0ad519aadc86013c to your computer and use it in GitHub Desktop.
Rappel.py is a pretty janky assembly REPL. It works by using keystone for R, and GDB for EPL.
""" Assembly REPL in gdb / possible sketchy binary patcher.
Usage:
gdb -q ./target
-x rappel.py adds 'rappel' command
[-write] patches binary on disk, sometimes!
"""
import gdb, tempfile, keystone as ks
class Rappel(gdb.Command):
"""Assemble a patch at $pc and step over it (interactive assembly repl)
Extra semicolons will do extra steps. Endianness may require edits.
Examples on x86:
rappel rdrand eax
print/x $eax
rappel inc rax; push rax; pop rbx; cmp rax, rbx
info reg
rappel pcmpistri xmm0, xmm1, 5
info all-registers
"""
def invoke(self, arg:str, _from_tty:bool):
if not arg:
return print('No assembly instructions passed. Try "help rappel".')
if 'ks' not in self.__dict__:
# endian/architecture are usually set to 'auto', hard to query :(
arch = gdb.selected_frame().architecture().name()
if arch not in TESTED_MAP:
print('Could not guess options for {0}, set manually!' % arch)
print('Tested architectures: ' + ', '.join(TESTED_MAP.keys()))
return
self.ks = ks.Ks(*TESTED_MAP[arch])
text, isn_count = self.ks.asm(arg)
with tempfile.NamedTemporaryFile() as hnd:
hnd.write(bytes(text))
hnd.flush()
gdb.execute('restore %s binary $pc' % hnd.name)
gdb.execute('disassemble/r $pc, +%d' % len(text))
[gdb.execute('stepi') for _ in range(isn_count)]
def __init__(self):
super(Rappel, self).__init__('rappel', gdb.COMMAND_RUNNING)
Rappel()
KSTOOL = {
# Scraped from kstool.cpp, v0.9.1 + armv8/thumbv8* addition
# Covers most possible settings, MIPS ISA variants being the exception
# Run `kstool` to check for new additions/see descriptions
"x16": [ks.KS_ARCH_X86, ks.KS_MODE_16],
"x32": [ks.KS_ARCH_X86, ks.KS_MODE_32],
"x64": [ks.KS_ARCH_X86, ks.KS_MODE_64],
"x16att": [ks.KS_ARCH_X86, ks.KS_MODE_16],
"x32att": [ks.KS_ARCH_X86, ks.KS_MODE_32],
"x64att": [ks.KS_ARCH_X86, ks.KS_MODE_64],
"x16nasm": [ks.KS_ARCH_X86, ks.KS_MODE_16],
"x32nasm": [ks.KS_ARCH_X86, ks.KS_MODE_32],
"x64nasm": [ks.KS_ARCH_X86, ks.KS_MODE_64],
"arm": [ks.KS_ARCH_ARM, ks.KS_MODE_ARM+ks.KS_MODE_LITTLE_ENDIAN],
"armbe": [ks.KS_ARCH_ARM, ks.KS_MODE_ARM+ks.KS_MODE_BIG_ENDIAN],
"thumb": [ks.KS_ARCH_ARM, ks.KS_MODE_THUMB+ks.KS_MODE_LITTLE_ENDIAN],
"thumbbe": [ks.KS_ARCH_ARM, ks.KS_MODE_THUMB+ks.KS_MODE_BIG_ENDIAN],
"armv8": [ks.KS_ARCH_ARM, ks.KS_MODE_ARM+ks.KS_MODE_LITTLE_ENDIAN+ks.KS_MODE_V8],
"armv8be": [ks.KS_ARCH_ARM, ks.KS_MODE_ARM+ks.KS_MODE_BIG_ENDIAN+ks.KS_MODE_V8],
"thumbv8": [ks.KS_ARCH_ARM, ks.KS_MODE_THUMB+ks.KS_MODE_LITTLE_ENDIAN+ks.KS_MODE_V8],
"thumbv8be": [ks.KS_ARCH_ARM, ks.KS_MODE_THUMB+ks.KS_MODE_BIG_ENDIAN+ks.KS_MODE_V8],
"arm64": [ks.KS_ARCH_ARM64, ks.KS_MODE_LITTLE_ENDIAN],
"hex": [ks.KS_ARCH_HEXAGON, ks.KS_MODE_BIG_ENDIAN],
"mips": [ks.KS_ARCH_MIPS, ks.KS_MODE_MIPS32+ks.KS_MODE_LITTLE_ENDIAN],
"mipsbe": [ks.KS_ARCH_MIPS, ks.KS_MODE_MIPS32+ks.KS_MODE_BIG_ENDIAN],
"mips64": [ks.KS_ARCH_MIPS, ks.KS_MODE_MIPS64+ks.KS_MODE_LITTLE_ENDIAN],
"mips64be": [ks.KS_ARCH_MIPS, ks.KS_MODE_MIPS64+ks.KS_MODE_BIG_ENDIAN],
"ppc32be": [ks.KS_ARCH_PPC, ks.KS_MODE_PPC32+ks.KS_MODE_BIG_ENDIAN],
"ppc64": [ks.KS_ARCH_PPC, ks.KS_MODE_PPC64+ks.KS_MODE_LITTLE_ENDIAN],
"ppc64be": [ks.KS_ARCH_PPC, ks.KS_MODE_PPC64+ks.KS_MODE_BIG_ENDIAN],
"sparc": [ks.KS_ARCH_SPARC, ks.KS_MODE_SPARC32+ks.KS_MODE_LITTLE_ENDIAN],
"sparcbe": [ks.KS_ARCH_SPARC, ks.KS_MODE_SPARC32+ks.KS_MODE_BIG_ENDIAN],
"sparc64": [ks.KS_ARCH_SPARC, ks.KS_MODE_SPARC64+ks.KS_MODE_LITTLE_ENDIAN],
"sparc64be": [ks.KS_ARCH_SPARC, ks.KS_MODE_SPARC64+ks.KS_MODE_BIG_ENDIAN],
"systemz": [ks.KS_ARCH_SYSTEMZ, ks.KS_MODE_BIG_ENDIAN],
}
# Needs testing: armv5, armv5t, aarch64, powerpc:common, powerpc:common64,
# mips:isa32, mips:isa64, ...
TESTED_MAP = {
# gdb keystone-engine
'i386:x86-32': KSTOOL['x32'],
'i386:x86-64': KSTOOL['x64'],
# ^ ^
# | +- Start by checking if kstool has something close
# | Full options in include/keystone/keystone.h
# +- Type "set architecture <TAB>" in gdb to see built options
# Check gdb-multiarch on Ubuntu/Debian for a long list
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment