TL;DR Zusammenfassung, wie vorgefertigte Binärfunktionen später ersetzt werden
Bereiten Sie ptintf und fprintf mit und ohne Argumente variabler Länge als zu ersetzende Beispiele vor.
print.c
#include <stdio.h>
int main(int argc, char const* argv[])
{
printf("printf no args\n");
printf("printf %d\n", 1);
fprintf(stdout, "fprintf no args\n");
fprintf(stdout, "fprintf %d\n", 1);
return 0;
}
Die Erstellungs- und Ausführungsergebnisse sind wie folgt.
Ergebnisse erstellen und ausführen
$ gcc print.c
$ ./a.out
printf no args
printf 1
fprintf no args
fprintf 1
Bereiten Sie als Nächstes den Code für den Ersatz durch LD_PRELOAD vor. Grundsätzlich können Sie die Definition der Funktion, die Sie ersetzen möchten, einfügen und neu definieren, unabhängig davon, ob Argumente variabler Länge vorhanden sind oder nicht.
override.c
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) {
const char *c = "override fwrite\n";
write(1, c, strlen(c)); // stdout
return 0;
}
int fprintf (FILE *__restrict __stream, const char *__restrict __format, ...) {
const char *c = "override fprintf\n";
write(1, c, strlen(c)); // stdout
return 0;
}
int puts(const char *s) {
const char *c = "override puts\n";
write(1, c, strlen(c)); // stdout
return 0;
}
int printf (const char *__restrict __format, ...) {
const char *c = "override printf\n";
write(1, c, strlen(c)); // stdout
return 0;
}
Wenn Sie dies mit LD_PRELOAD angeben und ausführen, können Sie die Definition später ersetzen.
Ergebnisse erstellen und ausführen
$ gcc -shared -fPIC override.c -o liboverride.so
$ LD_PRELOAD=./liboverride.so ./a.out
override puts
override printf
override fwrite
override fprintf
Wenn jedoch in GCC das Argumentelement mit variabler Länge in printf
und fprintf
0 ist, werden sie zur Kompilierungszeit durch put
bzw. fwrite
ersetzt. (GCC kann sogar durch -O0 ersetzt werden, in Klang 3.6 gibt es keinen Ersatz durch printf bei -O0, ersetzt durch -O1 oder höher)
$ gcc -S print.c
$ cat print.s
.file "print.c"
.section .rodata
.LC0:
.string "printf no args"
.LC1:
.string "printf %d\n"
.LC2:
.string "fprintf no args\n"
.LC3:
.string "fprintf %d\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl %edi, -4(%rbp)
movq %rsi, -16(%rbp)
movl $.LC0, %edi
call puts <-printf ist setzt
movl $1, %esi
movl $.LC1, %edi
movl $0, %eax
call printf
movq stdout(%rip), %rax
movq %rax, %rcx
movl $16, %edx
movl $1, %esi
movl $.LC2, %edi
call fwrite <-fprintf ist fwrite
movq stdout(%rip), %rax
movl $1, %edx
movl $.LC3, %esi
movq %rax, %rdi
movl $0, %eax
call fprintf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",@progbits
Wenn Sie diesen Ersatz in GCC deaktivieren möchten, erstellen Sie mit -fno-builtin-printf`` -fno-builtin-fprintf
.
Build- und Ausführungsergebnisse mit deaktiviertem Ersatz
$ gcc -fno-builtin-printf -fno-builtin-fprintf print.c
$ LD_PRELOAD=./liboverride.so ./a.out
override printf
override printf
override fprintf
override fprintf
Natürlich ist es natürlich, aber wenn Sie dieselbe Funktion in der ersetzten Funktion erneut aufrufen, handelt es sich um einen rekursiven Aufruf, und Sie können nicht entkommen. Wenn Sie beispielsweise printf ersetzen, kann es in der Bibliothek verwendet werden, die beim Ersetzen verwendet wird. Sie müssen daher separat vorsichtig sein.
Rekursiver Aufruf
int puts(const char *s) {
const char *c = "override puts\n";
write(1, c, strlen(c)); // stdout
puts("recursive call?"); //* Ich komme nicht aus Puts heraus
return 0;
}
"BINARY HACKS" #HACK 60: Ersetzen Sie die gemeinsam genutzte Bibliothek durch LD_PRELOAD
Alle In / Out-Laufzeitfunktionen verfolgen - Qiita
Ändern Sie das Verhalten der gemeinsam genutzten Linux-Bibliothek (.so). Viel Spaß beim Spielen mit LD_PRELOAD: Garbage In Garbage Out Lassen Sie uns die Funktion mit LD_PRELOAD verknüpfen! - Wie man binär geht Dynamische Bibliotheksfunktionen mit LD_PRELOAD | Siguniang's Blog überschreiben