Skip to content

Commit

Permalink
Merge branch 'dev' into allow_new_file_format
Browse files Browse the repository at this point in the history
  • Loading branch information
hugsy committed Jun 26, 2022
2 parents 5dd793d + 9834252 commit 09b2f13
Show file tree
Hide file tree
Showing 9 changed files with 574 additions and 481 deletions.
142 changes: 66 additions & 76 deletions docs/commands/gef-remote.md
@@ -1,108 +1,98 @@
## Command gef-remote ##
## 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.
[`target remote`](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Debugging.html#Remote-Debugging) is the traditional GDB way of debugging process or system remotely. However this command by itself does a limited job (80's bandwith FTW) to collect more information about the target, making the process of debugging more cumbersome. GEF greatly improves that state with the `gef-remote` command.

### With a local copy ###
📝 **Note**: If using GEF, `gef-remote` **should** be your way or debugging remote processes. Maintainers will not provide support or help if you decide to use the traditional `target remote` command.

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.
`gef-remote` can function in 2 ways:
- `remote` which is meant to enrich use of GDB `target remote` command, when connecting to a "real" gdbserver instance
- `qemu-mode` when connecting to GDB stab of either `qemu-user` or `qemu-system`.

The reason for this difference being that Qemu provides *a lot* less information that GEF can extract to enrich debugging. Whereas GDBServer allows to download remote file (therefore allowing to create a small identical environment), GDB stub in Qemu does not support file transfer. As a consequence, in order to use GEF in qemu mode, it is required to provide the binary being debugged. GEF will create a mock (limited) environment so that all its most useful features are available.

### Remote mode

#### `remote`

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
$ gdbserver :1234 /tmp/default.out
Process /tmp/default.out created; pid = 258932
Listening on port 1234
```

![](https://i.imgur.com/Zc4vnBd.png)
![gef-remote-1](https://i.imgur.com/Zc4vnBd.png)

And on the client, simply run `gdb`:
On the client, when the original `gdb` would use `target remote`, GEF's syntax is roughly similar (shown running in debug mode for more verbose output, but you don't have to):

```
$ gdb /bin/uname
gef➤ target remote 192.168.56.1:1234
Process /bin/uname created; pid = 10851
Listening on port 1234
$ gdb -ex 'gef config gef.debug 1'
GEF for linux ready, type `gef' to start, `gef config' to configure
90 commands loaded and 5 functions added for GDB 10.2 using Python engine 3.8
gef➤ gef-remote localhost 1234
[=] [remote] initializing remote session with localhost:1234 under /tmp/tmp8qd0r7iw
[=] [remote] Installing new objfile handlers
[=] [remote] Enabling extended remote: False
[=] [remote] Executing 'target remote localhost:1234'
Reading /tmp/default.out from remote target...
warning: File transfers from remote targets can be slow. Use "set sysroot" to access files locally instead.
Reading /tmp/default.out from remote target...
Reading symbols from target:/tmp/default.out...
[=] [remote] in remote_objfile_handler(target:/tmp/default.out))
[=] [remote] downloading '/tmp/default.out' -> '/tmp/tmp8qd0r7iw/tmp/default.out'
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
Reading /lib64/ld-linux-x86-64.so.2 from remote target...
[=] [remote] in remote_objfile_handler(/usr/lib/debug/.build-id/45/87364908de169dec62ffa538170118c1c3a078.debug))
[=] [remote] in remote_objfile_handler(target:/lib64/ld-linux-x86-64.so.2))
[=] [remote] downloading '/lib64/ld-linux-x86-64.so.2' -> '/tmp/tmp8qd0r7iw/lib64/ld-linux-x86-64.so.2'
[=] [remote] in remote_objfile_handler(system-supplied DSO at 0x7ffff7fcd000))
[*] [remote] skipping 'system-supplied DSO at 0x7ffff7fcd000'
0x00007ffff7fd0100 in _start () from target:/lib64/ld-linux-x86-64.so.2
[=] Setting up as remote session
[=] [remote] downloading '/proc/258932/maps' -> '/tmp/tmp8qd0r7iw/proc/258932/maps'
[=] [remote] downloading '/proc/258932/environ' -> '/tmp/tmp8qd0r7iw/proc/258932/environ'
[=] [remote] downloading '/proc/258932/cmdline' -> '/tmp/tmp8qd0r7iw/proc/258932/cmdline'
[...]
```

Or
And finally breaking into the program, showing the current context:

```
$ gdb
gef➤ file /bin/uname
gef➤ target remote 192.168.56.1:1234
```
![gef-remote](https://i.imgur.com/IfsRDvK.png)

### Without a local copy ###
You will also notice the prompt has changed to indicate the debugging mode is now "remote". Besides that, all of GEF features are available:

It is possible to use `gdb` internal functions to copy our targeted binary.
![gef-remote-command](https://i.imgur.com/05epyX6.png)

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 `--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
gef➤ gef-remote 192.168.56.1:1234
[+] Connected to '192.168.56.1:1234'
[+] Downloading remote information
[+] Remote information loaded, remember to clean '/tmp/gef/10851' when your session is over
```
#### `remote-extended`

As you can observe, if it cannot find the debug information, `gef` will try to
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.
Extended mode works the same as `remote`. Being an extended session, gdbserver has not spawned or attached to any process. Therefore, all that's required is to add the `--pid` flag when calling `gef-remote`, along with the process ID of the process to debug.

![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.
### Qemu mode

### Handling remote libraries ###
Qemu mode of `gef-remote` allows to connect to the [Qemu GDB stub](https://qemu-project.gitlab.io/qemu/system/gdb.html) which allows to live debug into either a binary (`qemu-user`) or even the kernel (`qemu-system`), of any architecture supported by GEF, which makes now even more sense 😉 And using it is very straight forward.

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`).
#### `qemu-user`

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.
1. Run `qemu-x86_64 :1234 /bin/ls`
2. Use `--qemu-user` and `--qemu-binary /bin/ls` when starting `gef-remote`

