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

Windows Discussion :

Transmettre du "code" via DeviceIoControl ?


Sujet :

Windows

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de - Robby -
    Inscrit en
    Juillet 2003
    Messages
    266
    Détails du profil
    Informations forums :
    Inscription : Juillet 2003
    Messages : 266
    Par défaut Transmettre du "code" via DeviceIoControl ?
    J'ose ? ......
    Mon driver existe, il "tourne", il comprends tous ce qu'il faut ... j'ai en premier lieu utilisé "CreateFile/WriteFile", pour afficher mon "Hello" en Ring0 ... je peux échanger des données entre User et Kernel, dans un sens et dans l'autre ... maintenant, j'utilise DeviceIoControl ... mais ... j'aimerais échanger du "code" et non des données. J'aimerais que mon Driver me permette d'exécuter une portion de mon "code user" en mode kernel ! ... J'aimerais que mon driver me permette d'exécuter ma fonction "toto" (user) ... en mode kernel ! Et si je "passais" mon code dans le Buffer ? Avec l'option "Do_Direct_Io", mes pages physiques sont verouillées, non ?

  2. #2
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    Le code est compilé pour être exécuté à une adresse particulière. C'est pour ça que dans les dll il y a un mécanisme de relocation.
    Le plus simple serait, je pense, de lui donner le nom d'une dll à charger et le nom de la fonction à exécuter (note que ton exe peut faire office de dll en exportant la fonction).

  3. #3
    mat.M
    Invité(e)
    Par défaut
    : :

    c'est le code qui permet d'échanger des données ert non autrement.
    Pourquoi vouloir échanger du code ?
    Un programme informatique est stocké sous forme de code machine .
    A l'exécution ce code manipule des données pas du code que je sache.

    J'aimerais que mon Driver me permette d'exécuter une portion de mon "code user" en mode kernel ! ... J'aimerais que mon driver me permette d'exécuter ma fonction "toto" (user) ... en mode kernel
    Non ce n'est pas le driver qui va exécuter le code "user" mais l'inverse !
    Les Device Drivers sont à la couche la plus basse sur un système informatique proches du matériel.
    C'est le programme qui appelle le DD qui doit exécuter les fonctions du DD pas l'inverse !
    Pour la bonne et unique raison que le DD peut-être appelé par plusieurs programmes ; un DD c'est indépendant des couches logicielles supérieures.
    Par exemple le GDI de WIndows appelle les DD d'affichage.
    Et les programmes utilisateurs font appel au GDI

  4. #4
    Membre confirmé Avatar de - Robby -
    Inscrit en
    Juillet 2003
    Messages
    266
    Détails du profil
    Informations forums :
    Inscription : Juillet 2003
    Messages : 266
    Par défaut
    je savais que j'allais chatouiller les sensibilités ... Arffff ... j'aurais pas du ! Le "code" manipulle des "données " ... bein oui, "ça" on sait... (y'a longtemps) ! Mais le Paradis est la propriété des Anges, non ? Le "code" manipulle des "données" et pas l'inverse ... et pourquoi pas l'inverse ? ... celui qui a imaginé Windows a "osé " l'inverse .... et bien d'autres choses ... un peu d'audace grand Dieu !!!

  5. #5
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    Oui ce que tu veux faire est clairement déconseillé, exécuter n'importe quoi en ring0, huhu, ça va pas mettre longtemps à se crasher.
    Balancer un bout de code à exécuter, ça reste jouable, en prenant les précautions qu'il faut (segment exécutable etc...). Mais une question se pose : une fois que ton driver a exécuté la routine, comment celle-ci alloue de la mémoire, appelle des fonctions, rend la main au driver et aussi : renvoie un résultat ?
    Tu as tant de choses que ça à exécuter en ring0 ? Quel type de code ?

  6. #6
    mat.M
    Invité(e)
    Par défaut
    Citation Envoyé par - Robby -
    Mais le Paradis est la propriété des Anges, non ? Le "code" manipulle des "données" et pas l'inverse ... et pourquoi pas l'inverse ? ... celui qui a imaginé Windows a "osé " l'inverse .... et bien d'autres choses ... un peu d'audace grand Dieu !!!
    Pour les miracles par contre je ne peux rien faire .
    Se rendre à Lourdes pour cela
    Comme Aurélien j'avais pressenti aussi la même chose faire tourner en ring0.
    Mais c'est assez instable.
    Je ne suis pas assz spécialiste demande dans le forum assembleur

  7. #7
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    En attendant, Aurélien a raison pour les moyens aussi: Je pense que passer par une DLL serait mieux (si LoadLibrary() marche en Ring0, ça devrait bien fonctionner...)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    mat.M
    Invité(e)
    Par défaut
    Citation Envoyé par Médinoc
    En attendant, Aurélien a raison pour les moyens aussi: Je pense que passer par une DLL serait mieux (si LoadLibrary() marche en Ring0, ça devrait bien fonctionner...)
    !! LoadLibrary ne peut pas fonctionner en ring0 !
    C'est une API Windows contenue dans une dll donc appelée par un autre programme.
    Une dll c'est une couche logicielle chargée en mémoire et exécutée sur un niveau de privilège supérieur à l'OS et les drivers.
    Qui eux ne tournent qu'en ring 0.
    Un peu de logique

  9. #9
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    LoadLibrary oui, c'est un fonction du sous-système Win32, donc absente du kernel land. Aucune fonction Win32 ne doit être utilisée.
    Le principe des dll lui n'est pas une couche logicielle, et est utilisé pour réaliser les driver (les .sys sont des dll) : ntddl.dll, hadl.dll, etc...
    S'il crée une dll (driver en fait) qui n'utilise que des dll kernel (ntoskrnl.exe...), à priori, ça devrait marcher. Faut trouver l'équivalent de LoadLibrary côté noyau (là j'y connais rien).
    Masi bon, cette fameuse dll étant pratiquement un driver, on se demande l'utilité de se compliquer ainsi

  10. #10
    Membre confirmé Avatar de - Robby -
    Inscrit en
    Juillet 2003
    Messages
    266
    Détails du profil
    Informations forums :
    Inscription : Juillet 2003
    Messages : 266
    Par défaut
    Merci Aurélien, Mat, Medinoc ...
    LoadLibrary ? oui, c'est une fonction de l'api win32 et inutilisable depuis le noyau ... mais pourquoi faire LoadLibrary ? Je n'ai pas envie de faire tourner le code d'un autre, mais "mon" code. Allouer de la mémoire, appeler une fonction ... et bien pareil ... segment exécutable ? ici, Aurelien, tu parles privilèges et protections. En mode noyeau, plus besoin de se "soumettre" aux mécanismes ... mais il faut cependant continuer de respecter le "mode de pensée" du systeme ... bien entendu, pas question de faire tourner n'importe quoi, c'est évident ... se servir de CR0 comme registre temporaire ne serait pas un bon choix ! ... Il n'est pas question ici d'efficacité et de rendement, mais de compréhension du noyau ... ça sert à rien ? ... si, si, à se faire plaisir Il est bien clair que faire un "call" dans un buffer transmis depuis le user ... comme ça ... ça fait hurler ! Données, code, segments ... sont des concepts hierarchiques imposés par le noyau (et c'est bien) ... mais un driver est une extension du noyau. A partir du moment ou un morceau de mémoire physique est verouillée, je ne vois pas ce qui m'empècherait de faire tourner du code à l'intérieur ... en respectant les règles du jeu, bien entendu ... Bon, je vais essayer ça ! j'ai déjà acheté deux pigeons ... si je "plante" .... à mon avis, je vais changer d'écran de veille ... va devenir tout bleu

  11. #11
    Expert confirmé

    Homme Profil pro
    pdg
    Inscrit en
    Juin 2003
    Messages
    5 756
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : pdg

    Informations forums :
    Inscription : Juin 2003
    Messages : 5 756
    Billets dans le blog
    3
    Par défaut
    Un driver est soumis aux même contrôles qu'un code user, la différence c'est qu'il peut s'approprier tous les droits. En user mode aussi tu peux créer un buffer d'opcode et faire un call dedans, mais il faut que ce buffer soit exécutable, sinon, si le processeur supporte cette vérification (propriétés du poste de travail->avancé->performances->prévention de l'exécution des données), ben ça marchera pas. En ring0 comme en ring3, il faut allouer de la mémoire exécutable.
    Données, code, segments ... sont des concepts hierarchiques imposés par le noyau (et c'est bien) ... mais un driver est une extension du noyau. A partir du moment ou un morceau de mémoire physique est verouillée, je ne vois pas ce qui m'empècherait de faire tourner du code à l'intérieur
    Le processeur. C'est lui qui impose l'organisation données/code, pas le noyau qui ne fait que s'adapter. Les références mémoires sont codées en dur dans les opcode. Certaines références sont relatives, et alors le code peut être exécuté n'importe où, mais d'autres sont absolues => un code est compilé pour être exécuté à une adresse très précise (voir l'option /BASE du linker).
    Quand tu déclares une varible toto, le linker va décider où il place cette variable en mémoire, et générer le code en fonction de ça. Lui, il a décidé de la placer en base + 0x1000, avec base = 0x400000, et génère les opcode de lecture/écriture pour aller taper à l'adresse 0x401000.
    Si toi tu places ton code en 0x800000, le code reste compilé pour aller lire/écrire en 0x401000 au lieu de 0x801000. Et là, tu as gagné un nouveau écran de veille comme tu as dit

  12. #12
    Rédacteur
    Avatar de Neitsa
    Homme Profil pro
    Chercheur sécurité informatique
    Inscrit en
    Octobre 2003
    Messages
    1 041
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Chercheur sécurité informatique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 041
    Par défaut
    Bonjour,

    Comme le dit Aurélien, aucune DLL pouvant être appelée par un processus en mode utilisateur (aka ring3) ne peut être appelée en ring0. Le ring0 étant le privilège le plus haut disponible, il est uniquement réservé au kernel et au drivers.

    Même ntddl n'est qu'une porté d'entrée au ring0, mais ne contient pas une once de code s'exécutant en ring0. Le principe est relativement simple :

    Exemple avec l'API CreateFile :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Mode utilisateur
    
    Processus (appel CreateFile) => Kernel32.dll - CreateFileW() [vérification des paramètres passés en arg.]  => ntdll.dll - NtCreateFile() [ajout de paramètre avant de passer en ring0]
    
    Une fois tous les paramètres vérifiés on arrive au "SSD" (System Service Dispatcher) qui ne contient que quelques lignes d'asm opérant la transition ring3 => ring0, avec notamment l'instruction SYSENTER.
    
    -----------
    Kernel Mode
    
    le SSD coté ring0 (exporté par le kernel sous le nom "KiSystemService") copie la pile user-mode en Kernel mode et regarde dans une table (SSDT : System Service Dispatch Table) ,  quel est l'index du service qu'il doit appeler.
    
    L'index amène à une table (KeServiceDescriptorTable) contenant les adresses des fonctions natives en kernel mode, dans notre exemple, ZwCreateFile().
    Donc, pour répondre à Robby, si tu veux exécuter ton code passé depuis le ring3 en ring 0, n'exécute que du code sans appel aux apis !

    Il n'existe aucun chargement de "DLL" en ring0, bien qu'un driver puisse appelé un autre driver. Au contraire des dlls, il n'y a donc pas de "LoadLibrary" ring0, il faut s'attacher un autre driver, et c'est nettement plus complexe (voir "layered drivers") et n'a pas tout à fait la même vocation.

    Pour exécuter ton code ring3 en ring0 tu peux faire un driver simple qui sera ton propre "SSD". Quelque soit la méthode utilisée pour le buffering (DIRECT, BUFFERED, NEITHER), je propose quelque chose comme ca (en partant d'un IOCTL personnel , donc envoyé avec DeviceIoControl) :

    ring3 (exemple):

    InPutBuffer est le buffer contenant le code, le reste (buffer de sortie) est facultatif :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	DeviceIoControl (hDevice, 
    		(DWORD)IOCTL_MON_IOCTL_METHOD_BUFFERED,
    		&InputBuffer,
    		inBuffSize,
    		&OutputBuffer,
    		sizeof (OutputBuffer),
    		&BytesRet,
    		NULL
    		);

    ring0 (DriverEntry [bout de code]) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
        DriverObject->MajorFunction[IRP_MJ_CREATE] = ioctlCreateClose;
        DriverObject->MajorFunction[IRP_MJ_CLOSE] = ioctlCreateClose;
        DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ioctlDeviceControl; // on gére ici
        DriverObject->DriverUnload = ioctlUnloadDriver;
    //... etc.
    ring0, handling d'IRP_MJ_DEVICE_CONTROL :

    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
    NTSTATUS
    ioctlDeviceControl(
        IN PDEVICE_OBJECT DeviceObject,
        IN PIRP Irp
        )
    {
        PIO_STACK_LOCATION  irpSp;// Pointer to current stack location
        NTSTATUS            ntStatus = STATUS_SUCCESS;// Assume success
        ULONG               inBufLength; // Input buffer length
        ULONG               outBufLength; // Output buffer length
        PCHAR               inBuf, outBuf; // pointer to Input and output buffer
        PMDL                mdl = NULL;
        PCHAR               buffer = NULL;  
    
        irpSp = IoGetCurrentIrpStackLocation( Irp );
        inBufLength = irpSp->Parameters.DeviceIoControl.InputBufferLength;
        outBufLength = irpSp->Parameters.DeviceIoControl.OutputBufferLength;
    
        if(!inBufLength || !outBufLength)
        {
            ntStatus = STATUS_INVALID_PARAMETER;
            //cleanup code ...
        }
    
        //
        // Determine which I/O control code was specified.
        //
    
        switch ( irpSp->Parameters.DeviceIoControl.IoControlCode )
        {
        case IOCTL_MON_IOCTL_METHOD_BUFFERED: 
    
    	__asm {int 3}; // debug purpose ONLY !!!
    
            inBuf = Irp->AssociatedIrp.SystemBuffer;
            outBuf = Irp->AssociatedIrp.SystemBuffer;
    
    
    	PVOID pMem = ExAllocatePoolWithTag (NonPagedPool,100,'NEIT');
    //...
    L'allocation mémoire finale est facultative. A partir de là tu peux soit sauter sur inbuf qui contient ton code passé depuis le ring3 au ring0, soit copier ton code dans pMem depuis inBuf (avec un simple memcpy).

    de là, tu peux inliner un simple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    __asm{
    JMP pMem ; // et hop ! :p [ou CALL pMEM]
    }
    et tu exécutes du code passé depuis le ring3 en ring0...

    Ce type de drivers ma déjà été utile pour programmer les compteurs haute précision dispo en ring0 sous X86 depuis le Ring3 sans avoir à recompiler à chaque fois le driver.

  13. #13
    Membre confirmé Avatar de - Robby -
    Inscrit en
    Juillet 2003
    Messages
    266
    Détails du profil
    Informations forums :
    Inscription : Juillet 2003
    Messages : 266
    Par défaut
    Hé hé ... sur Developpez.com .... y'a des super modo, des gars qui connaissent le truc, c'est clair ! Oui, en effet, en mode user, y'a aussi moyen de déclarer un buffer de données et de tapper un call dedans. L'adressage relatif codé en dur dans les opcodes ... oui, suis d'accord, ça fait partie de ce que j'apelle les "règles du jeu" ... un driver peut s'approprier, mais doit se soumettre ... suis d'accord aussi ! Un driver sera toujours une extension du noyau, mais pas le noyau .... ou alors, il faut réellement s'intégrer au noyau, en déviant une fonction de la table des services, ou en déviant une exception ... mais là ... on se retrouve en 1925, lors de la prohibition .... j'ai touché qq qui "sait" ... respect ! PS: oups, j'édite ... Neitsa, tu as posté en même temps ... super intéressant ce que tu dis ... vais faire dodo, j'analyse ça demain ... bonne nuit à tous.

  14. #14
    Membre confirmé Avatar de - Robby -
    Inscrit en
    Juillet 2003
    Messages
    266
    Détails du profil
    Informations forums :
    Inscription : Juillet 2003
    Messages : 266
    Par défaut
    Après une longue et mure réflexion, j'ai préféré supprimer mon dernier message. Je pense que son contenu, un peu limite, bloquait le débat. Plus de réponses est le signe d'une approche qui gène un peu ... et je comprends ... d'autant que le sujet au départ était intéressant et intéressait. J'espère ainsi rendre une fluidité à cette discussion.

    edit
    ----
    allez ...
    d'autres ont-ils réussi a éxécuter du code ring3, en ring0, via un driver ?
    La solution de Neitsa est super intéressante .... d'autres solutions existent elles ? ...

Discussions similaires

  1. Augmenter la hauteur du div/span de la balise "code"
    Par Djakisback dans le forum Evolutions du club
    Réponses: 10
    Dernier message: 24/01/2009, 14h31

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