Accueil
Qui suis-je ?
 
Mes livres
Les pompes rotodynamiques
Commander un livre
 
Mes programmes
Nopopup
Aide française
Télécharger
English help
Download
 
Optipump
English help
Download
 
SaveRes
Aide française
Télécharger
English help
Download
 
TTFName
Aide française
Télécharger
 
Mes articles
Composant ASP en C/C++
VxD W9x en ASM
 
Mes photos
Afrique australe
Autres photos
 
 visiteurs.
 pages vues.
 connecté(s).
Accueil-->VxD W9x en ASM - Chapitre 6

L’interface DeviceIoControl

1 Introduction

Nous parlerons de VxD dynamiques dans ce chapitre. Plus particulièrement, nous apprendrons comment les créer, les charger et les employer.

2 Interfaces de VxD

2.1 Généralités

Les VxD fournissent 4 interfaces :

  • Les services VxD
  • Les interfaces V86
  • Les interfaces de mode protégé

2.2 L’interfaçe Win32 DeviceIoControl

Nous connaissons déjà les services VxD. Les interfaces V86 et PMI sont les fonctions qui sont accessibles depuis les applications V86 et celles en mode protégé. Comme les applications V86 et celles en mode protégé sont 16-bit, nous ne pouvons pas employer ces deux interfaces depuis une application win32.

Avec Windows 9x, Microsoft ajoute une interface complémentaire pour que les applications win32 puissent appeler ces services de VxD : DeviceIoControl Interface.

2.3 L’interfaçe DeviceIoControl

2.3.1 Préanbule

Pour rester simple, l'interface DeviceIoControl est une façon pour les applications win32 d'appeler des fonctions à l'intérieur de VxD.

Ne confondez pas les fonctions appelées via DeviceIoControl avec les services VxD, ça n'est pas la même chose. Par exemple,la fonction N°1 de DeviceIoControl n'est pas identique au service N°1 du VxD. Vous devez imaginer les fonctions de DeviceIoControl comme un groupe séparé de fonctions, prévues pour les applications win32 seulement.

Puisque c'est une interface, il y a deux côtés :

2.3.2 Côté application win32

Il doit appeler CreateFile pour ouvrir ou charger le VxD d'abord. Si l'appel est réussi, le VxD sera mis en mémoire et CreateFile retournera le handle du VxD dans eax.

Ensuite vous appelez la fonction API DeviceIoControl pour choisir la fonction à exécuter. DeviceIoControl a la syntaxe suivante :

DeviceIoControl PROTO hDevice:DWORD,\
      dwIoControlCode:DWORD,\
      lpInBuffer:DWORD,\
      nInBufferSize:DWORD,\
      lpOutBuffer:DWORD,\
      nOutBufferSize:DWORD,\
      lpBytesReturned:DWORD,\
      lpOverlapped:DWORD

  • hDevice est le handle du VxD retourné par CreateFile
  • dwIoControlCode est la valeur qui spécifie l'opération que le VxD doit exécuter. Vous devez d'une façon ou d'une autre obtenir la liste de valeurs de dwIoControlCode possibles pour un VxD avant que vous ne sachiez quelle opération vous devez choisir. Mais la plupart du temps, vous êtes celui qui code le VxD donc vous savez la liste de toutes les valeurs de dwIoControlCode possibles.
  • lpInBuffer est l'adresse du buffer qui contient les données que le VxD doit employer pour exécuter l'opération indiquée dans dwIoControlCode. Si l'opération n'a pas besoin de données, vous pouvez passer NULL.
  • nInBufferSize est la taille, en octets, des données du buffer pointé par lpInBuffer.
  • lpOutBuffer est l'adresse du buffer que le VxD remplira des données  quand l'opération réussie. Si l'opération n'a pas de données à transmette, ce champ peut être NULL.
  • nOutBufferSize est la taille, en octets, du buffer pointé par lpOutBuffer
  • lpBytesReturned est l'adresse d'une variable dword qui recevra la taille de données que le VxD rempli dans lpOutBuffer
  • lpOverlapped est l'adresse de la structure OVERLAPPED si vous voulez que l'opération soit asynchrone. Si vous voulez attendre que l'opération finisse, mette le NULL dans ce champ.

2.3.3 Du côté VxD

