Skip to content

Commit

Permalink
Fix gef-remote: retrieve pid of inferior process after having conne…
Browse files Browse the repository at this point in the history
…cted to target (#686)
  • Loading branch information
theguy147 committed Aug 15, 2021
1 parent 0b7c616 commit 5a9b2a2
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 20 deletions.
48 changes: 33 additions & 15 deletions docs/commands/gef-remote.md
@@ -1,22 +1,23 @@
## Command gef-remote ##

It is possible to use `gef` in a remote debugging environment. Required files
will be automatically downloaded and cached in a temporary directory (`/tmp/gef` on most
Unix systems). Remember to manually delete the cache if you change the target file or
`gef` will use the outdated version.

will be automatically downloaded and cached in a temporary directory (`/tmp/gef`
on most Unix systems). Remember to manually delete the cache if you change the
target file or `gef` will use the outdated version.

### With a local copy ###

If you want to remotely debug a binary that you already have, you simply need to
tell to `gdb` where to find the debug information.

For example, if we want to debug `uname`, we do on the server:

```
$ gdbserver 0.0.0.0:1234 /bin/uname
Process /bin/uname created; pid = 32280
Listening on port 1234
```

![](https://i.imgur.com/Zc4vnBd.png)

And on the client, simply run `gdb`:
Expand All @@ -36,16 +37,16 @@ gef➤ file /bin/uname
gef➤ target remote 192.168.56.1:1234
```


### Without a local copy ###

It is possible to use `gdb` internal functions to copy our targeted binary.

Following our previous example, if we want to debug `uname`, run `gdb` and
connect to our `gdbserver`. To be able to locate the right process in the
`/proc` structure, the command `gef-remote` requires 1 argument, the target
host and port. The option `-p` must be provided and indicate the process PID
on the remote host, only if the extended mode (`-E`) is being used.
host and port. The option `--pid` must be provided and indicate the process
PID on the remote host, only if the extended mode (`--is-extended-remote`)
is being used.

```
$ gdb
Expand All @@ -60,12 +61,26 @@ automatically download the target file and store in the local temporary
directory (on most Unix `/tmp`). If successful, it will then automatically load
the debug information to `gdb` and proceed with the debugging.

![gef-remote-autodownload](https://i.imgur.com/8JHpOTV.png)
![gef-remote-autodownload](https://i.imgur.com/nLtvCxP.png)

You can then reuse the downloaded file for your future debugging sessions, use it under IDA
and such. This makes the entire remote debugging process (particularly for Android applications)
a child's game.
You can then reuse the downloaded file for your future debugging sessions, use
it under IDA and such. This makes the entire remote debugging process
(particularly for Android applications) a child's game.

### Handling remote libraries ###

Often times you are missing a specific library the remote process is using.
To remedy this `gef-remote` can download remote libraries (and other files) if
the remote target supports it (and the remote gdbserver has sufficient
permissions). The `--download-lib LIBRARY` option can download a remote file
specified by its filepath. Furthermore `--download-everything` downloads all
remote libs found in the process's virtual memory map (`vmmap`).

Another issue with libraries is that even if you have the same libraries that
are used remotely they might have different filepaths and GDB can't
automatically find them and thereby can't resolve their symbols. The option
`--update-solib` adds the previously (with `--dowload-everything`) downloaded
libraries to the solib path so GDB can take full advantage of their symbols.

### QEMU-user mode ###

Expand All @@ -77,14 +92,17 @@ for `gef` will not work either, as `gef` won't be able to fetch the content of
the remote procfs.

To circumvent this and still enjoy `gef` features with QEMU-user, a simple stub
can be artificially added, with the option `-q` option of `gef-remote`. Note
that you need to set the architecture properly first:
can be artificially added, with the option `--qemu-mode` option of `gef-remote`.
Note that you need to set the architecture to match the target binary first:

```
$ qemu-arm -g 1234 ./my/arm/binary
$ gdb-multiarch ./my/arm/binary
gef➤ set architecture arm
gef➤ gef-remote -q localhost:1234
gef➤ gef-remote --qemu-mode localhost:1234
```

![gef-qemu-user](http://i.imgur.com/JtEQndv.png)
![gef-qemu-user](https://i.imgur.com/A0xgEdR.png)

When debugging a process in QEMU both the memory map of QEMU and of the process
are being shown alongside.
14 changes: 9 additions & 5 deletions gef.py
Expand Up @@ -2776,8 +2776,11 @@ def get_os():

@lru_cache()
def get_pid():
"""Return the PID of the debuggee process."""
return gdb.selected_inferior().pid if not __gef_qemu_mode__ else gdb.selected_thread().ptid[1]
"""Return the PID of the target process."""
pid = gdb.selected_inferior().pid if not __gef_qemu_mode__ else gdb.selected_thread().ptid[1]
if not pid:
raise RuntimeError("cannot retrieve PID for target process")
return pid


@lru_cache()
Expand Down Expand Up @@ -6155,7 +6158,8 @@ class RemoteCommand(GenericCommand):

_cmdline_ = "gef-remote"
_syntax_ = "{:s} [OPTIONS] TARGET".format(_cmdline_)
_example_ = "\n{0:s} -p 6789 localhost:1234\n{0:s} -q localhost:4444 # when using qemu-user".format(_cmdline_)
_example_ = "\n{0:s} --pid 6789 localhost:1234"\
"\n{0:s} --qemu-mode localhost:4444 # when using qemu-user".format(_cmdline_)

def __init__(self):
super().__init__(prefix=False)
Expand All @@ -6170,7 +6174,7 @@ def __init__(self):
"--download-lib": "",
"--is-extended-remote": True,
"--pid": 0,
"--qemu-mode": True,})
"--qemu-mode": True})
def do_invoke(self, argv, *args, **kwargs):
global __gef_remote__

Expand All @@ -6189,7 +6193,6 @@ def do_invoke(self, argv, *args, **kwargs):
return

target = args.target
pid = args.pid if args.is_extended_remote and args.pid else get_pid()
self.download_all_libs = args.download_everything

if args.qemu_mode:
Expand All @@ -6205,6 +6208,7 @@ def do_invoke(self, argv, *args, **kwargs):
if not self.connect_target(target, args.is_extended_remote):
return

pid = args.pid if args.is_extended_remote and args.pid else get_pid()
if args.is_extended_remote:
ok("Attaching to {:d}".format(pid))
hide_context()
Expand Down

0 comments on commit 5a9b2a2

Please sign in to comment.