Skip to content

Commit

Permalink
Add optional flags to disable auto-alignment of heap chunks
Browse files Browse the repository at this point in the history
  • Loading branch information
theguy147 committed Aug 3, 2021
1 parent c590f71 commit 2a47ff8
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 28 deletions.
38 changes: 21 additions & 17 deletions docs/commands/heap.md
Expand Up @@ -9,6 +9,9 @@ for `malloc` structure information). Syntax to the subcommands is straight forwa
gef➤ heap <sub_commands>
```

Note that the LOCATION passed to a heap command that optionally accepts one
needs to be aligned to your memory according to glibc's
architecture-specific requirements (usually either 8 or 16 Bytes).

### `heap chunks` command ###

Expand All @@ -19,14 +22,18 @@ gef➤ heap chunks
```

In some cases, the allocation will start immediately from start of the page. If
so, specify the base address of the first chunk as follow:
so, specify the base address of the first chunk as follows:

```
gef➤ heap chunks <LOCATION>
gef➤ heap chunks [LOCATION]
```

![heap-chunks](https://i.imgur.com/2Ew2fA6.png)

Because usually the heap chunks are aligned to a certain number of bytes in
memory GEF automatically re-aligns the chunks data start addresses to match
Glibc's behavior. To be able to view unaligned chunks as well, you can
disable this with the `--allow-unaligned` flag.

### `heap chunk` command ###

Expand All @@ -35,12 +42,15 @@ provide the address to the user memory pointer of the chunk to show the
information related to a specific chunk:

```
gef➤ heap chunk <LOCATION>
gef➤ heap chunk [LOCATION]
```

![heap-chunk](https://i.imgur.com/SAWNptW.png)


Because usually the heap chunks are aligned to a certain number of bytes in
memory GEF automatically re-aligns the chunks data start addresses to match
Glibc's behavior. To be able to view unaligned chunks as well, you can
disable this with the `--allow-unaligned` flag.

### `heap arenas` command ###

Expand All @@ -51,22 +61,19 @@ call the command**.

![heap-arenas](https://i.imgur.com/ajbLiCF.png)



### `heap set-arena` command ###

In cases where the debug symbol are not present (e.g. statically stripped
binary), it is possible to instruct GEF to find the `main_arena` at a different
location with the command:

```
gef➤ heap set-arena <LOCATION>
gef➤ heap set-arena [LOCATION]
```

If the arena address is correct, all `heap` commands will be functional, and use
the specified address for `main_arena`.


### `heap bins` command ###

Glibc uses bins for keeping tracks of `free`d chunks. This is because making
Expand All @@ -77,13 +84,12 @@ single or doubly linked list, I found that quite painful to always interrogate
I decided to implement the `heap bins` sub-command, which allows to get info
on:

- `fastbins`
- `bins`
- `unsorted`
- `small bins`
- `large bins`
- `tcachebins`

- `fastbins`
- `bins`
- `unsorted`
- `small bins`
- `large bins`
- `tcachebins`

#### `heap bins fast` command ####

Expand All @@ -110,15 +116,13 @@ Fastbin[8] 0x00
Fastbin[9] 0x00
```


#### Other `heap bins X` command ####

All the other subcommands (with the exception of `tcache`) for the `heap bins`
work the same way as `fast`. If no argument is provided, `gef` will fall back
to `main_arena`. Otherwise, it will use the address pointed as the base of the
`malloc_state` structure and print out information accordingly.


#### `heap bins tcache` command ####

Modern versions of `glibc` use `tcache` bins to speed up multithreaded
Expand Down
26 changes: 15 additions & 11 deletions gef.py
Expand Up @@ -799,7 +799,7 @@ class GlibcChunk:
address pointed to as the chunk data. Setting from_base to True instead treats that data as the chunk header.
Ref: https://sploitfun.wordpress.com/2015/02/10/understanding-glibc-malloc/."""

def __init__(self, addr, from_base=False, allow_unaligned=False):
def __init__(self, addr, from_base=False, allow_unaligned=True):
self.ptrsize = current_arch.ptrsize
if from_base:
self.data_address = addr + 2 * self.ptrsize
Expand Down Expand Up @@ -6602,24 +6602,26 @@ class GlibcHeapChunkCommand(GenericCommand):
See https://github.com/sploitfun/lsploits/blob/master/glibc/malloc/malloc.c#L1123."""

_cmdline_ = "heap chunk"
_syntax_ = "{:s} LOCATION".format(_cmdline_)
_syntax_ = "{:s} [-h] [--allow-unaligned] LOCATION".format(_cmdline_)

def __init__(self):
super().__init__(complete=gdb.COMPLETE_LOCATION)
return

@parse_arguments({"LOCATION": ""}, {"--allow-unaligned": True})
@only_if_gdb_running
def do_invoke(self, argv):
if not argv:
def do_invoke(self, *args, **kwargs):
args = kwargs["arguments"]
if not args.LOCATION:
err("Missing chunk address")
self.usage()
return

if get_main_arena() is None:
return

addr = to_unsigned_long(gdb.parse_and_eval(argv[0]))
chunk = GlibcChunk(addr)
addr = to_unsigned_long(gdb.parse_and_eval(args.LOCATION))
chunk = GlibcChunk(addr, allow_unaligned=args.allow_unaligned)
gef_print(chunk.psprint())
return

Expand All @@ -6630,32 +6632,34 @@ class GlibcHeapChunksCommand(GenericCommand):
it must correspond to the base address of the first chunk."""

_cmdline_ = "heap chunks"
_syntax_ = "{0} [LOCATION]".format(_cmdline_)
_syntax_ = "{0} [-h] [--allow-unaligned] [LOCATION]".format(_cmdline_)
_example_ = "\n{0}\n{0} 0x555555775000".format(_cmdline_)

def __init__(self):
super().__init__(complete=gdb.COMPLETE_LOCATION)
self.add_setting("peek_nb_byte", 16, "Hexdump N first byte(s) inside the chunk data (0 to disable)")
return

@parse_arguments({"LOCATION": ""}, {"--allow-unaligned": True})
@only_if_gdb_running
def do_invoke(self, argv):
def do_invoke(self, *args, **kwargs):
args = kwargs["arguments"]

if not argv:
if not args.LOCATION:
heap_section = HeapBaseFunction.heap_base()
if not heap_section:
err("Heap not initialized")
return
else:
heap_section = int(argv[0], 0)
heap_section = int(args.LOCATION, 0)

arena = get_main_arena()
if arena is None:
err("No valid arena")
return

nb = self.get_setting("peek_nb_byte")
current_chunk = GlibcChunk(heap_section, from_base=True)
current_chunk = GlibcChunk(heap_section, from_base=True, allow_unaligned=args.allow_unaligned)
while True:
if current_chunk.base_address == arena.top:
gef_print("{} {} {}".format(str(current_chunk), LEFT_ARROW, Color.greenify("top chunk")))
Expand Down

0 comments on commit 2a47ff8

Please sign in to comment.