L'exécution de code machine dans la mémoire
Je suis à essayer de comprendre comment exécuter du code machine stockées dans la mémoire.
J'ai le code suivant:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
FILE* f = fopen(argv[1], "rb");
fseek(f, 0, SEEK_END);
unsigned int len = ftell(f);
fseek(f, 0, SEEK_SET);
char* bin = (char*)malloc(len);
fread(bin, 1, len, f);
fclose(f);
return ((int (*)(int, char *)) bin)(argc-1, argv[1]);
}
Le code ci-dessus compile bien dans GCC, mais quand j'essaie d'exécuter le programme à partir de la ligne de commande comme ceci:
./my_prog /bin/echo hello
Le programme de segmentation. J'ai compris que le problème est sur la dernière ligne, comme en commentant les arrêts de l'erreur de segmentation.
Je ne pense pas que je vais le faire tout à fait le droit, car je suis toujours obtenir ma tête autour de pointeurs de fonction.
Est le problème à une défaillance de la fonte, ou quelque chose d'autre?
- Charlie: Si jamais vous rendre sence de toutes ces réponses, plutôt coulé à l'aide d'un pointeur à une fonction que vous avez, vous pourriez être mieux adaptés à écrire des thunk qui gère la pile des arguments de façon dynamique. Si vous utilisez gcc, une fonction déclarée comme "fonction() attribut ((nu));" et voir gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html pour plus d'exemples. De cette façon, vous pouvez appeler la même fonction qui décide si le chargement dynamique de code devra être fourni avec N le nombre d'arguments/convention d'appel etc... de toute façon, vous devriez probablement lookino FFI et autres.
- Je suis sûr que l'OP est juste de l'incompréhension des fondements de la façon dont les fichiers exécutables de travail. Utiliser une bibliothèque de liens dynamiques pour l'exécution de votre propre code dynamique, et exec pour exécuter d'autres applications.
- Vous avez entièrement raison. Je voulais voir si je pouvais faire cela, alors j'ai pensé "où puis-je trouver le code machine?", et a décidé de prendre juste un fichier exécutable sans réfléchir plus sérieusement à ça :/
- Vous pouvez avoir de la chance et compilation pour web de l'assemblée.
Vous devez vous connecter pour publier un commentaire.
Il me semble que vous êtes en train de charger une image ELF, puis en essayant de sauter directement dans l'en-tête ELF? http://en.wikipedia.org/wiki/Executable_and_Linkable_Format
Si vous essayez d'exécuter une autre binaire, pourquoi n'utilisez-vous pas le processus de création des fonctions de la plate-forme que vous utilisez?
Vous avez besoin d'une page à écrire des autorisations d'exécution. Voir mmap(2) et mprotect(2) si vous êtes sous unix. Vous ne devriez pas le faire à l'aide de malloc.
Aussi, lire ce que les autres ont dit, vous ne pouvez exécuter raw code de l'ordinateur à l'aide de votre chargeur. Si vous essayez d'exécuter un en-tête ELF, il ne sera probablement erreur tout de même.
Concernant le contenu des réponses et downmods:
1 - OP a dit qu'il essayait d'exécuter du code machine, j'ai donc répondu sur ce, plutôt que de l'exécution d'un fichier exécutable.
2 - Voir pourquoi vous ne mélangez pas de malloc et mman fonctions:
Il affiche exactement ce problème sur Linux x86_64 autre laid comportement sûr de se poser sur d'autres implémentations.
À l'aide de malloc fonctionne très bien.
OK c'est ma dernière réponse, veuillez noter que j'ai utilisé l'original de l'affiche du code.
Je suis de chargement de disque, la version compilée de ce code à un segment de mémoire allouée zone "bin", tout comme l'originale code (le nom est fixé non pas à l'aide argv, et la valeur 0x674 est de;
Ceci peut être regardé, au moment de l'exécution de la BFD (Binaire Descripteur de Fichier de la bibliothèque) ou quelque chose d'autre, vous pouvez appeler d'autres fichiers binaires (et pas seulement vous-même), tant qu'ils sont liés statiquement le même ensemble de lib de l'.
en cours d'exécution...
Vous pouvez utiliser UPX à gérer la charge de travail/modifier/exec d'un fichier.
P. S. désolé pour le précédent lien brisé 😐
malloc
ne garantit pas la page d'alignement, votre code peut ou peut ne pas fonctionner. vous pouvez utiliser une page alignés sous-ensemble de la mallocd bloc, qui serait à l'abri, ou peut-être l'utiliserposix_memalign
si vous l'avezUn typique fichier exécutable a:
main(int, char **)
La première signifie que vous ne pouvez généralement s'attendre octet 0 du fichier exécutable; intead, les informations contenues dans l'en-tête décrit comment charger le reste du fichier en mémoire et par où commencer l'exécution de ce.
La seconde signifie que lorsque vous avez trouvé le point d'entrée, vous ne pouvez pas vous attendre à le traiter comme une fonction C en prenant les arguments
(int, char **)
. Il peut, peut-être, être utilisable comme une fonction prenant pas paramétrée (et donc nécessitant rien d'être poussé en avant de l'appeler). Mais vous ne devez remplir l'environnement qui va à son tour être utilisé par le code d'entrée pour construire la ligne de commande chaînes passées à main.Faire cela à la main sous un OS serait aller dans la profondeur qui est au delà de moi; mais je suis sûr qu'il est beaucoup plus agréable de faire ce que vous essayez de faire. Êtes-vous essayer d'exécuter un fichier externe comme un marche-arrêt de l'opération, ou de la charge externe binaire et de traiter ses fonctions dans le cadre de votre programme? Les deux sont pris en charge par les librairies en C sous Unix.
Ce que vous essayez de faire est quelque chose de semblable à ce que les interprètes ne. Sauf qu'un interpréteur lit d'un programme écrit dans un langage interprété comme le Python, qui compile le code à la volée, met le code de l'exécutable en mémoire, puis l'exécute.
Vous pouvez lire plus à propos de " juste-à-temps de compilation trop:
Juste au moment de la compilation
Java HotSpot JIT runtime
Il existe des bibliothèques disponibles pour JIT génération de code tels que la GNU foudre et libJIT, si vous êtes intéressé. Que vous avez à faire beaucoup plus que juste de la lecture du fichier et en essayant d'exécuter du code. Un exemple de scénario d'utilisation sera:
votre propre).
intermédiaire langue comprise par
l'équipe de la bibliothèque.
par cet intermédiaire
la représentation, pour votre plate-forme cible centrale.
Et d'exécuter le code que vous auriez à utiliser des techniques telles que l'utilisation de mmap() à la carte le code exécutable dans l'espace d'adressage du processus, le marquage de la page exécutable et le saut à ce morceau de mémoire. C'est plus compliqué que cela, mais c'est un bon début pour comprendre ce qu'il se passe en dessous de tous ces interprètes de langages de script comme Python, Ruby, etc.
La version en ligne du livre "Les Linkers et les Chargeurs" vous donnera plus d'informations sur l'objet de formats de fichiers, ce qui se passe derrière les coulisses lors de l'exécution d'un programme, les rôles des linkers et les chargeurs et ainsi de suite. C'est une très bonne lecture.
Il est plus probable que c'est le code qui est sauté par l'appel à l'aide de la fonction de pointeur qui est à l'origine de l'erreur plutôt que de l'appel lui-même. Il n'y a aucun moyen de le code que vous avez posté pour déterminer que le code chargé dans le bac est valide. Votre meilleur pari est d'utiliser un débogueur, passer à l'assembleur vue, pause sur l'instruction de retour et étape dans l'appel de la fonction pour déterminer que le code que vous vous attendez à exécuter est en effet en cours d'exécution, et qu'il est valide.
Note également que, pour fonctionner à tous les code devra être indépendant de la position et entièrement résolu.
En outre, si votre processeur/système d'exploitation permet à la prévention d'exécution des données, puis la tentative est probablement vouée à l'échec. Il est, au mieux, mal conseillé dans tous les cas, le chargement de code est ce que l'OS est pour.
Utiliser le système d'exploitation pour le chargement et l'exécution de programmes.
Sur unix, le exec appels peuvent le faire.
Votre extrait de code dans la question pourrait être réécrite:
Vous pouvez dlopen() sur un fichier, recherchez le symbole "main" et de l'appeler avec 0, 1, 2 ou 3 arguments (tous de type char*) par une troupe de pointeur de fonction-retour-int-prendre-0,1,2,ou3-char*
Fichiers exécutables qui contiennent beaucoup plus que juste le code. L'en-tête, de code, de données, de plus en plus de données, ce genre de choses est séparé et chargé dans les différentes zones de la mémoire par le système d'exploitation et de ses bibliothèques. Vous ne pouvez pas charger un fichier de programme dans un seul morceau de la mémoire et de s'attendre à passer du premier octet.
Si vous essayez d'exécuter votre propre code arbitraire, vous avez besoin de regarder dans les bibliothèques dynamiques parce que c'est exactement ce qu'ils sont pour.