• 文章/ARTICLE
  • iOS进程通讯安全和利用
  • 360NirvanTeam 2015-12-23 4178

  iOS有Mach Message,XPC等多种进程通讯方式,由于越狱环境权限较大,进程之间的通讯安全尤为重要。本文通过介绍iOS进程通讯的常用方式,对方式的实现进行安全性分析,给出通讯方式的伪造利用案例及防护方案。

 

一,iOS IPC概述

 

 Mach Message为iOS进程通信的基本方式,常用的进程通讯均在Mach Message上进行封装

常用的IPC如下:

 

  • Mach Message->MIG->Distributed Notifications
  • Mach Message->Distributed Objects
  • Mach Message->XPC->NSXPC
  • Mach Message->CFPort->CFMessage Port

 

iOS全部通讯方式Ian Beer整理了一份详细的关系图:

 

屏幕快照 2015-12-19 下午8.57.20

 

 

 

 

 

 

 

 

 

 

 

 

 

 

二,常用IPC和适用场景

1,Distributed Notifications

 

系统层通讯,接收端通过在注册监听系统消息中心,发送端通过发送全局广播的方式进行通讯,适用快捷方便适合轻量级的通讯,越狱插件与前端的通讯方式几乎全部使用此方法。

 

接收端监听消息demo:

CFNotificationCenterRef distributedCenter = CFNotificationCenterGetDistributedCenter();
CFNotificationSuspensionBehavior behavior =CFNotificationSuspensionBehaviorDeliverImmediately;
CFNotificationCenterAddObserver(distributedCenter,
                                NULL,
                                Callback,
                                CFSTR("xxx"),
                                NULL,
                                behavior);

 

接收端接收消息后的回调函数:

 

static void Callback(CFNotificationCenterRef center,
                     void *observer,
                     CFStringRef name,
                     const void *object,
                     CFDictionaryRef userInfo)
{

}

发送端使用底层c函数notify_post(“xxx”)即可发送全局广播,或使用封装好的CFNotificationCenterPostNotification如下

void *object;
CFDictionaryRef userInfo;
CFNotificationCenterRef distributedCenter =CFNotificationCenterGetDistributedCenter();
CFNotificationCenterPostNotification(distributedCenter,
                                     CFSTR("xxx"),
                                     object,
                                     userInfo,
                                     true);

2,CFMessage Port

 

CFMessage Port通过Mach port实现,适合简单的一对一通讯,通过CFMessagePortCreateLocal创建一个有唯一标识符的本地CFMessagePortRef对象,同时设置回调函数用于处理事件,最后将创建的对象添加到Runloop中实现端口的监听,Runloop收到端口相应的事件即调用指定的回调函数

 

在iOS7以后CFMessage Port通讯方式已被弃用。

 

接收端demo:

static CFDataRef Callback(CFMessagePortRef port,
                          SInt32 messageID,
                          CFDataRef data,
                          void *info)
{
}
CFMessagePortRef localPort = CFMessagePortCreateLocal(nil,
                             CFSTR("com.example.app.port.server"),
                             Callback,
                             nil,
                             nil);

CFRunLoopSourceRef runLoopSource =CFMessagePortCreateRunLoopSource(nil, localPort, 0);

CFRunLoopAddSource(CFRunLoopGetCurrent(),
                   runLoopSource,
                   kCFRunLoopCommonModes);

发送端demo:

CFDataRef data;
SInt32 messageID = 0x1111; // Arbitrary
CFTimeInterval timeout = 10.0;
CFMessagePortRef remotePort =
CFMessagePortCreateRemote(nil,CFSTR("com.example.app.port.client"));
SInt32 status =CFMessagePortSendRequest(remotePort,
                                        messageID,
                                        data,
                                        timeout,
                                        timeout,
                                        NULL,
                                        NULL);
if (status == kCFMessagePortSuccess) {
    // ...
}

 

3,XPC

 

2011年开始使用,最早用于OSX10.7和iOS5,在Mach Message基础上进行封装,简化了消息传递细节,通过客户端和服务端建立连接的方式,现作为iOS系统服务的主流通讯方式,除少数系统服务直接只用Mach Message通讯外其他均为XPC

 

