2012-02-10 9 views
30

Próbuję sprawdzić bufor, który zawiera binarnie sformatowaną wiadomość, ale także zawiera ciąg danych. Jako przykład, używam tego kodu C:Zrzut pamięci sformatowany jak xxd z gdb

int main (void) { 
    char buf[100] = "\x01\x02\x03\x04String Data\xAA\xBB\xCC"; 

    return 0; 
} 

Chciałbym uzyskać zrzut szesnastkowy, co w buf, o formacie zbliżonym do xxd (I nie obchodzi mnie, czy jest to dokładne dopasowanie , czego tak naprawdę szukam, to zrzut heksowy obok siebie z drukowanymi znakami).

Wewnątrz GDB mogę używać coś takiego:

(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 

który jest w porządku, ale trudno wyłowić sznurki w ten sposób ... czy mogę używać

(gdb) x /100bs buf 
0x7fffffffdf00: "\001\002\003\004String Data\252\273\314" 
0x7fffffffdf13: "" 
0x7fffffffdf14: "" 
0x7fffffffdf15: "" 
0x7fffffffdf16: "" 
0x7fffffffdf17: "" 
... 

który sprawia, że ​​trudno do czytania części binarnej ... rzeczywiste wiadomości, z którymi mam do czynienia, mają w sobie także wiele ascii, więc tak naprawdę wygląda jak bałagan.

Najlepszym mogę wymyślić to, aby to zrobić:

(gdb) dump binary memory dump.bin buf buf+100 

a następnie

$ 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        .... 

ale to ból robić to za każdym razem. Pomyślałem, że ktoś tam chciał tego wcześniej, więc zastanawiam się, czy ktoś znalazł sposób, aby to zrobić wewnątrz gdb. Plus tracisz adresy z oryginalnej pamięci w ten sposób.

Używam GDB 7.4 z wbudowanym wsparciem Pythona, więc jestem otwarty na pomysł użycia ładnej drukarki lub podobnej, ale nie wiem jak to ustawić.

Odpowiedz

52
(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 

Wydaje się dość łatwe ;-)

Można prawdopodobnie napisać skrypt Pythona (współczesne wersje GDB mają wbudowany interpreter Pythona), aby zrobić to samo, i pozbyć się konieczności „bulić”.

+0

Ah, dobre myślenie. Nie zdawałem sobie sprawy, że tak łatwo można dodać skróty do GDB. Zakończyłem to w pythonie, o którym wspomniałeś, ale jestem pewien, że będę mógł użyć tego idiomu. – FatalError

+0

Należy zauważyć, że jeśli '$ arg0' jest wskaźnikiem do struktury, to' $ arg1' będzie traktowane jako liczba obiektów, a nie bajtów. Użyj '((void *) $ arg0) + $ arg1' zamiast' $ arg0 + $ arg1' jeśli to będzie problem. –

+0

Należy również zauważyć, że nowsze wersje 'xxd' obsługują flagę' -o', która dodaje przesunięcie do wyświetlanych wartości adresów. –

23

Więc skończyło się odtwarzanie z interfejsu Python i podszedł z tym:

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() 

zdaję sobie sprawę, że może nie być najbardziej piękne i eleganckie rozwiązanie, ale dostaje zadanie i pracuje jako pierwszy projekt. To może być zawarte w ~/.gdbinit jak:

python 
sys.path.insert(0, '/path/to/module/dir') 
import hexdump 
end 

Następnie może być używany z programem powyżej tak:

(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          .... 

i kilka innych detali na dokładkę:

(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    .... 

nr obiecuje, że nie ma błędów :). Mogę go wetknąć w github albo coś, jeśli ludzie są zainteresowani.

Testowałem tylko z GDB 7.4.

+1

+1, ponieważ to rozwiązanie zachowuje oryginalny adres, bardzo przydatne! –

+0

Otrzymuję komunikat 'ImportError: no module named hexdump' error – haneefmubarak

+0

Upewnij się, że zapisałeś skrypt jako hexdump.py i że ścieżka w .gdbinit jest poprawna – FatalError

2

dostosowaną wersją rozwiązania FatalError użytkownika

  • współpracuje z pytona 3
  • dodał HEX-Col-nagłówek
  • parametr długość opcjonalnie
  • przemianowano na HD

przykłady

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() 
1

Niestety @ FatalError i wersje @ gunthor za nie działa dla mnie, więc napisałem jeszcze innym siebie. Tak to wygląda:

(gdb) xxd hello_string 0xc 
00000001_00000f87:     48 656c 6c6f 0957 6f72   Hello.Wor 
00000001_00000f90: 6c64 0a         ld. 

Nowsze wersje xxd obsługuje flagę -o który umożliwia określające przesunięcie dodać do wyświetlanego jeden (który zawsze rozpocznie się 0000000).

W przypadku, gdy xxd -o nie jest dostępny, oto substytut, który poprawnie wyrównuje i pokazuje adres lokalizacji, która jest xxd 'd.

xxd polecenie:

define xxd 
    dump binary memory /tmp/dump.bin $arg0 $arg0+$arg1 
    eval "shell xxd-o %p /tmp/dump.bin", $arg0 
end 

zapewne brzydka skrypt Perl xxd-o (xxd z offset):

#!/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 
} 

Poprawki mile widziane! :-)

+0

Na' xxd -o': https://stackoverflow.com/q/10233526/8446 –