Discovering the ios Instruments Server

Similar documents
Short Notes of CS201

CS201 - Introduction to Programming Glossary By

CIS-331 Fall 2014 Exam 1 Name: Total of 109 Points Version 1

CIS-331 Exam 2 Fall 2014 Total of 105 Points. Version 1

CIS-331 Exam 2 Fall 2015 Total of 105 Points Version 1

Here is a C function that will print a selected block of bytes from such a memory block, using an array-based view of the necessary logic:

Chapter 1 Getting Started

SYSTEM CALL IMPLEMENTATION. CS124 Operating Systems Fall , Lecture 14

CIS-331 Exam 2 Spring 2016 Total of 110 Points Version 1

CSci 4061 Introduction to Operating Systems. Programs in C/Unix

RM0327 Reference manual

IRIX is moving in the n32 direction, and n32 is now the default, but the toolchain still supports o32. When we started supporting native mode o32 was

Recitation #11 Malloc Lab. November 7th, 2017

There are, of course, many other possible solutions and, if done correctly, those received full credit.

Debugging. ICS312 Machine-Level and Systems Programming. Henri Casanova

An Introduction to IDA and crackmes - Cruehead[MiB] crackme 2 writeup Mitchell Adair 08/14/2011 utdcsg.org

T Hands-on 2. User-mode debuggers OllyDbg

ECE 2400 Computer Systems Programming, Fall 2017 Prelim 1 Prep

Visual Profiler. User Guide

Intro to x86 Binaries. From ASM to exploit

CSE 509: Computer Security

Common Misunderstandings from Exam 1 Material

This time. Defenses and other memory safety vulnerabilities. Everything you ve always wanted to know about gdb but were too afraid to ask

The IA-32 Stack and Function Calls. CS4379/5375 Software Reverse Engineering Dr. Jaime C. Acosta

1. A student is testing an implementation of a C function; when compiled with gcc, the following x86-32 assembly code is produced:

noforth website How noforth is made noforth is a standalone forth for MSP430

CSE 333 Final Exam June 6, 2017 Sample Solution

Objective-C Runtime. Cocoa s Jewel in the Crown. NSConference Nicolas

Variables and Data Representation

Dynamic memory. EECS 211 Winter 2019

Analysis of MS Multiple Excel Vulnerabilities

Lecture 09 Code reuse attacks. Stephen Checkoway University of Illinois at Chicago CS 487 Fall 2017

Here is a C function that will print a selected block of bytes from such a memory block, using an array-based view of the necessary logic:

Memory Management: The process by which memory is shared, allocated, and released. Not applicable to cache memory.

Hardware: Logical View

CPSC213/2014W1 Midterm EXTRA Practice

Section 3: File I/O, JSON, Generics. Meghan Cowan

CIS-331 Spring 2016 Exam 1 Name: Total of 109 Points Version 1

CSCI-243 Exam 1 Review February 22, 2015 Presented by the RIT Computer Science Community

Armide Documentation. Release Kyle Mayes

4. Specifications and Additional Information

Reverse Engineering with IDA Pro. CS4379/5375 Software Reverse Engineering Dr. Jaime C. Acosta

Chapter 2: System Structures

Autodesk AutoCAD DWG-AC1021 Heap Corruption

CSC 1600 Memory Layout for Unix Processes"

Stream Computing using Brook+

Questions. Exams: no. Get by without own Mac? Why ios? ios vs Android restrictions. Selling in App store how hard to publish? Future of Objective-C?

When you add a number to a pointer, that number is added, but first it is multiplied by the sizeof the type the pointer points to.

Is stack overflow still a problem?

CSE 333 Midterm Exam 5/10/13

Objectives. Chapter 2: Operating-System Structures. 2.1 Operating System Services

C1098 JPEG Module User Manual

EE355 Lab 5 - The Files Are *In* the Computer

Vector and Free Store (Pointers and Memory Allocation)

GDB Tutorial. A Walkthrough with Examples. CMSC Spring Last modified March 22, GDB Tutorial

Binary, Hexadecimal and Octal number system

QUIZ. What is wrong with this code that uses default arguments?

CSE 333 Midterm Exam Cinco de Mayo, 2017 (May 5) Name UW ID#

6. Pointers, Structs, and Arrays. 1. Juli 2011

Do not start the test until instructed to do so!

Finding Bugs Using Xcode Runtime Tools

