65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.44/5 (9投票s)

2013年7月15日

GPL3

3分钟阅读

viewsIcon

21662

在 iOS 中获取敏感信息的有趣方法。

Sample Image

引言

在 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 中使用,但无论如何都值得一试。

感谢您的关注。

© . All rights reserved.