Blog ENI : Toute la veille numérique !
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
💥 1 livre papier acheté 
= la version en ligne automatiquement offerte. Cliquez ici
  1. Livres et vidéos
  2. Python et l'analyse forensique
  3. Inspection des processus du noyau Linux
Extrait - Python et l'analyse forensique Récupérer et analyser les données produites par les ordinateurs
Extraits du livre
Python et l'analyse forensique Récupérer et analyser les données produites par les ordinateurs Revenir à la page d'achat du livre

Inspection des processus du noyau Linux

Introduction

1. Ptrace et le noyau Linux

a. Exécutables et processus

Il convient de faire la différence entre un fichier exécutable et un processus. Les processus sont les « programmes en cours d’exécution ». C’est l’objet abstrait manipulé par le système d’exploitation pour permettre l’exécution de plusieurs programmes simultanément. Les processus, associés à un identifiant (PID), disposent tour à tour de l’accès aux ressources. Comme décrit dans la partie dédiée au traitement parallèle, il est possible qu’un seul programme se réalise grâce à plusieurs processus travaillant ensemble.

Les processus sont démarrés à partir de fichiers exécutables. Les systèmes d’exploitation de type UNIX partagent un format de représentation de ces fichiers : ELF (Executable and Linkable Format pour « Format exécutable et liable »). Ce format permet de représenter un exécutable ou des objets de liaison. Il fait abstraction de l’architecture du processeur et peut donc être utilisé sur de nombreuses plateformes. Ce format est documenté dans la page elf(5) du manuel de Linux.

Les objets de liaisons sont des morceaux de code compilés, prêts à être inclus dans un exécutable. Dans le langage C (langage avec lequel est écrit le noyau Linux), ces objets de liaison participent au mécanisme de bibliothèques. Celles-ci, quand elles ne sont pas incluses aux binaires exécutables, sont chargées à partir de ces objets de liaison lors de la création en mémoire du processus découlant de l’exécution d’un fichier ELF.

Ce format définit la manière de stocker un programme avant son exécution. À ce titre, il permet déjà de connaître un ensemble d’informations sur le programme. Par exemple, la liste des instructions le constituant, les bibliothèques qui seront chargées à l’exécution ou encore la valeur, et/ou...

Inspection d’un processus avec Python

1. La bibliothèque python-ptrace

a. Introduction

Le package python-ptrace contient un ensemble de modules relatifs à ptrace et à l’inspection des processus. Pour commencer, il contient des bindings Python : un ensemble de fonctions utilitaires destinées à Python, écrites en C, faisant appel à ptrace. Elles permettent de s’interfacer au noyau avec des objets Python. 

Le package contient, en plus, un ensemble de modules et de classes utilitaires dédiées à l’inspection d’un processus. Les deux classes « principales » sont PtraceDebugger et PtraceProcess.

La première, PtraceDebugger, permet de gérer un ou plusieurs processus tracés. Elle dispose notamment de méthodes pour ajouter ou supprimer des processus et de méthodes pour se mettre en attente d’un événement (breakpoint, syscall ou signal). Elle possède aussi des options pour définir le comportement en cas de création d’un processus enfant par un processus tracé.

La seconde, PtraceProcess, représente un processus tracé. Elle dispose de méthodes utilitaires pour accéder aux fonctionnalités de ptrace : inspection des registres, lecture/écriture de la mémoire, etc. D’autres méthodes ne reposent pas directement sur l’utilisation de ptrace, mais proposent des fonctionnalités pratiques. C’est notamment le cas de la méthode PtraceProcess.readMappings() qui lit le pseudo système de fichiers proc pour fournir une représentation pour Python des projections mémoire en cours pour un processus tracé.

b. Installation de python-ptrace

Au moment de l’écriture de ce livre, le paquet python3-ptrace (la version Python 3 de python-ptrace) n’est disponible qu’à partir de Debian Buster, la version testing de Debian. Le gel des logiciels (étape précédant le passage d’une testing en stable ) est prévu pour mars 2019. Il y a donc fort à parier qu’un utilisateur d’une Debian stable pourra, au moment de sa lecture, installer cette bibliothèque avec apt.

# apt-get install pyhon3-ptrace 

De manière plus générale, python-ptrace est référencé...

Exemple d’utilisation

1. Extraire le texte

a. Objectif du programme

L’objectif du programme présenté dans cette section sera d’extraire les chaînes de caractères présentes dans la mémoire d’un processus donné. Le principal problème dans ce type de traitement est le « bruit » généré : tous les ensembles d’octets qui peuvent être interprétés comme une chaîne, mais qui n’en sont pas.

La première mesure pour réduire le bruit généré est de limiter la recherche à certaines projections mémoires. Le premier critère de sélection pour une projection peut être ses permissions. Seules les projections disposant du droit en écriture seront analysées : une projection en lecture seule fournira vraisemblablement un contenu accessible par une analyse statique. De plus, seules les projections de l’exécutable (pour la mémoire statique), la map « [heap] » et les maps anonymes seront analysées.

La seconde série de mesures concernera les données lues à proprement parler. Pour commencer, Python essayera de convertir des séries de 1 à 4 octets en caractères UTF-8, opérant un premier filtre. Ensuite, seuls les caractères affichables seront conservés.

La recherche de caractère UTF-8 est chronophage. Les Pool du module multiprocessing seront utilisées pour accélérer le traitement : chaque processus de la Pool se voyant attribuer une map distincte.

b. La fonction d’extraction des chaînes de caractères

Cette fonction contiendra le code dédié à la recherche des chaînes UTF-8 dans une projection mémoire. Elle aura le rôle particulier d’être utilisée par les processus de la Pool de traitement. Or, les données envoyées aux sous-processus (les arguments de la fonction) doivent être sérialisées afin d’être communiquées.

La sérialisation consiste à représenter un objet Python sous la forme d’une chaîne d’octets. Cette représentation doit permettre de reconstruire une instance identique. Ce mécanisme est utilisé...