Skip to content

Commit

Permalink
pretty printer
Browse files Browse the repository at this point in the history
  • Loading branch information
matrix1001 committed Oct 30, 2018
1 parent a0e148b commit 1965da3
Show file tree
Hide file tree
Showing 8 changed files with 201 additions and 55 deletions.
151 changes: 129 additions & 22 deletions HeapInspect.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from proc_util import *
from libc_util import *
from auxiliary import *
import struct
import re
import sys
import os

def u64(data):
return struct.unpack('<Q', data.ljust(8, '\0'))[0]
Expand Down Expand Up @@ -350,35 +352,140 @@ def whereis(self, addr):
return mapname
return ''

class PrettyPrinter(object):
def __init__(self, hi, relative=False):
self.hi = hi
self.relative = relative

@property
def fastbins(self):
lines = []
header_fmt = color.green('({size:#x}) fastbins[{index}] ')
for index in sorted(self.hi.fastbins.keys()):
size = 2*self.hi.size_t * (index+2)
chunks = self.hi.fastbins[index]
tail = ''
for chunk in chunks:

tail += "-> " + color.blue("{:#x} ".format(chunk._addr))
line = header_fmt.format(size=size, index=index) + tail
if tail != '':lines.append(line)

return '\n'.join(lines)

@property
def unsortedbins(self):
head = color.magenta('unsortedbins: ')
tail = ''
for chunk in self.hi.unsortedbins:
tail += '<-> ' + color.blue("{:#x} ".format(chunk._addr))
if tail == '': tail = color.blue('None')

return head+tail

@property
def smallbins(self):
lines = []
header_fmt = color.green('({size:#x}) smallbins[{index}] ')
for index in sorted(self.hi.smallbins.keys()):
size = 2*self.hi.size_t * (index+1)
chunks = self.hi.smallbins[index]
tail = ''
for chunk in chunks:
tail += "<-> " + color.blue("{:#x} ".format(chunk._addr))
line = header_fmt.format(size=size, index=index-1) + tail
if tail != '':lines.append(line)

return '\n'.join(lines)

@property
def largebins(self):
lines = []
header_fmt = color.green('largebins[{index}] ')
for index in sorted(self.hi.largebins.keys()):
size = 2*self.hi.size_t * (index+1)
chunks = self.hi.largebins[index]
tail = ''
for chunk in chunks:
tail += "<-> " + color.blue("{:#x}".format(chunk._addr) + color.green("({:#x}) ".format(chunk.size & ~0b111)))
line = header_fmt.format(size=size, index=index-0x3f) + tail
if tail != '':lines.append(line)

return '\n'.join(lines)

@property
def tcache_chunks(self):
lines = []
header_fmt = color.yellow('({size:#x}) entries[{index}] ')
for index in sorted(self.hi.tcache_chunks.keys()):
size = 4*self.hi.size_t + index*0x10
chunks = self.hi.tcache_chunks[index]
tail = ''
for chunk in chunks:
tail += "-> " + color.blue("{:#x} ".format(chunk._addr+2*self.hi.size_t))
line = header_fmt.format(size=size, index=index) + tail
if tail != '':lines.append(line)

return '\n'.join(lines)

@property
def all(self):
lines = [self.banner('HeapInspect', 'green')]
lines.append(self.basic)
lines.append(self.fastbins)
lines.append(self.smallbins)
lines.append(self.largebins)
lines.append(self.tcache_chunks)
lines.append(color.magenta('top: ') + color.blue('{:#x}'.format(self.hi.main_arena.top)))
lines.append(color.magenta('last_remainder: ') + color.blue('{:#x}'.format(self.hi.main_arena.last_remainder)))
lines.append(self.unsortedbins)

return '\n'.join(lines)

@property
def basic(self):
return '''libc_version:{}
arch:{}
tcache_enable:{}
libc_base:{}
heap_base:{}'''.format(
color.yellow(self.hi.libc_version),
color.yellow(self.hi.arch),
color.yellow(self.hi.tcache_enable),
color.blue(hex(self.hi.libc_base)),
color.blue(hex(self.hi.heap_base)))


def banner(self, msg, color1='white'):
w, h = terminal_size()
return color.__getattr__(color1)('{:=^{width}}'.format(' {} '.format(msg), width=w))

if __name__ == '__main__':
pid = int(sys.argv[1])
hi = HeapInspector(pid)
r = hi.record
print("libc version:{} arch:{} tcache_enable:{} libc_base:{:#x} heap_base:{:#x}".format(
r.libc_version,
r.arch,
r.tcache_enable,
r.libc_base,
r.heap_base))
#print()

#hs = HeapShower(r)
#print(hs.heap_chunks)
#print(hs.fastbins)
#print(hs.unsortedbins)
#print(hs.smallbins)
#print(hs.largebins)
#print(hs.tcache_chunks)

#print('\nrelative mode\n')
#hs.relative = True
#print(hs.heap_chunks)
#print(hs.fastbins)
#print(hs.unsortedbins)
#print(hs.smallbins)
#print(hs.largebins)
#print(hs.tcache_chunks)

pp = PrettyPrinter(r)
print(pp.all)

hs = HeapShower(r)
print(hs.heap_chunks)
print(hs.fastbins)
print(hs.unsortedbins)
print(hs.smallbins)
print(hs.largebins)
print(hs.tcache_chunks)

