python - Volcado de memoria formateado como xxd desde gdb
debugging pretty-print (4)
Desafortunadamente, las versiones de @ FatalError y @ gunthor no me funcionaron, así que escribí otra más. Así es como esto luce:
(gdb) xxd hello_string 0xc
00000001_00000f87: 48 656c 6c6f 0957 6f72 Hello.Wor
00000001_00000f90: 6c64 0a ld.
Las versiones más recientes de xxd
admiten el indicador -o
que permite especificar un desplazamiento para agregar al visualizado (que siempre comenzará en 0000000
).
En caso de que xxd -o
no esté disponible, aquí hay un sustituto que se alinea correctamente y muestra la dirección de la ubicación que es xxd
''d.
El comando xxd
:
define xxd
dump binary memory /tmp/dump.bin $arg0 $arg0+$arg1
eval "shell xxd-o %p /tmp/dump.bin", $arg0
end
La secuencia de comandos de perl posiblemente feo xxd-o
( xxd
con desplazamiento):
#!/usr/bin/env perl
use IPC::Open2;
$SIG{''__WARN__''} = sub{ die "$0: $!/n" };
my $offset = shift // "0";
$offset = oct($offset) if $offset =~ /^0/;
my $base = $offset >= 2**32 ? 16 : 8;
my $zeroes = $offset % 16;
my $padding = 1 + int($zeroes / 2) + 2*$zeroes;
my $bytestr = "/0" x $zeroes;
{ local $/; $bytestr .= <> }
open2(/*XXD_OUT, /*XXD_IN, "xxd") or die "xxd is not available!";
print XXD_IN $bytestr; close XXD_IN;
if ($zeroes) {
$_ = <XXD_OUT>;
s/^(.{50}).{$zeroes}/$1 . ('' '' x $zeroes)/ge;
s/^([[:xdigit:]]+:).{$padding}/$1 . ('' '' x $padding)/ge;
my $newoff = sprintf("%0${base}x",hex($1)+$offset) =~ s/^(.{8})(.{8})$/$1_$2/r;
s/^([[:xdigit:]]+):/$newoff:/g;
print
}
while (<XXD_OUT>) {
s/^([[:xdigit:]]+)(?=:)/sprintf("%0${base}x", hex($1)+$offset-$offset%16) =~ s[^(.{8})(.{8})$][$1_$2]r/ge;
print
}
Mejoras bienvenidas! :-)
Estoy intentando inspeccionar un buffer que contiene un mensaje con formato binario, pero también contiene datos de cadena. Como ejemplo, estoy usando este código C:
int main (void) {
char buf[100] = "/x01/x02/x03/x04String Data/xAA/xBB/xCC";
return 0;
}
Me gustaría obtener un volcado hexadecimal de lo que está en buf
, de un formato similar a xxd
(no me importa si es una coincidencia exacta, lo que realmente estoy buscando es un volcado hexadecimal al lado del otro con caracteres imprimibles) .
Dentro de GDB puedo usar algo como:
(gdb) x /100bx buf
0x7fffffffdf00: 0x01 0x02 0x03 0x04 0x53 0x74 0x72 0x69
0x7fffffffdf08: 0x6e 0x67 0x20 0x44 0x61 0x74 0x61 0xaa
0x7fffffffdf10: 0xbb 0xcc 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf18: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf20: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf28: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf30: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf38: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf40: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf48: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf50: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffdf58: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
lo cual está bien, pero es difícil elegir cadenas de esa manera ... o puedo usar
(gdb) x /100bs buf
0x7fffffffdf00: "/001/002/003/004String Data/252/273/314"
0x7fffffffdf13: ""
0x7fffffffdf14: ""
0x7fffffffdf15: ""
0x7fffffffdf16: ""
0x7fffffffdf17: ""
...
lo que hace que sea difícil leer la parte binaria ... los mensajes reales con los que estoy lidiando tienen un montón de ascii nul también, así que realmente parece un desastre.
Lo mejor que se me ocurre es hacer esto:
(gdb) dump binary memory dump.bin buf buf+100
y entonces
$ xxd dump.bin
0000000: 0102 0304 5374 7269 6e67 2044 6174 61aa ....String Data.
0000010: bbcc 0000 0000 0000 0000 0000 0000 0000 ................
0000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................
0000060: 0000 0000 ....
pero eso es un dolor hacer eso cada vez. Pensé que alguien por ahí quería esto antes, así que me pregunto si alguien ha encontrado la manera de hacerlo dentro de gdb. Además, pierde las direcciones de la memoria original de esta manera.
Estoy usando GDB 7.4 con soporte de python integrado, por lo que estoy abierto a la idea de usar una impresora bonita o similar, pero no sé cómo configurarlo.
Entonces, terminé jugando con la interfaz de python y se me ocurrió esto:
import gdb
from curses.ascii import isgraph
def groups_of(iterable, size, first=0):
first = first if first != 0 else size
chunk, iterable = iterable[:first], iterable[first:]
while chunk:
yield chunk
chunk, iterable = iterable[:size], iterable[size:]
class HexDump(gdb.Command):
def __init__(self):
super (HexDump, self).__init__ (''hex-dump'', gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
if len(argv) != 2:
raise gdb.GdbError(''hex-dump takes exactly 2 arguments.'')
addr = gdb.parse_and_eval(argv[0]).cast(
gdb.lookup_type(''void'').pointer())
try:
bytes = int(gdb.parse_and_eval(argv[1]))
except ValueError:
raise gdb.GdbError(''Byte count numst be an integer value.'')
inferior = gdb.selected_inferior()
align = gdb.parameter(''hex-dump-align'')
width = gdb.parameter(''hex-dump-width'')
if width == 0:
width = 16
mem = inferior.read_memory(addr, bytes)
pr_addr = int(str(addr), 16)
pr_offset = width
if align:
pr_offset = width - (pr_addr % width)
pr_addr -= pr_addr % width
for group in groups_of(mem, width, pr_offset):
print ''0x%x: '' % (pr_addr,) + '' ''*(width - pr_offset),
print '' ''.join([''%02X'' % (ord(g),) for g in group]) + /
'' '' * (width - len(group) if pr_offset == width else 0) + '' '',
print '' ''*(width - pr_offset) + ''''.join(
[g if isgraph(g) or g == '' '' else ''.'' for g in group])
pr_addr += width
pr_offset = width
class HexDumpAlign(gdb.Parameter):
def __init__(self):
super (HexDumpAlign, self).__init__(''hex-dump-align'',
gdb.COMMAND_DATA,
gdb.PARAM_BOOLEAN)
set_doc = ''Determines if hex-dump always starts at an "aligned" address (see hex-dump-width''
show_doc = ''Hex dump alignment is currently''
class HexDumpWidth(gdb.Parameter):
def __init__(self):
super (HexDumpWidth, self).__init__(''hex-dump-width'',
gdb.COMMAND_DATA,
gdb.PARAM_INTEGER)
set_doc = ''Set the number of bytes per line of hex-dump''
show_doc = ''The number of bytes per line in hex-dump is''
HexDump()
HexDumpAlign()
HexDumpWidth()
Me doy cuenta de que puede que no sea la solución más bella y elegante, pero hace el trabajo y funciona como un primer borrador. Podría incluirse en ~/.gdbinit
como:
python
sys.path.insert(0, ''/path/to/module/dir'')
import hexdump
end
Entonces podría ser utilizado con el programa anterior como así:
(gdb) hex-dump buf 100
0x7fffffffdf00: 01 02 03 04 53 74 72 69 6E 67 20 44 61 74 61 AA ....String Data.
0x7fffffffdf10: BB CC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf60: 00 00 00 00 ....
Y algunos otros toques para una buena medida:
(gdb) set hex-dump-align on
Determines if hex-dump always starts at an "aligned" address (see hex-dump-width
(gdb) hex-dump &buf[5] 95
0x7fffffffdf00: 74 72 69 6E 67 20 44 61 74 61 AA tring Data.
0x7fffffffdf10: BB CC 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
0x7fffffffdf60: 00 00 00 00 ....
(gdb) set hex-dump-width 8
Set the number of bytes per line of hex-dump
(gdb) hex-dump &buf[5] 95
0x7fffffffdf00: 74 72 69 tri
0x7fffffffdf08: 6E 67 20 44 61 74 61 AA ng Data.
0x7fffffffdf10: BB CC 00 00 00 00 00 00 ........
0x7fffffffdf18: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf20: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf28: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf30: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf38: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf40: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf48: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf50: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf58: 00 00 00 00 00 00 00 00 ........
0x7fffffffdf60: 00 00 00 00 ....
No hay promesas de que no haya errores :). Podría ponerlo en github o algo si la gente está interesada.
Solo lo he probado con GDB 7.4.
una versión adaptada de la solución de User FatalError
- funciona con python 3
- agregado un encabezado hex-col-header
- parámetro de longitud opcional
- renombrado a hd
ejemplos
hd 0xbfffe4f1
hd 0xbfffe4f1 500
import gdb
from curses.ascii import isgraph
def groups_of(iterable, size, first=0):
first = first if first != 0 else size
chunk, iterable = iterable[:first], iterable[first:]
while chunk:
yield chunk
chunk, iterable = iterable[:size], iterable[size:]
class HexDump(gdb.Command):
def __init__(self):
super (HexDump, self).__init__ (''hd'', gdb.COMMAND_DATA)
def invoke(self, arg, from_tty):
argv = gdb.string_to_argv(arg)
addr = gdb.parse_and_eval(argv[0]).cast(
gdb.lookup_type(''void'').pointer())
if len(argv) == 2:
try:
bytes = int(gdb.parse_and_eval(argv[1]))
except ValueError:
raise gdb.GdbError(''Byte count numst be an integer value.'')
else:
bytes = 500
inferior = gdb.selected_inferior()
align = gdb.parameter(''hex-dump-align'')
width = gdb.parameter(''hex-dump-width'')
if width == 0:
width = 16
mem = inferior.read_memory(addr, bytes)
pr_addr = int(str(addr), 16)
pr_offset = width
if align:
pr_offset = width - (pr_addr % width)
pr_addr -= pr_addr % width
start=(pr_addr) & 0xff;
print ('' '' , end="")
print ('' ''.join([''%01X'' % (i&0x0f,) for i in range(start,start+width)]) , end="")
print ('' '' , end="")
print ('' ''.join([''%01X'' % (i&0x0f,) for i in range(start,start+width)]) )
for group in groups_of(mem, width, pr_offset):
print (''0x%x: '' % (pr_addr,) + '' ''*(width - pr_offset), end="")
print ('' ''.join([''%02X'' % (ord(g),) for g in group]) + /
'' '' * (width - len(group) if pr_offset == width else 0) + '' '', end="")
print ('' ''*(width - pr_offset) + '' ''.join(
[chr( int.from_bytes(g, byteorder=''big'')) if isgraph( int.from_bytes(g, byteorder=''big'') ) or g == '' '' else ''.'' for g in group]))
pr_addr += width
pr_offset = width
class HexDumpAlign(gdb.Parameter):
def __init__(self):
super (HexDumpAlign, self).__init__(''hex-dump-align'',
gdb.COMMAND_DATA,
gdb.PARAM_BOOLEAN)
set_doc = ''Determines if hex-dump always starts at an "aligned" address (see hex-dump-width''
show_doc = ''Hex dump alignment is currently''
class HexDumpWidth(gdb.Parameter):
def __init__(self):
super (HexDumpWidth, self).__init__(''hex-dump-width'',
gdb.COMMAND_DATA,
gdb.PARAM_INTEGER)
set_doc = ''Set the number of bytes per line of hex-dump''
show_doc = ''The number of bytes per line in hex-dump is''
HexDump()
HexDumpAlign()
HexDumpWidth()
(gdb) define xxd
>dump binary memory dump.bin $arg0 $arg0+$arg1
>shell xxd dump.bin
>end
(gdb) xxd &j 10
0000000: 0000 0000 0000 0000 0000 0000 4d8c a7f7 ............M...
0000010: ff7f 0000 0000 0000 0000 0000 c8d7 ffff ................
0000020: ff7f 0000 0000 0000
Parece bastante fácil ;-)
Es probable que pueda escribir un script de Python (las versiones modernas de GDB tienen incorporado el intérprete de Python) para hacer lo mismo y deshacerse de la necesidad de "pagar".