We're working on a project with my colleagues which involves using a lot of private and non official code. This is not intended for AppStore use.
The first and only requirement we have is to not use jailbreak.
First of all, UDID
or OpenUDID
or any other solutions don't work here and they're not expected to.
We've done a lot of background research and tests, starting with trying to get the IMEI, ICCID, IMSI and the Serial Number programatically. None of the above methods work with iOS 7 and above without jailbreak.
We've also spent a couple of months to play with IOKit
framework using the famous IOKitBrowser and dumping the whole contents of iOS
internals. Unfortunately, we discovered that with iOS 8.3
it stopped working.
We're talking here not about getting the UDID
or any other "mainstream" thing, but generally speaking we need a way to get
any permanent hardware identifier unique enough to identify a device that would persist in spite of device wipes and amongst different iOS versions
This question is no duplicate to others (no solutions are found here, for example) and is targeting solely private APIs.
Any help would be highly appreciated.
I'm sorry to say that apparently from iOS 8.3, to get any unique identifier you need a higher access level than normal user.
Without exploiting anything, just with private frameworks, libraries and kernel requests, any request to unique identifiers returns null.
Illustrating:
Trying to use 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);
}
Fails. Reason: IOPlatformSerialNumber
is not accessible. Many other requests work fine.
Trying to use Mach calls to get network adapters HW IDs:
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));
Fails. Reason: Returns 02:00:00:00:00:00
for any network adapter.
Trying to connect to 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());
}
Fails. Reason: lockdown_connect()
fails, returning null
.
Trying to use 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);
}
Fails. Reason: requests for unique identifiers return null
. Any other request works fine.
My suggestion is to use some privilege escalation technique to get superuser access, then run any of the methods listed here to get the property.
Also, extend the study on liblockdown. If it's accessible at user-level (with something other than lockdown_connect), it might be possible to read these things.