
framework d'exploitation du heap jemalloc
shadow est un framework d'exploitation du tas jemalloc. Il a été conçu pour être agnostique de l'application cible qui utilise jemalloc comme allocateur de tas (que ce soit la libc d'Android, Firefox, la libc de FreeBSD, jemalloc autonome, ou autre). La version actuelle (2.0) a été testée de manière approfondie avec les cibles suivantes :
Outre le code source de l'outil, ce dépôt comprend également de la documentation sur la mise en place d'un environnement de débogage userland Android pour utiliser shadow, un aperçu rapide des structures jemalloc d'Android à l'aide de shadow, et quelques notes sur la manière dont les bugs de double libération, de libération non alignée et de libération arbitraire se comportent sur le jemalloc d'Android.
Lorsque vous émettez une commande spécifique à jemalloc pour la première fois, shadow analyse toutes les métadonnées jemalloc qu'il connaît et les enregistre dans un fichier pickle Python. Les commandes suivantes utilisent ce fichier pickle au lieu de ré-analyser les métadonnées à partir de la mémoire pour être plus rapides.
Lorsque vous savez que l'état des métadonnées jemalloc a changé (par exemple lorsque vous avez effectué des allocations ou déclenché un garbage collection), utilisez la commande jeparse pour ré-analyser les métadonnées et recréer le fichier pickle.
La première étape consiste à installer pyrsistence sur votre machine hôte.
Sur un appareil rooté, faites ce qui suit :
host$ adb shell
phone$ su root
phone# ps -e
À partir de la sortie de ps, sélectionnez un processus, par exemple com.google.process.gapps :
...
u0_a19 4679 3214 1668980 69216 SyS_epoll_ 7fa5f41430 S com.google.process.gapps
...
phone$ cd /data/local/tmp
phone$ ./gdbserver64 :5039 --attach 4679
Vous pouvez trouver les binaires du serveur GDB pour ARM32 et ARM64 dans le répertoire "bin". Ou, si vous ne nous faites pas confiance, faites :
host$ git clone http://android.googlesource.com/toolchain/gdb
host$ cd ./gdb/gdb-7.11
host$ mkdir build64; cd build64
host$ ../configure --program-prefix=aarch64-eabi-linux- --target=aarch64-eabi-linux --disable-werror
host$ make
host$ sudo make install
Ensuite, sur la machine hôte, faites :
host$ adb forward tcp:5039 tcp:5039
host$ aarch64-eabi-linux-gdb
(gdb) target remote :5039
(gdb) source /dir/with/shadow/gdb_driver.py
(gdb) jeparse -c /dir/with/shadow/cfg/android7_64.cfg
(gdb) jeruns -c
Parfois, le serveur GDB cesse d'écouter si vous mettez trop de temps à émettre la commande target remote :5039. Donc, si vous voyez des erreurs étranges lorsque vous émettez la commande jeparse, recommencez depuis le début.
shadow pour Windows/Firefox a été testé avec les éléments suivants :
Remarque : Si vous travaillez avec une version de Firefox antérieure à 36.0, utilisez la branche mozjs !
Vous devez d'abord configurer WinDBG avec [le serveur de symboles de Mozilla] (https://developer.mozilla.org/fr/docs/Using_the_Mozilla_symbol_server). Vous devez également installer pykd. Copiez ensuite le répertoire shadow que vous avez cloné depuis GitHub dans un chemin (par exemple C:\tmp\).
Vous trouverez également un exemple de script d'initialisation WinDBG dans le fichier "windbg-init.cmd". Placez-le dans C:\tmp\ et démarrez WinDBG avec windbg.exe -c "$$>< C:\tmp\windbg-init.cmd".
Enfin, depuis WinDBG, émettez les commandes suivantes :
!load pykd.pyd
!py c:\\tmp\\shadow\\pykd_driver help
[shadow] De Mysteriis Dom jemalloc
[shadow] shadow v2.0
[shadow] Firefox v56.0a1 (x86-64)
[shadow] Commandes spécifiques à jemalloc :
[shadow] jechunks : affiche les informations sur tous les chunks disponibles
[shadow] jearenas : affiche les informations sur les arènes jemalloc
[shadow] jerun [-m] <adresse> : affiche les informations sur un seul run
[shadow] -m : prévisualisation du contenu mappé aux métadonnées
[shadow] jeruns [-cs] : affiche les informations sur les runs jemalloc
[shadow] -c : uniquement les runs actuels
[shadow] -s <classe de taille> : runs pour la classe de taille donnée uniquement
[shadow] jebins : affiche les informations sur les bins jemalloc
[shadow] jebininfo : affiche les informations sur les tailles des bins
[shadow] jesize2bin : convertit une taille en index de bin
[shadow] jeregions <classe de taille> : affiche tous les runs qui hébergent les régions de
[shadow] la classe de taille donnée
[shadow] jesearch [-cs] <hex> : recherche dans le tas le double mot hexadécimal donné
[shadow] -c : uniquement les runs actuels
[shadow] -s <classe de taille> : uniquement les régions de la taille donnée
[shadow] jeinfo <adresse> : affiche tous les détails disponibles pour une adresse
[shadow] jedump [chemin] : stocke l'instantané du tas dans le répertoire de
[shadow] travail actuel ou dans le chemin spécifié
[shadow] jestore [chemin] : alias de jedump
[shadow] jetcaches : affiche les informations sur tous les tcaches
[shadow] jetcache [-bs] <tid> : affiche les informations sur un seul tcache
[shadow] -b <index de bin> : informations pour l'index de bin donné uniquement
[shadow] -s <classe de taille> : informations pour la classe de taille donnée uniquement
[shadow] jeparse [-crv] : analyse les structures jemalloc depuis la mémoire
[shadow] -c <fichier de config> : fichier de configuration de la cible jemalloc
[shadow] -r : lit la prévisualisation du contenu
[shadow] -v : produit debug.log
[shadow] Commandes spécifiques à Firefox (pykd uniquement) :
[shadow] nursery : affiche les informations sur la nursery GC de SpiderMonkey
[shadow] symbol [-vjdx] <taille> : affiche tous les symboles Firefox de la taille donnée
[shadow] -v : uniquement les symboles de classe avec vtable
[shadow] -j : uniquement les symboles de SpiderMonkey
[shadow] -d : uniquement les symboles DOM
[shadow] -x : uniquement les symboles non-SpiderMonkey
[shadow] pa <adresse> [<longueur>] : modifie la longueur de l'ArrayObject (nouvelle longueur par défaut 0x666)
[shadow] Commandes spécifiques à Android :
[shadow] jefreecheck [-bm] : affiche les adresses pouvant être passées à free()
[shadow] -b <index de bin> : affiche les adresses qui seront libérées dans
[shadow] le bin tcache de l'index de bin donné
[shadow] -m <nom> : ne rechercher que dans ce module spécifique
[shadow] Commandes génériques :
[shadow] jeversion : affiche le numéro de version
[shadow] jehelp : ce message d'aide
Si vous ne voyez pas le message d'aide ci-dessus, vous avez fait quelque chose de mal ;)
Remarque : Cette fonctionnalité est actuellement réservée à Firefox/Windows !
La commande symbol vous permet de rechercher des classes (et structures) de SpiderMonkey et DOM de tailles spécifiques. Cela est utile lorsque vous essayez d'exploiter des bugs use-after-free, ou lorsque vous souhaitez positionner des objets victimes intéressants à écraser/corrompre.
Dans le répertoire principal de shadow, vous trouverez deux petits utilitaires d'analyse PDB, symhex.py et pdbdy.py (plus rapide). Exécutez-les sur "xul.pdb" pour générer le fichier pickle Python que shadow attend dans le répertoire "pdb" (sous "pdb/xul-VERSION.pdb.pkl"). Avant de les exécuter, assurez-vous d'avoir enregistré "msdia90.dll" ; par exemple sur Windows 8.1 x86-64, vous pouvez le faire avec :
regsvr32 "c:\Program Files (x86)\Common Files\Microsoft Shared\VC\msdia90.dll"
à partir d'une invite Administrateur. Vous avez également besoin du module Python "comtypes" ; installez pip puis faites pip install comtypes.
Pour obtenir "xul.pdb", vous devez configurer WinDBG avec [le serveur de symboles de Mozilla] (https://developer.mozilla.org/fr/docs/Using_the_Mozilla_symbol_server).
unmask_jemalloc a été initialement repensé avec une conception modulaire pour prendre en charge les trois principaux débogueurs et plateformes (WinDBG, GDB et LLDB). L'outil a été renommé shadow lorsque des fonctionnalités propres à Firefox/Windows/WinDBG ont été ajoutées.
Voici un aperçu de la nouvelle conception (lisez les flèches comme "importations"). Le but est, évidemment, de placer tout le code dépendant du débogueur dans les modules *_driver et *_engine.
---------------------------------------------------------------------------------------
frontal requis par le débogueur (colle)
+------------+ +-------------+ +-------------+
| gdb_driver | | lldb_driver | | pykd_driver |
+------------+ +-------------+ +-------------+
^ ^ ^
| | |
------+-------------------+-------------------+----------------------------------------
| | |
| +--------+ |
+------------------------ | +-----+ logique centrale (agnostique du débogueur)
| | |
| | |
+-----------------+
+------+ | |
| |---------------> | shadow |<-----+
| util | +------> | | |
| | | +-----------------+ |
+------+ | ^ ^ ^ ^ |
| | | | | | | | | +--------+
| | | +-----+----------+ | +----+--------+---| symbol |
| | | | | | | | +--------+
+-+ | | | +----------+ | | | +---------+
| | | | | jemalloc | | +--------+---| nursery |
| | | | +----------+ | | +---------+
| | | | ^ ^ ^ | |
| | | | | | | | |
| | | | | | +------+--------+ |
| | | | | | | | |
| | +---+---+----+----------+--------+-----+ |
| | | | | | | | |
| +-----+---+----+----+ | | | |
| | | | | | | | |
--+---------+---+----+----+-----+--------+-----+----+----------------------------------
| | | | | | | | |
| | | | | | | | | API dépendantes du débogueur
| | | | | | | | |
| | | | | | | | |
| | | | v | | v |
| +------------+ | +-------------+ | +-------------+
+->| gdb_engine | +--| lldb_engine | +--| pykd_engine |
+------------+ +-------------+ +-------------+
^ ^ ^
| | |
+---+ +---------+ +---------------+
| | |
| | |
-------+-------------+-------------+---------------------------------------------------
| | |
| | | backend fourni par le débogueur
| | |
| | |
+-----+ +------+ +------+
| gdb | | lldb | | pykd |
+-----+ +------+ +------+
---------------------------------------------------------------------------------------