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 8

La structure des registres client

1 Généralités

Les VxD diffèrent des applications normales win32, win16 ou DOS. Les VxD ne font rien la plupart du temps alors  que les applications normales travaillent. Ils agissent comme les superviseurs du ring-3 et les corrigent quand les applications font quelque chose mal. La situation typique est la suivante :

Une interruption survient

  • La VMM obtient la main
  • La VMM sauvegarde le contenu des registres
  • La VMM traite une interruption ou appelle un autre VxD
  • La VMM retourne le contrôle au programme interrompu
  • L’intéressant dans ce processus est que, la seule manière pour la VMM d'affecter l'application interrompue, est en modifiant l'image du registre sauvegardé. Par exemple, si la VMM considère que le programme interrompu doit reprendre à une adresse différente, elle peut changer la valeur de CS:IP dans l'image de registre sauvegardé et ensuite quand le programme est réactivé, il reprendra l'exécution à la nouvelle adresse CS:IP.

    Le VMM sauvegarde les valeurs des registres au point interrompu dans la structure de registres client.

    Client_Reg_Struc STRUC
       Client_EDI          DD ?
       Client_ESI          DD ?
       Client_EBP          DD ?
       Client_res0         DD ?
       Client_EBX          DD ?
       Client_EDX          DD ?
       Client_ECX          DD ?
       Client_EAX          DD ?
       Client_Error        DD ?
       Client_EIP          DD ?
       Client_CS           DW ?
       Client_res1         DW ?
       Client_EFlags       DD ?
       Client_ESP          DD ?
       Client_SS           DW ?
       Client_res2         DW ?
       Client_ES           DW ?
       Client_res3         DW ?
       Client_DS           DW ?
       Client_res4         DW ?
       Client_FS           DW ?
       Client_res5         DW ?
       Client_GS           DW ?
       Client_res6         DW ?
       Client_Alt_EIP      DD ?
       Client_Alt_CS       DW ?
       Client_res7         DW ?
       Client_Alt_Eflags   DD ?
       Client_Alt_ESP      DD ?
       Client_Alt_SS       DW ?
       Client_res8         DW ?
       Client_Alt_ES       DW ?
       Client_res9         DW ?
       Client_Alt_DS       DW ?
       Client_res10        DW ?
       Client_Alt_FS       DW ?
       Client_res11        DW ?
       Client_Alt_GS       DW ?
       Client_res12        DW ?
    Client_Reg_Struc ENDS

    Vous pouvez voir qu'il y a deux jeux de membres dans cette structure : Client_xxx et Client_Alt_xxx. Cela exige une petite explication. Dans une VM donnée, il peut y avoir deux threads, un en mode V86 et un en mode protégé. Si une interruption survient quand un programme V86 est actif, Client_xxx contiendra les images des registres du programme V86, Client_Alt_xxx contiendra ceux du programme en mode protégé. Inversement, si une interruption survient quand le programme en mode protégé est actif, Client_xxx contiendra les valeurs des registres du programme en mode protégé tandis que Client_Alt_xxx contiendra les valeurs des registres du programme V86. Client_resX est réservé et non employé.

    Vous pourriez avoir une question après avoir examiner la structure : Que ce passe t'il si je change seulement un octet ? La structure reprend seulement les registres de format WORD et DWORD. N'ayez aucune crainte. Jetez un coup d’œil à l'intérieur de vmm.inc. Il y a en complément deux structures dans ce but : Client_Word_Reg_Struc et Client_Byte_Reg_Struc. Si vous voulez avoir accès aux registres de format WORD ou BYTE, transtypez Client_Reg_Struc en Client_Word_Reg_Struc ou Client_Byte_Reg_Struc selon vos besoins.

    Vous pouvez aussi créer une union qui englobe ces trois structures ou vous pourrez vous référer sans transtypage.

    Client_Reg Union
        DwordReg Client_Reg_Struc <>
        WordReg  Client_Word_Reg_Struc <>
        ByteReg Client_Byte_Reg_Struc <>
    Client_Reg Ends

    2 Pointeur vers la structure de registres client

    La plupart du temps, le VMM met l'adresse de la structure de registres client dans ebp quand il appelle notre VxD. La structure de registre de client dans ce cas correspond à la VM actuelle. Alternativement, vous pouvez obtenir cet indicateur à partir du handle de la VM. Rappelez-vous qu'un handle de VM est en réalité l'adresse linéaire du bloc de contrôle de VM.

    cb_s STRUC
       CB_VM_Status        DD ?
       CB_High_Linear      DD ?
       CB_Client_Pointer   DD ?
       CB_VMID             DD ?
       CB_Signature        DD ?
    cb_s ENDS

    CB_Client_Pointer contient le pointeur sur la structure de registre du client VM. Par exemple, vous pouvez obtenir un pointeur sur la structure de registre de la VM courante par le code suivant :

    VMMCall Get_Cur_VM_Handle   ; retourne handle VM courante dans ebx
    assume ebx:ptr cb_s
    mov ebp,[ebx+CB_Client_Pointer] ; pointeur sur client reg struct

    Maintenant que nous comprenons la structure des registres client, nous pouvons passer à son utilisation. Nous emploierons cette structure pour passer les valeurs dans les registres d'une interruption MS-DOS, à savoir int 21h, service 2h (Affichage de caractère). Ce service de MS-DOS prend le caractère à afficher dans dl. Si nous passons le caractère cloche (07h) à ce service, il jouera la cloche via le haut-parleur du PC.

    Rappelez-vous que int 21h est un service de MS-DOS. Comme tel il est disponible en mode V86.

    Comment pouvons-nous appeler une interruption V86 interrompt à partir d'un VxD ?

    Une façon de faire est d'employer le service Exec_int. Ce service du VMM prend le N° d'interruption à appeler dans eax. Il simule l’interruption et reprend l'exécution de la VM. Cependant, il doit être appelé dans un bloc d'exécution imbriqué.

    Un bloc d'exécution imbriqué est inclus entre Begin_Nest_V86_Exec (ou Begin_Nest_Exec) et End_Nest_Exec.

    Ainsi si nous voulons appeler le service 2 de l’int 21h, nous devons modifier les valeurs des registres Client_ah et Client_Dl de la structure Client_Byte_Reg_Struc dans le bloc d'exécution emboîté et stocker ensuite la valeur 21h dans eax. Quand tout est prêt, appelez Exec_int.

    3 Exemple

    L'exemple est un VxD dynamique qui utilise l'interruption 21h service pour faire fonctionner le haut-parleur du PC.

    .386p
    include \masm\include\vmm.inc
    include \masm\include\vwin32.inc
    include \masm\include\v86mmgr.inc

    VxDName TEXTEQU <VXDINT>
    ControlName TEXTEQU <VXDINT_Control>
    VxDMajorVersion TEXTEQU <1>
    VxDMinorVersion TEXTEQU <0>

    VxD_STATIC_DATA_SEG
    VxD_STATIC_DATA_ENDS

    VXD_LOCKED_CODE_SEG
    ;------------------------------------------------------------------
    ;Le nom du vxd DOIT être en majuscule
    ;------------------------------------------------------------------
    DECLARE_VIRTUAL_DEVICE %VxDName,%VxDMajorVersion,%VxDMinorVersion, %ControlName, UNDEFINED_DEVICE_ID, UNDEFINED_INIT_ORDER

    Begin_control_dispatch %VxDName
            Control_Dispatch W32_DEVICEIOCONTROL, OnDeviceIoControl
    End_control_dispatch %VxDName

    VXD_LOCKED_CODE_ENDS

    VXD_PAGEABLE_CODE_SEG
    BeginProc OnDeviceIoControl
    assume esi:ptr DIOCParams
    .if [esi].dwIoControlCode==1
       Push_Client_State
       VMMCall Begin_Nest_V86_Exec
         assume ebp:ptr Client_Byte_Reg_Struc
         mov [ebp].Client_dl,7
         mov [ebp].Client_ah,2
         mov eax,21h
         VMMCall Exec_Int
         VMMCall End_Nest_Exec
      &   Pop_Client_State
    EndI:
     .endif
     xor eax, eax
     ret
    EndProc OnDeviceIoControl
    VXD_PAGEABLE_CODE_ENDS

    end

    4 Analyse

    Push_Client_State

    Il n'y a pas grand chose à analyser. Quand le VxD reçoit le message DeviceIoControl, ebp pointe déjà sur la structure de registres client de la VM actuelle.

    Nous appelons la macro Push_Client_State pour sauvegarder l'état actuel des registres client sur la pile. Nous plus tard reconstituons la valeur des registres client avec Pop_Client_State.

    VMMCall Begin_Nest_V86_Exec

    Commence le bloc d'exécution emboîté en appelant Begin_Nest_V86_Exec.

    assume ebp:ptr Client_Byte_Reg_Struc
    mov [ebp].Client_dl,7
    mov [ebp].Client_ah,2

    Change les images des registres dl et ah dans la structure de registres du client. Ces valeurs modifiées seront employées par l'interruption.

    mov eax,21h
    VMMCall Exec_Int

    Exec_int attend le numéro d'interruption dans eax. Nous voulons utiliser int 21h. Puis nous appelons Exec_int pour simuler l'interruption.

    VMMCall End_Nest_Exec
    Pop_Client_State

    Au retour de Exec_Int , nous finissons le bloc emboîté et rétablissons les valeurs sauvegardées des registres de client à partir de la pile.

    Vous pouvez entendre le haut-parleur du PC jouer le caractère de cloche.

    Page:  1  2  3  4  5  6  7  9 

    Précédent       Suivant

    Copyright © Jean-Pierre Fayeulle