home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
DP Tool Club 24
/
CD_ASCQ_24_0995.iso
/
dos
/
fr
/
hexutil
/
int_f.doc
< prev
Wrap
Text File
|
1995-02-02
|
11KB
|
239 lines
Etude de l'évolution du pointeur de pile dans mes lanceurs
----------------------------------------------------------
1) Fonctionnement d'une interruption:
Lors de l'appel d'une interruption on a dans l'ordre;
a) Le registre des FLAGS est sauvé sur la pile.
b) Le registre IP est sauvé sur la pile.
c) Puis le registre CS est poussé sur la pile.
d) Le double mot sur lequel pointe l'INT représente la nouvelle
adresse CS:IP que l'on va charger. Et l'éxecution du
programme continu à cette adresse.
Il faut noter que dans la table des INT qui va de 0000 à 03FF,
chaque vecteur d'INT occupe 2 mots ( un pour CS et l'autre pour IP )
soit 4 octets. Ce qui fait que lorsqu'on appelle par exemple l'INT
9 on ne va pas charger le mot à l'emplacement 9 dans IP et le
suivant dans CS. Il faut pour avoir l'adresse réelle ou se trouvent
les vecteurs CS et IP multiplier 9 * 4 ( puisque chaque INT prend
4 octets ) Et donc en 36 on trouve CS qui occupe l'octet 36 et 37
puis IP qui occupe les deux octets suivant soit 38 et 39. La
prochaine INT qui est la 10 commencera en 40.
2) Pour simuler une INT on peut utiliser un CALLF et un PUSHF.
a) Un PUSHF qui place le registre des FLAGS sur la pile.
b) Un CALLF lequel appelle la routine de l'INT considérée.
3) Cas de mes lanceurs:
a) L'INT 21 est détournée de son vecteur d'origine.
b) Le nouveau vecteur pointe sur une routine personnelle.
c) La fin de ma routine est un peu spéciale car soit on appelle
l'ancien vecteur de l'INT 21 par un CALL FAR et PUSHF, soit
on revient par un RETF corrigé.
Ci-dessous l'incrémentation/décrémentation du pointeur de pile lors
de l'appel de l'INT 21 détournée;
.
.
│ . │
│ . │
│ Progr. │ L'INT 21 pousse ces
│principal│ 3 REGS. sur la pile
├─────────┤ ┌──────────────┐
│ INT 21 │ ──────> │ PUSH Flags │ SP-2
────────── ├─────────┤ ├──────────────┤
SP=0 │ suite │ <────┐ │ PUSH CS et IP│ SP-4 ┌────────────┐
│ . │ │ └───────┬──────┘ │ Nouveau │
│ . │ │ │ │ vecteur │
. │ └────────────────> ├────────────┤
. │ 8 Regs │ Push REGs │ SP-16
│ ├────────────┤
│ │ Traitement │
│ ├────────────┤
│ 8 Regs │ POP REGs │ SP+16
│ ├────────────┤
│ │
│ Ici deux choix: │
│ ┌──────────────────────┤ Appel de
│ │ Ou retour │ l'ancien
│ │ par RETF. │ vecteur.
│ ├────────────┤ ├────────────┤
│ │ RETF + 2 │ SP+4+2 │ PUSH Flags│ SP-2
│ └──────┬─────┘ ├────────────┤
│ │ │ CALL Far 21│ SP-4+6
│ │ ├────────────┤
│ │ │ IRET │ SP+6
│ │ └──────┬─────┘
│ │ │
└─────────────┴──────────────────────┘
Etat de la pile:
Donc avant l'appel de l'INT: SP=0
Après l'appel de l'INT 21 : SP-6 SP-6
Les PUSH de mon lanceur : SP-16 SP-22
Les POP de mon lanceur : SP+16 SP-6
1) Retour par RETF +2 : SP+4+2=+6 SP=0
2) Retour par CALLF+IRET : SP-2-4+6+6=+6 SP=0
Retour par RETF:
----------------
Le +2 qui suit le RETF dans le cas où l'on revient avec ce dernier
sert à aligner le pointeur de pile car le retour d'une INT se fait
par l'instruction IRET qui restaure IP ( +2 ), CS ( +2 ), puis le
registre des flags ( +2 ) ce qui fait +6. Alors que dans le cas
présent on revient avec un RETF qui lui ne restaure qu'IP et CS
( +2 et +2 ) il manque donc les fameux +2 que l'on trouve dans
l'instruction RETF +2.
Retour par CALLF et IRET:
-------------------------
Certainement le plus compliqué à comprendre. Je pense que vous êtes
d'accord avec mes push/pop qui s'annullent avec -16 et +16. Ok, il
nous reste donc -6 dù au départ à l'appel de l'INT21.
Alors voilà ce qui se passe maintenant: j'appelle l'INT 21 avec
un CALL Far donc -4 et un PUSHF donc -2.
(-4) + (-2) font -6 ( Vous m'arrêtez si vous avez des difficultés ).
On se retrouve maintenant dans l'INT 21 avec un SP à -12 (-6)+(-6).
On revient de l'INT 21 par un IRET dans mon lanceur ce qui fait
-12+6=-6. Et de mon lanceur je refais un IRET pour le quitter
et revenir vers le programme appelant: donc encore une fois +6.
Et, comme vous l'aurez deviné: -6+6=0 !
Donc mon lanceur redonne bien correctement le control au programme
principal. Pourtant il y a une erreur d'écriture dans ce dernier qui
fait que certains de mes patchs ne fonctionnaient pas.
Mon programme se plantait dans certain cas où l'un des flags était
testés lors du retour de l'appel de l'INT 21 pour la raison suivante:
Lors de l'appel de l'INT 21 le registre des flags est sauvé sur la
pile avant l'éxecution de ma routine. Puis ma routine est éxecutée
à son tour avant de simuler l'appel de l'INT 21 par un PUSH Flags
et un CALL far sur l'ancien vecteur de l'INT 21. Nous avons ici un
second PUSH flags qu'il est impossible d'éviter puisque toute inter-
ruption y est soumise en se terminant par un IRET qui restaure IP,
CS, et les flags. C'est donc le second PUSHF qui se retrouvait au
sommet de la pile lors du retour au programme principal et non plus
le premier qui avait été sauvé. Tant que mon traitement n'affectait
pas un des flags, le contenu du second PUSHF était égal au premier et
tout se passait sans problème.
Dans le cas où mon traitement modifiait le contenu d'un des drapeaux
mais tant que celui-ci n'était pas testé au retour de ma routine
aucune interaction ne survenait. Mais il a suffit d'une fois dans le
programme XXXXXXXXXX pour me faire prendre conscience de ce bug !
La solution consiste donc à faire un PUSH flags en même temps que mes
registres puis à les restaurer une fois le traitement terminé.
Dans ce cas ma routine fonctionne correctement ( enfin ), et comme
l'on se trouve avec un POPF et un PUSHF avant l'appel de l'INT 21 par
le CALL far, celà permet de supprimer ces deux instructions. Un POP
et un PUSH s'annulent.
On obtient donc l'organigramme suivant:
.
.
│ . │
│ . │
│ Progr. │ L'INT 21 pousse ces
│principal│ 3 REGS. sur la pile
├─────────┤ ┌──────────────┐
│ INT 21 │ ──────> │ PUSH Flags │ SP-2
────────── ├─────────┤ ├──────────────┤
SP=0 │ suite │ <────┐ │ PUSH CS et IP│ SP-4 ┌────────────┐
│ . │ │ └───────┬──────┘ │ Nouveau │
│ . │ │ │ │ vecteur │
. │ └────────────────> ├────────────┤
. │ │ Push Flags │ SP-2
. │ ├────────────┤
. │ 8 Regs │ Push REGs │ SP-16
│ ├────────────┤
│ │ Traitement │
│ ├────────────┤
│ 8 Regs │ POP REGs │ SP+16
│ ├────────────┤
│ │
│ Ici deux choix: │
│ ┌──────────────────────┤ Appel de
│ │ Ou retour │ l'ancien
│ │ par RETF. │ vecteur.
│ ├────────────┤ │
│ │ RETF+4 │ SP+4+4 │
│ └──────┬─────┘ ├────────────┤
│ │ │ CALL Far 21│ SP-4+6
│ │ ├────────────┤
│ │ │ IRET │ SP+6
│ │ └──────┬─────┘
│ │ │
└─────────────┴──────────────────────┘
Il existe aussi une autre solution qui est décrite ci-dessous en
utilisant uniquement un JMP FAR sur l'INT 21 ce qui évite de repasser
par mon lanceur au retour.
.
.
│ . │
│ Progr. │
│principal│
├─────────┤ ┌──────────────┐
SP=0 │ INT 21 │ ──────> │ PUSH Flags │ SP-2
────────── ├─────────┤ ├──────────────┤
SP=0 │ suite │ <────┐ │ PUSH CS et IP│ SP-4 ┌────────────┐
│ . │ │ └──────────────┘ │ Nouveau │
│ . │ │ │ │ vecteur │
. │ └────────────────> ├────────────┤
. │ │ Push REGs │ SP-X
│ │ + FLAGS │
│ ├────────────┤
│ │ Traitement │
│ ├────────────┤
│ │ POP REGs │ SP+X
│ │ + FLAGS │
│ ├────────────┤
│ Ancien Vecteur ├─>│ JMPF INT 21│
│ └────────────┘
└─────┤ Retour par une IRET de l'INT 21 ( SP+6 )
Le petit proggy AFF_INT.COM affiche de gauche à droite:
- Le numéro de l'INT à partir de 00 jusqu'à FFh.
- La valeur du vecteur CS:IP sur lequel pointe l'INT considérée.
- La première instruction en HEXA allant être exécuté à l'emplacement
défini par ce vecteur.
- La traduction mnémonique en ASM permettant rapidemment de savoir
si l'INT en question est utilisée ou si elle retourne vers le
programme appellant avec une instruction IRET.
- Un commentaire.
Nota: toutes les instructions ne sont pas décodées...
Essai pratique:
Lancer _DEBUG.COM en choississant l'observation octet mémoire ou IO.
Puis comme véhicule, utilisez une INT quelconque au choix, le
meilleur choix pourrait être dans la plage 78h à ECh - qui représentent
les INT non utilisées.
En lancant AFF_INT vous remarquerez que l'INT en question ne pointe
plus sur son vecteur d'origine et que sa première instruction est
un JMP ( première instruction de l'INT détournée de _DEBUG.COM ).
FREDDY