Questions sur Windows et son mode protégé

Résolu
Oeil_de_taupe Messages postés 150 Date d'inscription samedi 31 janvier 2004 Statut Membre Dernière intervention 16 février 2009 - 7 oct. 2006 à 11:21
Oeil_de_taupe Messages postés 150 Date d'inscription samedi 31 janvier 2004 Statut Membre Dernière intervention 16 février 2009 - 9 oct. 2006 à 02:28
Bonjour,




J'utilise mes longue vacances pour me mettre à l'assembleur, et plus particulièrement la création d'exécutable assembleur pour Windows (donc API Win32 et mode protégé).


J'ai décidé d'utiliser NASM pour ma programmation Windows mais de multiples questions me viennent à l'esprit et mes recherches sur internet n'ont rien données!


Voilà quatre questions, sans doute idiotes pour la majorité de personne sur ce forum, mais je le répète encore, je n'ai rien trouvé me donnant une piste pour continuer à chercher.





1 ère question





Es-ce qu'un exécutable Win32 doit créer une pile lui-même comme il le fait en mode réel? (même si en mode réel on peut laisser par défaut et utiliser la fin de l'unique segment).
Je n'en ai pas trouvé avec Ollydbg dans les programmes normaux. La pile serait à l'"extérieur" du programme et créée par Windows?





2 ème question





J'ai compris l'utilisation du CALL NEAR/FAR et RETN et RETF. Ceci permet de savoir si il faut empiler le registre CS (pour le retour).
J'ai remarqué que en mode protégé pour sauter d'un segment à un autre à l'intérieur d'un programme il fallait utiliser que "CALL NEAR" sinon le compilateur faisait une erreur. Mais comment expliquer ceci?


Il existe toujours un registre CS! (sélecteur de segment OK, mais registre quand même...)







3 ème question





J'utilise Ollydbg (un débugger) pour voir ce que produit un changement dans le code source sur mon exécutable. Et j'ai remarqué que dans le PE Header un champs notifiait si l'accès aux données était: lecture / écriture / données initialisées / données non-initialisées / exécutable.


Mais je n'arrive pas à modifier ces champs depuis mon code ASM! Je n'arrive pas à dire à NASM que un segment est un segment de données et un autre du code.
Pour vous donner un exemple voici un de mes codes extrêmement simple.

[BITS 32]



extern MessageBoxA
import MessageBoxA user32.dll





segment codeasm USE32 PRIVATE
..start:
 push 0
 push caption
 push msg
 push 0
 call [MessageBoxA]
 ret



segment donnee USE32
msg: db "Le text", 0
caption: db "Le titre", 0



Après vérification (avec OllyDbg) le segment donnee et codeasm sont les deux en READ|WRITE|INITIALIZED_DATA, je ne peux pas changer ces attributs alors que le compilateur Visual Studio 2005 (C++) modifie ces attributs pour rendre le code "EXECUTABLE" et le segment qui accueil les constantes (rdata) n'a pas l'accès : WRITE


Savez-vous comment modifier ces attributs indépendamment pour chaque sections?
Es-ce que le faite que je compile via un fichier objet plutôt que en format "win32" comme le propose NASM pourrait expliquer cette impossibilité de modification?





4 ème et dernière question (je vous promet)





Cette question concerne les accès à plusieurs segment avec le même registre de base. Si je compile ce code il marche! :



[BITS 32]



extern MessageBoxA
import MessageBoxA user32.dll





segment codeasm USE32 PRIVATE
..start:
 push 0
 push caption
 push msg
 push 0
 call [MessageBoxA]
 ret



segment donnee1 USE32
caption: db "Le titre", 0



segment donnee2 USE32
msg: db "Le text", 0




Mais pourtant je vais piocher dans deux segments différents! Si j'ai bien compris le tas de documentation que j'ai lu le segment de base devrait être celui que je pointe avec DS (sauf avec EBP). Mais ici comme je vais chercher dans deux segment différent je devrais lire au moins une variable à la mauvaise case mémoire non?

Rien qu'un tout petit indice me permettrait d'amorcer de nouvelles recherches sans doute plus concluantes.


Merci d'avance

4 réponses

BruNews Messages postés 21040 Date d'inscription jeudi 23 janvier 2003 Statut Modérateur Dernière intervention 21 août 2019
8 oct. 2006 à 01:40
La taille de pile voulue se donne au linker, 1 Mo par défaut. Windows va allouer l'espace qu'il faut (par pages de 4 Ko) pour l'image de ton module + taille de pile, le tout de manière linéaire (FLAT) sur les 2 Go dont tu peux théoriquement disposer.

CS comme les autres existent mais tu n'en tiens absolument plus compte, ne sert qu'au kernel pour calculer les adresses de mémoire virtuelle qu'on emploie à translater en adresses physiques.

Exemple de segment avec MASM, tu verras si idem avec NASM:
Dans fichier asm, un segment de données partagées entre différentes instances d'un même module physique (au même endroit):
Partage      SEGMENT
g_hPrev     DD   0
Partage      ENDS
Pour linker on ajoute: /section:Partage,rws
'Partage' est juste un identifiant au choix, ce qui suit indique Read Write Shared.

Le reste est du sabir propre à NASM, aucune idée.
EBP, j'en fais ce que je veux sur MASM.

ciao...
BruNews, MVP VC++
3
Oeil_de_taupe Messages postés 150 Date d'inscription samedi 31 janvier 2004 Statut Membre Dernière intervention 16 février 2009
8 oct. 2006 à 12:30
Merci beaucoup pour cette réponse.

Je ne savais pas que on pouvait indiquer la taille de la pile au linker (ainsi que les droits donnés aux segments).

Je note au passage, pour les NASM-fan, que en compilant en "Fichier objet Win32" on peut indique le droits dans le fichier .asm mais pas en compilant au format "Fichier objet OMF".
0
cs_patatalo Messages postés 1466 Date d'inscription vendredi 2 janvier 2004 Statut Modérateur Dernière intervention 14 février 2014 2
8 oct. 2006 à 23:40
salut,




je suis etonné que ton programme fonctionne, tu devrais avoir la fonction
"ExitProcess" en fin de code au lieu du ret qui retourne je sais pas ou d'ailleurs.

si tu fais ctrl+alt+suppr, ne retrouve tu pas ton programme encore en execution dans la liste des processus ?

@++
0
Oeil_de_taupe Messages postés 150 Date d'inscription samedi 31 janvier 2004 Statut Membre Dernière intervention 16 février 2009
9 oct. 2006 à 02:28
Oui en effet, ceci m'a aussi étonné . Certaines personnes le mettent et d'autres pas...

Mais je crois avoir trouvé l'explication. J'ai débuggé mon exécutable (dans lequel j'ai omis le ExitProcess) pour constater que le RETN final renvoie dans la librairie Kernel32 (.dll?), mappée dans l'espace mémoire du processus (je sais pas si le terme est juste). Et à l'endroit pointé il y a un appel à "ExitThread".

Je me suis rendu sur MSDN et pour ExitThread il y a cet phrase:
If the thread is the last thread in the process when this function is called, the thread's process is also terminated.

Le fait d'oublier ExitProcess ne causerait donc aucun problème dans mon cas. Par contre, si c'est une application multi-threadée, l'application ne serait pas stoppée mais juste le thread principal (il devrait y avoir de la casse...).

Autre chose, lors de l'utilisation de RETN, eax est passé en paramètre à ExitThread. A mon avis ce code devrait correspondre à la valeur de retour du processus (a vérifier.. je n'en ai pas le temps actuellement).
0
Rejoignez-nous