print('\nrelative mode\n')
hs.relative = True
print(hs.heap_chunks)
print(hs.fastbins)
print(hs.unsortedbins)
print(hs.smallbins)
print(hs.largebins)
print(hs.tcache_chunks)



Expand Down
42 changes: 9 additions & 33 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,41 +29,13 @@ __Now support multi glibc (tested on 2.23-2.27, both x64 and x86)__
## Quick shot

A quick use of this tool.
```raw
heapinspect $ python HeapInspect.py 7018
libc version:2.19 arch:32 tcache_enable:False libc_base:0xf7d36000 heap_base:0xf8e97000
========================= heapchunks =========================
chunk(0xf8e97000): prev_size=0x0 size=0x2c1 fd=0xf7edd450 bk=0xf8e97318
chunk(0xf8e972c0): prev_size=0x2c0 size=0x58 fd=0x0 bk=0x0
chunk(0xf8e97318): prev_size=0x0 size=0x59 fd=0xf8e97000 bk=0xf7edd450
chunk(0xf8e97370): prev_size=0x58 size=0x58 fd=0x0 bk=0x0
chunk(0xf8e973c8): prev_size=0x0 size=0x20c39 fd=0x0 bk=0x0
========================= fastbins =========================
========================= unsortedbins =========================
chunk(0xf8e97000): prev_size=0x0 size=0x2c1 fd=0xf7edd450 bk=0xf8e97318
chunk(0xf8e97318): prev_size=0x0 size=0x59 fd=0xf8e97000 bk=0xf7edd450
========================= smallbins =========================
========================= largebins =========================
========================= tcache =========================

relative mode
========================= relative heapchunks =========================
chunk(heap+0x0 ): prev_size=0x0 size=0x2c1 fd=libc+0x1a7450 bk=heap+0x318
chunk(heap+0x2c0 ): prev_size=0x2c0 size=0x58 fd=0x0 bk=0x0
chunk(heap+0x318 ): prev_size=0x0 size=0x59 fd=heap+0x0 bk=libc+0x1a7450
chunk(heap+0x370 ): prev_size=0x58 size=0x58 fd=0x0 bk=0x0
chunk(heap+0x3c8 ): prev_size=0x0 size=0x20c39 fd=0x0 bk=0x0
========================= relative fastbins =========================
========================= relative unsortedbins =========================
chunk(heap+0x0 ): prev_size=0x0 size=0x2c1 fd=libc+0x1a7450 bk=heap+0x318
chunk(heap+0x318 ): prev_size=0x0 size=0x59 fd=heap+0x0 bk=libc+0x1a7450
========================= relative smallbins =========================
========================= relative largebins =========================
========================= relative tcache =========================
![pp1](img/pp1.png)

![pp2](img/pp2.png)

![pp3](img/pp3.png)

```

## Basic

Expand All @@ -87,6 +59,9 @@ print(hs.fastbins)
sleep(10)
#now assume that the heap state has changed
hs.hi = hi.record #use this to refresh. if you used `hs = HeapShower(hi)`, no need of this.

pp = PrettyPrinter(hi.record)
print(pp.all) #pretty printer
```

## Test
Expand Down Expand Up @@ -144,6 +119,7 @@ next version will be a release.
- CRLF to LF
- code refine
- readme refine
- pretty printer

## 2018/10/29 version 0.0.7

Expand Down
2 changes: 2 additions & 0 deletions auxiliary/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from ezcolor import color
from utils import terminal_size
55 changes: 55 additions & 0 deletions auxiliary/ezcolor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#https://github.com/matrix1001/ezcolor
class Color:
def __init__(self):
self._colors = {
'black': 0,
'red': 1,
'green': 2,
'yellow': 3,
'blue': 4,
'magenta': 5,
'cyan': 6,
'white': 7,
}
self._style = {
'default': 0,
'bold': 1,
'light': 2,
'on': 3,
'underline':4,
'on2': 5,
}
self._fg = 30
self._bg = 40

self.fmt = u'\033[{style};{fg};{bg}m{msg}\033[m'
def __getattr__(self, attr):
'''sample: bold_red_bg_blue'''
style = self._style['default']
fg = self._colors['white'] + self._fg
bg = self._colors['black'] + self._bg
lst = attr.split('_')

ind = 0
while ind < len(lst):
if lst[ind] in self._style:
style = self._style[lst[0]]
elif lst[ind] in self._colors:
fg = self._colors[lst[ind]] + self._fg
elif lst[ind] == 'bg':
assert ind+1 < len(lst)
assert lst[ind+1] in self._colors
color = lst[ind+1]
bg = self._colors[color] + self._bg
ind += 1
else:
raise Exception('no such color')
ind += 1
def format(msg):
return self.fmt.format(style=style, fg=fg, bg=bg, msg=msg)
return format

color = Color()
if __name__ == '__main__':
print(color.on_red('test red'))
print(color.bold_red_bg_white('test 2'))
6 changes: 6 additions & 0 deletions auxiliary/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def terminal_size():
import fcntl, termios, struct
h, w, hp, wp = struct.unpack('HHHH',
fcntl.ioctl(0, termios.TIOCGWINSZ,
struct.pack('HHHH', 0, 0, 0, 0)))
return w, h
Binary file added img/pp1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/pp2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added img/pp3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 1965da3

Please sign in to comment.