Repository: pwndbg/pwndbg

Issue:
The return address register not restored when initializing the Emulator
<!--
Before reporting a new issue, make sure that we do not have any duplicates already open.
If there is one it might be good to take part in the discussion there.

Please make sure you have checked that the issue persists on LATEST pwndbg version.

Below is a template for BUG REPORTS.
Don't include it if this is a FEATURE REQUEST.
-->


### Description

The return address register not restored for non-x86 arches when initializing the `Emulator` class, and cause `pc` to be set to `0x0` after the `ret` instruction.

Here is the [https://github.com/pwndbg/pwndbg/blob/dev/pwndbg/emu/emulator.py](https://github.com/pwndbg/pwndbg/blob/dev/pwndbg/emu/emulator.py), line 144~146:

```py
# Initialize the register state
for reg in list(self.regs.misc) + list(self.regs.common) + list(self.regs.flags):
    enum = self.get_reg_enum(reg)
```

~~#556  is the reason of hanging.~~

### Steps to reproduce

<!--
What do we have to do to reproduce the problem?
If this is connected to particular C/asm code, 
please provide the smallest C code that reproduces the issue.
-->

### My setup

```
Gdb:      8.0.1
Python:   2.7.10 (default, Aug 17 2018, 17:41:52)  [GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.0.42)]
Pwndbg:   1.1.0 build: 4a34137
Capstone: 4.0.1024
Unicorn:  1.0.1
```
<!--
Show us your gdb/python/pwndbg/OS/IDA Pro version (depending on your case).

NOTE: We are currently supporting only Ubuntu installations.
It is known that pwndbg is not fully working e.g. on Arch Linux (the heap stuff is not working there).
If you would like to change this situation - help us improving pwndbg and supporting other distros!

This can be displayed in pwndbg through `version` command.

If it is somehow unavailable, use:
* `show version` - for gdb
* `py import sys; print(sys.version)` - for python
* pwndbg version/git commit id
-->
The return address register not restored when initializing the Emulator
<!--
Before reporting a new issue, make sure that we do not have any duplicates already open.
If there is one it might be good to take part in the discussion there.

Please make sure you have checked that the issue persists on LATEST pwndbg version.

Below is a template for BUG REPORTS.
Don't include it if this is a FEATURE REQUEST.
-->


### Description

The return address register not restored for non-x86 arches when initializing the `Emulator` class, and cause `pc` to be set to `0x0` after the `ret` instruction.

Here is the [https://github.com/pwndbg/pwndbg/blob/dev/pwndbg/emu/emulator.py](https://github.com/pwndbg/pwndbg/blob/dev/pwndbg/emu/emulator.py), line 144~146:

```py
# Initialize the register state
for reg in list(self.regs.misc) + list(self.regs.common) + list(self.regs.flags):
    enum = self.get_reg_enum(reg)
```

~~#556  is the reason of hanging.~~

### Steps to reproduce

<!--
What do we have to do to reproduce the problem?
If this is connected to particular C/asm code, 
please provide the smallest C code that reproduces the issue.
-->

### My setup

```
Gdb:      8.0.1
Python:   2.7.10 (default, Aug 17 2018, 17:41:52)  [GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.0.42)]
Pwndbg:   1.1.0 build: 4a34137
Capstone: 4.0.1024
Unicorn:  1.0.1
```
<!--
Show us your gdb/python/pwndbg/OS/IDA Pro version (depending on your case).

NOTE: We are currently supporting only Ubuntu installations.
It is known that pwndbg is not fully working e.g. on Arch Linux (the heap stuff is not working there).
If you would like to change this situation - help us improving pwndbg and supporting other distros!

This can be displayed in pwndbg through `version` command.

If it is somehow unavailable, use:
* `show version` - for gdb
* `py import sys; print(sys.version)` - for python
* pwndbg version/git commit id
-->


Discussion:
Hey,

Thanks for reporting this issue. As a quick workaround you can disable emulation by `set emulate off`.

Since you already looked over the code, can you find a fix for that and send us a PR, please?
Also, any chance that you could prepare and push a docker image that would contain qemu + pwndbg from git, so it is easy to validate the issue and a fix for it?

Note that you can do it e.g. by:
* creating a docker image based on some official image - e.g. ubuntu: `docker run --rm -it --cap-add SYS_PTRACE ubuntu:18.04 bash`, the `--cap-add` part is crucial, so you can use `ptrace` inside of the container and so debug processes
* `apt update && apt install git cmake` -> clone pwndbg, install it
* install qemu
* copy the aarch64 kernel from host to the container: use `docker ps` to see the name/id of your container, then `docker cp <kernel file> <container_id>:<path in container>`
* check if you can debug the kernel using qemu and pwndbg
* if everything works, create a docker image based on current container state by `docker commit <container name/id> pwndbg_qemu_emulate:latest` - this will create an image named `pwndbg_qemu_emulate:latest`
* push the docker image to docker registry hub - you will need an account there and then you just follow steps from https://docs.docker.com/docker-cloud/builds/push-images/ (`docker login`, `docker push pwndbg_qemu_emulate:latest` I believe)

PS: If `SYS_PTRACE` capability is not enough, you can launch the container with `--privileged` flag BUT be careful as it gives full root capabilities to the root in the container.
Also note that debugging a Linux kernel might not work properly, see https://github.com/pwndbg/pwndbg/issues/438 for more info.

It would be cool to make it possible, but I simply don't have time to add support for it. I would be happy to merge a PR with that.
I will send a PR and try to push a docker image soon.

And I'm debugging [a simple OS kernel](https://github.com/s-matyukevich/raspberry-pi-os) for Raspberry Pi instead of Linux.
Hey,

Thanks for reporting this issue. As a quick workaround you can disable emulation by `set emulate off`.

Since you already looked over the code, can you find a fix for that and send us a PR, please?
Also, any chance that you could prepare and push a docker image that would contain qemu + pwndbg from git, so it is easy to validate the issue and a fix for it?

Note that you can do it e.g. by:
* creating a docker image based on some official image - e.g. ubuntu: `docker run --rm -it --cap-add SYS_PTRACE ubuntu:18.04 bash`, the `--cap-add` part is crucial, so you can use `ptrace` inside of the container and so debug processes
* `apt update && apt install git cmake` -> clone pwndbg, install it
* install qemu
* copy the aarch64 kernel from host to the container: use `docker ps` to see the name/id of your container, then `docker cp <kernel file> <container_id>:<path in container>`
* check if you can debug the kernel using qemu and pwndbg
* if everything works, create a docker image based on current container state by `docker commit <container name/id> pwndbg_qemu_emulate:latest` - this will create an image named `pwndbg_qemu_emulate:latest`
* push the docker image to docker registry hub - you will need an account there and then you just follow steps from https://docs.docker.com/docker-cloud/builds/push-images/ (`docker login`, `docker push pwndbg_qemu_emulate:latest` I believe)

PS: If `SYS_PTRACE` capability is not enough, you can launch the container with `--privileged` flag BUT be careful as it gives full root capabilities to the root in the container.
Also note that debugging a Linux kernel might not work properly, see https://github.com/pwndbg/pwndbg/issues/438 for more info.

It would be cool to make it possible, but I simply don't have time to add support for it. I would be happy to merge a PR with that.
I will send a PR and try to push a docker image soon.

And I'm debugging [a simple OS kernel](https://github.com/s-matyukevich/raspberry-pi-os) for Raspberry Pi instead of Linux.

Resolving patch:
diff --git a/pwndbg/emu/emulator.py b/pwndbg/emu/emulator.py
--- a/pwndbg/emu/emulator.py
+++ b/pwndbg/emu/emulator.py
@@ -142,7 +142,7 @@ def __init__(self):
         self._curr = None
 
         # Initialize the register state
-        for reg in list(self.regs.misc) + list(self.regs.common) + list(self.regs.flags):
+        for reg in list(self.regs.retaddr) + list(self.regs.misc) + list(self.regs.common) + list(self.regs.flags):
             enum = self.get_reg_enum(reg)
 
             if not reg:
@@ -450,7 +450,7 @@ def single_step_hook_code(self, _uc, address, instruction_size, _user_data):
         self._single_step = (address, instruction_size)
 
     def dumpregs(self):
-        for reg in list(self.regs.misc) + list(self.regs.common) + list(self.regs.flags):
+        for reg in list(self.regs.retaddr) + list(self.regs.misc) + list(self.regs.common) + list(self.regs.flags):
             enum = self.get_reg_enum(reg)
 
             if not reg or enum is None:


Test patch: