đŸ Archived View for heyplzlookat.me âș articles âș embed-exec.gmi captured on 2024-08-18 at 17:24:39. Gemini links have been rewritten to link to archived content
âŹ ïž Previous capture (2024-07-08)
-=-=-=-=-=-=-
Il existe plusieurs façons dâembarquer des fichiers dans un code source C. La mĂ©thode suivante Ă lâavantage dâĂȘtre indĂ©pendante du compilateur utilisĂ© et donc plus portable.
Lâarchive complĂšte est disponible ici :
emb.c :
#include <stdio.h> int main(void) { printf("Hello World !\n"); return 0; }
embb.h :
unsigned char emb[] = { 0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ⊠}; unsigned int emb_len = 15952;
main.c :
#define _GNU_SOURCE #include <unistd.h> #include <stdio.h> #include <errno.h> #include <sys/mman.h> #include "embb.h" int main(void) { int fd = memfd_create("embb", 0); if (fd == -1) fprintf(stderr, "fd error %d\n", errno); int bw = write(fd, emb, emb_len); if (bw != emb_len) fprintf(stderr, "bytes write %d\n", bw); char *newargv[] = { "emb", NULL }; char *newenvp[] = { NULL }; fexecve(fd, newargv, newenvp); perror("fexecve"); fprintf(stderr, "fexecve error %d\n", errno); return 0; }
make embb main
On peut alors tester les exĂ©cutables produits avec `./emb` et `./main` dans le terminal. Les exĂ©cutables donnent alors la mĂȘme sortie `Hello World !`, cela signifie que tout sâest dĂ©roulĂ© comme prĂ©vu.
Du cĂŽtĂ© du fichier emb.c, il nây a pas grand-chose Ă dire, le programme se contente dâafficher `Hello World !`.
Dans le fichier embb.h il y a un tableau de type `unsigned char` remplit de valeurs hexadĂ©cimaless et une variable de type `unsigned int`. Ă bien regarder, la valeur de cette variable correspond Ă la taille du fichier emb en octets. Câest aussi la taille du tableau. En fait, embb.h est un hex dump formatĂ© dans le format C de lâexĂ©cutable emb. Chaque valeur hexadĂ©cimale du tableau est un octet du fichier emb. Ainsi le fichier est stockĂ© tel-quel dans un format accessible via du code C. Pour cela, lâoutil xxdÂč est utilisĂ© avec la commande `xxd -i emb > embb.h`.
Enfin, le fichier main.c est le plus complexe. Le cĆur du programme est constituĂ© de trois parties :
#define _GNU_SOURCE #include <sys/mman.h> #include <stdio.h> #include <errno.h> int fd = memfd_create("embb", 0); if (fd == -1) fprintf(stderr, "fd error %d\n", errno);
`memfd_create`ÂČ va crĂ©er un fichier anonyme dans la mĂ©moire RAM et renvoyer un file descriptor du fichier qui permet dây accĂ©der. Attention, un file descriptor est de type `int`, câest une abstraction des fichiers diffĂ©rente dâun file pointer de type `FILE *`. Les deux derniĂšres lignes sâassurent que lâappel systĂšme sâest dĂ©roulĂ© sans encombres.
#include <unistd.h> #include <stdio.h> #include "embb.h" int bw = write(fd, emb, emb_len); if (bw != emb_len) fprintf(stderr, "bytes write %d\n", bw);
`write`Âł va Ă©crire le contenu du tableau contenu dans le fichier embb.h dans notre fichier anonyme nouvellement crĂ©Ă© et ainsi recrĂ©er le fichier emb dâorigine dans la mĂ©moire RAM. LĂ encore, les deux derniĂšres lignes nous signalent les Ă©ventuelles erreurs.
#include <unistd.h> #include <stdio.h> #include <errno.h> char *newargv[] = { "emb", NULL }; char *newenvp[] = { NULL }; fexecve(fd, newargv, newenvp); perror("fexecve"); fprintf(stderr, "fexecve error %d\n", errno);
`fexecve`⎠va Ă enfin exĂ©cuter notre binaire, qui se trouve dans la mĂ©moire RAM, en lui donnant des arguments et un environnement spĂ©cifiĂ©s respectivement par `newargv` et `newenvp`. Les deux tableaux de chaĂźnes de caractĂšre doivent se finir par la valeur `NULL` et en gĂ©nĂ©ral le premier Ă©lĂ©ment des arguments est le nom de lâexĂ©cutable appelĂ©, sinon sa valeur doit ĂȘtre `NULL`. Si lâappel de lâexĂ©cutable fonctionne correctement, le programme appelant ne se termine jamais et se transforme pour laisser la place Ă lâexĂ©cutable appelĂ©. Dans le cas dâune erreur lors de lâappel, le programme continue et les deux derniĂšres ligne affichent un message dâerreur correspondant au problĂšme. Pour Ă©viter que le programme appelant ne soit remplacĂ© par le programme appelĂ©, il est possible dâutiliser lâappel systĂšme `fork`â”.
Pas encore de commentaires