
Un toolkit IDA pour analyser les kernelcaches iOS.
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 toute 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 exploitant la structure connue du kernelcache pour propager automatiquement les 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 bêta. 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() puis 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
que IDA identifie et analyse de nouvelles fonctions.
ida_kernelcache essaiera de ne pas écraser les noms définis par l'utilisateur pour les adresses. Cela signifie que si le
kernelcache a été analysé manuellement avant l'initialisation avec kernelcache_process, les
résultats peuvent être moins complets car les noms spécifiés par l'utilisateur peuvent bloquer la propagation automatique des noms.
Cependant, il n'y a pas non plus de garantie qu'ida_kernelcache ne perturbera pas une analyse antérieure. Donc, si vous
décidez d'exécuter kernelcache_process sur un fichier kernelcache que vous avez déjà analysé, faites une
sauvegarde d'abord.
ida_kernelcache est conçu pour ê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 peupler automatiquement une struct IDA en se basant sur 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. initialize_vtable_structs analyse les tables de méthodes virtuelles (symbolisées) et crée des structs
IDA pour contenir les pointeurs de méthodes virtuelles. initialize_class_structs 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.
classes :
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
peupler 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 de 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.