Ser*_*yov 32 iphone cocoa-touch iokit iphone-privateapi ios
我们正与同事一起开展一个项目,涉及使用大量私有和非官方代码.这不适用于AppStore.
我们的第一个也是唯一的要求是不使用越狱.
首先,UDID
或者OpenUDID
或者任何其他解决方案在这里不起作用,并且它们不被期望.
我们已经做了很多背景研究和测试,从尝试以编程方式获取IMEI,ICCID,IMSI和序列号开始.如果没有越狱,上述方法都不适用于iOS 7及更高版本.
我们还花了几个月的时间IOKit
使用着名的IOKitBrowser来使用框架并抛弃iOS
内部的全部内容.不幸的是,我们发现随着iOS 8.3
它停止工作.
我们在这里谈的不是关于获得UDID
或任何其他"主流"的东西,但一般来说我们需要一种方法来获得
任何永久性硬件标识符,其唯一性足以识别在设备擦除和不同iOS版本之间仍然存在的设备
这个问题与其他人没有重复(例如,这里没有找到解决方案),并且仅针对私有API.
任何帮助将受到高度赞赏.
gbu*_*any 15
我很遗憾地说,显然来自iOS 8.3,要获得任何唯一标识符,您需要比普通用户更高的访问级别.
在没有利用任何东西的情况下,只需使用私有框架,库和内核请求,对唯一标识符的任何请求都将返回null.
举例说明:
尝试使用IOKit:
void *IOKit = dlopen("/System/Library/Frameworks/IOKit.framework/IOKit", RTLD_NOW);
if (IOKit)
{
mach_port_t *kIOMasterPortDefault = dlsym(IOKit, "kIOMasterPortDefault");
CFMutableDictionaryRef (*IOServiceMatching)(const char *name) = dlsym(IOKit, "IOServiceMatching");
mach_port_t (*IOServiceGetMatchingService)(mach_port_t masterPort, CFDictionaryRef matching) = dlsym(IOKit, "IOServiceGetMatchingService");
CFTypeRef (*IORegistryEntryCreateCFProperty)(mach_port_t entry, CFStringRef key, CFAllocatorRef allocator, uint32_t options) = dlsym(IOKit, "IORegistryEntryCreateCFProperty");
kern_return_t (*IOObjectRelease)(mach_port_t object) = dlsym(IOKit, "IOObjectRelease");
if (kIOMasterPortDefault && IOServiceGetMatchingService && IORegistryEntryCreateCFProperty && IOObjectRelease)
{
mach_port_t platformExpertDevice = IOServiceGetMatchingService(*kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
if (platformExpertDevice)
{
CFTypeRef platformSerialNumber = IORegistryEntryCreateCFProperty(platformExpertDevice, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
if (platformSerialNumber && CFGetTypeID(platformSerialNumber) == CFStringGetTypeID())
{
serialNumber = [NSString stringWithString:(__bridge NSString *)platformSerialNumber];
CFRelease(platformSerialNumber);
}
IOObjectRelease(platformExpertDevice);
}
}
dlclose(IOKit);
}
Run Code Online (Sandbox Code Playgroud)
失败.原因:IOPlatformSerialNumber
无法访问.许多其他请求工作正常.
尝试使用Mach调用来获取网络适配器HW ID:
int mib[6], len;
char *buf;
unsigned char *ptr;
struct if_msghdr *ifm;
struct sockaddr_dl *sdl;
mib[0] = CTL_NET;
mib[1] = AF_ROUTE;
mib[2] = 0;
mib[3] = AF_LINK;
mib[4] = NET_RT_IFLIST;
if ((mib[5] = if_nametoindex("en0")) == 0) {
perror("if_nametoindex error");
exit(2);
}
if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
perror("sysctl 1 error");
exit(3);
}
if ((buf = malloc(len)) == NULL) {
perror("malloc error");
exit(4);
}
if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
perror("sysctl 2 error");
exit(5);
}
ifm = (struct if_msghdr *)buf;
sdl = (struct sockaddr_dl *)(ifm + 1);
ptr = (unsigned char *)LLADDR(sdl);
printf("%02x:%02x:%02x:%02x:%02x:%02x\n", *ptr, *(ptr+1), *(ptr+2),
*(ptr+3), *(ptr+4), *(ptr+5));
Run Code Online (Sandbox Code Playgroud)
失败.原因:02:00:00:00:00:00
任何网络适配器的返回.
试图连接到lockdownd:
void *libHandle = dlopen("/usr/lib/liblockdown.dylib", RTLD_LAZY);
if (libHandle)
{
lockdown_connect = dlsym(libHandle, "lockdown_connect");
lockdown_copy_value = dlsym(libHandle, "lockdown_copy_value");
id connection = lockdown_connect();
NSString *kLockdownDeviceColorKey
NSString *color = lockdown_copy_value(connection, nil, kLockdownDeviceColorKey);
NSLog(@"color = %@", color);
lockdown_disconnect(connection);
dlclose(libHandle);
}
else {
printf("[%s] Unable to open liblockdown.dylib: %s\n",
__FILE__, dlerror());
}
Run Code Online (Sandbox Code Playgroud)
失败.原因:lockdown_connect()
失败,回归null
.
试图使用libMobileGestalt:
void *libHandle = dlopen("/usr/lib/libMobileGestalt.dylib", RTLD_LAZY);
if (libHandle)
{
MGCopyAnswer = dlsym(libHandle, "MGCopyAnswer");
NSString* value = MGCopyAnswer(CFSTR("SerialNumber"));
NSLog(@"Value: %@", value);
CFRelease(value);
}
Run Code Online (Sandbox Code Playgroud)
失败.原因:返回唯一标识符的请求null
.任何其他请求工作正常.
我的建议是使用一些权限提升技术来获取超级用户访问权限,然后运行此处列出的任何方法来获取属性.
另外,扩展对liblockdown的研究.如果它可以在用户级访问(使用lockdown_connect之外的其他内容),则可以阅读这些内容.
bzz*_*bzz 14
经过一番挖掘后,我发现所有私有API都libMobileGestalt
用于获取任何硬件标识符,而后者又使用这些标识符IOKit
.MobileGestalt
检查当前pid的沙箱规则并查找com.apple.private.MobileGestalt.AllowedProtectedKeys
权利.
请参阅以下代码:
signed int __fastcall sub_2EB8803C(int a1, int a2, int a3, int a4)
{
int v4; // r5@1
int v5; // r4@1
int v6; // r10@1
int v7; // r2@1
int v8; // r0@3
int v9; // r6@3
int v10; // r11@4
int v11; // r4@4
int v12; // r0@5
signed int v13; // r6@6
int v14; // r6@7
char *v15; // r0@7
int v16; // r1@7
int v17; // r1@14
int v18; // r3@16
int v19; // r5@16
signed int v20; // r1@17
int v21; // r0@17
__CFString *v22; // r2@19
int v23; // r4@27
__CFString *v24; // r2@27
int v26; // [sp+8h] [bp-428h]@1
char v27; // [sp+10h] [bp-420h]@1
int v28; // [sp+414h] [bp-1Ch]@1
v26 = a2;
v4 = a1;
v5 = a3;
v6 = a4;
v28 = __stack_chk_guard;
memset(&v27, 0, 0x401u);
v7 = *(_DWORD *)(dword_32260254 + 260);
if ( !v7 )
v7 = sub_2EB8047C(65, 2);
v8 = ((int (__fastcall *)(int, _DWORD))v7)(v4, "com.apple.private.MobileGestalt.AllowedProtectedKeys");
v9 = v8;
if ( !v8 )
goto LABEL_12;
v10 = v5;
v11 = CFGetTypeID(v8);
if ( v11 != CFArrayGetTypeID() )
{
v14 = (int)"/SourceCache/MobileGestalt/MobileGestalt-297.1.14/MobileGestalt.c";
v15 = rindex("/SourceCache/MobileGestalt/MobileGestalt-297.1.14/MobileGestalt.c", 47);
v16 = *(_DWORD *)(dword_32260254 + 288);
if ( v15 )
v14 = (int)(v15 + 1);
if ( !v16 )
v16 = sub_2EB8047C(72, 2);
((void (__fastcall *)(int))v16)(v4);
_MGLog(3, v14);
LABEL_12:
v13 = 0;
goto LABEL_13;
}
v12 = CFArrayGetCount(v9);
if ( CFArrayContainsValue(v9, 0, v12, v26) )
v13 = 1;
else
v13 = sub_2EB7F948(v9, v26, v10, "MGCopyAnswer");
LABEL_13:
if ( !v6 )
goto LABEL_30;
v17 = *(_DWORD *)(dword_32260254 + 288);
if ( !v17 )
v17 = sub_2EB8047C(72, 2);
v19 = ((int (__fastcall *)(int))v17)(v4);
if ( v13 != 1 )
{
v21 = *(_DWORD *)v6;
if ( *(_DWORD *)v6 )
{
v22 = CFSTR(" and IS NOT appropriately entitled");
goto LABEL_22;
}
v23 = CFStringCreateMutable(0, 0);
*(_DWORD *)v6 = v23;
sub_2EB7F644(v19, &v27);
v24 = CFSTR("pid %d (%s) IS NOT appropriately entitled to fetch %@");
goto LABEL_29;
}
v20 = MGGetBoolAnswer((int)CFSTR("LBJfwOEzExRxzlAnSuI7eg"));
v21 = *(_DWORD *)v6;
if ( v20 == 1 )
{
if ( v21 )
{
v22 = CFSTR(" but IS appropriately entitled; all is good in the world");
LABEL_22:
CFStringAppendFormat(v21, 0, v22, v18);
goto LABEL_30;
}
v23 = CFStringCreateMutable(0, 0);
*(_DWORD *)v6 = v23;
sub_2EB7F644(v19, &v27);
v24 = CFSTR("pid %d (%s) IS appropriately entitled to fetch %@; all is good in the world");
LABEL_29:
CFStringAppendFormat(v23, 0, v24, v19);
goto LABEL_30;
}
if ( v21 )
{
CFRelease(v21);
*(_DWORD *)v6 = 0;
}
*(_DWORD *)v6 = 0;
LABEL_30:
if ( __stack_chk_guard != v28 )
__stack_chk_fail(__stack_chk_guard - v28);
return v13;
}
signed int __fastcall sub_2EB88228(int a1, int a2, int a3)
{
int v3; // r4@1
int v4; // r10@1
int v5; // r0@1
int v6; // r6@1
int v7; // r5@5
signed int result; // r0@6
char v9; // [sp+8h] [bp-420h]@5
int v10; // [sp+40Ch] [bp-1Ch]@1
v3 = a1;
v4 = a3;
v10 = __stack_chk_guard;
v5 = sandbox_check();
v6 = v5;
if ( v5 )
v5 = 1;
if ( v4 && v5 == 1 )
{
memset(&v9, 0, 0x401u);
v7 = CFStringCreateMutable(0, 0);
*(_DWORD *)v4 = v7;
sub_2EB7F644(v3, &v9);
CFStringAppendFormat(v7, 0, CFSTR("pid %d (%s) does not have sandbox access for %@"), v3);
}
result = 0;
if ( !v6 )
result = 1;
if ( __stack_chk_guard != v10 )
__stack_chk_fail(result);
return result;
}
Run Code Online (Sandbox Code Playgroud)
如上所述这里,UDID计算如下:
UDID = SHA1(serial + ECID + wifiMac + bluetoothMac)
Run Code Online (Sandbox Code Playgroud)
MobileGestalt
通过IOKit
这样获取这些值:
CFMutableDictionaryRef service = IOServiceMatching("IOPlatformExpertDevice");
io_service_t ioservice = IOServiceGetMatchingService(kIOMasterPortDefault, service);
CFTypeRef entry = IORegistryEntryCreateCFProperty(ioservice, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
const UInt8 * data = CFDataGetBytePtr(entry);
CFStringRef string = CFStringCreateWithCString(kCFAllocatorDefault, data, kCFStringEncodingUTF8);
Run Code Online (Sandbox Code Playgroud)
如果您尝试自己动手,它将失败,因为iOS 8.3中的新沙盒规则非常严格,并拒绝访问所有硬件标识符,如下所示:
deny iokit-get-properties IOPlatformSerialNumber
Run Code Online (Sandbox Code Playgroud)
可能解决方案
看起来你可以获得UDID的唯一方法如下:
确认的工作解决方案
以下是基于RoutingHTTPServer的示例:
import UIKit
import RoutingHTTPServer
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var bgTask = UIBackgroundTaskInvalid
let server = HTTPServer()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
application.openURL(NSURL(string: "http://localhost:55555")!)
return true
}
func applicationDidEnterBackground(application: UIApplication) {
bgTask = application.beginBackgroundTaskWithExpirationHandler() {
dispatch_async(dispatch_get_main_queue()) {[unowned self] in
application.endBackgroundTask(self.bgTask)
self.bgTask = UIBackgroundTaskInvalid
}
}
}
}
class HTTPServer: RoutingHTTPServer {
override init() {
super.init()
setPort(55555)
handleMethod("GET", withPath: "/") {
$1.setHeader("Content-Type", value: "application/x-apple-aspen-config")
$1.respondWithData(NSData(contentsOfFile: NSBundle.mainBundle().pathForResource("udid", ofType: "mobileconfig")!)!)
}
handleMethod("POST", withPath: "/") {
let raw = NSString(data:$0.body(), encoding:NSISOLatin1StringEncoding) as! String
let plistString = raw.substringWithRange(Range(start: raw.rangeOfString("<?xml")!.startIndex,end: raw.rangeOfString("</plist>")!.endIndex))
let plist = NSPropertyListSerialization.propertyListWithData(plistString.dataUsingEncoding(NSISOLatin1StringEncoding)!, options: .allZeros, format: nil, error: nil) as! [String:String]
let udid = plist["UDID"]!
println(udid) // Here is your UDID!
$1.statusCode = 200
$1.respondWithString("see https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/ConfigurationProfileExamples/ConfigurationProfileExamples.html")
}
start(nil)
}
}
Run Code Online (Sandbox Code Playgroud)
以下是内容udid.mobileconfig
:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>PayloadContent</key>
<dict>
<key>URL</key>
<string>http://localhost:55555</string>
<key>DeviceAttributes</key>
<array>
<string>IMEI</string>
<string>UDID</string>
<string>PRODUCT</string>
<string>VERSION</string>
<string>SERIAL</string>
</array>
</dict>
<key>PayloadOrganization</key>
<string>udid</string>
<key>PayloadDisplayName</key>
<string>Get Your UDID</string>
<key>PayloadVersion</key>
<integer>1</integer>
<key>PayloadUUID</key>
<string>9CF421B3-9853-9999-BC8A-982CBD3C907C</string>
<key>PayloadIdentifier</key>
<string>udid</string>
<key>PayloadDescription</key>
<string>Install this temporary profile to find and display your current device's UDID. It is automatically removed from device right after you get your UDID.</string>
<key>PayloadType</key>
<string>Profile Service</string>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)
配置文件安装将失败(我没有打算实现预期的响应,请参阅文档),但应用程序将获得正确的UDID.你还应该签署mobileconfig.
归档时间: |
|
查看次数: |
6815 次 |
最近记录: |