Fix #1153 nextproginstr command

Fixes the `nextproginst` command and adds two simple tests for it.

The command had two following issues:
1) It assumed that the program vmmap was always the first vmmap with
   proc.exe objfile name -- this assumption has two flaws. First, newer
linkers will create the first memory page for the binary file as
read-only. This is because you do not need the ELF header content to be
executable, and that was the case in old linkers or linux distributions.
As an example, see those vmmap from a simple hello world binary compiled
on Ubuntu 18.04 vs Ubuntu 22.04:

Ubuntu 18.04:
```
  pwndbg> vmmap
  LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
      0x555555554000     0x555555555000 r-xp     1000 0      /home/dc/a.out
      0x555555754000     0x555555755000 r--p     1000 0      /home/dc/a.out
      0x555555755000     0x555555756000 rw-p     1000 1000   /home/dc/a.out
      [...]
```

Ubuntu 22.04:
```
  pwndbg> vmmap
  LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
      0x555555554000     0x555555555000 r--p     1000 0      /home/user/a.out
      0x555555555000     0x555555556000 r-xp     1000 1000   /home/user/a.out
      0x555555556000     0x555555557000 r--p     1000 2000   /home/user/a.out
      0x555555557000     0x555555558000 r--p     1000 2000   /home/user/a.out
      0x555555558000     0x555555559000 rw-p     1000 3000   /home/user/a.out
```

So, before this commit on Ubuntu 22.04 we ended up taking the first
vmmap which was non-executable and we compared the program counter
register against it after each instruction step executed by the
nextproginstr command. As a result, we ended up never getting back to
the user and just finishing the debugged program this way!

Now, after this commit, we will grab only and all the executable pages for
the binary that we debug and compare and compare against them.

2) The second problem was that we printed out the current Pwndbg context
   after executing nextproginstr succesfully. This does not seem to make
much sense because the context should be printed by the prompt hook.
(Without removing this, we ended up printing the context twice)
pull/1160/head
disconnect3d 3 years ago committed by Disconnect3d
parent 96d90d18a5
commit 703a7bdab9

@ -67,9 +67,7 @@ def stepret():
)
@pwndbg.commands.OnlyWhenRunning
def nextproginstr():
"""Breaks at the next instruction that belongs to the running program"""
if pwndbg.gdblib.next.break_on_program_code():
pwndbg.commands.context.context()
pwndbg.gdblib.next.break_on_program_code()
parser = argparse.ArgumentParser(

@ -129,20 +129,24 @@ def break_on_program_code():
Breaks on next instruction that belongs to process' objfile code.
:return: True for success, False when process ended or when pc is at the code.
"""
mp = pwndbg.proc.mem_page
start = mp.start
end = mp.end
exe = pwndbg.proc.exe
binary_exec_page_ranges = [
(p.start, p.end) for p in pwndbg.vmmap.get() if p.objfile == exe and p.execute
]
if start <= pwndbg.gdblib.regs.pc < end:
print(message.error("The pc is already at the binary objfile code. Not stepping."))
return False
pc = pwndbg.gdblib.regs.pc
for start, end in binary_exec_page_ranges:
if start <= pc < end:
print(message.error("The pc is already at the binary objfile code. Not stepping."))
return False
while pwndbg.proc.alive:
gdb.execute("si", from_tty=False, to_string=False)
addr = pwndbg.gdblib.regs.pc
if start <= addr < end:
return True
pc = pwndbg.gdblib.regs.pc
for start, end in binary_exec_page_ranges:
if start <= pc < end:
return True
return False

@ -69,10 +69,6 @@ class module(ModuleType):
"""
return gdb.current_progspace().filename
@property
def mem_page(self):
return next(p for p in pwndbg.vmmap.get() if p.objfile == self.exe)
def OnlyWhenRunning(self, func):
@functools.wraps(func)
def wrapper(*a, **kw):

Loading…
Cancel
Save