Repository: pwndbg/pwndbg

Issue:
Incorrect conversion from gdb.Value to python int
<!--
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

<!--
Briefly describe the problem you are having in a few paragraphs.
-->

When debugging certain binary, pwndbg may show incorrect register value, missing high 32 bit for 64 bit register.
e.g.

```
pwndbg> regs rax
 RAX  0x555c4160
pwndbg> i r rax
rax            0x5555555c4160   93824992690528
pwndbg> telescope $rax
<Could not read memory at 0x555c4160>
pwndbg> regs rsp
 RSP  0xffffffffffffc2f0
pwndbg> i r rsp
rsp            0x7fffffffc2f0   0x7fffffffc2f0
pwndbg> telescope $rsp
<Could not read memory at 0xffffc2f0>
pwndbg>
```

**If I strip the binary, everything goes well.**

After checking code of pwndbg, I found that the bug happens when trying to convert a `gdb.Value` instance to python `int`.

```
pwndbg> python
>print(hex(pwndbg.regs.rsp))
>rsp = pwndbg.regs.value
>print(type(rsp))
>print(rsp.type)
>print(rsp)
>print(hex(rsp))
>print(int(rsp))
>print(long(rsp))
>print(str(rsp))
>print(hex(pwndbg.arch.ptrmask))
>print(hex(int(rsp) & pwndbg.arch.ptrmask))
>end
0xffffffffffffc2f0
<class 'gdb.Value'>
u64
140737488339696
0x7fffffffc2f0
-15632
-15632
140737488339696
0xffffffffffffffff
0xffffffffffffc2f0
```

Seems the `int(value)` works as converting to 32 bit c type int instead of python type int. Maybe we need to use `int(str(value))` to get the correct value.

### 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.
-->

Here is an example binary which can reproduce the bug.

[babi.zip](https://github.com/pwndbg/pwndbg/files/3508243/babi.zip)

1. Execute `babi` with gdb & break at `0x5555555D0C97`.
1. Execute the attached `test.py`.
1. Breakpoint will hit with the bug.

*PS: stop in `libc` or `main` function won't see the bug.*

### My setup

<!--
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
-->

```
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.2 LTS
Release:        18.04
Codename:       bionic
```

```
pwndbg> version
Gdb:      8.1.0.20180409-git
Python:   3.6.8 (default, Jan 14 2019, 11:02:34)  [GCC 8.0.1 20180414 (experimental) [trunk revision 259383]]
Pwndbg:   1.1.0 build: 7f5d8e7
Capstone: 4.0.1024
Unicorn:  1.0.1
```


Discussion:
For whatever reason, when I run babi with test.py, babi errors before hitting the breakpoint.
```
thread 'main' panicked at 'groups: Sys(EPERM)', src/libcore/result.rs:997:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
thread 'main' panicked at 'uid: Sys(EPERM)', src/libcore/result.rs:997:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
```
What commit are you on? The output of version seems to refer to a commit that doesn't exist on the mainline.  Could you test on the latest if you aren't already there?
Sorry, I forget that I've modified pwndbg, which cause the commit id incorrect. I tested again on the latest default `dev` branch and updated the info above.
`babi` may need root permission to execute. It's a challenge from DEF CON CTF 2019 Final and should do no harm. You may run it inside docker to avoid risk.
Thanks for the quick response! I am able to reproduce it when running babi as root.

The problem seems to come from inthook. When doing int, we cast everything to long or ulong, but long and ulong are not ptrsize.

Resolving patch:
diff --git a/pwndbg/inthook.py b/pwndbg/inthook.py
--- a/pwndbg/inthook.py
+++ b/pwndbg/inthook.py
@@ -37,15 +37,15 @@ class xint(with_metaclass(IsAnInt, builtins.int)):
     def __new__(cls, value, *a, **kw):
         if isinstance(value, gdb.Value):
             if pwndbg.typeinfo.is_pointer(value):
-                value = value.cast(pwndbg.typeinfo.ulong)
+                value = value.cast(pwndbg.typeinfo.size_t)
             else:
-                value = value.cast(pwndbg.typeinfo.long)
+                value = value.cast(pwndbg.typeinfo.ssize_t)
 
         elif isinstance(value, gdb.Symbol):
             symbol = value
             value = symbol.value()
             if symbol.is_function:
-                value = value.cast(pwndbg.typeinfo.ulong)
+                value = value.cast(pwndbg.typeinfo.size_t)
 
         elif not isinstance(value, (six.string_types, six.integer_types)) \
                 or isinstance(cls, enum.EnumMeta):
diff --git a/pwndbg/typeinfo.py b/pwndbg/typeinfo.py
--- a/pwndbg/typeinfo.py
+++ b/pwndbg/typeinfo.py
@@ -65,18 +65,22 @@ def update():
     module.int32  = lookup_types('int', 'i32', 'int32')
     module.int64  = lookup_types('long long', 'long', 'i64', 'int64')
 
-    module.ssize_t = module.long
-    module.size_t = module.ulong
-
     module.pvoid  = void.pointer()
     module.ppvoid = pvoid.pointer()
     module.pchar  = char.pointer()
 
     module.ptrsize = pvoid.sizeof
 
-    if pvoid.sizeof == 4: module.ptrdiff = uint32
-    if pvoid.sizeof == 8: module.ptrdiff = uint64
-
+    if pvoid.sizeof == 4: 
+        module.ptrdiff = module.uint32
+        module.size_t = module.uint32
+        module.ssize_t = module.int32
+    elif pvoid.sizeof == 8: 
+        module.ptrdiff = module.uint64
+        module.size_t = module.uint64
+        module.ssize_t = module.int64
+    else:
+        raise Exception('Pointer size not supported')
     module.null = gdb.Value(0).cast(void)
 
 # Call it once so we load all of the types


Test patch: