|
Accueil-->VxD W9x en ASM - Chapitre 9
Le Virtual Memory Manager1 IntroductionDans le chapitre précédent vous avez appris à simuler une interruption V86. Cependant, il y a un problème qui n'a pas été vu encore : l'échange de données entre code VxD et code V86. Nous apprendrons comment employer le Memory Manager V86 pour vous faciliter la tache. 2 ThéorieSi votre VxD travaille avec des routines V86, ce sera nécessaire tôt ou tard de passer des données de grande taille vers ou depuis un programme V86. Le passage d'une grande quantité de données via les registres est hors de question. La tentative suivante pourrait être d'allouer un bloc de mémoire dans le ring-0 et de passer un pointeur vers ce bloc de mémoire via des registres de manière à ce que le code de V86 puisse avoir accès aux données. Si vous faites ainsi, votre système a toute les chances de planter parce que le mode V86 exige une adresse de type segment:offset, et non une adresse linéaire. Il y a pas mal de solutions à ce problème. Cependant, je choisis une solution aisée pour faire la démonstration des services fournis par le Memory Manager V86. Si vous pouvez trouver un bloc de mémoire libre dans la région V86 que vous utilisez comme buffer de communication, cela résoudrait un des problèmes. Cependant, la traduction d'adresse de pointeur reste un problème. Vous pouvez résoudre ces deux problèmes en employant les services du Memory Manager V86. Le Memory Manager V86 est un VxD statique qui gère la mémoire des applications V86. Il fournit aussi des services EMS et XMS aux applications V86 et des services de traduction d'API aux autres VxD. La traduction d'API est en réalité un processus de copie de données en ring-0 vers un buffer en région V86 et de passation d'adresse du buffer au code V86. Aucune magie ici. Le Memory Manager V86 gère un buffer de traduction qui est un bloc de mémoire dans la région V86 pour la passation de données de VxD vers la région V86 et vice versa. De base ce buffer fait 4 kilo-octets. Vous pouvez augmenter la taille de ce buffer V86MMGR_Set_Mapping_Info. Maintenant que vous savez ce qu’est le buffer de traduction, comment copier ou extraire des données de ce buffer ? Cette question implique deux services : V86MMGR_Allocate_Buffer et V86MMGR_Free_Buffer. Notez que le Memory Manager V86 gère les buffers alloués comme une pile. Cela signifie que l’allocation et la désallocation doit observer la règle FIFO. Ainsi si vous faites deux appels à V86MMGR_Allocate_Buffe, le premier appel V86MMGR_Free_Buffer libérera le buffer alloué lors du second appel V86MMGR_Allocate_Buffer. Nous pouvons maintenant continuer à examiner la définition V86MMGR_Allocate_Buffer. C'est un service basé sur les registres. Handle de la VM courante. Pointeur vers la structure de registres clients de la VN courante. Nombre d’octets à allouer depuis le buffer de traduction. Désarmé si vous ne voulez pas copier de données depuis le buffer en ring-0 vers le bloc alloué. Activé si vous voulez copier de données depuis le buffer en ring-0 vers le bloc alloué. Offset du sélecteur du bloc de mémoire en ring-0 qui contient les données à copier vers le buffer alloué. Ignoré si carry flag est désarmé. Si l’appel est réussi : Cette valeur peut être inférieure à la valeur demandée, aussi devez vous sauvegarder cette valeur pour l’appel futur de V86MMGR_Free_Buffer. Le carry flag est armé si une erreur survient. V86MMGR_Free_Buffer accepte exactement les mêmes paramètres que V86MMGR_Allocate_Buffer. Ce qui arrive en réalité quand vous appelez V86MMGR_Allocate_Buffer est que vous allouez un bloc de mémoire dans la région V86 de la VM courante et obtenez l'adresse V86 de ce bloc de mémoire dans edi. Nous pouvons employer ces services pour échanger des données. En plus de la traduction d'API, le Memory Manager V86 offre aussi le mapping d'API vers d'autres VxD. Le mapping d'API est en réalité le processus consistant à mapper des pages de mémoire étendue dans la région V86 de chaque VM. Vous pouvez employer V86MMGR_Map_Pages pour faire le mapping d'API. Avec ce service, les pages sont mappées dans la même adresse linéaire dans chaque VM. C'est un gaspillage d'espace mémoire si vous voulez travailler avec une seule VM. Le mapping d'API est également plus lent que la traduction d'API, aussi préférez la traduction d'API autant que possible. Le mapping d'API est exigé pour quelques opérations V86 qui doivent avoir accès à la même adresse linéaire et être présents dans toutes les VM. 3 Exemple3.1 Le VxDCet exemple utilise la traduction d’API avec le service 440Dh code mineur 66h de l’int 21h (Get_Media_ID), pour obtenir le label de volume de votre premier disque non amovible.
;--------------------------------------------------------------- 3.2 Le chargeur du VxD
;------------------------------------------------------------ 4 Analyse4.1 Le chargeur de VxD
invoke Device IoControl, hVxD,1,NULL,0,addr DiskLabel,12,\ Il appelle DeviceIoControl avec le code de périphérique égal à 1, aucun buffer , un pointeur sur un buffer de sortie et sa taille. DiskLabel est le buffer dimensionné pour recevoir le label de volume retourné par le VxD. Le nombre d'octets réel retourné sera stocké dans la variable BytesReturned. Cet exemple démontre comment passer des données à un VxD et recevoir des données d'un VxD : vous passez des buffers d'entrée / sortie au VxD et celui ci lit ou écrit dans les buffers. 4.2 Le VxD
VMMCall Get_Sys_VM_Handle Quand le VxD reçoit le message W32_DeviceIoControl, il appelle Get_Sys_VM_Handle pour obtenir le handle de la VM système et le stocker dans une variable nommée Handle. Il place ensuite dans ebp un pointeur sur la structure de registres client du bloc de contrôle de la VM.
mov ecx, sizeof MID Ensuite, nous préparons les paramètres qui seront passés à V86MMGR_Allocate_Buffer. Nous devons initialiser le buffer avec l'instruction stc. Nous mettons l'offset de MediaID dans esi et le sélecteur dans fs puis appelons V86MMGR_Allocate_Buffer. Rappellerez vous que esi contient le pointeur sur DIOCPARAMS que nous sauvegardons par push esi et pop esi.
Push_Client_State Nous initialisons. les valeurs de la structure de registres du client pour l'int 21, 440Dh, 66h. Nous spécifiions que nous voulons obtenir le nom du disque C. Nous copions aussi la valeur contenue dans edi dans edx (edi contient l'adresse V86 du bloc de mémoire alloué par V86MMGR_Allocate_Buffer).
mov [ebp].Client_dx, dx Comme le service 440Dh, 66h de l’int 21h attend un pointeur sur une structure MID dans ds:dx, nous devons découper les parties segment et offset de edx et mettre ces éléments dans les images de registre correspondantes.
mov eax,21h Quand tout est prêt, nous appelons Exec_Int pour simuler l'interruption
mov ecx, AllocSize Après le retour de Exec_Int, le buffer alloué est rempli par l'information que nous voulons. L'étape suivante est de récupérer cette information. Nous réalisons cela en appelant V86MMGR_Free_Buffer. Ce service libère le bloc de mémoire alloué par V86MMGR_Allocate_Memory et copie les données du bloc alloué dans le bloc de mémoire spécifié en ring-0. Comme V86MMGR_Allocate_Memory, si vous voulez copier, vous devez armer le carry flag avant l'appel au service.
mov edx, esi Après que nous ayons reçu l'information dans le buffer ring-0, nous copions le label de volume dans le buffer fourni par l'application win32. Nous pouvons avoir accès au buffer en employant lpvOutBuffer, membre de DIOCParams.
Page:
1
2
3
4
5
6
7
8
9
Copyright © Jean-Pierre Fayeulle |