CSE 303: Concepts and Tools for Software Development

For personnal use only

Systems/DBG Debugger Version 2.20

Malloc Lab & Midterm Solutions. Recitation 11: Tuesday: 11/08/2016

// Initially NULL, points to the dynamically allocated array of bytes. uint8_t *data;

API for Auxiliary Processing Unit

Assignment II: Foundation Calculator

CSE 303, Winter 2006, Final Examination 16 March Please do not turn the page until everyone is ready.

CIS-331 Fall 2013 Exam 1 Name: Total of 120 Points Version 1

Inheritance, Polymorphism and the Object Memory Model

The goal of this tutorial is to install an example app on your ios device and use IDA to debug it.

ITP 342 Mobile App Development. Data Persistence

Linked data structures. EECS 211 Winter 2019

QUIZ. 1. Explain the meaning of the angle brackets in the declaration of v below:

User Mode Debugging Internals

RCU. ò Walk through two system calls in some detail. ò Open and read. ò Too much code to cover all FS system calls. ò 3 Cases for a dentry:

CS Programming In C

We have the pointers reference the next node in an inorder traversal; called threads

CSE 333 Section 8 - Client-Side Networking

VFS, Continued. Don Porter CSE 506

11 'e' 'x' 'e' 'm' 'p' 'l' 'i' 'f' 'i' 'e' 'd' bool equal(const unsigned char pstr[], const char *cstr) {

An application: foreign function bindings

static CS106L Spring 2009 Handout #21 May 12, 2009 Introduction

CS 241 Data Organization Binary Trees

CTF Workshop. Crim Synopsys, Inc. 1

CSCI E-119 Section Notes. Section 5 Solutions

Flare- On 4: Challenge 6 Solution payload.dll

Week 5, continued. This is CS50. Harvard University. Fall Cheng Gong

CSCE : Computer Systems Homework #1 Part 1 (25 pts) Due date: 1/24/19

This is an open book, open notes exam. But no online or in-class chatting.

Static Vulnerability Analysis

dmrlib Documentation Release Wijnand Modderman-Lenstra

C++ Tutorial AM 225. Dan Fortunato

C++ Addendum: Inheritance of Special Member Functions. Constructors Destructor Construction and Destruction Order Assignment Operator

LibSysCTr(3) System Call Tracing Library LibSysCTr(3)

A brief introduction to C programming for Java programmers

CSCE 548 Building Secure Software Integers & Integer-related Attacks & Format String Attacks. Professor Lisa Luo Spring 2018

Lecture 14 Notes. Brent Edmunds

Lecture Notes on Memory Layout

Transcription:

Discovering the ios Instruments Server Troy Bowman Hex-Rays troy@hex-rays.com Recon Montreal 2018

Purpose of This Talk Share our discoveries Document all of our steps Fun!

What is Instruments? Instruments is a set of debugging tools developed by Apple: Time Profiling Leak Checking Tracking File I/O All of these tasks can be performed on ios apps as well To do this, Apple implements a server that is designed to provide ios debugging statistics to the Instruments front-end running on OSX This server is a goldmine of useful info

What We Want ios OSX Instruments Server? Instruments/Xcode How does the server transmit info to OSX? Could IDA interact with it? Start with a specific objective: find out how Xcode queries the Instruments server for the process list (i.e. the name of each process running on the target device, along with its PID)

What We Know Somehow, we'll have to communicate with an internal ios process (normally forbidden on ios) MobileDevice.framework provides ability for OSX apps to communicate with certain ios processes, a.k.a. Services This is how IDA communicates with the ios debugserver If we're lucky, there is also a Service for the Instruments server: $ 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] Binaries DTServiceHub, DVTInstrumentsFoundation implement core functionality of the Instruments server In DVTInstrumentsFoundation we find an interesting method: -[DTDeviceInfoService runningprocesses] This method calls + [NSProcessInfo processinfo], then populates an NSMutableArray with a description of each process, and returns it Great! It looks like we are on the right track. But... There are no xrefs to this method Selector runningprocesses appears nowhere else in the ios developer tools Who calls it?? A stack trace would help...

DTXMessage DTXMessage class is responsible for serializing/deserializing Objective-C messages An instance of this class can encode all the information necessary to call a given Objective-C method: method selector method arguments DTXMessage Binary data message receiver Note: reverse direction (deserialization) is also possible The Instruments server is invoking critical logic by reading serialized messages from a buffer. What is the source of this serialized data?

