IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage C++ Discussion :

Une fonction en binaire


Sujet :

Langage C++

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 20
    Par défaut Une fonction en binaire
    Bonjour,

    tout d'abord, je tiens à préciser que je suis tout a fait conscient que ce que je tente de faire n'est pas normal

    En réalité, j'essaye de récupérer le code binaire d'une fonction afin de l'enregistrer dans un fichier, puis de charger le code binaire depuis le fichier jusque dans un pointeur de fonction afin de lancer cette fonction.

    J'ai donc déjà mis en place le code nécessaire à cette opération :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    #include <deque>
    #include <list>
    #include <map>
    #include <windows.h>
     
    using namespace std;
     
    uint64_t get_file_size(std::ofstream &file);
     
    uint64_t get_file_size(std::ofstream &file)
    {
        file.seekp(0, std::ios::end);
        uint64_t taille=file.tellp();
        file.seekp(0, std::ios::beg);
        return taille;
    }
     
    uint64_t get_file_size(std::ifstream &file);
     
    uint64_t get_file_size(std::ifstream &file)
    {
        file.seekg(0,std::ios::end);
        uint64_t taille=file.tellg();
        file.seekg(0,std::ios::beg);
        return taille;
    }
     
    void fonction();
     
    void fonction()
    {
        int test = 5;
        cout<<test<<endl;
    }
     
    int main()
    {
        void (*pointeur)() = fonction;
     
        char* save_char = reinterpret_cast<char*>(pointeur);
     
        cout<<save_char<<endl;
     
        ofstream save("test.txt", ios::binary);
     
        int save_size = strlen(save_char);
     
        save.write(save_char, save_size);
     
        save.close();
     
        char* load_char;
     
        ifstream load("test.txt", ios::binary);
     
        int load_size = get_file_size(load);
     
        load_char = new char[load_size];
     
        load.read(load_char, load_size);
     
        cout<<"'"<<load_char<<"' '"<<save_char<<"'"<<endl;
     
     
        void (*pointeur2)() = reinterpret_cast<void (*)()>(load_char);
     
        (*pointeur2)();
     
        system("pause");
        return 0;
    }
    la phase d'enregistrement fonctionne, mais c'est au moment de lancer la fonction que le programme plante

    Bon en fait, ça m'étonne pas plus que ça... j'imagine que les variables et les fonctions ne sont pas stocké dans le même espace mémoire et du coup il veut pas.

    Évidement, j'obtiens deux jolis warning me disant qu'il est interdit de faire un cast entre une fonction et une variable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    warning: ISO C++ forbids casting between pointer-to-function and pointer-to-object
    Ma question est donc la suivante :

    Y aurait-il un mot-clé/fonction qui permettrait d'enregistrer une fonction ?

    Si oui, lequel ?

    Si non, est-ce faisable en assembleur ? ( je sais que c'est pas le bon forum )

    Voila voila c'est une idée à la con qui m'a empêché de dormir hier soir donc je voulais essayé, ne serais-ce que pour le défis technique.

    Merci pour votre aide et vos remarques que j'espère constructives.

    exkise

  2. #2
    Membre émérite
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Par défaut
    Ton problème est sûrement le fait qu'une sécurité rend la mémoire accédée par le programme inexécutable par défaut.

    Sous linux, il faut utiliser du mprotect() pour désactiver cette précaution.
    Sous windows, je ne sais pas.

    Au passage, pourquoi include <windows.h> ? Pour uint64_t ? <cstdint> fournit std::int64_t et bien d'autres.

    Enfin, si tu es sous linux, il y a bien plus efficace que ce code : mmap puis mprotect. Le premier fait "apparaître" le fichier dans l'espace mémoire du processus (sans le charger totalement, ne sera chargé que ce qui sera utilisé), et le second rend la mémoire exécutable. Ensuite, ce n'est plus qu'une histoire de cast.
    Et si tu es sous windows, il doit sûrement y avoir un truc dans le même genre, mais à toi de chercher dans la doc' officielle.

    Deux dernières remarques au passage : system("pause") est à bannir (autant utiliser un std::cin.get() pour rester interopérable), et, en fait, la technique que tu utilises ici est très proche d'un compilateur JIT, sauf que ce dernier génère le code à la volée au lieu de le lire depuis un fichier. [edit: Une troisième et dernière remarque, en lisant tes casts : caster un pointeur de fonction en un entier ... Tu devrais plutôt utiliser le uint64 / uint32 (selon si tu es sous 32bits ou 64) que le char, pour conserver la taille du pointé.] [edit bis: Finalement une autre remarque : return 0 est inutile à la fin du main ; il est ajouté automatiquement par le compilateur.]

    Bon courage pour la lecture de la doc' microsoft pour l'équivalent à mprotect, donc !

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gard (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2012
    Messages : 20
    Par défaut
    Merci pour ta réponse, je vais regardé du coté de la doc windows ^^

    Pour le system("pause") et le include de windows, je dirais a mon corps défendant que c'est en fait un simple projet "bidon" dans lequel je teste tous les trucs qui me passent par la tête, et comme je suis sous windows, je met ca par habitude, mais en réalité j'ai qq part une fonction pause.

    Merci pour tes remarques

  4. #4
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Tu essaye de transformer un char * (en fait, un tableau de load_size caractères) en ... un pointeur de fonction ne prenant aucun paramètres et renvoyant aucune valeur... Et tu t'étonnes que cela ne fonctionne pas

    Le compilateur se contente de t'avertir qu'il ne peut pas effectuer la conversion parce que tu lui mens en disant qu'il peut te faire confiance, que la conversion peut se faire, avec le reinterpret_cast, mais, une fois que c'est compilé, l'exécution n'a aucune chance de se faire, car load_char est tout, sauf une adresse valide pour une fonction
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  5. #5
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    et surtout pourquoi ca plutot que dlopen ?

  6. #6
    Membre émérite
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,
    [...] car load_char est tout, sauf une adresse valide pour une fonction
    Faux.
    Une adresse est une adresse, et toutes les adresses sont valides pour une fonction. La seule nécessité est que le contenu pointé soit effectivement un code compilé. Les restrictions sur le cast sont du plus pur sucre syntaxique.
    Et, puisque l'appel de fonction équivaut grosso modo à un saut vers la fonction, et qu'on peut sauter vers n'importe quelle adresse mémoire, il est parfaitement possible de caster un pointeur sur char en un pointeur sur fonction. A la protection de la mémoire près.

    Citation Envoyé par Joel F Voir le message
    et surtout pourquoi ca plutot que dlopen ?
    Parce qu'on parle de windows ?
    Et surtout parce que, apparemment, au vu du code proposé, la fonction est donné sans symbole ni rien, juste comme si on assemblait un "jmp $0" (exemple idiot), sans table de symboles ni rien.
    Et pas directement trouvée dans une biblio dynamique / un exécutable.
    Et pour l'exercice de style ?

  7. #7
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    Faux.
    Une adresse est une adresse, et toutes les adresses sont valides pour une fonction. La seule nécessité est que le contenu pointé soit effectivement un code compilé. Les restrictions sur le cast sont du plus pur sucre syntaxique.
    Et, puisque l'appel de fonction équivaut grosso modo à un saut vers la fonction, et qu'on peut sauter vers n'importe quelle adresse mémoire, il est parfaitement possible de caster un pointeur sur char en un pointeur sur fonction. A la protection de la mémoire près.
    A ceci près que ce que le processeur va rencontrer à l'adresse mémoire indiquée sera sans doute tout sauf une fonction, et qu'il risque de prendre des données pour des instructions

    Maintenant, si on prend la précaution d'ouvrir un fichier dans lequel se trouvent de vraies fonctions en binaire, cela peut effectivement marcher, mais c'est un cas particulièrement tordu que je préférerais éviter à moins d'être occupé à coder... un éditeur de liens
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  8. #8
    Membre émérite
    Avatar de Ekleog
    Homme Profil pro
    Étudiant
    Inscrit en
    Janvier 2012
    Messages
    448
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Janvier 2012
    Messages : 448
    Par défaut
    Citation Envoyé par koala01 Voir le message
    A ceci près que ce que le processeur va rencontrer à l'adresse mémoire indiquée sera sans doute tout sauf une fonction, et qu'il risque de prendre des données pour des instructions
    Sauf que la question se basait justement sur un chargement depuis un fichier qui, selon l'OP, contient le code binaire d'une fonction.

    Maintenant, si on prend la précaution d'ouvrir un fichier dans lequel se trouvent de vraies fonctions en binaire, cela peut effectivement marcher, mais c'est un cas particulièrement tordu que je préférerais éviter à moins d'être occupé à coder... un éditeur de liens
    Bof ... Depuis quand un éditeur de lien a-t-il besoin de faire tourner le code qu'il compile ?
    (J'avoue que tout ce que je sais sur le sujet se base sur un article lu que QEmu, qui utilise une technique similaire, tout en modifiant le code source qu'il lit.)
    Et puis, ça fait toujours plaisir de savoir qu'on peut recoder execve tout seul (en version light).

  9. #9
    Membre Expert
    Avatar de Joel F
    Homme Profil pro
    Chercheur en informatique
    Inscrit en
    Septembre 2002
    Messages
    918
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Chercheur en informatique
    Secteur : Service public

    Informations forums :
    Inscription : Septembre 2002
    Messages : 918
    Par défaut
    Citation Envoyé par Ekleog Voir le message
    Parce qu'on parle de windows ?
    Et surtout parce que, apparemment, au vu du code proposé, la fonction est donné sans symbole ni rien, juste comme si on assemblait un "jmp $0" (exemple idiot), sans table de symboles ni rien.
    Et pas directement trouvée dans une biblio dynamique / un exécutable.
    Et pour l'exercice de style ?
    Sauf que bon GetHandle etc c'ets pas fait pour les manchots :o (cf Boost.Plugin). L'argument de portatbilité et assez caduque.

    Ce genre de chose marche sur embarqué car t'as souvent des memoires scratchpad, dans des machines classiques, ca sent le drame aux niveau OS et au niveau execution protection dans les CPUs.

Discussions similaires

  1. Réponses: 4
    Dernier message: 30/09/2012, 08h50
  2. Réponses: 8
    Dernier message: 24/10/2006, 16h50
  3. [VBA-E] avec une fonction value
    Par laas dans le forum Macros et VBA Excel
    Réponses: 3
    Dernier message: 28/11/2002, 13h22
  4. [Turbo Pascal] Allocation et désallocation de pointeurs dans une fonction
    Par neird dans le forum Turbo Pascal
    Réponses: 13
    Dernier message: 17/11/2002, 20h14
  5. Une fonction avec des attributs non obligatoires
    Par YanK dans le forum Langage
    Réponses: 5
    Dernier message: 15/11/2002, 13h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo