heaptrace is a ptrace-based debugger for tracking glibc heap operations in ELF64 (x86_64) binaries

Overview

About

heaptrace is a ptrace-based debugger for tracking glibc heap operations in ELF64 (x86_64) binaries. Its purpose is to help visualize heap operations when debugging binaries or doing heap pwn.

screenshot.png

  • Prints out heap operations using symbols instead of pointers. This allows users to understand what is going on on the heap without having to compare pointer values at each operation.
  • Detects some forms of heap corruption, double free vulnerabilities, and memory leakage issues (NOTE: this feature is temporarily disabled).
  • Allows users to set "breakpoints" at any heap operation via --break and --break-after . When heaptrace reaches the requested heap operation number number, it immediately detaches itself from the tracee (the target binary) and attaches the GNU debugger (gdb). This allows users to easily debug the heap interactively at any point.
  • Automatically resolves symbols if available. If the binary is stripped, it attempts to automatically identify function offsets based on function signatures.

Installation

Official Releases

See the .deb and .rpm release files, and a pre-compiled binary at the Releases page.

Arch User Repository (PKGBUILD)

Use your preferred AUR helper to install the heaptrace-git package.

$ trizen -S heaptrace-git

Compile from Source

$ git clone https://github.com/Arinerron/heaptrace.git && cd heaptrace
$ make
$ sudo make install
...
$ heaptrace ./target
$ heaptrace -- ./target -a -f3 # if you have arguments

Usage

You can specify arguments to heaptrace before specifying the binary name:

, --break-after= Similar to `--break`. Replaces the tracer process with gdb, but only after the heap function returns. -F, --follow-fork, --follow Tells heaptrace to detach the parent and follow the child if the target calls fork(), vfork(), or clone(). The default behavior is to detatch the child and only trace the parent. -G , --gdb-path Tells heaptrace to use the path to gdb specified in `path` instead of /usr/bin/gdb (default). -p , --attach , --pid Tells heaptrace to attach to the specified pid instead of running the binary from the `target` argument. Note that if you specify this argument you do not have to specify `target`. -o , --output= Write the heaptrace output to `file` instead of /dev/stderr (which is the default output path). -v, --verbose Prints verbose information such as line numbers in source code given the required debugging info is stored in the ELF. -h, --help Shows this help menu. ">
Usage:
  ./heaptrace [options...] 
           
            
  ./heaptrace [options...] -- 
            
              [args...]
  ./heaptrace [options...] -p/--attach 
             
              

