Skip to content

Commit

Permalink
feat: pwndbg compatibility layer, work on fixing multithread support,…
Browse files Browse the repository at this point in the history
… heap example
  • Loading branch information
ndrewh committed Jun 21, 2024
1 parent 7eb84cd commit 45a6478
Show file tree
Hide file tree
Showing 17 changed files with 1,017 additions and 87 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
build/
cpython/
dynamorio/
Dockerfile
22 changes: 17 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ RUN cd /opt/custom-python/cpython-3.10.12/ && git apply cpython-3.10.12.patch
RUN cd /opt/custom-python/cpython-3.10.12/ && ./configure --prefix=/opt/custom-python-root/ --with-ensurepip=install --enable-shared --with-openssl=/usr/local/ --with-openssl-rpath=auto && \
make install -

ARG PYDA_DEBUG=0
ARG PYDA_DEBUG=1

# install dynamorio
RUN git clone --recurse-submodules -j4 https://github.com/DynamoRIO/dynamorio.git /opt/dynamorio && cd /opt/dynamorio/ && git checkout release_10.0.0
Expand All @@ -32,8 +32,6 @@ ENV DYNAMORIO_HOME=/opt/dynamorio/build/
ENV PYTHONHOME=/opt/custom-python-root/
ENV PYTHONPATH=/opt/custom-python-root/lib/python3.10/:/opt/pyda/lib

RUN pip3 install pwntools

COPY ./ /opt/pyda/
WORKDIR /opt/pyda
RUN mkdir build && cd build && \
Expand All @@ -42,6 +40,20 @@ RUN mkdir build && cd build && \

ENV PATH=$PATH:/opt/pyda/bin

RUN pip3 install pwntools
WORKDIR /tmp

RUN git clone https://github.com/pwndbg/pwndbg.git && \
cd pwndbg && git checkout cada600b0f2be0e2873465f59cc9c4c31425951a && \
sed -i 's/signal.signal/__import__("pls_no_signal").signal/' pwndbg/__init__.py && \
pip3 install -e .

# RUN bash -c "$(wget https://gef.blah.cat/sh -O -)"
# RUN pip3 install pwntools
WORKDIR /opt/pyda

ARG PYDA_GEF=1
RUN bash -c 'if [[ "$PYDA_GEF" = "1" ]]; then \
apt install -y file; \
PYTHONPATH= PYTHONHOME= bash -c "$(wget https://raw.githubusercontent.com/hugsy/gef/main/scripts/gef.sh -O -)"; \
fi'

RUN pip3 install pwntools
2 changes: 1 addition & 1 deletion bin/pyda
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/bash

ROOT=$(dirname "$0")/../
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PYTHONHOME/lib/ PYDA_SCRIPT=$1 $DYNAMORIO_HOME/bin64/drrun -stack_size 1024K -c $ROOT/build/pyda_core/libtool.so ${@:2}
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PYTHONHOME/lib/ PYDA_SCRIPT=$1 PWNLIB_NOTERM=1 $DYNAMORIO_HOME/bin64/drrun -stack_size 1024K -c $ROOT/build/pyda_core/libtool.so ${@:2}
53 changes: 53 additions & 0 deletions examples/heap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from pwn import *
from pyda import *

import pwndbg # must come after pyda import, i think
from termcolor import colored, cprint

import string
import sys

p = process()

e = ELF(p.exe_path)
e.address = p.maps[p.exe_path].base

libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc.address = p.maps[libc.path].base

sym_map = {
libc.symbols["malloc"]: "malloc",
libc.symbols["free"]: "free",
libc.symbols["realloc"]: "realloc",
}

# todo: use dwarf to figure out where tcache pointer is in tls?
# print(f"dwarf: {libc.dwarf}")

def heap_hook(p):
name = sym_map[p.regs.rip]

print(f"{name}(" + ", ".join([
f"rdi={hex(p.regs.rdi)}",
]) + ")")

def after_heap_hook(p):
heap = pwndbg.heap.current
tcachebins = heap.tcachebins()
if tcachebins is not None:
for (s, b) in tcachebins.bins.items():
if len(b.fd_chain) < 2:
continue
print(f"tcache {colored(hex(s), 'yellow')}: ", end="")
print(colored(' -> ', 'yellow').join([hex(x) for x in b.fd_chain]))

print()
else:
print("heap not initialized yet?")


for sym in sym_map:
p.hook(sym, heap_hook)
p.hook_after_call(sym, after_heap_hook)

p.run()
5 changes: 4 additions & 1 deletion lib/pyda/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
from .base import *
import sys, os
from .base import *

sys.path.append(os.path.join(os.path.dirname(__file__), 'hacks'))
24 changes: 24 additions & 0 deletions lib/pyda/arch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

from enum import Enum

ARCH = Enum("Arch", "X86 X64")


def arch():
# todo: arch detection from dynamorio
return ARCH.X64

def gdb_arch():
return {
ARCH.X86: "i386",
ARCH.X64: "i386:x86-64",
}[arch()]

def endianness():
return "little"

def os():
return "linux"

def ptrsize():
return 8
30 changes: 28 additions & 2 deletions lib/pyda/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,32 @@
import pyda_core
from .process import Process
from pyda_core import MemoryError
from .process import Process, Map
from . import arch
import sys

INIT = False

def process():
global INIT

# todo: remove the bogus argument
return Process(pyda_core.process(""))
proc = Process(pyda_core.process(""))

if not INIT:
# by this point, hacks/ is in pythonpath
import pwndbg_compat

INIT = True
if "pwndbg" in sys.modules:
pwndbg_compat.patch_pwndbg(sys.modules["pwndbg"], proc)

return proc

def xinfo(addr):
# print(f"find page: {hex(int(addr))}")
res = pyda_core.get_module_for_addr(addr)
# print(f"res: {res}")
if res is None:
return None
path, start, end, perms = res
return Map(path=path, vaddr=start, size=end - start, perms=perms)
Loading

0 comments on commit 45a6478

Please sign in to comment.