
Un toolkit IDA pour analyser les kernelcaches iOS.
Ce fork a été mis à jour pour fonctionner avec IDA 9.x / Python 3 / iOS 27.0 beta 1
ida_kernelcache est un module IDAPython pour IDA Pro qui facilite le travail avec les kernelcaches iOS. Le module fournit des fonctions pour :
__PRELINK_INFO du noyau dans un dictionnaire Python.__got et les fonctions stub dans les sections __stubs.La fonction de traitement principale est conçue pour être exécutée avant toute analyse manuelle ou rétro-ingénierie. Avec les paramètres par défaut, IDA a tendance à manquer beaucoup d'informations utiles dans le kernelcache. Ces scripts aident IDA en tirant parti de la structure connue du kernelcache pour propager automatiquement des informations utiles.
En plus des fonctionnalités standard du module, ida_kernelcache contient plusieurs scripts pour faciliter l'analyse du kernelcache iOS. Par exemple, vous pouvez utiliser les scripts pour générer automatiquement des structs C utilisées par une fonction.
Bon nombre des techniques utilisées dans ida_kernelcache ont été développées pour memctl et empruntées directement à celui-ci.
ida_kernelcache a été testé avec IDA Pro 6.95 sur des kernelcaches pour les versions iOS 10.1.1, 11.0, 11.2, 11.3.1 et 12.0 beta. Actuellement, seuls les kernelcaches Arm64 d'iOS 10 et ultérieurs sont pris en charge.
Vous devez déjà avoir un fichier kernelcache décompressé chargé dans IDA. Vous pouvez trouver l'URL pour télécharger un IPSW particulier auprès d'Apple en ligne, et il existe un certain nombre d'outils publics (dont memctl) capables de décompresser le kernelcache.
Dans IDA, sélectionnez « File » -> « Script file... » dans la barre de menu, puis choisissez le script ida_kernelcache.py
dans le répertoire principal. Cela chargera le module ida_kernelcache dans l'interpréteur IDAPython
sous les noms ida_kernelcache et kc. Dans l'invite IDAPython, tapez
kc.kernelcache_process() et appuyez sur Entrée pour commencer à analyser le kernelcache. Cette fonction effectue
toutes les analyses principales prises en charge par ida_kernelcache. La fonction s'exécutera pendant plusieurs minutes pendant
qu'IDA identifie et analyse de nouvelles fonctions.
ida_kernelcache essaiera de ne pas écraser les noms d'utilisateur pour les adresses. Cela signifie que si le
kernelcache a été analysé manuellement avant l'initialisation avec kernelcache_process, les
résultats peuvent ne pas être aussi approfondis car les noms spécifiés par l'utilisateur peuvent bloquer la propagation automatique des noms.
Cependant, rien ne garantit non plus qu'ida_kernelcache ne perturbera pas une analyse antérieure. Par conséquent, si vous
décidez d'exécuter kernelcache_process sur un fichier kernelcache que vous avez déjà analysé, faites une
sauvegarde au préalable.
ida_kernelcache est destiné à être chargé via ida_kernelcache.py ; les sous-modules du répertoire
ida_kernelcache ne sont pas destinés à être chargés directement. Cependant, ida_kernelcache expose
les fonctionnalités de bon nombre de ces sous-modules. Voici ce que fait chacun d'eux :
ida_utilities :
Ce module encapsule certaines fonctions d'IDA pour fournir une API plus facile à utiliser. Particulièrement utiles sont
is_mapped, read_word, read_struct, force_function et ReadWords. is_mapped vérifie
si une adresse est mappée et, éventuellement, si elle contient une valeur connue. read_word lit un
mot de taille variable à partir d'une adresse. read_struct lit un type de structure dans un dictionnaire Python
ou un objet accesseur Python, ce qui rend l'analyse des structures de données beaucoup plus facile. force_function essaie
plusieurs astuces pour convertir une adresse en début de fonction dans IDA. ReadWords est un
générateur pour itérer sur les mots de données et leurs adresses dans une plage.
build_struct : Ce module interne contient des utilitaires pour remplir automatiquement une struct IDA en fonction d'une séquence d'accès à la struct.
class_struct : Ce module fournit des fonctions pour générer des structs IDA représentant les tables de méthodes virtuelles C++ et les classes. analyse les tables de méthodes virtuelles (symbolisées) et crée des structs IDA pour contenir les pointeurs de méthodes virtuelles. effectue une analyse de flux de données sur les méthodes virtuelles pour identifier les accès aux champs de chaque classe, puis construit des structs IDA pour représenter les classes. Les instructions qui semblent référencer un champ sont également converties en références d'offset de structure. Voir la docstring du module pour plus de détails.
Le script ida_kernelcache_reload.py est identique à ida_kernelcache.py, sauf qu'il force le
rechargement du module ida_kernelcache et de tous les sous-modules. Il est surtout utile pour le développement.
Le répertoire scripts contient des scripts qui utilisent ida_kernelcache pour effectuer une certaine forme d'analyse.
Ces scripts sont trop spécifiques pour faire partie du module ida_kernelcache principal, mais ils sont utiles
lors de la rétro-ingénierie du kernelcache. Ils comprennent :
find_virtual_method_overrides.py : Un script pour trouver les descendants d'une classe qui remplacent une méthode virtuelle contenant la chaîne spécifiée. Les remplacements correspondants sont affichés sur la console.
populate_struct.py : Remplit les champs d'une classe C++ ou d'une struct C en effectuant une analyse de flux de données à partir de l'adresse actuelle.
process_external_methods.py :
Traite un tableau IOExternalMethod ou IOExternalMethodDispatch dans un formulaire standard pour une utilisation par les
outils de fuzzing.
Si vous utilisez le décompilateur Hex-Rays, l'une des fonctionnalités les plus intéressantes d'ida_kernelcache est la reconstruction automatique des classes C++, qui utilisera les informations OSMetaClass et l'analyse de flux de données pour créer des structs IDA représentant les classes trouvées dans le kernelcache. Ces représentations peuvent considérablement améliorer la lisibilité de la représentation en pseudo-code. Pour en savoir plus, consultez l'article Reconstructing C++ classes in the iOS kernelcache using IDA Pro.
Avec iOS 12, Apple a introduit un nouveau format de kernelcache sur certains appareils. Parmi les changements, les
pointeurs du noyau de ce nouveau kernelcache sont tagués pour les relier dans une liste, vraisemblablement pour permettre à iBoot de
faire glisser le noyau sans les données _PrelinkLinkKASLROffsets du dictionnaire prelink. Essayer d'analyser
un kernelcache standard utilisant ce format dans IDA est difficile en raison des références croisées manquantes. Voir
l'article Analyzing the iOS 12 kernelcache's tagged pointers pour plus de détails.
Si vous voulez simplement détagger les pointeurs du kernelcache sans effectuer de traitement supplémentaire,
exécutez kc.tagged_pointers.untag_pointers().
Une partie de ces fonctionnalités s'applique probablement plus largement qu'aux seuls kernelcaches Apple (par
exemple, l'analyse des vtables et la propagation des symboles, ou la plupart des fonctions de ida_utilities.py).
Néanmoins, j'ai limité la portée des imports au seul module ida_kernelcache car je n'ai
testé aucune de ces fonctionnalités sur d'autres types de binaires.
ida_kernelcache est publié sous la licence MIT.
Une grande partie des fonctionnalités d'ida_kernelcache est empruntée à memctl, qui est également publié sous la licence MIT. D'autres sources sont mentionnées dans les commentaires des fichiers correspondants.
Brandon Azad
initialize_vtable_structsinitialize_class_structsclasses :
Ce module définit le type ClassInfo qui contient des informations sur les classes C++ du
kernelcache et fournit la fonction collect_class_info pour analyser le kernelcache à la recherche de classes et
remplir le dictionnaire global class_info avec une correspondance entre les noms de classes et les objets ClassInfo. Le
type ClassInfo enregistre le nom de la classe, l'instance OSMetaClass, la table de méthodes virtuelles et
le nom de la superclasse pour chaque classe C++. De plus, chaque objet ClassInfo stocke des références vers
le ClassInfo de la superclasse et le ClassInfo de toutes les sous-classes directes, ce qui facilite
l'examen et le parcours de la hiérarchie des classes. collect_class_info stocke également l'ensemble de toutes les tables
de méthodes virtuelles dans l'ensemble global vtables.
data_flow : Ce module interne contient les opérations de flux de données utilisées par le reste d'ida_kernelcache.
kernel :
Ce module fournit les variables globales base et prelink_info. base est l'adresse de base de
l'image du noyau (le début de l'en-tête Mach-O du noyau). prelink_info est le dictionnaire
__PRELINK_INFO analysé.
kplist :
Ce module fournit la fonction kplist_parse pour analyser les plists de style noyau.
metaclass :
Ce module fournit la fonction initialize_metaclass_symbols qui ajoute un symbole pour chaque
instance OSMetaClass connue.
offset :
Ce module fournit les fonctions initialize_data_offsets et initialize_offset_symbols. La première
analyse les segments à la recherche de pointeurs pouvant être convertis en offsets. La seconde
symbolise les offsets dans la section __got de chaque kext si la cible de l'offset possède un
symbole.
segment :
Ce module fournit la fonction initialize_segments pour renommer les segments d'IDA afin qu'ils soient plus utiles.
Par défaut, IDA semble créer les noms de segments en combinant une estimation de l'identifiant de bundle
avec la section Mach-O décrivant la région. initialize_segments extrait le véritable identifiant de bundle
du dictionnaire __PRELINK_INFO et renomme chaque segment pour inclure l'identifiant de bundle,
le segment Mach-O et la section Mach-O. Cela permet, par exemple, de faire la distinction
entre __TEXT.__const et __DATA_CONST.__const. Ce module fournit également la fonction
kernelcache_kext (ré-exportée au niveau supérieur) pour déterminer le kext contenant l'adresse
spécifiée (uniquement sur l'ancien format de kernelcache à kexts séparés d'iOS 11).
stub :
De nombreux kexts du kernelcache contiennent des fonctions stub dans une section __stubs qui sautent vers des fonctions
du noyau proprement dit. Malheureusement, ces stubs constituent une barrière pour la propagation des références croisées
et des informations de type. Ce module ne résout pas ces problèmes, mais il facilite un peu l'examen des stubs
en renommant automatiquement les fonctions stub afin que le nom de la fonction cible soit visible.
Les stubs et leurs cibles sont forcés d'être convertis en fonctions dans IDA, ce qui aide à faire
correspondre les fonctions dans IDA avec les fonctions du code source original.
tagged_pointers : Le nouveau format de kernelcache fusionné d'iOS 12 a les 2 octets supérieurs de chaque pointeur tagués avec un offset afin de chaîner les pointeurs ensemble dans une liste. Ce module contient des fonctions pour traiter et restaurer ces pointeurs tagués.
vtable :
Ce module fournit de nombreuses fonctions utiles pour travailler avec les tables de méthodes virtuelles, notamment
vtable_length, convert_vtable_to_offsets, vtable_overrides, initialize_vtable_symbols et
initialize_vtable_method_symbols. vtable_length vérifie si l'adresse spécifiée pourrait être une
vtable et renvoie la longueur de la vtable. Le générateur vtable_overrides énumère les méthodes
virtuelles d'une classe qui remplacent les méthodes virtuelles utilisées par la superclasse. La fonction
initialize_vtable_symbols ajoute un symbole pour le début de chaque vtable identifiée.
initialize_vtable_method_symbols itère à travers les méthodes remplacées dans chaque vtable et
propage les symboles de la superclasse vers la sous-classe. Cela est possible car la plupart des classes de base
dans IOKit sont définies dans XNU avec des informations de symboles relativement complètes. Chaque
remplacement de méthode dans la vtable d'une sous-classe doit se conformer à la même interface que la méthode de la
superclasse, ce qui signifie que nous pouvons générer un symbole pour le remplacement en substituant le nom de la
sous-classe au nom de la superclasse dans le symbole de méthode virtuelle de la superclasse. Par exemple, si
nous n'avons aucun nom pour la méthode virtuelle à l'index 7 dans la classe AppleKeyStore, mais que nous savons que la
méthode virtuelle à l'index 7 dans sa superclasse IOService s'appelle
__ZNK9IOService12getMetaClassEv, alors nous pouvons en déduire que l'index 7 devrait s'appeler
__ZNK13AppleKeyStore12getMetaClassEv dans la sous-classe. Cette technique peut être utilisée pour symboliser
la plupart des méthodes virtuelles de la plupart des classes.