Suchen von Funktionsparametern für Funktionen in gemeinsam genutzten Objektbibliotheken

7

Ich spiele gerade mit einigen C-Bibliotheken ohne Dokumentation herum. Ich frage mich, ob es überhaupt möglich ist, mehr Metadaten wie Parameter und Rückgabewerte abzurufen, als durch Aufrufen von nm -Doder bereitgestellt werden objdump -T filename | grep text. Ich bin mir nicht sicher, ob dies möglich ist, aber wenn ja, erspart es mir, den Verantwortlichen der Bibliothek zu jagen!

Bearbeiten: Ich möchte dies tun können, ohne wenn möglich Maschinencode zu lesen. Es scheint, dass es einige Lösungen gibt, die es mir ermöglichen, dies einfach zu tun, wenn ich ein Experte für Maschinencode war, aber da ich nicht den aktuellen Wunsch habe und nicht habe, in dieses Kaninchenloch zu springen, hoffe ich wirklich, dass es eine andere gibt Weg.

Edward Shen
quelle
C / C ++ - Bibliotheken, richtig?
slm
Ja, ich meine C-Bibliotheken. Entschuldigung, das war nicht klar, ich werde meine Frage bearbeiten
Edward Shen
1
Mit C kannst du nicht. Die Informationen sind einfach nicht da. (Es gibt teilweise Informationen, wenn die Bibliotheken mit Debugging-Symbolen kompiliert wurden.) Dies ist ein Reverse Engineering-Job. Wenn Sie sich dazu entschließen, können Sie Hilfe zum Reverse Engineering erhalten .
Gilles 'SO - hör auf böse zu sein'

Antworten:

8

Eine sehr ähnliche Frage wurde zum Stapelüberlauf gestellt: Wie extrahiere ich einen Funktionsprototyp aus einer ELF-Datei?

Kurzum: Im Allgemeinen können Sie nicht. Wenn die ausführbare Datei (oder gemeinsam genutzte Bibliothek) keine Debug-Informationen enthält, werden die Informationen zu Anzahl und Art der Argumente nicht in der ausführbaren Datei gespeichert.

Wenn die gemeinsam genutzte Objektdatei Debug-Informationen enthält, sollten Sie in der Lage sein, die Informationen mit readelf -wioder mithilfe eines Debuggers zu extrahieren .

Zum Beispiel habe ich eine ausführbare ELF-Datei, die eine Funktion enthält int foo(char a, long b), die mit Debug-Informationen kompiliert wurde. GDB sagt mir:

(gdb) p foo
$1 = {int (char, long int)} 0x40051c <foo>

Und readelf -wi(ein bisschen kryptisch, Sie müssen die Einträge selbst abgleichen) hat:

 <1><2d>: Abbrev Number: 2 (DW_TAG_subprogram)            <= function
    <2e>   DW_AT_external    : 1    
    <2f>   DW_AT_name        : foo                        <= func name
    <33>   DW_AT_decl_file   : 1    
    <34>   DW_AT_decl_line   : 1    
    <35>   DW_AT_prototyped  : 1    
    <36>   DW_AT_type        : <0x6c>                     <= return type
    <3a>   DW_AT_low_pc      : 0x40051c 
    <42>   DW_AT_high_pc     : 0x400532 
    <4a>   DW_AT_frame_base  : 0x0  (location list)
    <4e>   DW_AT_GNU_all_call_sites: 1  
    <4f>   DW_AT_sibling     : <0x6c>   
 <2><53>: Abbrev Number: 3 (DW_TAG_formal_parameter)      <= parameter
    <54>   DW_AT_name        : a    
    <56>   DW_AT_decl_file   : 1    
    <57>   DW_AT_decl_line   : 1    
    <58>   DW_AT_type        : <0x73>   
    <5c>   DW_AT_location    : 2 byte block: 91 6c  (DW_OP_fbreg: -20)
 <2><5f>: Abbrev Number: 3 (DW_TAG_formal_parameter)      <= other param
    <60>   DW_AT_name        : b    
    <62>   DW_AT_decl_file   : 1    
    <63>   DW_AT_decl_line   : 1    
    <64>   DW_AT_type        : <0x7a>   
    <68>   DW_AT_location    : 2 byte block: 91 60  (DW_OP_fbreg: -32)
 <1><6c>: Abbrev Number: 4 (DW_TAG_base_type)
    <6d>   DW_AT_byte_size   : 4    
    <6e>   DW_AT_encoding    : 5    (signed)
    <6f>   DW_AT_name        : int  
 <1><73>: Abbrev Number: 5 (DW_TAG_base_type)
    <74>   DW_AT_byte_size   : 1    
    <75>   DW_AT_encoding    : 6    (signed char)
    <76>   DW_AT_name        : (indirect string, offset: 0x2e): char    
 <1><7a>: Abbrev Number: 5 (DW_TAG_base_type)
    <7b>   DW_AT_byte_size   : 8    
    <7c>   DW_AT_encoding    : 5    (signed)
    <7d>   DW_AT_name        : (indirect string, offset: 0x0): long int 

Beachten Sie, dass für C ++ die Symbole, die mit nmangezeigt werden, mehr Informationen enthalten (sofern sie nicht deklariert wurden extern "C"- die Anzahl und der Typ der Parameter müssen dem Linker zur Verfügung stehen, um eine Überladung zu bewältigen. Die Informationen zum Rückgabetyp sind jedoch auch nicht vorhanden Die Symbole sind verstümmelt - c++filtkönnen zum Entwirren verwendet werden.)

Das Kompilieren derselben Quelldatei wie C ++ ergibt die folgende Ausgabe für nm a.out | c++filt:

...
0000000000400554 T foo(char, long)
...
Matte
quelle
1
Wo ist die Zuordnung von so etwas 0x6czu einem tatsächlichen Typ?
Mowwwalker
Es wird in der Ausgabe die Abschnitte DW_TAG_base_type mit dieser ID angezeigt.
Mat