Possible? Pas la façon dont vous semblez vouloir. La tâche est en deux parties:
1) Comment obtenir le binaire dans la mémoire
Quand nous indiquons /dev/stdout
comme fichier de sortie dans Linux, nous pouvons alors tuyau dans notre programme x0
qui lit
un exécutable à partir de stdin et l'exécute:
gcc -pipe YourFiles1.cpp YourFile2.cpp -o/dev/stdout -Wall | ./x0
En x0
il nous suffit de les lire depuis l'entrée standard jusqu'à atteindre la fin du fichier:
int main(int argc, const char ** argv)
{
const int stdin = 0;
size_t ntotal = 0;
char * buf = 0;
while(true)
{
/* increasing buffer size dynamically since we do not know how many bytes to read */
buf = (char*)realloc(buf, ntotal+4096*sizeof(char));
int nread = read(stdin, buf+ntotal, 4096);
if (nread<0) break;
ntotal += nread;
}
memexec(buf, ntotal, argv);
}
Il serait également possible pour x0
directement exécuter le compilateur et de lire la sortie. Cette question a été posée ici: Redirection exec sortie d'un tampon ou d'un fichier
Mise en garde: je viens de comprendre que pour une raison étrange, cela ne fonctionne pas lorsque j'utilise pipe |
mais fonctionne quand j'utilise l' x0 < foo
.
Remarque: Si vous êtes prêt à modifier votre compilateur ou vous ne JIT comme LLVM, clang et d'autres cadres de vous pourrait générer directement le code de l'exécutable. Cependant, pour le reste de cette discussion, je suppose que vous voulez utiliser un compilateur.
Remarque: l'Exécution via fichier temporaire
D'autres programmes tels que UPX obtenir un comportement similaire par l'exécution d'un fichier temporaire, il est plus facile et plus portable que l'approche décrite ci-dessous. Sur les systèmes où l' /tmp
est associé à un disque RAM pour l'exemple typique des serveurs, le fichier temporaire sera basé en mémoire de toute façon.
int memexec(void * exe, size_t exe_size, const char * argv)
{
/* random temporary file name in /tmp */
char name[15] = "/tmp/fooXXXXXX";
/* creates temporary file, returns writeable file descriptor */
int fd_wr = mkostemp(name, O_WRONLY);
/* makes file executable and readonly */
chmod(name, S_IRUSR | S_IXUSR);
/* creates read-only file descriptor before deleting the file */
int fd_ro = open(name, O_RDONLY);
/* removes file from file system, kernel buffers content in memory until all fd closed */
unlink(name);
/* writes executable to file */
write(fd_wr, exe, exe_size);
/* fexecve will not work as long as there in a open writeable file descriptor */
close(fd_wr);
char *const newenviron[] = { NULL };
/* -fpermissive */
fexecve(fd_ro, argv, newenviron);
perror("failed");
}
Mise en garde: la gestion des Erreurs est laissée de côté pour les clartés du saké. Comprend pour des raisons de concision.
Remarque: En combinant l'étape main()
et memexec()
en une seule fonction et l'utilisation de splice(2)
pour copier directement entre stdin
et fd_wr
le programme pourrait être considérablement optimisé.
2) l'Exécution directement à partir de la mémoire
On ne se contente pas de charger et d'exécuter un ELFE binaire à partir de la mémoire. Un peu de préparation, pour la plupart liés à la liaison dynamique, qui doit arriver. Il y a beaucoup de matériel à expliquer les différentes étapes de l'ELFE processus de liaison et d'étudier ce qui me fait croire que théoriquement possible. Voir, par exemple, de cette étroitement liée à la question sur SI toutefois il ne semble pas exister une solution de travail.
Mise à jour UserModeExec semble venir de très près.
La rédaction d'un travail de mise en œuvre serait très coûteuse en temps, et sûrement soulever quelques questions intéressantes dans son propre droit. J'aime à croire que c'est voulu par la conception: pour la plupart des applications, il est fortement souhaitable d' (accidentellement) l'exécution de ses données d'entrée, car elle permet l'injection de code.
Ce qui se passe exactement quand un ELFE est exécuté? Normalement le noyau reçoit un nom de fichier, puis crée un processus, des charges et des cartes différentes sections de l'exécutable en mémoire, effectue beaucoup de vérifications et le marque comme exécutable avant de passer le contrôle et un nom de fichier dos au moment de l'exécution linker ld-linux.so
(une partie de la libc). La prend soin de la délocalisation de fonctions de manipulation des bibliothèques supplémentaires, la configuration des objets globaux et de sauter à la exécutables point d'entrée. AIU ce gros du travail est fait par dl_main()
(mis en œuvre dans la libc/elfe/rtld.c).
Même fexecve
est mis en œuvre à l'aide d'un fichier dans /proc
, et c'est ce besoin d'un nom de fichier qui nous amène à ré-écrire certaines parties de ce processus de liaison.
Les bibliothèques
La lecture
Questions liées au SI
Il semble donc possible, à vous de décider si est aussi pratique.