📜 ⬆️ ⬇️

Non-standard way to get unavailable information on iOS



In the wake of my speech at Positive Hack Days, I would like to share with you the results of the investigation of the configd daemon at the MACH level in iOS 6. As you know, not much information about the Wi-Fi connection status is available in iOS. In general, the Public API makes it impossible to learn anything except the SSID, BSSID, and network settings of the adapter. And the encryption mode? signal strength? Under the cut, I'll tell you how to find out all this without using Private API and Jailbreak.

I apologize in advance, but in this article I will post a lot of source code. First, let's remember how it was done before, on iOS 5 firmware. *. Apple System Log facility was used : it was possible to receive system messages which OS displays at the time of connection to a network. They featured encryption mode and signal strength. And we received them like this:

aslmsg asl, message; aslresponse searchResult; int i; const char *key, *val; NSMutableArray *result_dicts = [NSMutableArray array]; asl = asl_new(ASL_TYPE_QUERY); if (!asl) { DDLogCError(@"Failed creating ASL query"); } asl_set_query(asl, "Sender", "kernel", ASL_QUERY_OP_EQUAL); asl_set_query(asl, "Message", "AppleBCMWLAN Joined BSS:", ASL_QUERY_OP_PREFIX|ASL_QUERY_OP_EQUAL); searchResult = asl_search(NULL, asl); while (NULL != (message = aslresponse_next(searchResult))) { NSMutableDictionary *tmpDict = [NSMutableDictionary dictionary]; for (i = 0; (NULL != (key = asl_key(message, i))); i++) { NSString *keyString = [NSString stringWithUTF8String:(char *)key]; val = asl_get(message, key); NSString *string = [NSString stringWithUTF8String:val]; [tmpDict setObject:string forKey:keyString]; } [result_dicts addObject:tmpDict]; } aslresponse_free(searchResult); asl_free(asl); 

')
But, as is usual with Apple, having learned about it, they closed access to system messages in ASL. I had to look for a new way to get this data. Then the question was put differently: how can you get this data on Mac OS and iOS?

First of all, with the help of the scutil utility, which allows you to get data about the system configuration, including the ones we need. A test iPhone with iOS 6 and Jailbreak showed that the utility works well on it. For me, this became a hint, a guiding thread, and I began to look for how else you can “reach out” to SystemConfiguration on iOS.

The path turned out to be simple and trivial to the point of madness - the SystemConfiguration.framework library. With its help, on Mac OS, you can programmatically connect to the value store and get the property list with data about wireless networks.

But if you look at the header files of this library on iOS, it becomes sad: the use of the required method is prohibited.

 CFPropertyListRef SCDynamicStoreCopyValue ( SCDynamicStoreRef store, CFStringRef key ) __OSX_AVAILABLE_STARTING(__MAC_10_1,__IPHONE_NA); 


To begin with, make sure that the method is generally operable.

  void *handle = dlopen("/System/Library/Frameworks/SystemConfiguration.framework/SystemConfiguration", RTLD_LAZY); CFArrayRef (*_SCDynamicStoreCopyKeyList)(int store, CFStringRef pattern) = dlsym(handle, "SCDynamicStoreCopyKeyList"); NSLog(@"Lib handle: %u", handle); NSString *key = @"State:/Network/Global/DNS"; CFArrayRef testarrray = _SCDynamicStoreCopyKeyList(0, CFSTR("State:/Network/Interface/en0/AirPort")); NSLog(@"Tested array res: %@", testarrray); 


Everything is fine, the result is returned. So, we do not have any software locks, except for a formal ban of Apple, which will not give the opportunity to pass the validation in the AppStore. However, why don't we write a piece of this library on our own?

It was very easy to find the sources: this is part of the configd daemon. The most interesting thing starts when you read the description of the function SCDynamicStoreCopyValue .

 #include "config.h" /* MiG generated file */ ... /* send the key & fetch the associated data from the server */ status = configget(storePrivate->server, myKeyRef, myKeyLen, &xmlDataRef, (int *)&xmlDataLen, &newInstance, (int *)&sc_status); 


