iMessage es una aplicación y un protocolo de mensajería segura ampliamente utilizado en todo el ecosistema de Apple. Con curiosidad por saber cómo sería ejecutar iMessage en otras plataformas, adoptamos un enfoque de ingeniería inversa para comprender cómo funciona iMessage y examinar las posibilidades de extenderlo a otras plataformas.
El objetivo de este artículo es mostrar cómo Apple aprovecha el hecho de que produce el hardware para proteger su software. Para explorar esto, intentaremos conectarnos a través de Apple Push Notification (APN) directamente en el nivel de la red y ver qué desafíos enfrentamos. A lo largo del camino, realizaremos ingeniería inversa en pequeñas partes del demonio (daemon) apsd en macOS y el protocolo APN en sí mediante herramientas populares de código abierto.
Soluciones actuales
Las soluciones de facto actuales para ejecutar iMessage fuera del ecosistema de Apple requieren un servidor Mac y se basan en secuencias de comandos de AppleScript para automatizar las acciones de la interfaz de usuario de Messages.app. Esto elimina la necesidad de volver a implementar el protocolo de envío de mensajes en el cliente. Sin embargo, la gran desventaja es que la Mac tiene que estar funcionando todo el tiempo que desee utilizar iMessage.
A diferencia de revertir un binario autónomo, el código de envío de iMessage (como la mayoría de las funciones internas en los sistemas operativos XNU) va más allá del alcance de Messages.app y muchos demonios (daemons) del sistema están involucrados en el proceso, es decir, una arquitectura de microservicio, y se basan en mensajes XPC como un mecanismo de IPC (comunicación entre procesos).
Project Zero ya ha realizado una excelente investigación sobre la estructura de los demonios (daemons) involucrados en iMessage, así que le ahorraré todos los detalles sangrientos innecesarios. Pero en resumen, una vez que escribe un mensaje y presiona Enter, viaja a través de múltiples procesos, a saber, Messages.app -> imagent -> identityservicesd -> apsd. Escribí dos herramientas basadas en Frida para analizar este proceso y encontré dos desafíos principales.
Primero, simplemente buscar métodos ObjC de forma estática en el desensamblador consumía demasiado tiempo; hay una gran cantidad de llamadas a la API y capas sobre capas para cada tarea. Escribí un simple interceptor de mensajes Objective-C, objtree, que registra todos los mensajes dentro del alcance de uno que me interesa. La salida se proporciona en forma de árbol. Por ejemplo, debido a que sé que un determinado método de evento de la interfaz de usuario desencadena el envío de mensajes, usaría mi herramienta para conectar ese método y ver todas las llamadas ObjC subsiguientes dispuestas maravillosamente con el formato de pila consciente de la profundidad. Aquí está objtree en acción volcando casualmente más de 3,000 selectores al activar el evento keyDown:
sudo objtree Messages -m “-[NSResponder keyDown:]”
Segundo, después de encontrar los métodos ObjC más importantes, todo se reduce a enviar un mensaje XPC a algún proceso / demonio del sistema. Escribí otra herramienta para el trabajo, xpcspy, que intercepta los mensajes XPC y permite el filtrado.
Al final, descubrimos que el demonio apsd se encarga de enviar mensajes a través de la red. Gracias al sistema de envío de mensajes de Objective-C, la búsqueda de selectores con nombres como connectTo y send proporcionará una idea rápida y buena de dónde ocurren las llamadas a la API de conexión TCP.
Ahora tenemos apsd detenido en _dyld_start:
Interceptación de mensajes APN
Comunicándose con el APN
Conexión interrumpida
0x07
: Conectar al usuario conuid
0 (Cada usuario tiene su propio token de inserción público.)0x0c
: Keep alive.0x14
: Active state.0x07
: Conectar al usuario con uid 501.0x09
: Filtrar temas.0x0a
: Enviar mensaje.
Conclusión de nuestras pruebas
Como viste, replicar el tráfico APN es fácil, pero hay una advertencia: el comando de filtro (filter) hará que el servidor descarte cualquier conexión anterior para el mismo token público.
Supongamos que alguien ya ha pasado por el dolor de revertir el protocolo, ha generado mensajes válidos para APN desde cero, luego ha creado un cliente APN de Linux llamado fakeapsd y ha copiado los parámetros del mensaje de conexión connect (token público y par de claves) tal cual desde un dispositivo Mac. La implicación de la caída de la conexión con el comando de filtro (filter) como se explicó anteriormente es que cada vez que fakeapsd intenta tener una comunicación significativa con el servidor, hará que la conexión del apsd real se caiga, que a su vez intentará reconectarse y lo hará. será una lucha interminable por la conexión entre fakeapsd y apsd.