
Un kit de herramientas de IDA para analizar kernelcaches de iOS.
ida_kernelcache es un módulo de IDAPython para IDA Pro que facilita el trabajo con kernelcaches de iOS. El módulo proporciona funciones para:
__PRELINK_INFO del kernel y convertirlo en un diccionario de Python.__got y las funciones stub en las secciones __stubs.La función de procesamiento principal está diseñada para ejecutarse antes de cualquier análisis manual o ingeniería inversa. Con la configuración predeterminada, IDA tiende a pasar por alto mucha información útil en el kernelcache. Estos scripts ayudan a IDA aprovechando la estructura conocida del kernelcache para propagar automáticamente información útil.
Además de la funcionalidad estándar del módulo, ida_kernelcache contiene varios scripts para facilitar el análisis del kernelcache de iOS. Por ejemplo, puedes usar los scripts para autogenerar estructuras C utilizadas por una función.
Muchas de las técnicas utilizadas en ida_kernelcache fueron desarrolladas para memctl y tomadas directamente de él.
ida_kernelcache ha sido probado con IDA Pro 6.95 en kernelcaches para las versiones de iOS 10.1.1, 11.0, 11.2, 11.3.1 y 12.0 beta. Actualmente solo se admiten kernelcaches Arm64 de iOS 10 y posteriores.
Ya necesitas tener un archivo de kernelcache descomprimido cargado en IDA. Puedes encontrar la URL para descargar un IPSW concreto de Apple en línea, y hay una serie de herramientas públicas (incluido memctl) capaces de descomprimir el kernelcache.
En IDA, selecciona "File" -> "Script file..." en la barra de menú y luego elige el script
ida_kernelcache.py en el directorio principal. Esto cargará el módulo ida_kernelcache en el
intérprete de IDAPython con los nombres ida_kernelcache y kc. En el indicador de IDAPython, escribe
kc.kernelcache_process() y pulsa Enter para comenzar a analizar el kernelcache. Esta función realiza
todos los análisis principales que admite ida_kernelcache. La función se ejecutará durante varios
minutos mientras IDA identifica y analiza nuevas funciones.
ida_kernelcache intentará no sobrescribir los nombres de usuario de las direcciones. Esto significa que
si el kernelcache ha sido analizado manualmente antes de la inicialización con kernelcache_process,
los resultados pueden no ser tan exhaustivos porque los nombres especificados por el usuario pueden
bloquear la propagación automática de nombres. Sin embargo, tampoco hay garantía de que ida_kernelcache
no estropee un análisis previo, así que si decides ejecutar kernelcache_process en un archivo de
kernelcache que ya has analizado, haz una copia de seguridad primero.
ida_kernelcache está pensado para cargarse mediante ida_kernelcache.py; los submódulos del directorio
ida_kernelcache no están pensados para cargarse directamente. Sin embargo, ida_kernelcache expone la
funcionalidad de muchos de estos submódulos. Esto es lo que hace cada uno de ellos:
ida_utilities:
Este módulo envuelve algunas de las funciones de IDA para proporcionar una API más fácil de usar.
Particularmente útiles son is_mapped, read_word, read_struct, force_function y ReadWords.
is_mapped comprueba si una dirección está mapeada y, opcionalmente, si contiene un valor conocido.
read_word lee una palabra de tamaño variable desde una dirección. read_struct lee un tipo de
estructura en un diccionario de Python o en un objeto de acceso de Python, lo que facilita mucho el
análisis de estructuras de datos. force_function intenta varios trucos para convertir una dirección
en el inicio de una función en IDA. ReadWords es un generador para iterar sobre las palabras de datos
y sus direcciones en un rango.
build_struct: Este módulo interno contiene utilidades para rellenar automáticamente una estructura de IDA basándose en una secuencia de accesos a la estructura.
class_struct: Este módulo proporciona funciones para generar estructuras de IDA que representan tablas de métodos virtuales y clases de C++. escanea las tablas de métodos virtuales (simbolizadas) y crea estructuras de IDA para contener los punteros a métodos virtuales. realiza un análisis de flujo de datos en los métodos virtuales para identificar los accesos a los campos de cada clase y luego construye estructuras de IDA para representar las clases. Las instrucciones que parecen hacer referencia a un campo también se convierten en referencias de desplazamiento de estructura. Consulta la cadena de documentación del módulo para más detalles.
El script ida_kernelcache_reload.py es idéntico a ida_kernelcache.py, salvo que fuerza la recarga del
módulo ida_kernelcache y de todos los submódulos. Es útil sobre todo para el desarrollo.
El directorio scripts contiene scripts que usan ida_kernelcache para realizar algún tipo de análisis.
Estos scripts son demasiado específicos para formar parte del módulo principal de ida_kernelcache, pero
son útiles a la hora de hacer ingeniería inversa del kernelcache. Incluyen:
find_virtual_method_overrides.py: Un script para encontrar descendientes de una clase que sobrescriban un método virtual que contenga la cadena especificada. Las sobrescrituras coincidentes se imprimen en la consola.
populate_struct.py: Rellena los campos de una clase de C++ o de una estructura C realizando un análisis de flujo de datos a partir de la dirección actual.
process_external_methods.py:
Procesa un array de IOExternalMethod o IOExternalMethodDispatch a un formato estándar para su uso por
herramientas de fuzzing.
Si estás usando el descompilador Hex-Rays, una de las características más interesantes de ida_kernelcache es la reconstrucción automática de clases de C++, que usará la información de OSMetaClass y el análisis de flujo de datos para crear estructuras de IDA que representen las clases encontradas en el kernelcache. Estas representaciones pueden mejorar drásticamente la legibilidad de la representación en pseudocódigo. Para obtener más información, consulta el artículo Reconstruyendo clases de C++ en el kernelcache de iOS con IDA Pro.
Con iOS 12, Apple introdujo un nuevo formato de kernelcache en algunos dispositivos. Entre los cambios,
los punteros de kernel de este nuevo kernelcache están etiquetados para enlazarlos en una lista,
presumiblemente para permitir que iBoot deslice el kernel sin los datos de _PrelinkLinkKASLROffsets en
el diccionario de prelink. Intentar analizar un kernelcache estándar con este formato en IDA es difícil
debido a la falta de referencias cruzadas. Consulta el artículo Analizando los punteros etiquetados del
kernelcache de iOS 12 para más detalles.
Si solo quieres quitar la etiqueta a los punteros del kernelcache sin realizar ningún procesamiento
adicional, ejecuta kc.tagged_pointers.untag_pointers().
Parte de esta funcionalidad probablemente se aplica de forma más amplia que solo a los kernelcaches de
Apple (por ejemplo, el análisis y la propagación de símbolos de vtable, o la mayoría de las funciones en
ida_utilities.py). No obstante, he limitado el ámbito de importación solo al módulo ida_kernelcache
porque no he probado nada de esto en otros tipos de binarios.
ida_kernelcache se publica bajo la licencia MIT.
Gran parte de la funcionalidad de ida_kernelcache está tomada de memctl, que también se publica bajo la licencia MIT. Otras fuentes se indican en los comentarios de los archivos correspondientes.
Brandon Azad
initialize_vtable_structsinitialize_class_structsclasses:
Este módulo define el tipo ClassInfo que contiene información sobre las clases de C++ en el
kernelcache y proporciona la función collect_class_info para escanear el kernelcache en busca de
clases y rellenar el diccionario global class_info con un mapa de nombres de clase a objetos
ClassInfo. El tipo ClassInfo registra el nombre de la clase, la instancia de OSMetaClass, la tabla
de métodos virtuales y el nombre de la superclase de cada clase de C++. Además, cada objeto ClassInfo
almacena referencias al ClassInfo de la superclase y al ClassInfo de todas las subclases directas,
lo que facilita examinar y recorrer la jerarquía de clases. collect_class_info también almacena el
conjunto de todas las tablas de métodos virtuales en el conjunto global vtables.
data_flow: Este módulo interno contiene operaciones de flujo de datos utilizadas por el resto de ida_kernelcache.
kernel:
Este módulo proporciona las variables globales base y prelink_info. base es la dirección base de
la imagen del kernel (el inicio del encabezado Mach-O del kernel). prelink_info es el diccionario
analizado de __PRELINK_INFO.
kplist:
Este módulo proporciona la función kplist_parse para analizar plists con formato de kernel.
metaclass:
Este módulo proporciona la función initialize_metaclass_symbols, que añade un símbolo para cada
instancia de OSMetaClass conocida.
offset:
Este módulo proporciona las funciones initialize_data_offsets e initialize_offset_symbols. La
primera escanea los segmentos en busca de punteros que puedan convertirse en desplazamientos. La segunda
simboliza los desplazamientos en la sección __got de cada kext si el destino del desplazamiento tiene
un símbolo.
segment:
Este módulo proporciona la función initialize_segments para renombrar los segmentos de IDA de forma
más útil. Por defecto, IDA parece crear los nombres de los segmentos combinando una suposición del
identificador de paquete con la sección Mach-O que describe la región. initialize_segments extrae el
verdadero identificador de paquete del diccionario __PRELINK_INFO y renombra cada segmento para incluir
el identificador de paquete, el segmento Mach-O y la sección Mach-O. Esto permite, por ejemplo,
distinguir entre __TEXT.__const y __DATA_CONST.__const. Este módulo también proporciona la función
kernelcache_kext (reexportada en el nivel superior) para determinar el kext que contiene la dirección
especificada (solo en el antiguo formato de kernelcache de kext divididos de iOS 11).
stub:
Muchos kexts en el kernelcache contienen funciones stub en una sección __stubs que saltan a funciones
del propio kernel. Desafortunadamente, estos stubs suponen una barrera para propagar referencias
cruzadas e información de tipos. Este módulo no resuelve estos problemas, pero sí facilita la
visualización de los stubs al renombrar automáticamente las funciones stub para que el nombre de la
función de destino sea visible. Los stubs y sus destinos se convierten a la fuerza en funciones en IDA,
lo que ayuda a que las funciones en IDA coincidan con las funciones del código fuente original.
tagged_pointers: El nuevo formato de kernelcache fusionado de iOS 12 tiene los 2 bytes superiores de cada puntero etiquetados con un desplazamiento para encadenar los punteros en una lista. Este módulo contiene funciones para procesar y restaurar esos punteros etiquetados.
vtable:
Este módulo proporciona muchas funciones útiles para trabajar con tablas de métodos virtuales, incluidos
vtable_length, convert_vtable_to_offsets, vtable_overrides, initialize_vtable_symbols e
initialize_vtable_method_symbols. vtable_length comprueba si la dirección especificada podría ser
una vtable y devuelve la longitud de la vtable. El generador vtable_overrides enumera los métodos
virtuales de una clase que sobrescriben métodos virtuales utilizados por la superclase. La función
initialize_vtable_symbols añade un símbolo para el inicio de cada vtable identificada.
initialize_vtable_method_symbols itera a través de los métodos sobrescritos en cada vtable y propaga
los símbolos de la superclase a la subclase. Esto es posible porque la mayoría de las clases base en
IOKit están definidas en XNU con información de símbolos relativamente completa. Cada sobrescritura de
método en la vtable de una subclase debe ajustarse a la misma interfaz que el método de la superclase,
lo que significa que podemos generar un símbolo para la sobrescritura sustituyendo el nombre de la
subclase por el nombre de la superclase en el símbolo del método virtual de la superclase. Por ejemplo,
si no tenemos ningún nombre para el método virtual en el índice 7 de la clase AppleKeyStore, pero
sabemos que el método virtual en el índice 7 de su superclase IOService se llama
__ZNK9IOService12getMetaClassEv, entonces podemos deducir que el índice 7 debería llamarse
__ZNK13AppleKeyStore12getMetaClassEv en la subclase. Esta técnica puede utilizarse para simbolizar la
mayoría de los métodos virtuales de la mayoría de las clases.