Okay. A call is being made to the file generated using the MACH Interface Generator . Accordingly, we have a description in the MIG language, lying in a file nearby .

 routine configget ( server : mach_port_t; key : xmlData; out data : xmlDataOut, dealloc; out newInstance : int; out status : int); 


After that, you have two paths - the path of a normal person and the path of a Jedi. You could run the mig utility on the config.defs file and get the codes to insert into the project. But, unfortunately, at the time of the study, we did not find this file and had to do reverse engineering :) Jedi eventually Dima Sklyarov , who was able to restore the process of accessing the configd MACH port. With it, it turned out to restore the method entirely.

 #define kMachPortConfigd "com.apple.SystemConfiguration.configd" -(NSDictionary *)getSCdata:(NSString *)key { if(SYSTEM_VERSION_LESS_THAN(@"6.0")) { // It does not work on iOS 5.* return nil; } struct send_body {mach_msg_header_t header; int count; UInt8 *addr; CFIndex size0; int flags; NDR_record_t ndr; CFIndex size; int retB; int rcB; int f24; int f28;}; mach_port_t bootstrapport = MACH_PORT_NULL; mach_port_t configport = MACH_PORT_NULL; mach_msg_header_t *msg; mach_msg_return_t msg_return; struct send_body send_msg; // Make request CFDataRef extRepr; extRepr = CFStringCreateExternalRepresentation(NULL, (__bridge CFStringRef)(key), kCFStringEncodingUTF8, 0); // Connect to Mach MIG port of configd task_get_bootstrap_port(mach_task_self(), &bootstrapport); bootstrap_look_up2(bootstrapport, kMachPortConfigd, &configport, 0, 8LL); // Make request send_msg.count = 1; send_msg.addr = (UInt8*)CFDataGetBytePtr(extRepr); send_msg.size0 = CFDataGetLength(extRepr); send_msg.size = CFDataGetLength(extRepr); send_msg.flags = 0x1000100u; send_msg.ndr = NDR_record; // Make message header msg = &(send_msg.header); msg->msgh_bits = 0x80001513u; msg->msgh_remote_port = configport; msg->msgh_local_port = mig_get_reply_port(); msg->msgh_id = 20010; // Request server msg_return = mach_msg(msg, 3, 0x34u, 0x44u, msg->msgh_local_port, 0, 0); if(msg_return) { if (msg_return - 0x10000002u >= 2 && msg_return != 0x10000010 ) { mig_dealloc_reply_port(msg->msgh_local_port); } else { mig_put_reply_port(msg->msgh_local_port); } } else if ( msg->msgh_id != 71 && msg->msgh_id == 20110 && msg->msgh_bits <= -1 ) { if ((send_msg.flags & 0xFF000000) == 0x1000000) { CFDataRef deserializedData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, send_msg.addr,send_msg.size0, kCFAllocatorNull); CFPropertyListRef proplist = CFPropertyListCreateWithData(kCFAllocatorDefault, deserializedData, kCFPropertyListImmutable, NULL, NULL); mig_dealloc_reply_port(msg->msgh_local_port); mach_port_deallocate(mach_task_self(), bootstrapport); mach_port_deallocate(mach_task_self(), configport); mach_msg_destroy(msg); NSDictionary *property_list = (__bridge NSDictionary*)proplist; if(proplist) CFRelease(proplist); CFRelease(deserializedData); CFRelease(extRepr); return property_list; } } mig_dealloc_reply_port(msg->msgh_local_port); mach_port_deallocate(mach_task_self(), bootstrapport); mach_port_deallocate(mach_task_self(), configport); mach_msg_destroy(msg); CFRelease(extRepr); return nil; } 


The values ​​of interest to us are located by the key @ "Setup: / Network / Interface / en0 / AirPort".

So, we implemented part of SystemConfiguration.framework independently and obtained the necessary data without resorting to Jailbreak or illegal use of libraries. Curiously, in iOS 6 there are more than 100 MACH ports open for connection with a wide variety of names. It seems to me that this provides quite a rich ground for various studies. Unfortunately, for the time being I cannot say whether the similar code passes in the AppStore, but it is definitely worth a try.

Thanks for attention.

References:

- MACH Kernel programming guide

- iOS Hackers handbook

- Mac OS X internals

Source: https://habr.com/ru/post/181936/


All Articles