Skip to content

Commit

Permalink
Add skipi command to skip N instructions (#964)
Browse files Browse the repository at this point in the history
  • Loading branch information
therealdreg authored Jul 19, 2023
1 parent 7fd94ab commit 577ad02
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 0 deletions.
18 changes: 18 additions & 0 deletions docs/commands/skipi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
## Command `skipi`

The `skipi` command allows you to easily skip instructions execution.

```
skipi [LOCATION] [--n NUM_INSTRUCTIONS]
```

`LOCATION` address/symbol from where to skip (default is `$pc`)

`--n NUM_INSTRUCTIONS` Skip the specified number of instructions instead of the default 1.

```bash
gef➤ skipi
gef➤ skipi --n 3
gef➤ skipi 0x69696969
gef➤ skipi 0x69696969 --n 6
```
34 changes: 34 additions & 0 deletions gef.py
Original file line number Diff line number Diff line change
Expand Up @@ -5985,6 +5985,40 @@ def do_invoke(self, _: List[str], **kwargs: Any) -> None:
return


@register
class SkipiCommand(GenericCommand):
"""Skip N instruction(s) execution"""

_cmdline_ = "skipi"
_syntax_ = ("{_cmdline_} [LOCATION] [--n NUM_INSTRUCTIONS]"
"\n\tLOCATION\taddress/symbol from where to skip"
"\t--n NUM_INSTRUCTIONS\tSkip the specified number of instructions instead of the default 1.")

_example_ = [f"{_cmdline_}",
f"{_cmdline_} --n 3",
f"{_cmdline_} 0x69696969",
f"{_cmdline_} 0x69696969 --n 6",]

def __init__(self) -> None:
super().__init__(complete=gdb.COMPLETE_LOCATION)
return

@only_if_gdb_running
@parse_arguments({"address": "$pc"}, {"--n": 1})
def do_invoke(self, _: List[str], **kwargs: Any) -> None:
args : argparse.Namespace = kwargs["arguments"]
address = parse_address(args.address)
num_instructions = args.n

last_addr = gdb_get_nth_next_instruction_address(address, num_instructions)
total_bytes = (last_addr - address) + gef_get_instruction_at(last_addr).size()
target_addr = address + total_bytes

info(f"skipping {num_instructions} instructions ({total_bytes} bytes) from {address:#x} to {target_addr:#x}")
gdb.execute(f"set $pc = {target_addr:#x}")
return


@register
class NopCommand(GenericCommand):
"""Patch the instruction(s) pointed by parameters with NOP. Note: this command is architecture
Expand Down
63 changes: 63 additions & 0 deletions tests/commands/skipi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""
`skipi` command test module
"""

import pytest

from tests.utils import (ARCH, GefUnitTestGeneric, _target, findlines,
gdb_run_cmd, gdb_run_silent_cmd, gdb_start_silent_cmd)


class SkipiCommand(GefUnitTestGeneric):
"""`skipi` command test module"""


cmd = "skipi"


def test_cmd_nop_inactive(self):
res = gdb_run_cmd(f"{self.cmd}")
self.assertFailIfInactiveSession(res)


@pytest.mark.skipif(ARCH not in ("i686", "x86_64"), reason=f"Skipped for {ARCH}")
def test_cmd_skipi_no_arg(self):

res = gdb_start_silent_cmd(
"pi gef.memory.write(gef.arch.pc, p32(0x9090feeb))", # 1 short jumps to pc + 2 nops
after=(
self.cmd,
"pi print(gef.memory.read(gef.arch.pc, 2))", # read 2 bytes
)
)
self.assertNoException(res)
self.assertIn(r"\x90\x90", res) # 2 nops


@pytest.mark.skipif(ARCH not in ("i686", "x86_64"), reason=f"Skipped for {ARCH}")
def test_cmd_skipi_skip_two_instructions(self):

res = gdb_start_silent_cmd(
"pi gef.memory.write(gef.arch.pc, p64(0x90909090feebfeeb))", # 2 short jumps to pc + 4 nops
after=(
f"{self.cmd} --n 2",
"pi print(gef.memory.read(gef.arch.pc, 4))", # read 4 bytes
)
)
self.assertNoException(res)
self.assertIn(r"\x90\x90\x90\x90", res) # 4 nops


@pytest.mark.skipif(ARCH not in ("i686", "x86_64"), reason=f"Skipped for {ARCH}")
def test_cmd_skipi_two_instructions_from_location(self):

res = gdb_start_silent_cmd(
"pi gef.memory.write(gef.arch.pc, p64(0x9090feebfeebfeeb))", # 2 short jumps to pc + 2 nops
after=(
f"{self.cmd} $pc+2 --n 2", # from the second short jump
"pi print(gef.memory.read(gef.arch.pc, 2))", # read 2 bytes
)
)
self.assertNoException(res)
self.assertIn(r"\x90\x90", res) # 2 nops

0 comments on commit 577ad02

Please sign in to comment.