在OSX10.8以后Foundation.framework中添加了NSXPCConnection相关的类,XPC即可使用NSXPCConnection的OC实现,也可使用底层的C实现

 

客户端demo:

xpc_connection_t client = xpc_connection_create_mach_service("com.apple.test", 
                                                              NULL,
                                                              XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
xpc_connection_set_event_handler(client, ^void(xpc_object_t response) {
double result = xpc_dictionary_get_double(response, "result");}); 
xpc_connection_resume(client);  
xpc_object_t dictionary = xpc_dictionary_create(NULL, NULL, 0);
xpc_object_t reply = xpc_connection_send_message_with_reply_sync(client, dictionary);

服务端demo:

xpc_connection_t listener=xpc_connection_create_mach_service("com.apple.test1",
                                                              NULL,
                                                              XPC_CONNECTION_MACH_SERVICE_LISTENER);
xpc_connection_set_event_handler(listener,^(xpc_object_t peer){ 
xpc_connection_set_event_handler(static_cast<xpc_connection_t>(peer), ^(xpc_object_t event) {
xpc_type_t type = xpc_get_type(event);
if(type==XPC_TYPE_DICTIONARY){
xpc_object_t dictionary = xpc_dictionary_create(NULL, NULL, 0);
xpc_connection_send_message(static_cast<xpc_connection_t>(peer), dictionary);}
});
xpc_connection_resume(static_cast<xpc_connection_t>(peer));
});
xpc_connection_resume(listener);

XPC为目前最先进的进程通讯方式,但在越狱插件的使用中比Distributed Notifications复杂,iOS所有服务由lauched组织启动,需通过task_get_bootstrap_porto找到lauchd端口,bootstrap_check_in通过lauchd寻找所要启动的服务

 

三,IPC安全分析及利用

 

1,越狱环境下主流app通讯方式和隐患

 

在非越狱环境下程序无法主动调用以上进程通讯方式,进程通讯发生在系统服务间

 

在越狱环境下分析目前市场上主流的越狱插件360手机卫士pro等,前端与dylib之间的通讯均使用Distributed Notifications

 

Distributed Notifications通讯为dylib注册监听通知中心中自定义消息名,前端发送此消息名的全局广播则dylib执行回调函数,而自定义的消息名硬编码在二进制文件中可通过IDA提取,所以通讯中存在安全隐患,可以创建第三方app发送带此消息名的广播调用dylib全部功能

 

2,腾讯手机管家密码破解

 

手机管家有隐私短信,隐私照片,隐藏app,软件锁等多项隐私保护功能,所有功能均由dylib实现,通过在前端输入密码如果前端判断输入密码正确则对dylib发送指定消息,在密码未知的情况下创建任意app发送此消息则实现密码的全部破解

 

以破解隐藏app为例,以下为管家监听和发送源码:

 

检查密码发送端:

屏幕快照 2015-12-23 下午9.05.25

dylib监听消息,收到消息执行sub_10800显示全部app:

 

屏幕快照 2015-12-23 下午9.05.32

 

设置密码隐藏全部指定app

 

屏幕快照 2015-12-21 上午11.23.59

 

创建任意app执行import<notify.h>

notify_post("DarwinPrivacyManagerUnHiddingNotification");隐藏全部显示

 

屏幕快照 2015-12-21 上午11.24.07

其他破解私密短信和相册同理。

 

3,其他通讯方式安全性分析

 

Distributed Notifications为系统级通讯,接收端监听消息无法判断消息来源是否合法。测试了其他进程通讯如Mach Message,XPC,由于所有进程通讯方式均会创建服务名或端口等唯一标示符号,而发送消息函数固定,提取唯一标识符后均可伪造消息。所以在越狱环境下所有进程通讯都是不安全的。

 

四,IPC保护

 

发送接收函数固定,在越狱环境阻止通讯伪造可通过阻止硬编码唯一标识符的提取,可使用代码混淆阻止定位到注册消息函数或使用硬编码混淆 https://github.com/pjebs/Obfuscator-iOS

https://github.com/obfuscator-llvm/obfuscator

微信 扫一扫

分享到