Nouveaux concepts: Processus et threads Nouvelles fonctions API: CreateProcess |
Un loader est un programme autonome utilisé pour charger et exécuter un autre programme. Il est utilisé lorsque nous voulons patcher une cible en mémoire, par exemple après une vérification CRC, ou lorsque l'on veut patcher quelque chose et restaurer les octets d'origine plus tard dans le programme. Un exemple de loader est le trainer généralement utilisé pour tricher dans les jeux. Dans ce tutoriel, nous allons coder un loader très simple et comparer son action avec le patcheur que nous avons créé dans le dernier tutoriel. Tout d'abord, nous devons aborder quelques notions théoriques générales sur les processus, les threads et la gestion de la mémoire. Processus et Threads Un processus fournit les ressources nécessaires pour exécuter un programme.
Chaque processus est une collection d'espace d'adresse mémoire virtuelle,
de code exécutable, de données, de handles ouverts vers des objets système,
d'un contexte de sécurité, d'un identifiant de processus unique,
de variables d'environnement, d'une priorité de base, de tailles minimale et maximale de l'ensemble de travail,
et au moins un thread d'exécution. Un thread est du code qui doit être exécuté au sein d'un processus.
Un processeur exécute des threads, pas des processus, donc chaque application a au moins un processus,
et un processus a toujours un thread en cours d'exécution, appelé thread principal.
Un processus peut également avoir plusieurs threads. L'utilisation de threads confère à Windows sa capacité apparente de multitâche,
c'est-à-dire la capacité d'exécuter plusieurs programmes simultanément.
Au lieu de continuer à exécuter un seul morceau de code jusqu'à son achèvement,
Windows peut décider d'interrompre un thread en cours d'exécution à n'importe quel moment
et passer à un autre thread. La séquence d'initialisation du processus Il est important de comprendre ce qui se passe lorsqu'un processus est créé. Ce qui suit fournit une brève description des étapes prises par le système dans la séquence d'initialisation moyenne d'un processus. 1. L'API CreateProcess crée un nouvel objet de processus et alloue
un espace d'adressage virtuel pour celui-ci (voir le paragraphe suivant). Gestion de la mémoire virtuelle de Windows Chaque processus a son propre espace d'adressage virtuel qui permet d'adresser jusqu'à 4 Go de mémoire. Tous les threads d'un processus peuvent accéder à son espace d'adressage virtuel, mais pas à la mémoire appartenant à un autre processus, ce qui protège un processus contre toute corruption par un autre processus. Les adresses virtuelles utilisées par un processus ne représentent pas
l'emplacement physique réel d'un objet en mémoire. Au lieu de cela, le système maintient une table
de pagination pour chaque processus - une structure de données interne utilisée pour traduire
les adresses virtuelles en adresses physiques correspondantes.
Chaque fois qu'un thread référence une adresse, le système traduit l'adresse virtuelle en adresse physique.
Les pages de l'espace d'adressage virtuel d'un processus peuvent se trouver dans l'un des états suivants : La fonction API VirtualAlloc est utilisée pour réserver et allouer de la mémoire, et spécifier les permissions d'accès à la mémoire pour les pages allouées : Un processus utilise d'abord VirtualAlloc pour réserver un bloc de pages dans son espace d'adressage. Plus tard, VirtualAlloc est appelé à nouveau chaque fois qu'il est nécessaire d'allouer une page à partir de cette région réservée. Allouer l'ensemble de la région au lieu de la réserver uniquement consomme un espace de stockage physique qui pourrait ne pas être nécessaire, le rendant indisponible pour une utilisation par d'autres processus. Le processus utilise VirtualFree pour libérer les pages réservées et allouées lorsqu'il en a terminé avec elles. VirtualAllocEx est une fonction importante qui peut réserver ou allouer une région de mémoire dans l'espace d'adressage virtuel d'un autre processus spécifié. Considérations lors de l'écriture d'un loader Un loader doit créer un nouveau processus et charger la cible, mais nous voulons mettre en pause le thread dès sa création afin de pouvoir modifier ce que nous voulons. Nous utilisons l'API CreateProcess à cet effet, avec la valeur CREATE_SUSPENDED dans dwCreationFlags. CreateProcess prend des pointeurs vers 2 structures importantes :
ProcessInformation et StartupInfo. La structure ProcessInformation est remplie avec le handle du processus,
le handle du thread et l'ID du processus/thread (consultez win32.hlp pour plus d'informations).
|
Notre loader se contente de créer un processus et de charger SuperCleaner avec le thread principal suspendu. Ensuite, il patchera le fichier en mémoire, reprendra l'exécution du thread principal et se terminera. Lancez WinAsm comme d'habitude et collez le code loader1.asm. Bien que ce loader n'ait pas vraiment d'interface graphique, il est préférable qu'il ait au moins une icône. Ajoutez un script de ressources au projet et ajoutez simplement une icône. Cela donne le script suivant : Le code d'assemblage est court mais efficace. Remarquez qu'il n'y a pas d'interface graphique (pas d'appel à DialogBoxParam), donc nous n'avons pas besoin de récupérer et de sauvegarder le handle du module. De plus, en cas d'erreur, nous devons terminer le processus cible suspendu avant de quitter : Une critique possible de ce code est que nous avons spécifié l'adresse virtuelle (VA) à patcher. Cela repose sur le fait que la cible est chargée à l'ImageBase préféré pour que le patch fonctionne. Une façon plus robuste serait de spécifier l'adresse relative (RVA) puis d'obtenir l'adresse de base de la cible et de les ajouter pour obtenir l'adresse virtuelle (VA) à patcher. Ainsi, si la cible était chargée à une adresse de base différente, le loader patcherait toujours les octets corrects, bien que cela s'applique principalement aux DLL. Une autre critique est que c'est un loader aveugle - il ne vérifie pas. Nous aborderons des concepts plus avancés dans le prochain tutoriel.
|
Copyright (C)- xtx Team (2021)