从 iOS 中获取无法访问数据的非标准方法






4.44/5 (9投票s)
在 iOS 中获取敏感信息的有趣方法。
引言
在 Positive Hack Days 演讲之后,我想分享一下我在 iOS 6 MACH 上探索守护进程 configd 时获得的信息。如您所知,iOS 提供的关于 Wi-Fi 连接状态的信息很少。基本上,公共 API 允许获取 SSID、BSSID、适配器网络设置,仅此而已。那么加密模式呢?信号强度呢?您可以在下方查看更多信息,了解如何在没有私有 API 和越狱的情况下获取此类数据。
现在我必须为发布如此多的源代码道歉。首先,让我们回顾一下之前的 iOS 5.*。那时,您可以使用 Apple 系统日志工具来获取连接到网络时显示的系统消息。加密模式和信号强度数据出现在这些消息中。您可以通过这种方式获取它们
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);
但是,正如苹果公司通常做的那样,一旦知道 ASL 中的系统消息,该公司就关闭了访问权限。所以我们必须找到一种新的方法来获取这些数据。问题表述不同:如何在 Mac OS 和 iOS 中获取这些数据?
首先,您可以使用 scutil,它允许获取系统配置数据,包括我们需要的信息。在 iOS 6 上测试越狱 iPhone 证明该工具运行良好。对我来说,这是一个线索,我开始寻找一种在 iOS 上访问 SystemConfiguration
的方法。
这就像吃馅饼一样简单:SystemConfiguration.framework
。它允许连接到 Mac OS 值存储并获取属性列表,其中包括无线网络数据。
但是,当您查看该库的头文件时,您会感到沮丧:使用所需方法受到限制。
CFPropertyListRef
SCDynamicStoreCopyValue (
SCDynamicStoreRef store,
CFStringRef key
) __OSX_AVAILABLE_STARTING(__MAC_10_1,__IPHONE_NA);
首先,确保该方法有效。
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);
一切正常。结果返回。所以没有阻塞,只有苹果公司的正式限制,这不会允许通过 App Store 的验证。无论如何,我们为什么不自己编写一部分库呢?源代码很容易找到:它是守护进程 configd 的一部分。当阅读 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);
好的。请求被传递到使用 MACH 接口生成器生成的文件。我们可以在附近的文件中找到 MIG 中的描述。
routine configget ( server : mach_port_t;
key : xmlData;
out data : xmlDataOut, dealloc;
out newInstance : int;
out status : int);
现在你有两个选择——普通人的方式和绝地武士的方式。您可以在文件 config.defs 上运行 mig,并获取要输入到项目中的代码。但不幸的是,在研究过程中我们没有发现该文件,所以我们不得不进行一些逆向工程 :) 然而,Dmitry Sklyarov 确实展示了他的绝地武士技能,设法恢复了向 MACH 端口 configd 发送请求的过程。因此,该方法被完全恢复。
#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;
}
我们需要的数据位于键 @«Setup:/Network/Interface/en0/AirPort»
中。
因此,我们自己实现了 SystemConfiguration.framework
的一部分,并在没有越狱和非法使用库的情况下获得了数据。有趣的是,在 iOS 6 中有超过 100 个具有各种名称的开放 MACH 端口。我想这为研究奠定了基础。不幸的是,目前我无法说这种代码是否可以在 App Store 中使用,但无论如何都值得一试。
感谢您的关注。