前言
These are some of the existing methods to implement IPC on iOS:
- Universal Links、URL Scheme
- Keychain
- UIDocumentInteractionController
- 利用socket进行本地通信
- Mach Ports
- Pasteboard
iOS 逆向:Tweak的开发例子【发红包】使用tweak和lua脚本结合进行实现https://blog.csdn.net/z929118967/article/details/76914272
UIPasteboard* pasteboard = [UIPasteboard generalPasteboard]; [pasteboard setString:@"A1"]; //使用tweak和lua脚本结合进行实现 //1、tweak侧的功能是hookapp的原生功能 //2、lua 是实现模拟用户点击 //3、通信通过剪切板:tweak 通过剪切板和lua脚本进行通信 //其实后面我继续研究,把lua侧的功能全部用tweak实现了。 这里分享的是一个思路。
- AppleEvents & AppleScript
- Distributed Objects
- XPC
- Notifications
- libobjcipc
- LightMessaging
Community Libraries
- 1、RocketBootstrap:Service registration and lookup system for iOS
- 2、OBJCIPC :High-level API for hosting services inside apps (by Alan Yip/a1anyip)
- 3、LightMessaging:Header-only library for simple IPC
本文重点讲解RocketBootstrap
的两种包装方式:CFMessagePort、CPDistributedMessagingCenter
I 、librocketbootstrap
- RocketBootstrap4Inter_process_Communication
- feature
1、Uses iOS7’s security model: Privileged processes can register, any process can look up 2、Works with existing mach-based IPC mechanisms 3、Similar to Apple’s bootstrap APIs: bootstrap_look_up becomes rocketbootstrap_look_up bootstrap_register becomes rocketbootstrap_register 4、Easy to use wrappers for CFMessagePort and CPDistributedMessagingCenter(todo: XPC) 5、Bring your own security model by using audit_token_to_au32 to know who’s calling 6、Requires package dependency, commonly installed on users’ devices
1.0 获取librocketbootstrap :
-Install this from Cydia 直接搜索rocketbootstrap安装即可
iPhone:/var/log root# ls -l /usr/lib/librocketbootstrap.dylib -rwxr-xr-x 1 root wheel 221776 Feb 6 2017 /usr/lib/librocketbootstrap.dylib* /Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist /usr/libexec/rocketd launchctl load /Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist launchctl unload /Library/LaunchDaemons/com.rpetrich.rocketbootstrapd.plist
1.1 CFMessagePort
- registerMsgCenter 基本可以解决双向通信;例子:避免重启其他进程从sb获取源地址信息的变更。守护进行都可以注册成为服务
+ (kern_return_t)rockettest_messageport_server { static CFMessagePortRef messagePort;// if (messagePort) return 0; messagePort = CFMessagePortCreateLocal(kCFAllocatorDefault, CFSTR("rockettest_messageport"), messagePortCallback, NULL, NULL);//CFSTR("rockettest_messageport")即server key, CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, messagePort, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, (CFStringRef)UITrackingRunLoopMode); return rocketbootstrap_cfmessageportexposelocal(messagePort); } typedef CFDataRef (*CFMessagePortCallBack)(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info); //回调的定义 static CFDataRef messagePortCallback(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info) { NSLog(@"rockettest_messageport_server: received %@", data); return CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"bootstrap", 9); }
- CFMessagePort: Only supports synchronous use
#import <UIKit/UIKit.h> #include "log.h" #import "rocketbootstrap.h" @implementation NSObject (rocketbootstrap) + (kern_return_t)rocketbootstrap_unlock:(NSString *)name { return rocketbootstrap_unlock([name UTF8String]); } static CFDataRef messagePortCallback(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info) { NSLog(@"rockettest_messageport_server: received %@", data); return CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"bootstrap", 9); } /** registerMsgCenter 基本可以解决双向通信; 例子:避免重启其他进程从sb获取源地址信息的变更。 守护进行都可以注册成为服务 */ + (kern_return_t)rockettest_messageport_server { static CFMessagePortRef messagePort; if (messagePort) return 0; messagePort = CFMessagePortCreateLocal(kCFAllocatorDefault, CFSTR("rockettest_messageport"), messagePortCallback, NULL, NULL); CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, messagePort, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, (CFStringRef)UITrackingRunLoopMode); return rocketbootstrap_cfmessageportexposelocal(messagePort); } + (NSData *)rockettest_messageport_client { CFMessagePortRef remote = rocketbootstrap_cfmessageportcreateremote(kCFAllocatorDefault, CFSTR("rockettest_messageport")); if (!remote) return nil; CFDataRef request = CFDataCreate(kCFAllocatorDefault, (const UInt8 *)"rocket", 6); CFDataRef response = NULL; CFMessagePortSendRequest(remote, 0, request, 10, 10, CFSTR("rocketboostrap_wait"), &response); CFRelease(remote); CFRelease(request); return [(NSData *)response autorelease]; }
II CPDistributedMessagingCenter
Asynchronous, if you go through the trouble
2.1 CFMessagePort Example
- Server
static CFDataRef Callback(CFMessagePortRef port, SInt32 messageID, CFDataRef data, void *info) { // ... } %ctor { static CFMessagePortRef localPort = CFMessagePortCreateLocal(nil, CFSTR("com.example.app.port.server"), Callback, nil, nil); CFRunLoopSourceRef runLoopSource = CFMessagePortCreateRunLoopSource(nil, localPort, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); rocketbootstrap_cfmessageportexposelocal(localPort); }
- Client
void doStuff() { CFDataRef data; SInt32 messageID = 0x1111; // Arbitrary CFTimeInterval timeout = 10.0; CFMessagePortRef remotePort = rocketbootstrap_cfmessageportcreateremote(nil, CFSTR("com.example.app.port.client")); SInt32 status = CFMessagePortSendRequest(remotePort, messageID, data, timeout, timeout, NULL, NULL); if (status == kCFMessagePortSuccess) { // ... } }
2.2 CPDistributedMessagingCenter的例子
目前发现这种方式只能在SpringBoard 注册为服务端,处理消息,;
进程间其实是单向通信;
#TweakDemo.xm SpringBoard 接受消息 #import "rocketbootstrap.h" #define kXPCCenterNameKey @"kXPCCenterNameKey_83641" %hook SpringBoard - (void)applicationDidFinishLaunching:(id)application { %orig; CPDistributedMessagingCenter *c = [%c(CPDistributedMessagingCenter) centerNamed:kXPCCenterNameKey]; rocketbootstrap_distributedmessagingcenter_apply(c); [c runServerOnCurrentThread]; [c registerForMessageName:@"myMessageName" target:self selector:@selector(handleMessage:withUserInfo:)]; NSLog(@"注册监听 start"); } %new - (void)handleMessage:(NSString *)name withUserInfo:(NSDictionary *)userInfo { NSLog(@"handleMessage withUserInfo:%@",userInfo); //TODO:something } %end //在需要发送的地方(沙盒 app ),如此这般的写: %hook SomeClass -(void)someMethod{ %orig; NSMutableDictionary *userInfo = [@{} mutableCopy]; [userInfo setObject:@"123" forKey:@"arg001"]; [userInfo setObject:@"456" forKey:@"arg002"]; NSLog(@"发送: %@=%@",kXPCCenterNameKey,userInfo); CPDistributedMessagingCenter *c = [%c(CPDistributedMessagingCenter) centerNamed:kXPCCenterNameKey]; rocketbootstrap_distributedmessagingcenter_apply(c); [c sendMessageName:@"myMessageName" userInfo:userInfo]; } %end
III、 UIPasteboard/NSPasteboard
OpenUDID的使用例子
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR #import <UIKit/UIPasteboard.h> #import <UIKit/UIKit.h> #else #import <AppKit/NSPasteboard.h> #endif #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR UIPasteboard* slotPB = [UIPasteboard pasteboardWithName:slotPBid create:NO]; #else NSPasteboard* slotPB = [NSPasteboard pasteboardWithName:slotPBid]; #endif
- 利用 pasteboardWithName 方法进行数据存储达到通信的目的
/** 应用级别的,数据在属于自己的应用内部共享; (默认情况下是不会把数据写进沙盒的,也就是说(复制、剪切)粘贴内容会因为应用的退出而销毁掉,我们可以设置相关属性 persistent值为 YES让其进行数据的持久化存储起来) Ps:例如 persistent 是否进行数据持久化 还有 changeCount 改变次数(剪切板)系统重启方才重新计数 */ - (NSObject *)model{ if (_model == nil) { NSString *contentUserID =@""; UIPasteboard *pasteboardUserID = [UIPasteboard pasteboardWithName:KNpasteboardWithNameKeyUserID create:NO]; if (pasteboardUserID){ contentUserID = pasteboardUserID.string;////获取内容 } _model = [[NSObject alloc]init]; // _model.UserId =contentUserID; } return _model; }
IV、LightMessaging
- feature
1、Mid-level API, 2、Message-oriented 3、Zero copy, for certain message types 4、No additional cost over standard mach calls 5、Easy integration with RocketBootstrap 6、No package dependencies
- using
1、Start services with LMStartService 2、Send messages with LMConnectionSendTwoWay (and friends) 3、Send replies with LMSendReply (and friends) 4、Bring your own security checks still :Community developers, your input on API please!
V 、IPC
allows processes to send each other messages and data
更多内容请看原文和关注公众号:iOS逆向
VI、libobjcipc
- feature
• High level API provides service lookup and IPC, easy to use • Background-launches and fakes app lifecycle for you • Message-oriented • Mostly asynchronous • “Open” security model • Requires separate package dependency, but very small • Simple Objective-C APIs: Register using --registerIncomingMessageFromAppHandlerForMessageName:handler: Send using -- sendMessageToAppWithIdentifier:messageName:dictionary:replyHandler:
• Similar patterns for App to SpringBoard
VII XPC
XPC can be accessed through either the libxpc C API, or the NSXPCConnection Objective-C API.
- feature
1、High level API, easy to use :One of Apple’s many wrappers for Mach messages;2、Message-oriented 3、Public API on OS X only 4、Asynchronous always, no synchronous versions 5、Service lookup is restricted on iOS 7+
VIII Tweaks on a multi-process iOS
- Inter-Process Communication
1、Mechanisms provided by the kernel to facilitate coordinated sharing of data and commands between processes 2、Used heavily in recent versions of iOS and OS X to implement system frameworks and APIs
- Standard Techniques
1、Save to temp files:High level APIs, easy to use 2、Unix Domain Sockets:Low level API ,Stream oriented, requires basic parsing to reconstruct messages
- Other standard techniques
• Shared Memory • Signals • Named pipes • Network sockets
- Apple/iOS-specific Techniques
1、Darwin Notifications:No data, only a simple “go” message,Any process can post or observe ,Always asynchronous 2、Mach Ports :seriously low level 3、CPDistributedNotificationCenter:Private API, does change between iOS versions 4、CFMessagePort:Public API,Only supports synchronous use ,Service lookup is restricted on iOS 6+ 5、XPC :High level API, easy to use �,One of Apple’s many wrappers for Mach messages ;
- Creative Techniques
1、Relax existing service permissions 2、Repurpose existing iOS services’ IPC channels:Service internals are frequently rewritten in new iOS versions 3、Delegate to someone else
- Libraries that use IPC under the hood
1、http://iphonedevwiki.net/index.php/AppList 2、http://iphonedevwiki.net/index.php/Flipswitch 3、http://iphonedevwiki.net/index.php/Libactivator 4、https://github.com/r-plus/libcanopenurl
- Community Libraries to Help
1、RocketBootstrap:Service registration and lookup system for iOS
- Be aware of potential deadlocks
1、 SpringBoard will block on backboardd—don’t call from backboardd to SpringBoard! 2、Communicate with these processes using one-way IPC, asynchronous IPC, or two-way IPC with timeouts 3、Avoid the pitfall of accidentally sending blocking API calls to one’s own process 4、SpringBoard is usually a good choice for coordinator as it often has much work to do anyway 5、Batch all of the operations for a single user action into one IPC call, if possible 6、Filter to only the data required before sending