Options:
  -e 
              
               , --environ=
               
                , --environment=
                
                  Sets a single environmental variable. Useful for setting runtime settings for the target such as LD_PRELOAD=./libc.so.6 without having them affect heaptrace's runtime configuration. -s 
                 
                  , --symbols=
                  
                    Override the values heaptrace detects for the malloc/calloc/free/realloc/reallocarray symbols. Useful if heaptrace fails to automatically identify heap functions in a stripped binary. See the wiki for more info. -b 
                   
                    , --break=
                    
                     , --break-at=
                     
                       Send SIGSTOP to the process at heap operation specified in `number` (before executing the heap function) and attach the GNU debugger (gdb) to the process. Also supports "segfault" in the `number` arg to launch gdb if the process exits abnormally (SIGSEGV, abort(), etc). And, "main" will break at the entry point to the binary (the binary's auxiliary vector). -B 
                      
                       , --break-after=
                       
                         Similar to `--break`. Replaces the tracer process with gdb, but only after the heap function returns. -F, --follow-fork, --follow Tells heaptrace to detach the parent and follow the child if the target calls fork(), vfork(), or clone(). The default behavior is to detatch the child and only trace the parent. -G 
                        
                         , --gdb-path 
                         
                           Tells heaptrace to use the path to gdb specified in `path` instead of /usr/bin/gdb (default). -p 
                          
                           , --attach 
                           
                            , --pid 
                            
                              Tells heaptrace to attach to the specified pid instead of running the binary from the `target` argument. Note that if you specify this argument you do not have to specify `target`. -o 
                             
                              , --output=
                              
                                Write the heaptrace output to `file` instead of /dev/stderr (which is the default output path). -v, --verbose Prints verbose information such as line numbers in source code given the required debugging info is stored in the ELF. -h, --help Shows this help menu. 
                              
                             
                            
                           
                          
                         
                        
                       
                      
                     
                    
                   
                  
                 
                
               
              
             
            
           

For example, if you wanted to automatically attach gdb at operation #3, you would execute:

heaptrace --break=3 ./my-binary

See the wiki documentation for more information on how to use the -s/--symbol argument to debug stripped binaries that heaptrace failed to automatically identify functions in.

Support

I'm happy to help if you experience a bug or have any feedback. Please see the GitHub Issues page.

Comments
  • Enhance: handle non-deterministic heap operations

    Enhance: handle non-deterministic heap operations

    Since this project invokes gdb later, it's this project's job to decide when the wanted program state is achieved and then launches gdb for debugging. The current approach, counting heap operation numbers, is not a reliable way to determine program state because real-world programs may invoke different numbers of heap operations each time to reach a specific program state (for example, initialization code behaves differently each time).

    I suggest supporting another interface that allows users to set a breakpoint at a specific address and using the times this breakpoint is invoked as an indicator whether the execution should be passed to gdb.

    enhancement 
    opened by Kyle-Kyle 8
  • Todo notes for self

    Todo notes for self

    I was in bed thinking about these and decided to write them down

    • make sure we're using size calculated from request2size to check ret vals. Update bst code to search for it -- nvm if we warn about this, we also have to track consolidation which is rly complicated. not worth it for now.
    • notify user if malloc etc returns pointer inside glibc/elf. This prob means we pwned the chal -- done
    • Add support for attach to pid -- done
    • Make it so we can trace both parent and.child at once. Copy context just change pid lol. Oh also copy all the heap stuff ofc -- this is harder than it sounds. We need to fork() to be able to waitpid both pids
    opened by Arinerron 8
  • heaptrace error: Failed to find target binary in process mapping (!bin_pme). Please report this!

    heaptrace error: Failed to find target binary in process mapping (!bin_pme). Please report this!

    Hi.

    Awesome project, really MUSTHAVE!

    But I catch some troubles:

    1. It doesn't compile because of undefined sigabbrev_np() Quick reading of man sigabbrev_np push me to change it to strsignal(), the binary compiled ok.

    But it doesn't launch with any attrs throwing the message from header.

    Checked on libc-2.31.so and libc-2.28.so. Same results.

    I didn't find any information about minimal required libc version. Am I was looking bad?

    Thanks.

    bug 
    opened by kotee4ko 5
  • Add support for statically linked binaries

    Add support for statically linked binaries

    Make a heaptrace program (not shared lib) with similar syntax to that of ltrace and add support for statically linked binaries.

    • If the target binary is dynamically linked, use LD_PRELOAD=./heaptrace.so automatically as this is significantly more reliable/less hacky. Pass the argv before the target binary's name/args to HEAPTRACE_ARGS environ var.

    • Otherwise, print an "unstable" warning. Then, resolve malloc/free/realloc symbols (require user to specify addresses if any syms aren't defined), use ptrace to set an int3 breakpoint at those functions, and, when breakpoints get hit, call the malloc/free/realloc tracing functions.

      The orig_malloc/orig_free/orig_realloc functions in the static version of heaptrace should just resume execution until a ret, at which point it should get its return value (if relevant) and continue executing the tracing function. Once the tracing function is done, it should remove the relevant ret breakpoint and continue execution as if nothing ever happened.

    enhancement help wanted 
    opened by Arinerron 5
  • Catch reallocarray's overflow failure and warn

    Catch reallocarray's overflow failure and warn

           However,  unlike  that  realloc()  call, reallocarray() fails safely in the case where the multiplication
           would overflow.  If such an overflow occurs, reallocarray() returns  NULL,  sets  errno  to  ENOMEM,  and
           leaves the original block of memory unchanged.
    
    enhancement 
    opened by Arinerron 4
  • Untracked pointer passed to reallocarray()&free() when tracing /bin/sh

    Untracked pointer passed to reallocarray()&free() when tracing /bin/sh

    I think it's prob because it exec()s

    ... #2843: malloc(0x20)		=  0x555555681e70
    ... #2844: malloc(0x03)		=  0x555555681ea0
    ... #2845: malloc(0x30)		=  0x555555681ec0
    ... #2846: malloc(0x08)		=  0x555555681f00
    ... #2847: malloc(0x08)		=  0x555555681f20
    ... #2848: malloc(0x20)		=  0x555555681f40
    ... #2849: malloc(0x04)		=  0x555555681f70
    ... #2850: malloc(0x7f0)		=  0x555555681f90
    ... #2851: malloc(0xff0)		=  0x555555682790
    ... #2852: malloc(0x06)		=  0x555555683790
    ... #2853: malloc(0x18)		=  0x5555556838d0
    ... #2854: malloc(0x18)		=  0x5555556838f0
    ... #2855: malloc(0x0c)		=  0x555555683910
    ... #2856: free(0x0)
    ... #2857: malloc(0x5e)		=  0x5555556705c0
    ... #2858: free(0x555555683960)
        |-- warning: freeing a pointer to unknown chunk
    ... #2859: malloc(0x1d8)		=  0x55555564d4d0
    ... #2860: malloc(0x1000)		=  0x555555683c40
    ... #2861: malloc(0x617)		=  0x555555684c50
    ... #2862: reallocarray(0x555555685270, 0x2e, 0x1e8)	
        |-- warning: attempting to reallocarray a chunk that was never allocated
    =  0x555555685270
    
    heaptrace error: heaptrace segfaulted. Please re-run with --debug and report this.
    
    bug 
    opened by Arinerron 3
  • heaptrace does not handle non-existing/non-executables well

    heaptrace does not handle non-existing/non-executables well

    heaptrace [ptrace] % ./heaptrace this-does-not-exist
    ================================ BEGIN HEAPTRACE ===============================
    
    [1]    738632 segmentation fault (core dumped)  ./heaptrace this-does-not-exist
    
    opened by Arinerron 3
  • Find a better way to get process mapping

    Find a better way to get process mapping

    Right now I have absolute trash of a hack code @ https://github.com/Arinerron/heaptrace/blob/main/src/debugger.c#L177 and https://github.com/Arinerron/heaptrace/blob/main/src/debugger.c#L109 to parse /proc/pid/maps. I need to find a better way to get the information (file path, address start, address end).

    I'd appreciate any tips if anyone knows of a way to get that information other than /proc/pid/maps

    enhancement help wanted research 
    opened by Arinerron 2
  • have BEGIN HEAPTRACE msg print program name

    have BEGIN HEAPTRACE msg print program name

    some programs fork() and execute another binary, so we get two+ BEGIN HEAPTRACE messages. It's not clear which is which. There's not really an easy solution to this, but it'd be helpful if it at least specified which program is which so it's easy to tell what's going on

    opened by Arinerron 2
  • Make `show_stats` only print out heap funcs that have non-zero calls

    Make `show_stats` only print out heap funcs that have non-zero calls

    Statistics:
    ... mallocs count: 7
    ... callocs count: 1
    ... frees count: 3
    ... reallocs count: 0
    ... reallocarrays count: 0
    

    | | V

    Statistics:
    ... mallocs count: 7
    ... callocs count: 1
    ... frees count: 3
    
    enhancement good first issue 
    opened by Arinerron 1
  • Visually distinguish between heap func calls from binary v.s. libraries

    Visually distinguish between heap func calls from binary v.s. libraries

    Just check if the return addr is in range of the ELF's start-end. If so, it's from binary. If not, it's from the ELF.

    Not sure how to best visualize this info yet. Maybe bold for ELF and not bold for libraries? Not very intuitive...

    enhancement good first issue 
    opened by Arinerron 1
  • Way to break when using a piped input

    Way to break when using a piped input

    Hello,

    my program takes input via a pipe, for example:

    cat input | heaptrace ./program

    This works without --break. When i try to --break, gdb instantly takes the input as commands (probably the remaining of input), and does quit out from the debugger. Is there a way to keep the debugger alive, or to not parse the piped input as gdb commands? Normaly there would be the run < input command in gdb, but this is not realy the value which would be provided by heaptrace breakpoints.

    Thanks for your help

    opened by GanbaruTobi 0
  • Use toolchain variables from execution environment if present

    Use toolchain variables from execution environment if present

    This PR patches the Makefile such that toolchain environment variables (CC, CFLAGS, ...) take precedence over the default values in the Makefile. This makes the work of distribution packagers more easy as the values don't have to be explicitly specified in the call of make.

    opened by hamarituc 0
  • AUR checksum not passing.

    AUR checksum not passing.

    Put a quick description of what happens here. What do you expect to happen? What happens instead?

    • Full output when run with --debug:
    (link to pastebin if it's long, please)
    Repository      : AUR
    Name            : heaptrace
    Version         : 2.2.8-1
    Maintainer      : arinerron
    URL             : https://github.com/Arinerron/heaptrace
    AUR URL         : https://aur.archlinux.org/packages/heaptrace
    License         : BSD
    Votes           : 0
    Popularity      : 0%
    Installed       : No
    Out Of Date     : No
    Depends On      : None
    Make Deps       : None
    Check Deps      : None
    Optional Deps   : None
    Provides        : None
    Conflicts With  : None
    Replaces        : None
    Package Base    : heaptrace
    Last Update     : Tue Dec  7 21:48:18 2021
    Description     : helps visualize heap operations for pwn and debugging
    
    ==> Making package: heaptrace 2.2.8-1 (Thu 12 May 2022 10:22:42 PM EDT)
    ==> Checking runtime dependencies...
    ==> Checking buildtime dependencies...
    ==> Retrieving sources...
      -> Downloading heaptrace-heaptrace...
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
      0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
    100 1051k  100 1051k    0     0  2066k      0 --:--:-- --:--:-- --:--:-- 3360k
      -> Downloading heaptrace-heaptrace.1...
      % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  2905  100  2905    0     0  15083      0 --:--:-- --:--:-- --:--:-- 15130
    ==> Validating source_x86_64 files with sha256sums...
        heaptrace-heaptrace ... Passed
        heaptrace-heaptrace.1 ... FAILED
    ==> ERROR: One or more files did not pass the validity check!
    :: Unable to build heaptrace - makepkg exited with code: 1
    

    Expected behavior: Package passes checksum Current behavior: Fails checksum

    Tried: Downloading it.

    bug 
    opened by Exiled1 1
  • Investigation:

    Investigation: "warning: return value is not a heap pointer"

    ... #471: malloc(0x18)                                                                              = 0x7ffff792da40 
    ... #472: malloc(0x18) 
        |-- warning: return value is not a heap pointer
        |   * this indicates some form of heap corruption
        |   * pointer is inside of section "<malware>" (0x555555554000-0x5555555f8000)                                           
    

    when I run it on the malware it:

    • doesn't bold the "warning" heading
    • returns a chunk inside of the elf?? todo investigate
    opened by Arinerron 0
Releases(2.2.8)
Owner
Aaron Esau
Aaron Esau
HyperDbg debugger is an open-source, hypervisor-assisted user-mode, and kernel-mode Windows debugger 🐞

HyperDbg debugger is an open-source, hypervisor-assisted user-mode, and kernel-mode Windows debugger with a focus on using modern hardware technologies. It is a debugger designed for analyzing, fuzzing and reversing. ??

HyperDbg 2k Dec 30, 2022
With xshellex you can paste any kind of c-shellcode strings in x64dbg, ollydbg & immunity debugger

With xshellex you can paste any kind of c-shellcode strings in x64dbg, ollydbg & immunity debugger. Also you can convert the "binary-copied-clipboard" to c-shellcode string.

David Reguera Garcia aka Dreg 30 Oct 7, 2022
Palanteer is a set of high performance visual profiler, debugger, tests enabler for C++ and Python

Palanteer is a set of lean and efficient tools to improve the general software quality, for C++ and Python programs.

Damien Feneyrou 1.9k Dec 29, 2022
A Garry's Mod module that creates a Remote DeBugger server

gm_rdb A Garry's Mod module that creates a Remote DeBugger server. Provides Lua debugging (using LRDB) and access to the Source engine console. Compil

Daniel 14 Jul 7, 2022
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows and Linux.

The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows and Linux.

null 12.1k Jan 2, 2023
Templight 2.0 - Template Instantiation Profiler and Debugger

Templight is a Clang-based tool to profile the time and memory consumption of template instantiations and to perform interactive debugging sessions to gain introspection into the template instantiation process.

Sven Mikael Persson 611 Dec 30, 2022
A small, educational debugger with no dependencies

smldbg A small, educational debugger with no dependencies. Prerequisites To build the project and run the tests, the following are required: A C++20 c

null 3 Jun 16, 2022
An efficient OpenFST-based tool for calculating WER and aligning two transcript sequences.

fstalign Overview Installation Dependencies Build Docker Quickstart WER Subcommand Align Subcommand Inputs Outputs Overview fstalign is a tool for cre

Rev 108 Dec 12, 2022
Hypervisor based anti anti debug plugin for x64dbg

HyperHide Table of Contents Description Compilation Support Usage Information Examples Features 1. Process Environment Block (PEB) 2. Heap Flags 3. Pr

Air 677 Jan 8, 2023
A tool to automatically benchmark the most performant core based on X% lows/percentile fps in lava-lamp.

AutoGpuAffinity A tool to automatically benchmark the best physical CPU for the GPU to execute dpcs/isrs on based on 0.1% percentile/lows fps. Tips to

AMIT 0 Jun 12, 2022
Debug heap useful for tracking down memory errors.

ig-debugheap - A debugging heap This is a debug heap useful when trying to track down memory errors (especially on Windows, where there's no Valgrind.

Andreas Fredriksson 168 Dec 3, 2022
libcurses and dependencies taken from netbsd and brought into a portable shape (at least to musl or glibc)

netbsd-libcurses portable edition this is a port of netbsd's curses library for usage on Linux systems (tested and developed on sabotage linux, based

null 124 Nov 7, 2022
HyperDbg debugger is an open-source, hypervisor-assisted user-mode, and kernel-mode Windows debugger 🐞

HyperDbg debugger is an open-source, hypervisor-assisted user-mode, and kernel-mode Windows debugger with a focus on using modern hardware technologies. It is a debugger designed for analyzing, fuzzing and reversing. ??

HyperDbg 2k Dec 30, 2022
RV-Debugger-BL702 is an opensource project that implement a JTAG+UART debugger with BL702C-A0.

BL702 is highly integrated BLE and Zigbee combo chipset for IoT applications, contains 32-bit RISC-V CPU with FPU, frequency up to 144MHz, with 132KB RAM and 192 KB ROM, 1Kb eFuse, 512KB embedded Flash, USB2.0 FS device interface, and many other features.

Sipeed 100 Jan 1, 2023
A refactored Proof-of-concept originally developed in 2017 to print all function calls with their arguments data types and values using Ptrace during program execution.

print-function-args-debugger A refactored Proof-of-concept originally developed in 2017 to print all function calls with their arguments data types an

*finixbit 15 Jun 17, 2022
A simple Linux kernel module that kills ptrace tracer and its tracees

dont_trace dont_trace is a simple Linux kernel module that kills ptrace tracer and its tracees. This kernel module relies upon the Linux kernel task_s

null 5 Mar 31, 2022
use ptrace hook Hotspot JavaVM, instrument java bytecode

taycan 通过native层修改java层(JVM),使用JVMTI及JNI API可以修改java任意类、执行任意代码,完成hook、插入内存马、反射等功能。 适用环境 LINUX KERNEL version > 3.2 GLIBC > 2.15 openJDK/OracleJDK 1.8

null 26 Jul 12, 2022
PoC for CVE-2021-3156 (sudo heap overflow)

CVE-2021-3156 PoC for CVE-2021-3156 (sudo heap overflow). Exploit by @gf_256 aka cts. Thanks to r4j from super guesser for help. Credit to Braon Samed

Stephen Tong 433 Jan 4, 2023
A ring buffer designed to work with embedded devices, does not use heap allocations.

Embedded Ring Buffer This is a header only ring buffer that is designed to work on embedded devices, it is able to handle non-blocking ISR spooling

Richard Bamford 49 Dec 2, 2022
Simple min heap timer

KTimer simple useable heap timer . Samples #include "ktimer.h" ktimer::KTimer<std::chrono::seconds, std::mutex> myTimer ; //default ktimer::KTimer<>

cageq 4 Nov 25, 2022