Recon Montreal 2018
(译者按:原文来自于一个安全会议上的演讲PPT,有疑问处请直接访问这里)
本次讨论的目的
什么是Instruments?
我们所知道的
不管怎么说,我们会和iOS的一个内部进程通信(通常在iOS上被禁止)
MobileDevice.framework提供了OSX上应用和iOS上进程通信的能力,也就是 “Services”
这是IDA和iOS debugserver通信的方式
- 我们够幸运的话,那儿也会有一个Instruments服务器的service:
$ hdiutil mount DeveloperDiskImage.dmg
– com.apple.debugserver.plist
– com.apple.instruments.remoteserver.plist
– com.apple.instruments.deviceservice.plist
// launch the debugserver service
static bool start_dbgsrv(void *device_handle)
{
void *srv_handle = NULL;
mach_error_t err = AMDeviceSecureStartService(
device_handle,
CFSTR(“com.apple.debugserver”),
&srv_handle);
if ( err != 0 )
return false;
char buf[1024];
size_t nrecv = AMDServiceConnectionReceive(
srv_handle,
buf,
sizeof(buf));
printf(“received %llx bytes\n”, nrecv);
return true;
}
DVTInstrumentsFoundation
__text:00000001000F96F4
__text:00000001000F96F4 ; =============== S U B R O U T I N E =======================================
__text:00000001000F96F4
__text:00000001000F96F4 ; Attributes: bp-based frame
__text:00000001000F96F4
__text:00000001000F96F4 ; id __cdecl -[DTDeviceInfoService runningProcesses](DTDeviceInfoService *self, SEL)
__text:00000001000F96F4 __DTDeviceInfoService_runningProcesses_ ; DATA XREF: __objc_const:00000001001935C8
o
__text:00000001000F96F4
__text:00000001000F96F4 var_250 = -0x250
__text:00000001000F96F4 var_230 = -0x230
__text:00000001000F96F4 ...
__text:00000001000F96F4
__text:00000001000F96F4 STP X28, X27, [SP,#-0x10+var_50]!
__text:00000001000F96F8 STP X26, X25, [SP,#0x50+var_40]
- DTServiceHub, DVTInstrumentsFoundation类库实现了Instruments的核心功能
- 在DVTInstrumentsFoundation中,我们发现了一个有趣的方法 - [DTDeviceInfoService runningProcesses]
*这个方法调用+[NSProcessInfo processInfo],然后生成一个带有每个进程描述的NSMutableArray,然后把它返回
- 棒呆!看起来我们在对的路上了,但是...
– There are no xrefs to this method
这个方法没有交叉引用
- 在iOS的开发者工具的其他地方似乎没出现runningProcesses这个Selector
- 谁调用的它??栈追踪应该有用
DTXMessage
- DTXMessage 类负责序列/反序列化Objective-C消息
- 此类的实例可以编码需要的信息来调用给定Objective-C方法:
- Instruments通过从缓冲区读取序列化消息来调用关键逻辑。此序列化数据的来源是什么?
00000001816A1014 000000018157E3E4 00000001000C8C4C 00000001000C87A4 00000001000C8510 000000018156D4B8
libsystem_kernel.dylib libdispatch.dylib DTXConnectionServices DTXConnectionServices DTXConnectionServices libdispatch.dylib
_semaphore_wait_trap+8
__dispatch_semaphore_wait_slow+F0
-[DTXMessageParser waitForMoreData:incrementalBuffer:]+68
-[DTXMessageParser parseMessageWithExceptionHandler:]+40
-[DTXMessageParser initWithMessageHandler:andParseExceptionHandler:]_block_invoke+24 __dispatch_call_block_and_release+14
00000001001096F4 0000000181B28ADC 0000000181A20544 00000001000CD3D0 00000001000C49980 000000018156D4B8
DVTInstrumentsFoundation CoreFoundation CoreFoundation DTXConnectionServices DTXConnectionServices libdispatch.dylib
id __cdecl -[DTDeviceInfoService runningProcesses](DTDeviceInfoService *self, SEL) ___invoking___+8C
-[NSInvocation invoke]+118
-[DTXMessage invokeWithTarget:replyChannel:validator:]+2C8
-[DTXChannel _scheduleMessage:tracker:withHandler:]_block_invoke697+7C __dispatch_call_block_and_release+14
浏览 Xcode IDE 二进制文件, 我们在 IDEiPhoneSupport 中发现了这一点:
这个关键的代码块实际上是一个反编译的block函数。原始源代码可能类似于:
@implementation DVTiPhoneProcessInformation
+ (void) requestCurrentProcessInformationForDevice:(id)device {
id server = [device primaryInstrumentsServer];
id channel = [server makeChannelWithIdentifier:@"com.apple.instruments.server.services.deviceinfo"];
if ( channel )
{
[DVTFuture futureWithBlock:^{
[channel sendControlAsync:[DTXMessage messageWithSelector:"runningProcesses" objectArguments:Nil]];
}]; }
}
@end
结论: DTXMessage 是一种通过网络传输Objective-C消息的机制。这允许进程在另一个进程中有效地 "调用" 给定的方法 (可以在完全独立的设备上运行)
现在怎么办?
可以从反汇编中逆向工程序列化Objective-C消息的, 但这是一个艰难的战斗
即使我们完全理解消息序列化, 它仍然没有把故事讲完整。如果服务器只响应特定的消息序列, 该怎么办?
另一种方法是获取通过导线传输的原始数据的样本。静态 + 方法动态获取的成功几率更高。
再次, iOS 调试器的救援!
特别设置的断点将允许我们记录服务器收到的每个序列化消息:
dtxmsg
我开发了一个 IDA 插件自动记录消息
https://github.com/troybowman/dtxmsg
插件使用反汇编的微代码检测在内存中序列化消息的位置和时间, 并将字节转储到文件
更多关于微码, 详见Ilfak在Recon Brussels 2018的谈话
该插件还可以反序列化每个截获的消息, 并以纯文本的形式将有效负载打印到文件中 (稍后再详细介绍)
解剖DTXMessage
它看起来像是使用 NSKeyedArchiver 序列化方法选择器, 但是方法参数呢?
runningProcesses 不接受任何参数, 所以让我们看一个不同的消息:
真相正在浮出水面, 但仍然有一个缺失的链接: 消息接收器。谁来决定接收邮件的对象?
记得, 我们注意到这样的东西在 Xcode:
id channel = [server makeChannelWithIdentifier:@"com.apple.instruments.server.services.deviceinfo"]; [channel sendControlAsync:[DTXMessage messageWithSelector:"runningProcesses" objectArguments:Nil]];
-[DTXConnection makeChannelWithIdentifier:] 似乎确定消息接收器。这个方法做了什么?请注意, 我们捕获了此消息:
让我们总结一下:
在查询进程列表时, Xcode 向仪器发送了5条消息
服务器:
– _notifyOfPublishedCapabilities:
– _requestChannelWithCode:identifier:
● identifier = "com.apple.instruments.server.services.deviceinfo" – _requestChannelWithCode:identifier
● identifier = "com.apple.instruments.server.services.device.applictionListing” – runningProcesses
– installedApplicationsMatching:registerUpdateToken:
最后步骤: 反编译
请记住, 我们的目标是独立地与服务器通信, 而无需 Apple 代码的帮助。
我们对序列化消息的理解必须是完美的
幸好我们已经有了很多线索
IDA 在这里是无价之宝。我们可以积极改进反编译迄今为止我们已经找到了的所有关键方法。
反编译产生一些重要的结构体:
// a DTXMessage object in memory
struct DTXMessage
{
NSObject super;
int32 _messageType;
int32 _compressionType;
uint32 _status;
id _destructor;
const char *_internalBuffer;
uint64 _internalBufferLength;
uint64 _cost;
id _payloadObject;
void *_auxiliary;
bool _deserialized;
bool _immutable;
bool _expectsReply;
uint32 _identifier;
uint32 _channelCode;
uint32 _conversationIndex;
NSDictionary *_auxiliaryPromoted;
};
// header for serialized message data
struct DTXMessageHeader
{
uint32 magic;
uint32 cb;
uint16 fragmentId;
uint16 fragmentCount;
uint32 length;
uint32 identifier;
uint32 conversationIndex;
uint32 channelCode;
uint32 expectsReply;
};
// layout of serialized payload
struct DTXMessagePayloadHeader
{
uint32 flags;
uint32 auxiliaryLength;
uint64 totalLength;
};
解剖 DTXMessage: 终章
我们终于准备好开始自己发送消息了
独立应用程序 (dtxmsg_client) 也包含在 dtxmsg 插件源中。
此应用程序能够调用 runningProcesses 方法, 检索其返回值, 并以纯文本形式打印它
目标完成!
此应用程序的源代码可供参考
我们还有其他一些可能感兴趣的方法:
– -[DTApplicationListingService installedApplicationsMatching:registerUpdateToken:]
– -[DTProcessControlService launchSuspendedProcessWithDevicePath:bundleIdentifier:environment:arguments:]
– -[DTProcessControlService killPid:]
dtxmsg_client 可以调用所有这些方法
它们提供了对如何处理复杂方法参数和返回值的更多了解
将来的工作
Instruments服务器负责的不仅仅是简单的进程控制
DTXMessage 也被其他 iOS 开发工具使用
希望这只是个开始!
谢谢大家赏脸!
原文:https://github.com/troybowman/dtxmsg/blob/master/slides.pdf
翻译:daemond【看雪翻译小组】
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法