DTXMessage One thread reads serialized messages from a buffer: 00000001816A1014 libsystem_kernel.dylib _semaphore_wait_trap+8 000000018157E3E4 libdispatch.dylib dispatch_semaphore_wait_slow+f0 00000001000C8C4C DTXConnectionServices -[DTXMessageParser waitformoredata:incrementalbuffer:]+68 00000001000C87A4 DTXConnectionServices -[DTXMessageParser parsemessagewithexceptionhandler:]+40 00000001000C8510 DTXConnectionServices -[DTXMessageParser initwithmessagehandler:andparseexceptionhandler:]_block_invoke+24 000000018156D4B8 libdispatch.dylib dispatch_call_block_and_release+14 After each message is parsed, another thread is dispatched to perform the invocation: 00000001001096F4 DVTInstrumentsFoundation id cdecl -[DTDeviceInfoService runningprocesses](dtdeviceinfoservice *self, SEL) 0000000181B28ADC CoreFoundation invoking +8C 0000000181A20544 CoreFoundation -[NSInvocation invoke]+118 00000001000CD3D0 DTXConnectionServices -[DTXMessage invokewithtarget:replychannel:validator:]+2c8 00000001000C49980 DTXConnectionServices -[DTXChannel _schedulemessage:tracker:withhandler:]_block_invoke697+7c 000000018156D4B8 libdispatch.dylib dispatch_call_block_and_release+14

DTXMessage Browsing through the Xcode IDE binaries, we find this in IDEiPhoneSupport: // simplified +[DVTiPhoneProcessInformation requestcurrentprocessinformationsfordevice:usepaireddevice:resulthandler:] void cdecl +[DVTiPhoneProcessInformation requestcurrentprocessinformationsfordevice:](id self, SEL a2, id a3) { id v1; id v2; Block_layout_5803 v3; } v1 = objc_msgsend(a3, "primaryinstrumentsserver"); v2 = objc_msgsend(v1, "makechannelwithidentifier:", CFSTR("com.apple.instruments.server.services.deviceinfo")); if ( v2 ) { } v3.isa = _NSConcreteStackBlock; v3.flags = 0xC2000000; v3.reserved = 0; v3.invoke = requestcurrentprocessinformationsfordevice_block_invoke; v3.descriptor = & block_descriptor_tmp_62; v3.lvar1 = objc_retain(v2); objc_msgsend(&objc_class DVTFuture, "futurewithblock:", &v3); found the selector of our favourite method. curious... // call -[DTDeviceInfoService runningprocesses] in the Instruments server process void cdecl requestcurrentprocessinformationsfordevice_block_invoke(block_layout_5803 *a1) { id v1; } v1 = objc_msgsend(&objc_class DTXMessage, "messagewithselector:objectarguments:, "runningprocesses", NULL); objc_msgsend(a1->lvar1, "sendcontrolasync:replyhandler:", v1, NULL);

DTXMessage This critical piece of code is actually a decompiled block function. The original source would probably look something like: @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 Conclusion: DTXMessage is a mechanism for transmitting Objective-C messages over the network. This allows a process to effectively call a given method in another process (that could be running on a totally separate device)

DTXMessage Now what? It is possible to reverse-engineer the format of serialized Objective-C messages from the disassembly, but this is an uphill battle Even if we understand message serialization perfectly, it still doesn't tell the whole story. What if the server only responds to a specific sequence of messages? An alternate approach would be to obtain samples of the raw data transmitted over the wire. A static + dynamic approach has a higher probability of success. Again, ios debugger to the rescue!

