Linux C-Programm: So finden Sie die Bibliothek, zu der eine Funktion gehört
Lesezeit: 5 Minuten
Suss
Angenommen, ich möchte zur Laufzeit herausfinden, wo eine Funktion “printf” definiert ist. Wie würde ich das tun? Mein erster Versuch bestand darin, die Adresse von “printf” auszudrucken und mit der virtuellen Adresszuordnung des Prozesses zu vergleichen:
mein programm:
#include <stdio.h>
#include <unistd.h>
void main()
{
printf("address of printf is 0x%X\n", printf);
printf("pid is %d\n", getpid());
while (1);
}
Ausgang:
-bash-4.1$ ./a &
[1] 28837
-bash-4.1$ address of printf is 0x4003F8
pid is 28837
Dies besagt jedoch, dass die Funktion in meinem eigenen Programm definiert ist!
Sollte es nicht ein Aufruf in libc sein? Wie finde ich heraus, woher dieses “printf” oder eine andere Funktion kommt?
Haha. Wie würde ich es zur Laufzeit finden? Bitte beachten Sie, dass ‘printf’ nur ein vereinfachtes Beispiel ist.
– Pusch
1. Oktober 2018 um 21:42 Uhr
Pseudocode system("man %s | grep \.h") (nur ein Scherz)
– ti7
1. Oktober 2018 um 21:43 Uhr
Was Sie möglicherweise bei Ihrer Adressübernahme gefunden haben, ist ein Stub, den der Linker verwendet, um den Aufruf in Ihrem Programm mit der Implementierung in der Bibliothek zu verbinden. Solche Stubs können für Dinge wie Umzüge, schwache Symbole und dergleichen nützlich sein. Ich kenne die unterschiedlichen Fälle nicht. Aber der Stub selbst ist im Allgemeinen kaum mehr als nur eine einfache Verzweigungsanweisung, die den Programmfluss zu seinem eigentlichen Ziel umleitet.
– Cmaster – Wiedereinsetzung von Monica
1. Oktober 2018 um 21:54 Uhr
@ti7 (und andere). Versuchen wir, Bibliotheken nicht mit Headern zu verwechseln.
– Rici
1. Oktober 2018 um 21:57 Uhr
@weather: wo sagt diese Manpage, dass printf in libc.so ist?
– Rici
1. Oktober 2018 um 21:58 Uhr
Ctx
Die beobachtete Adresse befindet sich in der Procedure Linkage Table (PLT). Dieser Mechanismus wird verwendet, wenn die Position eines externen (dynamisch gelinkten) Symbols zu dem Zeitpunkt, an dem Ihre Binärdatei kompiliert und gelinkt wird, nicht bekannt ist.
Der Zweck ist, dass die externe Verknüpfung nur an einer Stelle, dem PLT, erfolgt und nicht an allen Stellen in Ihrem Code, an denen ein Aufruf des Symbols erfolgt. Also, wenn printf() heißt, der Weg ist:
main -> printf@PLT -> printf@libc
Zur Laufzeit können Sie nicht ohne weiteres herausfinden, in welcher externen Bibliothek sich die aufgerufene Funktion befindet; Sie müssten die Opcodes am Ziel (dem PLT) parsen, das normalerweise die Adresse aus der .dynamic-Sektion holt und dorthin springt, dann schauen, wo sich das Symbol wirklich befindet, und schließlich /proc/pid/maps parsen, um es zu bekommen die externe Bibliothek.
Zur Laufzeit können Sie verwenden gdb dafür:
(terminal 1)$ ./a
pid is 16614
address of printf is 0x400450
(terminal 2)$ gdb -p 16614
(...)
Attaching to process 16614
(...)
0x00000000004005a4 in main ()
(gdb)
(gdb) info sym printf
printf in section .text of /lib/x86_64-linux-gnu/libc.so.6
Wenn Sie Ihr Programm nicht unterbrechen möchten oder nicht verwenden möchten gdbdarfst du auch fragen ld.so um einige Debugging-Informationen auszugeben:
(terminal 1)$ LD_DEBUG=bindings LD_DEBUG_OUTPUT=syms ./a
pid is 17180
address of printf is 0x400450
(terminal 2)$ fgrep printf syms.17180
17180: binding file ./a [0] to /lib/x86_64-linux-gnu/libc.so.6 [0]: normal symbol `printf' [GLIBC_2.2.5]
fukanchik
Zeiger sind printfed mit %pnicht %X:
printf("address of printf is 0x%p\n", printf);
Wenn Sie gegen statische libc kompilieren printf wird in Ihre Binärdatei eingebunden
Lesen Sie hier Was bedeutet @plt? um mehr darüber zu erfahren.
Leider kann ich fPIC nicht verwenden, dies ist ein riesiges Projekt bei der Arbeit, bei dem ich die Build-Prozedur nicht ändern kann.
– Pusch
5. Oktober 2018 um 16:41 Uhr
Basile Starynkevitch
Angenommen, ich möchte zur Laufzeit herausfinden, wo eine Funktion “printf” definiert ist.
Allgemein und absolut gesehen können Sie das wahrscheinlich nicht (zumindest nicht einfach). Eine gegebene Funktion könnte in definiert werden mehrere Bibliotheken (z printf, das ist unwahrscheinlich; da es sich in der C-Standardbibliothek befindet).
Wenn Sie Ihr Linux-System bauen von Grund auf neukönnten Sie davon träumen, dass etwas jede Bibliothek zur Erstellungszeit verarbeitet (wenn Sie beispielsweise jede gemeinsam genutzte Bibliothek erstellen, könnten Sie alle ihre öffentlichen Namen mit erhalten nm(1) und sie in eine Datenbank einfügen). Dies ist heute noch nicht wirklich geschehen, aber einige Forschungsprojekte gehen in diese Richtung (insbesondere Softwareerbeund andere im Jahr 2019).
Übrigens, hättest du haben können mehrere Bibliotheken definieren printf. Wenn Sie beispielsweise beide GNU glibc und musl-libc auf Ihrem Computer (oder wahrscheinlicher, falls vorhanden mehrere Varianten von glibc). Es ist unwahrscheinlich, dass ein bestimmtes Programm beide verwendet (könnte aber theoretisch dlopen beide).
Vielleicht möchten Sie die Linux-spezifischen dladdr(3) Funktion. Von einer gegebenen Adresse teilt es Ihnen mit, welches gemeinsame Objekt es hat.
Die Funktion ist in meinem eigenen Programm definiert
Analysieren Sie die elf-Datei für die benötigten dynamisch verknüpften Bibliotheken. Dann können Sie sie analysieren und nach dem erforderlichen Symbol suchen
KevinZ
Sie können dies statisch ableiten. Keine Ausführung erforderlich:
$ readelf -Ws a.out | grep printf
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@GLIBC_2.2.5 (2)
51: 0000000000000000 0 FUNC GLOBAL DEFAULT UND printf@@GLIBC_2.2.5
13973400cookie-checkLinux C-Programm: So finden Sie die Bibliothek, zu der eine Funktion gehörtyes
Haha. Wie würde ich es zur Laufzeit finden? Bitte beachten Sie, dass ‘printf’ nur ein vereinfachtes Beispiel ist.
– Pusch
1. Oktober 2018 um 21:42 Uhr
Pseudocode
system("man %s | grep \.h")
(nur ein Scherz)– ti7
1. Oktober 2018 um 21:43 Uhr
Was Sie möglicherweise bei Ihrer Adressübernahme gefunden haben, ist ein Stub, den der Linker verwendet, um den Aufruf in Ihrem Programm mit der Implementierung in der Bibliothek zu verbinden. Solche Stubs können für Dinge wie Umzüge, schwache Symbole und dergleichen nützlich sein. Ich kenne die unterschiedlichen Fälle nicht. Aber der Stub selbst ist im Allgemeinen kaum mehr als nur eine einfache Verzweigungsanweisung, die den Programmfluss zu seinem eigentlichen Ziel umleitet.
– Cmaster – Wiedereinsetzung von Monica
1. Oktober 2018 um 21:54 Uhr
@ti7 (und andere). Versuchen wir, Bibliotheken nicht mit Headern zu verwechseln.
– Rici
1. Oktober 2018 um 21:57 Uhr
@weather: wo sagt diese Manpage, dass printf in libc.so ist?
– Rici
1. Oktober 2018 um 21:58 Uhr