Skip to content

Commit

Permalink
Change hexdump_iter to not rely on the length of its input file
Browse files Browse the repository at this point in the history
We cannot determine the length of the file if passed e.g. a tube or a pipe or
or PTY or character device (e.g. stdin or /dev/null).
  • Loading branch information
zachriggle committed Jan 12, 2017
1 parent f792407 commit 14f717b
Showing 1 changed file with 26 additions and 22 deletions.
48 changes: 26 additions & 22 deletions pwnlib/util/fiddling.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from pwnlib.util import lists
from pwnlib.util import packing
from pwnlib.util.cyclic import cyclic
from pwnlib.util.cyclic import de_bruijn
from pwnlib.util.cyclic import cyclic_find

log = getLogger(__name__)
Expand Down Expand Up @@ -562,13 +563,15 @@ def _hexiichar(c):
}

cyclic_pregen = ''
de_bruijn_gen = de_bruijn()

def sequential_lines(a,b):
return (a+b) in cyclic_pregen

def update_cyclic_pregenerated(size):
global cyclic_pregen
cyclic_pregen = cyclic(size)
while size > len(cyclic_pregen):
cyclic_pregen += de_bruijn_gen.next()

def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
highlight=None, cyclic=False):
Expand Down Expand Up @@ -600,6 +603,12 @@ def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
>>> print '\n'.join(hexdump_iter(tmp))
00000000 48 45 4c 4c 4f 2c 20 57 4f 52 4c 44 │HELL│O, W│ORLD││
0000000c
>>> t = tube()
>>> t.unrecv('I know kung fu')
>>> print '\n'.join(hexdump_iter(t))
00000000 49 20 6b 6e 6f 77 20 6b 75 6e 67 20 66 75 │I kn│ow k│ung │fu│
0000000e
"""
style = style or {}
highlight = highlight or []
Expand All @@ -621,23 +630,6 @@ def hexdump_iter(fd, width=16, skip=True, hexii=False, begin=0, style=None,
spacer = ' '
marker = (style.get('marker') or (lambda s:s))('│')

# Total length of the input stream
total = 0

if hasattr(fd, 'len'):
total = fd.len
else:
# Save the current file offset
cur = fd.tell()

# Determine the total size of the file
fd.seek(0, os.SEEK_END)
total = fd.tell() - cur

# Restore the file offset
fd.seek(cur or 0, os.SEEK_SET)


if hexii:
column_sep = ''
line_fmt = '%%(offset)08x %%(hexbytes)-%is│' % (len(column_sep)+(width*byte_width))
Expand All @@ -657,17 +649,29 @@ def style_byte(b):
return hbyte, abyte
cache = [style_byte(chr(b)) for b in range(256)]

if cyclic:
update_cyclic_pregenerated(total)

numb = 0
while True:
offset = begin + numb
chunk = fd.read(width)

# If a tube is passed in as fd, it will raise EOFError when it runs
# out of data, unlike a file or StringIO object, which return an empty
# string.
try:
chunk = fd.read(width)
except EOFError:
chunk = ''

# We have run out of data, exit the loop
if chunk == '':
break

# Advance the cursor by the number of bytes we actually read
numb += len(chunk)

# Update the cyclic pattern in case
if cyclic:
update_cyclic_pregenerated(numb)

# If this chunk is the same as the last unique chunk,
# use a '*' instead.
if skip and last_unique:
Expand Down

0 comments on commit 14f717b

Please sign in to comment.