这是我参与8月更文挑战的第22天,活动详情查看: 8月更文挑战” juejin.cn/post/698796… ”
前言
These are some of the existing methods to implement IPC on iOS:
- Universal Links、URL Scheme
- UIDocumentInteractionController
- 利用socket进行本地通信
- Mach Ports
- Pasteboard
iOS 逆向:Tweak的开发例子【发红包】使用tweak和lua脚本结合进行实现 blog.csdn.net/z929118967/…
UIPasteboard* pasteboard = [UIPasteboard generalPasteboard];
[pasteboard setString:@"A1"];
//使用tweak和lua脚本结合进行实现
//1、tweak侧的功能是hookapp的原生功能
//2、lua 是实现模拟用户点击
//3、通信通过剪切板:tweak 通过剪切板和lua脚本进行通信
//其实后面我继续研究,把lua侧的功能全部用tweak实现了。 这里分享的是一个思路。
- AppleEvents & AppleScript
- Distributed Objects
- XPC
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
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);
}
#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
IV、 see also
更多内容请看原文,或者关注公众号:iOS逆向