Le VxD doit traiter le message w32_deviceIoControl. Quand le VxD reçoit le message w32_deviceIoControl, il met dans les registres les valeurs suivantes :

  • ebx contient le handle de la VM
  • esi est un pointeur sur la structure de DIOCParams qui contient l'information passée depuis l'application win32. DIOCParams est défini comme suit :
  • DIOCParams STRUC
        Internal1                 DD ?
        VMHandle                  DD ?
        Internal2                 DD ?
        dwIoControlCode           DD ?
        lpvInBuffer               DD ?
        cbInBuffer                DD ?
        lpvOutBuffer              DD ?
        cbOutBuffer               DD ?
        lpcbBytesReturned         DD ?
        lpoOverlapped             DD ?
        hDevice                   DD ?
        tagProcess                DD ?
    DIOCParams ENDS

  • I nternal1 est un pointeur sur la structure des registres de l'application win32 cliente.
  • VMHandle est le handle de la VM.
  • Internal2 est un pointeur sur le device descriptor block (DDB).
  • dwIoControlCode, lpvInBuffer, cbInBuffer, lpvOutBuffer, cbOutBuffer, lpcbBytesReturned. lpOverlapped sont les paramètres passés lors de l’appel de l’API DeviceIoControl API.
  • hDevice est le handle du ring 3.
  • tagProcess est le process tag.
  • Dans la structure DIOCParams, vous avez toute l'information que l'application win32 a passé à votre VxD.

    Votre VxD doit au moins traiter DIOC_OPEN. DOC_OPEN est un code passé dans dwIoControlCode que VWIN32 enverra à votre VxD quand une application win32 appelle CreateFile pour ouvrir votre VxD.

    Si votre VxD est prêt, il doit retourner 0 dans eax et l'appel de CreateFile sera correct. Si votre VxD n'est pas prêt, il doit retourner une valeur non nulle dans eax pour que CreateFile échoue. En plus de DIOC_OPEN, votre VxD recevra le code DIOC_CloseHandle quand l'application win32 refermera le handle

    3 Squelette minimum d’un VxD dynamique chargeable par CreateFile

    3.1 Code ASM

    .386p
    include vmm.inc
    include vwin32.inc
    DECLARE_VIRTUAL_DEVICE DYNAVXD,1,0, DYNAVXD_Control,\
         UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER
    Begin_control_dispatch DYNAVXD
        Control_Dispatch w32_DeviceIoControl, OnDeviceIoControl
    End_control_dispatch DYNAVXD
    VxD_PAGEABLE_CODE_SEG
    BeginProc OnDeviceIoControl
        assume esi:ptr DIOCParams
        .if [esi].dwIoControlCode==DIOC_Open
           xor eax, eax
        .endif
        ret
    EndProc OnDeviceIoControl
    VxD_PAGEABLE_CODE_ENDS
    end

    3.2 Fichier de définition de module

    VXD DYNAVXD DYNAMIC
    SEGMENTS
        _LPTEXT             CLASS 'LCODE' PRELOAD NONDISCARDABLE
        _LTEXT              CLASS 'LCODE' PRELOAD NONDISCARDABLE
        _LDATA              CLASS 'LCODE' PRELOAD NONDISCARDABLE
        _TEXT               CLASS 'LCODE' PRELOAD NONDISCARDABLE
        _DATA               CLASS 'LCODE' PRELOAD NONDISCARDABLE
        CONST               CLASS 'LCODE' PRELOAD NONDISCARDABLE
        _TLS                CLASS 'LCODE' PRELOAD NONDISCARDABLE
        _BSS                CLASS 'LCODE' PRELOAD NONDISCARDABLE
        _LMGTABLE           CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
        _LMSGDATA           CLASS 'MCODE' PRELOAD NONDISCARDABLE IOPL
        _IMSGTABLE          CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
        _IMSGDATA           CLASS 'MCODE' PRELOAD DISCARDABLE IOPL
        _ITEXT              CLASS 'ICODE' DISCARDABLE
        _IDATA              CLASS 'ICODE' DISCARDABLE
        _PTEXT              CLASS 'PCODE' NONDISCARDABLE
        _PMSGTABLE          CLASS 'MCODE' NONDISCARDABLE IOPL
        _PMSGDATA           CLASS 'MCODE' NONDISCARDABLE IOPL
        _PDATA              CLASS 'PDATA' NONDISCARDABLE SHARED
        _STEXT              CLASS 'SCODE' RESIDENT
        _SDATA              CLASS 'SCODE' RESIDENT
        _DBOSTART           CLASS 'DBOCODE'     PRELOAD NONDISCARDABLE CONFORMING
        _DBOCODE            CLASS 'DBOCODE'     PRELOAD NONDISCARDABLE CONFORMING
        _DBODATA            CLASS 'DBOCODE'     PRELOAD NONDISCARDABLE CONFORMING
        _16ICODE            CLASS '16ICODE'     PRELOAD DISCARDABLE
        _RCODE              CLASS 'RCODE'
    EXPORTS
        DYNAVXD_DDB  @1

    4 Exemple complet

    4.1 L’application win32

    Ci-dessous le code source de l'application win32 qui charge le VxD dynamique et appelle une fonction du VxD via l'API DeviceIoControl.

    ;VxDLoader.asm

    .386
    .model flat, stdcall
    include windows.inc
    include kernel32.inc
    includelib kernel32.lib
    include user32.inc
    includelib user32.lib

    .data

    AppName db "DeviceIoControl",0
       VxDName      db "\\.\shellmsg.vxd",0
       Success      db "VxD bien chargé !",0
       Failure      db "VxD non chargé!",0
       Unload       db "VxD déchargé!",0
       MsgTitle     db "Exemple DeviceIoControl",0
       MsgText      db "Je suis appelé par un VxD!",0
       InBuffer     dd offset MsgTitle
               dd offset MsgText

    .data?

       hVxD dd ?

    .code

    start:
       invoke CreateFile, addr VxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0
       .if eax!=INVALID_HANDLE_VALUE
            mov hVxD, eax
            invoke MessageBox, NULL, addr Success, addr AppName,
                  MB_OK+MB_ICONINFORMATION
            invoke DeviceIoControl, hVxD,1,addr InBuffer,8,NULL,NULL,NULL,NULL
            invoke CloseHandle, hVxD
      invoke MessageBox, NULL, addr Unload, addr AppName, MB_OK+MB_ICONINFORMATION
        .else
            invoke MessageBox, NULL,addr Failure, NULL,MB_OK+MB_ICONERROR
        .endif
        invoke ExitProcess, NULL
    end start

    4.2 Le VxD dynamique appelé

    ;ShellMsg.asm

    .386p
    include vmm.inc
    include vwin32.inc
    include shell.inc

    DECLARE_VIRTUAL_DEVICE SHELLMSG,1,0, SHELLMSG_Control,\
         UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER

    Begin_control_dispatch SHELLMSG
        Control_Dispatch w32_DeviceIoControl, OnDeviceIoControl
    End_control_dispatch SHELLMSG

    VxD_PAGEABLE_DATA_SEG
        pTitle dd ?
        pMessage dd ?
    VxD_PAGEABLE_DATA_ENDS

    VxD_PAGEABLE_CODE_SEG
    BeginProc OnDeviceIoControl
        assume esi:ptr DIOCParams

        .if [esi].dwIoControlCode==DIOC_Open
            xor eax, eax
        .elseif [esi].dwIoControlCode==1
            mov edi,[esi].lpvInBuffer

            ;----------------------------------------
            ;Copie le titre du message dans le buffer
            ;----------------------------------------
            VMMCall _lstrlen, <[edi]>
            inc eax
            push eax
            VMMCall _HeapAllocate,<eax, HEAPZEROINIT>
            mov pTitle, eax
            pop eax
            VMMCall _lstrcpyn,<pTitle,[edi],eax>

            ;----------------------------------------
           .;Copie le texte du message dans le buffer
            ;----------------------------------------
            VMMCall _lstrlen, <[edi+4]>
            inc eax
            push eax
            VMMCall _HeapAllocate,<eax, HEAPZEROINIT>
            mov pMessage, eax
            pop eax
            VMMCall _lstrcpyn,<pMessage,[edi+4],eax>
            mov edi, pTitle
            mov ecx, pMessage
            mov eax, MB_OK
            VMMCall Get_Sys_VM_Handle
            VxDCall SHELL_sysmodal_Message
            VMMCall _HeapFree, pTitle,0
            VMMCall _HeapFree, pMessage,0
            xor eax, eax
        .endif
        ret
    EndProc OnDeviceIoControl
    VxD_PAGEABLE_CODE_ENDS
    end

    5 Analyse

    Nous commençons par VxDLoader.asm.

    invoke CreateFile, addr VxDName,0,0,0,0,FILE_FLAG_DELETE_ON_CLOSE,0
    .if eax!=INVALID_HANDLE_VALUE
         mov hVxD, eax
         ....
    .else
         invoke MessageBox, NULL,addr Failure, NULL,MB_OK+MB_ICONERROR
    .endif

    Nous appelons CreateFile pour charger le VxD dynamique. Notez le flag FILE_FLAG_DELETE_ON_CLOSE. Ce flag indique à Windows de décharger le VxD quand le handle de VxD alloué par CreateFile est refermé. Si CreateFile réussi, nous stockons le handle de VxD pour utilisation future.

    invoke MessageBox, NULL,addr Success, addr appName, MB_OK+MB_ICONINFORMATION
    invoke DeviceIoControl, hVxD,1,addr InBuffer,8,NULL,NULL,NULL,NULL
    invoke CloseHandle, hVxD
    invoke MessageBox, NULL,addr Unload, addr AppName, MB_OK+MB_ICONINFORMATION

    Le programme affiche une boîte de message quand le VxD est chargé ou déchargé. Il appelle DeviceIoControl avec dwIoControlCode = 1 et passe l'adresse de InBuffer dans le paramètre lpInBuffer et la taille de InBuffer[8] dans nInBufferSize. InBuffer est un tableau de dword de deux éléments : chaque élément est l'adresse d'une chaîne de caractères.

    MsgTitle  db "Exemple DeviceIoControl",0
    MsgText   db "Je suis appelé par un VxD!",0
    InBuffer  dd offset MsgTitle
              dd offset MsgText

    Maintenant regardons le VxD. Il traite seulement le message w32_deviceIoControl . Quand le message w32_deviceIoControl est envoyé, la procédure OnDeviceIoControl est appelée.

    BeginProc OnDeviceIoControl
        assume esi:ptr DIOCParams
        .if [esi].dwIoControlCode==DIOC_Open
            xor eax, eax

    OnDeviceIoControl traite le code de DIOC_OPEN en retournant 0 dans eax.

    .elseif [esi].dwIoControlCode==1
         mov edi,[esi].lpvInBuffer

    La procédure traite aussi le code de contrôle 1. La première chose qu'elle fait est d'extraire les données dans lpvInBuffer qui sont les deux dword passés via lpInBuffer de l'API DeviceIoControl. Elle range l'adresse du tableau de dword dans edi pour extraction.

    Le premier dword est l'adresse du titre de la boîte de message. Le second dword est l'adresse du texte de la boîte de message.

    VMMCall _lstrlen, <[edi]>
    inc eax
    push eax
    VMMCall _HeapAllocate,<eax, HEAPZEROINIT>
    mov pTitle, eax
    pop eax
    VMMCall _lstrcpyn,<pTitle,[edi],eax>

    Elle calcule la longueur du titre de la boîte de message en appelant le service VMM _lstrlen. La valeur retournée dans eax par _lstrlen est la longueur de la chaîne. Nous augmentons la longueur de 1 pour tenir compte du caractère NULL de fin de chaîne. Ensuite nous allouons, en appelant _HeapAllocate, un bloc de mémoire assez grand pour contenir la chaîne avec son caractère NULL

    Le flag HEAPZEROINIT indique à HeapAllocate d'initialiser à 0 le bloc de mémoire. _HeapAllocate retourne l'adresse du bloc de mémoire dans eax. Nous copions alors la chaîne depuis l'espace d'adressage de l'application win32 dans le bloc mémoire alloué. Nous faisons la même opération sur la chaîne de caractères que nous emploierons comme texte de boîte de message.

    mov edi, pTitle
    mov ecx, pMessage
    mov eax, MB_OK
    VMMCall Get_Sys_VM_Handle
    VxDCall SHELL_SysModal_Message

    Nous stockons les adresses du titre et du message respectivement dans edi et ecx. Mettez le flag désiré dans eax, obtenez le handle de la VM système en appelant Get_Sys_VM_Handle et appelez ensuite SHELL_SysModal_Message. SHELL_SysModal_Message est la version modale système de SHELL_Message.

    Cela gèle le système tant que l’utilisateur n’a pas répondu à la boite de message.

    VMMCall _HeapFree, pTitle,0
    VMMCall _HeapFree, pMessage,0

    Au retour de SHELL_SysModal_Message, nous pouvons libérer le bloc de mémoire en appelant _HeapFree.

    6 Conclusion

    L'interface DeviceIoControl est idéale pour rajouter une extension ring 0 à une application win32.

    Page:  1  2  3  4  5  7  8  9 

    Précédent       Suivant

    Copyright © Jean-Pierre Fayeulle