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