### QEMU-user mode ###
![qemu-user](https://user-images.githubusercontent.com/590234/175072835-e276ab6c-4f75-4313-9e66-9fe5a3fd220e.png)

Although GDB through QEMU-user works, QEMU only supports a limited subset of all
commands existing in the `gdbremote` protocol. For example, commands such as
`remote get` or `remote put` (to download and upload a file from remote target,
respectively) are not supported. As a consequence, the default `remote` mode
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 `--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 --qemu-mode localhost:1234
```
#### `qemu-system`

To test locally, you can use the mini image linux x64 vm [here](https://mega.nz/file/ldQCDQiR#yJWJ8RXAHTxREKVmR7Hnfr70tIAQDFeWSYj96SvPO1k).
1. Run `./run.sh`
2. Use `--qemu-user` and `--qemu-binary vmlinuz` when starting `gef-remote`


![qemu-system](https://user-images.githubusercontent.com/590234/175071351-8e06aa27-dc61-4fd7-9215-c345dcebcd67.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.
9 changes: 9 additions & 0 deletions docs/commands/patch.md
Expand Up @@ -7,3 +7,12 @@ gef➤ patch byte $eip 0x90
gef➤ patch string $eip "cool!"
```

These commands copy the first 10 bytes of $rsp+8 to $rip:

```
gef➤ print-format --lang bytearray -l 10 $rsp+8
Saved data b'\xcb\xe3\xff\xff\xff\x7f\x00\x00\x00\x00'... in '$_gef0'
gef➤ patch byte $rip $_gef0
```

Very handy to copy-paste-execute shellcodes/data from different memory regions.
13 changes: 13 additions & 0 deletions docs/commands/print-format.md
Expand Up @@ -7,6 +7,7 @@ The command `print-format` (alias `pf`) will dump an arbitrary location as an ar
- Assembly (`asm`)
- Javascript (`js`)
- Hex string (`hex`)
- For patch byte command or GDB $_gef[N] byte access (`bytearray`)


```
Expand All @@ -26,3 +27,15 @@ gef➤ print-format --lang py --bitlen 8 -l 10 --clip $rsp
[+] Copied to clipboard
buf = [0x87, 0xfa, 0xa3, 0xf7, 0xff, 0x7f, 0x0, 0x0, 0x30, 0xe6]
```

These commands copy the first 10 bytes of $rsp+8 to $rip:

```
gef➤ print-format --lang bytearray -l 10 $rsp+8
Saved data b'\xcb\xe3\xff\xff\xff\x7f\x00\x00\x00\x00'... in '$_gef0'
gef➤ display/x $_gef0[5]
4: /x $_gef0[5] = 0x7f
gef➤ patch byte $rip $_gef0
```

Very handy to copy-paste-execute shellcodes/data from different memory regions.

0 comments on commit 09b2f13

Please sign in to comment.