Comment les DLL Windows sont-elles réellement partagées?

En examinant plusieurs DLL que j’ai dans ma machine Windows (par exemple, KERNEL32.DLL), j’ai remarqué qu’aucune de leurs sections, pas même la section en lecture seule des données, ne définit l’indicateur IMAGE_SCN_MEM_SHARED.

Les DLL sont mappées à partir du fichier .dll. Elles sont donc copiées dans la mémoire physique uniquement lorsque vous lisez une page du fichier. Néanmoins, si la même page de kernel32.dll est accessible à la fois par le processus A et le processus B, la page exister deux fois dans la mémoire physique. Je demande la véracité de cette dernière déclaration.

Si le segment .text ou le segment .rodata où ils étaient partagés étaient copiés dans la mémoire physique uniquement, même lorsque ASLR est activé, ASLR effectue la sélection aléatoire de la base d’un module lorsqu’il est chargé (avec les déplacements correspondants appliqués) mais Le processus suivant qui charge ce module jusqu’au redémarrage du système obtiendra le module à la même adresse afin que les fichiers .text et .rodata puissent être partagés de la même manière.

Ce sont toutes les hypothèses que j’ai faites, corrigez-moi s’il vous plaît.

Merci!

Le système d’exploitation pourra certainement mapper plusieurs adresses virtuelles sur la même page de mémoire physique, à condition que le contenu de la page ne change pas (ne doit pas être modifié) [de manière différente selon les processus]. Toutefois, si le code utilise une adresse absolue (interne ou externe à la DLL), par exemple un pointeur vtable / function, des pointeurs vers des données globales (constantes ou non) ou simplement des appels de fonction avec des adresses absolues, l’adresse doit être modifié pour faire correspondre l’adresse réelle donnée par le système d’exploitation à cette partie de la mémoire. Cela s’appelle “relocalisation”.

Donc, au moins en théorie, vous pouvez partager la même DLL même avec la randomisation de l’espace d’adressage, cela demande juste un peu plus de travail du compilateur et / ou du programmeur. En particulier, il faut qu’il n’y ait pas de relocalisation (en gros morceaux de code). Si le code a des adresses absolues qui sont déplacées en fonction de l’adresse de code, il devra alors en avoir une copie par DLL.

Je ne sais pas vraiment comment l’OS gère cela. Une solution simple consiste évidemment à randomiser l’adresse une seule fois par DLL (jusqu’à ce que cette DLL particulière soit déchargée), quel que soit le nombre d’applications utilisant la même DLL. Il est toujours difficile pour un étranger de savoir à quelle adresse la DLL est chargée, car elle se chargera à une adresse différente chaque fois qu’elle sera chargée la première fois (et plus important encore, ce ne sera pas une valeur statique pour TOUTES les machines). utilisant la même version du système d’exploitation, ce qui serait le cas sans cette fonctionnalité). Cela signifie toutefois que les processus de longue durée peuvent être “inspectés” en copiant le contenu, par exemple, de la stack dont le contenu est connu. Les serveurs Web, les serveurs de firebase database et les services système sont généralement des processus de longue durée et, en tant que tels, auront des adresses différentes uniquement lorsque le système est “arrêté” (ou au moins le processus de longue durée est redémarré).

La deuxième version, un peu plus délicate, consiste à vérifier si une page particulière (généralement une région de 4 Ko de mémoire) a des relocalisations et à partager toutes les pages sans relocalisation. Les pages déplacées doivent avoir une copie par adresse de base. Il est typique d’avoir “toutes les références aux ressources externes” dans un bloc de DLL (une “section thunk”), de sorte que la grande partie typique d’une DLL ne serait pas indépendante de l’adresse de base du code, ce qui signifie définitivement une solution réalisable.

Si aucun de ces modèles ne “fonctionne” dans le système d’exploitation, vous devez charger la même DLL plusieurs fois. Cela fonctionne clairement du sharepoint vue du système d’exploitation de toute façon, car avant ASLR, l’adresse de base de la même DLL devra être déplacée si deux DLL tentent de se charger à la même adresse cela arrive pour choisir la même adresse de base pour le code, ou le classique et commun “Je n’ai jamais donné d’adresse de base, donc il utilise l’adresse par défaut”) – le système d’exploitation résoudra de tels conflits en modifiant l’adresse de base de celle chargée. premier.

En ce qui concerne la signification de IMAGE_SCN_MEM_SHARED , j’aurais pensé que le développeur le demanderait, où le partage des pages dans une DLL est effectué automatiquement. En d’autres termes, IMAGE_SCN_MEM_SHARED sera défini par le développeur d’une DLL ou d’un fichier EXE particulier pour indiquer que le contenu doit être partagé avec d’autres utilisateurs du même contenu, plutôt que “le système d’exploitation peut le partager s’il peut le faire sans l’utilisateur du contenu. noticing “(ce qui est certainement le cas pour le partage de code et les données (en écriture) ne sont généralement pas partagées entre les DLL. Les données en lecture seule, tant qu’elles ne sont pas relogées, peuvent bien sûr être partagées de manière implicite [l’utilisateur du contenu peut pas dire si c’est partagé ou pas].