Skip to content

Commit

Permalink
Fix capstone-disassemble command and documentation (#695)
Browse files Browse the repository at this point in the history
This fixes the documentation and help messages for the capstone-disassemble command. Furthermore the command was not working in use cases like emulating aarch64 inside qemu. This was due to an uncaught exception caused in gef_get_auxiliary_values when gdb's info auxv doesn't return useful results. This bug has been fixed. Also resolving of LOCATIONs has been fixed.

I also change the syntax for the location argument back to how it was before argparse: as a positional argument.

I introduced a new convenience wrapper function around gdb's parse_and_eval to specifically resolve LOCATIONs. This way other commands can rely on it without having to handle the different possible cases necessary (because e.g. gdb resolves registers different from symbols and for symbols a simple conversion to int does not work directly). This new function does not aim at replacing gef_safe_parse_and_eval at this point because too many commands currently rely on it and there might be use cases that don't resolve locations.
  • Loading branch information
theguy147 committed Aug 23, 2021
1 parent 90d2c8c commit dcfa6f2
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 30 deletions.
12 changes: 4 additions & 8 deletions docs/commands/capstone-disassemble.md
Expand Up @@ -9,22 +9,18 @@ You can use its alias `cs-disassemble` or just `cs` with the location to
disassemble at. If not specified, it will use `$pc`.

```
gef➤ cs main
gef➤ cs main+0x10
```

![cs-disassemble](https://i.imgur.com/wypt7Fo.png)
![cs-disassemble](https://i.imgur.com/JG7aVRP.png)

Disassemble more instructions
```
gef➤ cs length=20
```

Show instructions before $pc
```
gef➤ cs nb_prev=3
gef➤ cs --length 20
```

Show opcodes next to disassembly
```
gef➤ cs op
gef➤ cs --show-opcodes
```
51 changes: 30 additions & 21 deletions gef.py
Expand Up @@ -1415,7 +1415,7 @@ def cs_insn_to_gef_insn(cs_insn):
return Instruction(cs_insn.address, loc, cs_insn.mnemonic, ops, cs_insn.bytes)

capstone = sys.modules["capstone"]
arch, mode = get_capstone_arch(arch=kwargs.get("arch", None), mode=kwargs.get("mode", None), endian=kwargs.get("endian", None))
arch, mode = get_capstone_arch(arch=kwargs.get("arch"), mode=kwargs.get("mode"), endian=kwargs.get("endian"))
cs = capstone.Cs(arch, mode)
cs.detail = True

Expand Down Expand Up @@ -3660,21 +3660,27 @@ def parse_string_range(s):

@lru_cache()
def gef_get_auxiliary_values():
"""Retrieves the auxiliary values of the current execution. Returns None if not running, or a dict()
of values."""
"""Retrieve the ELF auxiliary values of the current execution. This
information is provided by the operating system to transfer some kernel
level information to the user process. Return None if not found, or a
dict() of values as: {aux_vect_name: int(aux_vect_value)}."""
if not is_alive():
return None

res = {}
for line in gdb.execute("info auxv", to_string=True).splitlines():
tmp = line.split()
_type = tmp[1]
if _type in ("AT_PLATFORM", "AT_EXECFN"):
idx = line[:-1].rfind('"') - 1
tmp = line[:idx].split()

res[_type] = int(tmp[-1], base=0)
return res
__auxiliary_vector = {}
auxv_info = gdb.execute("info auxv", to_string=True)
if "failed" in auxv_info:
err(auxv_info) # print GDB error
return None
for line in auxv_info.splitlines():
line = line.split('"')[0].strip() # remove the ending string (if any)
line = line.split() # split the string by whitespace(s)
if len(line) < 4:
continue # a valid entry should have at least 4 columns
__av_type = line[1]
__av_value = line[-1]
__auxiliary_vector[__av_type] = int(__av_value, base=0)
return __auxiliary_vector


def gef_read_canary():
Expand Down Expand Up @@ -6470,9 +6476,9 @@ class CapstoneDisassembleCommand(GenericCommand):
"""Use capstone disassembly framework to disassemble code."""

_cmdline_ = "capstone-disassemble"
_syntax_ = "{:s} [LOCATION] [[length=LENGTH] [OPCODES] [option=VALUE]] ".format(_cmdline_)
_aliases_ = ["cs-dis",]
_example_ = "{:s} $pc length=50".format(_cmdline_)
_syntax_ = "{:s} [-h] [--show-opcodes] [--length LENGTH] [LOCATION]".format(_cmdline_)
_aliases_ = ["cs-dis"]
_example_ = "{:s} --length 50 $pc".format(_cmdline_)

def pre_load(self):
try:
Expand All @@ -6487,16 +6493,19 @@ def __init__(self):
return

@only_if_gdb_running
@parse_arguments({}, {("--location", "-l"): 0, ("--show-opcodes", "-s"): True, "--length": 0})
@parse_arguments({("location"): "$pc"}, {("--show-opcodes", "-s"): True, "--length": 0})
def do_invoke(self, argv, *args, **kwargs):
args = kwargs["arguments"]
show_opcodes = args.show_opcodes
location = args.location if args.location else current_arch.pc
length = args.length or get_gef_setting("context.nb_lines_code")
location = parse_address(args.location)
if not location:
info("Can't find address for {}".format(args.location))
return

insns = []
opcodes_len = 0
for insn in capstone_disassemble(location, length, skip=length*self.repeat_count, **kwargs):
for insn in capstone_disassemble(location, length, skip=length * self.repeat_count, **kwargs):
insns.append(insn)
opcodes_len = max(opcodes_len, len(insn.opcodes))

Expand All @@ -6513,7 +6522,7 @@ def do_invoke(self, argv, *args, **kwargs):
gef_print(reason)
break
else:
msg = "{} {}".format(" "*5, text_insn)
msg = "{} {}".format(" " * 5, text_insn)

gef_print(msg)
return
Expand All @@ -6533,7 +6542,7 @@ def capstone_analyze_pc(self, insn, nb_insn):
target_address = int(insn.operands[-1].split()[0], 16)
msg = []
for i, new_insn in enumerate(capstone_disassemble(target_address, nb_insn)):
msg.append(" {} {}".format (DOWN_ARROW if i == 0 else " ", str(new_insn)))
msg.append(" {} {}".format(DOWN_ARROW if i == 0 else " ", str(new_insn)))
return (True, "\n".join(msg))

return (False, "")
Expand Down
4 changes: 3 additions & 1 deletion tests/runtests.py
Expand Up @@ -67,12 +67,14 @@ def test_cmd_capstone_disassemble(self):
self.assertTrue(len(res.splitlines()) > 1)

self.assertFailIfInactiveSession(gdb_run_cmd("cs --show-opcodes"))
res = gdb_start_silent_cmd("cs --show-opcodes")
res = gdb_start_silent_cmd("cs --show-opcodes $pc")
self.assertNoException(res)
self.assertTrue(len(res.splitlines()) > 1)
# match the following pattern
# 0x5555555546b2 897dec <main+8> mov DWORD PTR [rbp-0x14], edi
self.assertRegex(res, r"0x.{12}\s([0-9a-f]{2})+\s+.*")
res = gdb_start_silent_cmd("cs --show-opcodes main")
self.assertNoException(res)
return

def test_cmd_checksec(self):
Expand Down

0 comments on commit dcfa6f2

Please sign in to comment.