TL;DR Résumé de la façon de remplacer ultérieurement les fonctions binaires prédéfinies
Préparez ptintf et fprintf avec et sans arguments de longueur variable comme échantillons à remplacer.
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;
}
Les résultats de la construction et de l'exécution sont les suivants.
Créer et exécuter des résultats
$ gcc print.c 
$ ./a.out 
printf no args
printf 1
fprintf no args
fprintf 1
Ensuite, préparez un code à remplacer par LD_PRELOAD. Fondamentalement, vous pouvez apporter la définition de la fonction que vous souhaitez remplacer et la redéfinir indépendamment de la présence ou de l'absence d'arguments de longueur variable.
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;
}
Si vous spécifiez ceci avec LD_PRELOAD et que vous l'exécutez, vous pouvez remplacer la définition ultérieurement.
Créer et exécuter des résultats
$ gcc -shared -fPIC override.c -o liboverride.so
$ LD_PRELOAD=./liboverride.so ./a.out
override puts
override printf
override fwrite
override fprintf
Cependant, dans GCC, si l'élément d'argument de longueur variable est 0 dans printf et fprintf, ils seront respectivement remplacés par put et fwrite au moment de la compilation. (GCC peut être remplacé même par -O0, dans clang 3.6 il n'y a pas de remplacement par printf à -O0, remplacé par -O1 ou supérieur)
$ 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 est met
        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 est 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
Si vous voulez désactiver ce remplacement dans GCC, construisez avec -fno-builtin-printf`` -fno-builtin-fprintf.
Résultat de construction et d'exécution avec remplacement désactivé
$ gcc -fno-builtin-printf -fno-builtin-fprintf print.c                                                                                                                
$ LD_PRELOAD=./liboverride.so ./a.out                                                                                                                                 
override printf
override printf
override fprintf
override fprintf
Bien sûr, c'est naturel, mais si vous appelez à nouveau la même fonction dans la fonction remplacée, ce sera un appel récursif et vous ne pourrez pas vous échapper. Par exemple, lors du remplacement de printf, il peut être utilisé dans la bibliothèque utilisée dans le processus de remplacement, vous devez donc faire attention séparément.
Appel récursif
int puts(const char *s) {
        const char *c = "override puts\n";
        write(1, c, strlen(c)); // stdout
        puts("recursive call?"); //* Je ne peux pas sortir des put
        return 0;
}
"BINARY HACKS" #HACK 60: Remplacez la bibliothèque partagée par LD_PRELOAD
Tracez toutes les entrées / sorties des fonctions d'exécution - Qiita
Modifiez le comportement de la bibliothèque partagée Linux (.so). Profitez de jouer avec LD_PRELOAD: Garbage In Garbage Out Accrochez la fonction avec LD_PRELOAD! - Comment marcher binaire Écraser les fonctions de la bibliothèque dynamique avec LD_PRELOAD | Blog de Siguniang