pwndbg / pwndbg

Exploit Development and Reverse Engineering with GDB Made Easy
https://pwndbg.re/
MIT License
7.22k stars 867 forks source link

IDA Pro Integration - library support #193

Closed cloudburst closed 1 month ago

cloudburst commented 7 years ago

I don't really know enough about pwndbg internals to fully debug this, so this may be user error and not an issue.

I'm running into an issue with the IDA Pro integration. Specifically the ida_script converts the EA using pwndbg.ida.l2r() and r2l(). The problem is that these just grab the vmmap for the initial exe/process:

def l2r(addr): 
    exe = pwndbg.elf.exe()
    if not exe:
        raise Exception("Can't find EXE base")
    result = (addr - int(exe.address) + base()) & pwndbg.arch.ptrmask

So this fails once you start stepping into anything else in the vmmap (such as a library).

AKA gdb.selected_frame().pc() is pointing inside a library vmmap that does not include the initial ELF pwndbg.elf.exe().address

Initial thoughts are maybe l2r() would need to be patched to support passing in a base address?

Or maybe the pwndbg.elf object has functionality to see if current pc() falls within the vmmap for elf.exe() and if not searches the vmmap for the pc() instead.

zachriggle commented 7 years ago

I think we can do this by fetching the object name for the current mapping, and checking if it matches the original file used to create the IDB. If none match, we can just fall back on the EXE or do something more complex like byte matching.

Thanks for the report! On Tue, Mar 28, 2017 at 8:03 PM cloud notifications@github.com wrote:

I don't really know enough about pwndbg internals to fully debug this, so this may be user error and not an issue.

I'm running into an issue with the IDA Pro integration. Specifically the ida_script converts the EA using pwndbg.ida.l2r() and r2l(). The problem is that these just grab the vmmap for the initial exe/process:

def l2r(addr): exe = pwndbg.elf.exe() if not exe: raise Exception("Can't find EXE base") result = (addr - int(exe.address) + base()) & pwndbg.arch.ptrmask

So this fails once you start stepping into anything else in the vmmap (such as a library).

AKA gdb.selected_frame().pc() is pointing inside a library vmmap that does not include the initial ELF pwndbg.elf.exe().address

Initial thoughts are maybe l2r() would need to be patched to support passing in a base address?

Or maybe the pwndbg.elf object has functionality to see if current pc() falls within the vmmap for elf.exe() and if not searches the vmmap for the pc() instead.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/pwndbg/pwndbg/issues/193, or mute the thread https://github.com/notifications/unsubscribe-auth/AAG0GKSnFAuMa3o8vcPHyT62PdU1QwN6ks5rqa3jgaJpZM4MsYJp .

cloudburst commented 7 years ago

This is a really terrible patch just to illustrate the issue (and semi-fixes it for me).

diff --git a/pwndbg/ida.py b/pwndbg/ida.py
index 9a9e71a..048707e 100644
--- a/pwndbg/ida.py
+++ b/pwndbg/ida.py
@@ -100,7 +100,15 @@ def l2r(addr):
     exe = pwndbg.elf.exe()
     if not exe:
         raise Exception("Can't find EXE base")
-    result = (addr - int(exe.address) + base()) & pwndbg.arch.ptrmask
+    # pc is outside the range of the EXE
+    lower_bound = exe.address
+    upper_bound = lower_bound + pwndbg.vmmap.find(pwndbg.elf.exe().address).memsz
+    pc = gdb.selected_frame().pc()
+    if (pc > upper_bound) or (pc < lower_bound):
+        lib_base = pwndbg.vmmap.find(pc).vaddr
+        result = (addr - lib_base + base()) & pwndbg.arch.ptrmask
+    else:
+        result = (addr - int(exe.address) + base()) & pwndbg.arch.ptrmask
     return result

@@ -108,7 +116,15 @@ def r2l(addr):
     exe = pwndbg.elf.exe()
     if not exe:
         raise Exception("Can't find EXE base")
-    result = (addr - base() + int(exe.address)) & pwndbg.arch.ptrmask
+    # pc is outside the range of the EXE
+    lower_bound = exe.address
+    upper_bound = lower_bound + pwndbg.vmmap.find(pwndbg.elf.exe().address).memsz
+    pc = gdb.selected_frame().pc()
+    if (pc > upper_bound) or (pc < lower_bound):
+        lib_base = pwndbg.vmmap.find(pc).vaddr
+        result = (addr - base() + lib_base) & pwndbg.arch.ptrmask
+    else:
+        result = (addr - base() + int(exe.address)) & pwndbg.arch.ptrmask
     return result

Your comment sounds way better.

zachriggle commented 7 years ago

Yes, much easier.

>>> pwndbg.vmmap.find(pwndbg.regs.pc).objfile
'/bin/bash'
cloudburst commented 7 years ago

How about not using the exe at all? This works on my setup but I don't know if there are some other situations where the exe would be needed:

  def l2r(addr):                                                                                                                                              
      vaddr = pwndbg.vmmap.find(pwndbg.regs.pc).vaddr                                                                                                         
      return (addr - vaddr + base()) & pwndbg.arch.ptrmask     

  def r2l(addr):                                                                                                                                              
      vaddr = pwndbg.vmmap.find(pwndbg.regs.pc).vaddr                                                                                                         
      return (addr - base() + vaddr) & pwndbg.arch.ptrmask
zachriggle commented 7 years ago

The issue with doing it that way is that we need to know which library we've stepped into. For example, if we step into libc but the IDB that's open is for bash, we don't want to jump to the address equivalent to the offset-from-libc-base in the bash IDB. We need a way to detect which ELF file is open in the IDB. The easiest way to do that is filename matching of the original file, followed by some fuzzy matching of read-only pages, and finally just defaulting to the main EXE.

disconnect3d commented 1 month ago

This issue is so old that I think it was either fixed at some point or IDA integration is not working with recent IDA versions. Closing this for now.