DTXMessage Specially placed breakpoints would allow us to log each serialized message received by the server: id cdecl -[DTXMessageParser parsemessagewithexceptionhandler:](dtxmessageparser *self, SEL a2, id a3) { _DWORD *v1; _DWORD *v2; id v3; // read the message header v1 = -[DTXMessageParser waitformoredata:incrementalbuffer:](self, "waitformoredata:incrementalbuffer:", 32LL, 0LL); if (!v1 ) return NULL; // validate header if ( *v1!= 0x1F3D5B79 ) assert_rtn( DTX_MESSAGE_MAGIC ); // read the complete payload v1 = -[DTXMessageParser waitformoredata:incrementalbuffer:](self, "waitformoredata:incrementalbuffer:", v1[3], &v2); if (!v1 ) return NULL; return value is a pointer to the message buffer // initialize a DTXMessage from the raw data v3 = objc_msgsend(&objc_class DTXMessage, "alloc"); v3 = -[DTXMessage initwithserializedform:length:destructor:compressor:]( v3, "initwithserializedform:length:destructor:compressor:", v2, v1[3], NULL, self->_compressor); } return v3;

dtxmsg I developed an IDA plugin to log the messages automatically: https://github.com/troybowman/dtxmsg The plugin uses the decompiler's microcode to detect where and when the serialized messages will be available in memory, and dumps the bytes to a file For more on the microcode, see Ilfak's talk at Recon Brussels 2018 The plugin can also deserialize each intercepted message and print the payload to a file in plain text (more on this later)

Anatomy of a DTXMessage 0x1F3D5B79: DTX_MESSAGE_MAGIC 00000000: 795b 3d1f 2000 0000 0000 0100 ac00 0000 y[=.... 00000010: 0400 0000 0000 0000 0100 0000 0100 0000... 00000020: 0210 0000 0000 0000 9c00 0000 0000 0000... 00000030: 6270 6c69 7374 3030 d401 0203 0405 0609 bplist00... 00000040: 0a58 2476 6572 7369 6f6e 5824 6f62 6a65.X$versionX$obje 00000050: 6374 7359 2461 7263 6869 7665 7254 2474 ctsy$archivert$t 00000060: 6f70 1200 0186 a0a2 0708 5524 6e75 6c6c op...u$null 00000070: 5f10 1072 756e 6e69 6e67 5072 6f63 6573 _..runningproces 00000080: 7365 735f 100f 4e53 4b65 7965 6441 7263 ses_..nskeyedarc 00000090: 6869 7665 72d1 0b0c 5472 6f6f 7480 0108 hiver...troot... 000000a0: 111a 232d 3237 3a40 5365 686d 0000 0000..#-27:@Sehm... 000000b0: 0000 0101 0000 0000 0000 000d 0000 0000... 000000c0: 0000 0000 0000 0000 0000 006f...o method selector NSKeyedArchiver : probably worth a google

Anatomy of a DTXMessage It looks like the method selector is serialized using an NSKeyedArchiver, but what about the method arguments? runningprocesses takes no arguments, so lets look at a different message: 00000000: 795b 3d1f 2000 0000 0000 0100 6d02 0000 y[=....m...... 000000c0: 6d65 5824 636c 6173 7365 735c 4e53 4469 mex$classes\nsdi 000000d0: 6374 696f 6e61 7279 a212 1458 4e53 4f62 ctionary...xnsob 000000e0: 6a65 6374 5f10 0f4e 534b 6579 6564 4172 ject_..nskeyedar 000000f0: 6368 6976 6572 d117 1854 726f 6f74 8001 chiver...troot.. 00000100: 0811 1a23 2d32 373b 4148 505b 6263 6466...#-27;AHP[bcdf... 00000160: 246f 626a 6563 7473 5924 6172 6368 6976 $objectsy$archiv 00000170: 6572 5424 746f 7012 0001 86a0 a207 0855 ert$top...u 00000180: 246e 756c 6c50 5f10 0f4e 534b 6579 6564 $nullp_..nskeyed 00000190: 4172 6368 6976 6572 d10b 0c54 726f 6f74 Archiver...Troot 000001a0: 8001 0811 1a23 2d32 373a 4041 5356 5b00...#-27:@ASV[.... 00000200: 7012 0001 86a0 a207 0855 246e 756c 6c5f p...u$null_ 00000210: 1032 696e 7374 616c 6c65 6441 7070 6c69.2installedAppli 00000220: 6361 7469 6f6e 734d 6174 6368 696e 673a cationsmatching: 00000230: 7265 6769 7374 6572 5570 6461 7465 546f registerupdateto 00000240: 6b65 6e3a 5f10 0f4e 534b 6579 6564 4172 ken:_..nskeyedar 00000250: 6368 6976 6572 d10b 0c54 726f 6f74 8001 chiver...troot.. installedapplicationsmatching:registerupdatetoken: (accepts two arguments) archived object (argument 1?) archived object (argument 2?)

Anatomy of a DTXMessage The picture is coming into focus, but there's still a missing link: the message receiver. Who decides which object will receive the message? Recall that we noticed something like this in Xcode: id channel = [server makechannelwithidentifier:@"com.apple.instruments.server.services.deviceinfo"]; [channel sendcontrolasync:[dtxmessage messagewithselector:"runningprocesses" objectarguments:nil]]; -[DTXConnection makechannelwithidentifier:] seems to determine the message receiver. What does this method do? Note that we captured this message: 00000000: 795b 3d1f 2000 0000 0000 0100 a301 0000 y[=....... 00000090: 0708 5524 6e75 6c6c 5f10 3063 6f6d 2e61..U$null_.0com.a 000000a0: 7070 6c65 2e69 6e73 7472 756d 656e 7473 pple.instruments 000000b0: 2e73 6572 7665 722e 7365 7276 6963 6573.server.services 000000c0: 2e64 6576 6963 6569 6e66 6f5f 100f 4e53.deviceinfo_..NS 000000d0: 4b65 7965 6441 7263 6869 7665 72d1 0b0c KeyedArchiver...... 00000150: 6e75 6c6c 5f10 235f 7265 7175 6573 7443 null_.#_requestc 00000160: 6861 6e6e 656c 5769 7468 436f 6465 3a69 hannelwithcode:i 00000170: 6465 6e74 6966 6965 723a 5f10 0f4e 534b dentifier:_..nsk 00000180: 6579 6564 4172 6368 6976 6572 d10b 0c54 eyedarchiver...t 00000190: 726f 6f74 8001 0811 1a23 2d32 373a 4066 root...#-27:@f com.apple.instruments.server.services.deviceinfo requestchannelwithcode:identifier:

dtxmsg: Synopsis Let's summarize: When querying the process list, Xcode sent 5 messages to the Instruments server: _notifyofpublishedcapabilities: _requestchannelwithcode:identifier: identifier = "com.apple.instruments.server.services.deviceinfo" _requestchannelwithcode:identifier identifier = "com.apple.instruments.server.services.device.applictionlisting runningprocesses installedapplicationsmatching:registerupdatetoken:

dtxmsg: Synopsis Let's summarize: When querying the process list, Xcode sent 5 messages to the Instruments server: _notifyofpublishedcapabilities: _requestchannelwithcode:identifier: identifier = "com.apple.instruments.server.services.deviceinfo" _requestchannelwithcode:identifier identifier = "com.apple.instruments.server.services.device.applictionlisting runningprocesses installedapplicationsmatching:registerupdatetoken: * These messages request a list of all installed apps. Interesting, but not absolutely necessary.

dtxmsg: Synopsis Let's summarize: When querying the process list, Xcode sent 5 messages to the Instruments server: _notifyofpublishedcapabilities: _requestchannelwithcode:identifier: identifier = "com.apple.instruments.server.services.deviceinfo" _requestchannelwithcode:identifier identifier = "com.apple.instruments.server.services.device.applictionlisting runningprocesses installedapplicationsmatching:registerupdatetoken: * Likely the minimal required behaviour for querying the proclist

Final Steps: Decompilation Remember that our goal is to communicate with the server independently, without the assistance of Apple's code Our understanding of serialized messages must be perfect Fortunately we already have a lot of clues IDA is invaluable here. We can aggressively refine the decompilation for all of the critical methods we've found so far.

Final Steps: Decompilation Decompilation yields some important structures: // 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; };

Anatomy of a DTXMessage: Finalized auxiliary payload data (array of archived method arguments) DTXMessageHeader complete payload DTXMessagePayloadHeader archived payload object (either a method selector, or a method's return value)

dtxmsg_client We're finally ready to start sending messages ourselves A standalone application (dtxmsg_client) is also included with the dtxmsg plugin source This app is able to invoke the runningprocesses method, retrieve its return value, and print it in plain text Objective complete! Source code for this app is available for reference

dtxmsg_client Extra credit: There are some other methods that might be of interest to us: -[DTApplicationListingService installedapplicationsmatching:registerupdatetoken:] -[DTProcessControlService launchsuspendedprocesswithdevicepath:bundleidentifier:environment:arguments:] -[DTProcessControlService killpid:] dtxmsg_client can invoke all of these methods as well They provide a little more insight into how complex method arguments and return values are handled

Future Work The Instruments server is responsible for much more than just simple process control DTXMessage is also used by other ios developer tools Hopefully this is just the beginning! Thanks for your time