Deobfuscating libMobileGestalt keys

Posted: January 24th, 2017 | Author: | Filed under: crypto, Debugging, iOS, Programming, Reverse Engineering | Tags: , , , , , , , , , , , , | 3 Comments »

/usr/lib/libMobileGestalt.dylib is a private library which provides an API to retrieve the capabilities of the iOS device, as well as some runtime information: system version, build version, device type, current status of the airplane mode, …

The implementation is similar to a key-value database. The library exposes a simple function to retrieve the value for a specified key:

id MGCopyAnswer(NSString *inKey);

When calling this method with a key, it returns the associated value stored in the database, or nil if the key does not exist.

MGCopyAnswer examples

The UIKit framework uses the libMobileGestalt.dylib in several methods. Let’s look at 4 examples.

-[UIDevice systemVersion]

The implementation of -[UIDevice systemVersion] looks like the following (note that I simplified the code for clarity). As you can see -[UIDevice systemVersion] simply returns the value for the key “ProductVersion”:

-(NSString *)systemVersion
{
	NSString *systemVersion = MGCopyAnswer(@"ProductVersion");
    if (systemVersion != nil)
    {
		return systemVersion;
    }
    
    return @"Unknown";
}

-[UIDevice buildVersion]


Similarly the private -[UIDevice buildVersion] method just returns the value corresponding to the key “BuildVersion”:

-(NSString *)buildVersion
{
	NSString *buildVersion = MGCopyAnswer(@"BuildVersion");
    if (buildVersion != nil)
    {
		return buildVersion;
    }
    
	return @"Unknown";
}

-[UIScreen _pointsPerInch]


Another interesting method is -[UIScreen _pointsPerInch] which uses the value corresponding to the key “main-screen-pitch”.

-[UIDevice systemName]


A last example is -[UIDevice systemName] (also simplified):

-(NSString *)systemName
{
	NSString *systemName = MGCopyAnswer(@"j9Th5smJpdztHwc+i39zIg");
	if (systemName != nil)
	{
		return systemName;
	}
	
	systemName = MGCopyAnswer(@"ProductName");
	if (systemName != nil)
	{
		return systemName;
	}
	
	return @"Unknown";
}

Note the string “j9Th5smJpdztHwc+i39zIg” used by -[UIDevice systemName] which I will refer as “obfuscated key”.

MGCopyAnswer implementation

Let’s look at how MGCopyAnswer is implemented:

  • It first checks if the string passed as parameter exists as key in the database. If this is the case the value associated to the key is returned.
  • Otherwise it calculates the obfuscated key from the key and checks if the obfuscated key exists in the database. In this case the value associated to the obfuscated key is returned.

Obfuscated keys

The code to calculate the obfuscated key is quite simple. Below is the annotated function:


CalculateObfuscatedKey, arm64, iOS 10.1.1

As you can see the implementation does the following:

  • add a “MGCopyAnswer” prefix to the string
  • calculate the MD5
  • use the CommonCrypto CNEncode function to calculate the base64 value

An equivalent Objective-C implementation is:


NSString *CalculateObfuscatedKey(const char *inString)
{
	// Add a prefix
	char buffer[256] = { 0 };
	snprintf(buffer, sizeof(buffer), "%s%s", "MGCopyAnswer", inString);
	
	// Calculate MD5
	unsigned char md5Hash[CC_MD5_DIGEST_LENGTH] = { 0 };
	CC_MD5(buffer, (CC_LONG)strlen(buffer), md5Hash);
	
	// Base64
	NSData *md5Data = [NSData dataWithBytes:md5Hash length:CC_MD5_DIGEST_LENGTH];
	NSString *obfuscatedKey = [md5Data base64EncodedStringWithOptions:0];
	
	// Base64 converts 3 bytes into 4 encoded characters.
	// The MD5 contains 16 bytes. 16 bytes not being a multiple of 3, the Base64 is padded with "=="
	// and we end up with (16+2) * 4 / 3 = 24 encoded characters
	// The last 2 characters are useless and they are dropped
	// (i.e. only keep the first 22 characters).
	return [obfuscatedKey substringToIndex:22];
}

Getting the list of all valid obfuscated keys

Is it possible to get the list of all valid keys? Not easy…

However getting the list of obfuscated keys is simple because it is stored inside the libMobileGestalt.dylib binary. You can get the list of the 646 obfuscated keys here: obfuscatedkeys.txt

/2V8H9h/+z0UxNUr9aRLeQ
/6FWCRjN1yRdUABG9vF8ow
/9luHerXthRoPoNt/PVkTg
/bSMNaIuUT58N/BN1nYUjw
/cMWdoU/88pcjJ1egxmIYw
/ej/HWmqnKV/QQptXhUZmg
[…]
zJUWenIp94snlzBD1cub3g
znvmheFkjr6hiqIK9TrCVw
zP3kBA1Biwz2d6PTIIbmUQ
zPSNnYDFk+x5ebOtenb3Eg
zxMIgVSILN6S5ee6MZhf+Q
ZYqko/XM5zD3XBfN5RmaXA

Note however that there is no guarantee the list is complete. It is possible that the libMobileGestalt.dylib binary does not include some obfuscated keys.

Obfuscated key -> key?

It is now possible to get the values for all the obfuscated keys… but we don’t know the key and thus the meaning of the value. For example the following information is not really useful:

MGCopyAnswer(“03hWmMtMs+4nzama4/PzHQ”) = YES
MGCopyAnswer(“cBy4BcYs5YWtFHbBpt4C6A”) = YES

Whereas if we knew the key, that would be much more interesting:

MGCopyAnswer(“CameraLiveEffectsCapability”) = YES
MGCopyAnswer(“DeviceSupportsHaptics”) = YES

Can we get the key from the obfuscated key? As we have seen, Apple uses the weak MD5 algorithm to calculate the obfuscated key. Moreover we can guess the possible formats for the key based on the examples:

  • word (lowercase word)
  • Word1Word2…Wordn (camel case words combination)
  • word1-word2-…-wordn (dash separated lowercase words)

This means that we can brute force the obfuscated keys to retrieve the keys with a good percentage of success.

Getting the list of raw MD5

To run a brute force attack, we first need to get the MD5 hashes. This is easy to get:

- (NSString *)md5StringForObfuscatedKey:(NSString *)inObfuscatedKey
{
	if([inObfuscatedKey length] <= 0)
		return nil;
	
	// As seen in CalculateObfuscatedKey(), the last 2 base64 characters
	// are dropped because it's a useless "==" padding sequence.
	// To decode the base64 encoded string to the MD5 hash,
	// we need to append back the "==" padding sequence.
	NSString *base64String = [NSString stringWithFormat:@"%@==", inObfuscatedKey];
	
	// Decode the base64 string
	NSData *md5Data = [[NSData alloc] initWithBase64EncodedString:base64String options:0];
	if([md5Data length] < 16)
		return nil;
	
	// Format the MD5 hash
	const uint8_t *md5 = [md5Data bytes];
	NSString *md5String = [NSString stringWithFormat:@"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
										md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9],
										md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]];
	
	return md5String;
}

You can get the list of the 646 md5 hashes here: md5hashes.txt

0055e1c6b685d5bbf26823250483993c
00915085e643c946ef23a46604c4fd0a
00e221d65ddc2320d794fe0a07fd3ce0
00f7a49c0e7964072ed0572e7ea54de1
010888a56d1479840a9e1cb675aec05e
01611f3f7c56874ab53233b7240cbf00
[…]
fdc31676853ff3ca5c8c9d5e83198863
fde8ff1d69aa9ca57f410a6d5e15199a
fe5d0acf66a4bd2bc41d336665e6349d
ff657c1fd87ffb3d14c4d52bf5a44b79
ffa1560918cdd7245d500046f6f17ca3
ffd96e1dead7b614683e836dfcf5644e

Now we just need to brute force these hashes…

hashcat

There are several good solutions to brute force MD5 hashes. I used hashcat (https://hashcat.net/hashcat/) because it supports macOS, it is GPU accelerated (OpenCL), it is open source and supports the attacks I wanted to perform.

Mask attack

A direct brute force attack is not practicable due to the large keyspace. But the first obvious attack is a mask attack. In a mask attack we provide a string with placeholders. The placeholder characters will be brute force with the specified charset. Such attack can quickly recover simple keys.

The keys to recover seem to mostly contain lowercase characters, uppercase characters, digits and dashes. hashcat provides several built-in charsets:

?l = abcdefghijklmnopqrstuvwxyz
?u = ABCDEFGHIJKLMNOPQRSTUVWXYZ
?d = 0123456789

In most of my mask attacks I used the custom charset “?l?u?d-” that consists of the characters “abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-“. In some cases when it would take too much time (or when targeting a specific format), I reduce the charset (to “?l” for example).

With the mask attacks I quickly recovered some keys. For example I got the following keys after running hashcat -a 3 -m 0 md5hashes.txt -1 ?l?u?d- MGCopyAnswer?1?1?1:

80accd25cc1e482580fa0206894409e7:MGCopyAnswermms
38fce1bd139952a09986060ccaf7b904:MGCopyAnswersms
6624a563161293269822653796b4975b:MGCopyAnswergps
3d4300aeb85ae0f15e3aa20d79044cdc:MGCopyAnswersim
b29195ba30c49b20b30f39d7a33077a0:MGCopyAnswerapn

Explanation for hashcat -a 3 -m 0 md5hashes.txt -1 ?l?u?d- MGCopyAnswer?1?1?1:

  • -a 3: set the attack mode to brute-force
  • -m 0: set the hash type to MD5
  • md5hashes.txt: the list of MD5 hashes to brute force
  • -1 ?l?u?d-: define the custom charset 1 to “abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-“
  • MGCopyAnswer?1?1?1: The mask to use for the attack. The brute force will try all words starting with MGCopyAnswer followed by 3 characters from the custom charset 1

4 characters keys could easily be recovered too using hashcat -a 3 -m 0 md5hashes.txt -1 ?l?u?d- MGCopyAnswer?1?1?1?1:

36440e259d71745939495e793c52a522:MGCopyAnswerwlan
861fcda16a44a2ad551789460dd3d4a7:MGCopyAnswerrole
644174a68eb7b1382956b73d09eed835:MGCopyAnswerDMin
022d33b09437fac4c5914ebf94b6dde4:MGCopyAnsweropal
68d65e0b2b96c48e9213f2b0675dbdc0:MGCopyAnswername
874394c20e77bcaa7e20f7732c6e0dac:MGCopyAnswermesa
8621eeb7f591f81f4bc7fbddd16c9e36:MGCopyAnswerwapi
9ad1d97751fc5c9d83315b4d5544a46a:MGCopyAnswerwifi
b8a73b14f9c43befa55611d61c59466d:MGCopyAnsweripad
5c4cc85d53e57afc6e108a59acc63ef0:MGCopyAnswerSkey
2e0d44257d7525bec46ef781ebe62055:MGCopyAnswer720p
f59a922faf0c2724044b34050ef2aa5c:MGCopyAnswervoip

5 characters keys can be quickly recovered too with hashcat -a 3 -m 0 md5hashes.txt -1 ?l?u?d- MGCopyAnswer?1?1?1?1?1:

e74fc29814d7ea38646fc67ad61cf085:MGCopyAnswerclass
3facfc78dad13dcbf401c28f30bd22a3:MGCopyAnswerwi-fi
87077d8a96fa79eccd95e379f7eea7d5:MGCopyAnswermetal
952a5ed501c8c9ad1a78dae32d3b5a24:MGCopyAnswerhidpi
1608e73243c93e92380b7f1d5844f0b7:MGCopyAnswerflash
90a809b1637fac150092298eb66ff06c:MGCopyAnswerarm64
31676eb801a9b6b97ba88cd6a8198ea9:MGCopyAnswerAWDID
83ef4da63992570b6899df27c8d2629a:MGCopyAnswerarmv6
0d6ae1ca1d41c18ca96265b9abbf16bb:MGCopyAnswerarmv7
67f4c94b421a2f2ab5d1d712bd44c63e:MGCopyAnswerDieId

Similar mask attacks can be used to recover keys with up to 7 characters. Starting with 8 characters the mask attack starts to take too much time with my hardware (multiple days).

It is however still possible to use the mask attack with more specific formats like:

hashcat -a 3 -m 0 md5hashes.txt -1 ?l MGCopyAnswer?1?1?1-?1?1?1?1
hashcat -a 3 -m 0 md5hashes.txt -1 ?l MGCopyAnswer?1?1-?1?1?1?1?1
hashcat -a 3 -m 0 md5hashes.txt -1 ?l MGCopyAnswer?1?1?1?1-?1?1?1
hashcat -a 3 -m 0 md5hashes.txt -1 ?l MGCopyAnswer?1?1?1?1?1-?1?1
hashcat -a 3 -m 0 md5hashes.txt -1 ?l MGCopyAnswer?1?1?1?1-?1?1?1?1
hashcat -a 3 -m 0 md5hashes.txt -1 ?l MGCopyAnswer?1?1?1?1?1?1-?1?1
hashcat -a 3 -m 0 md5hashes.txt -1 ?l MGCopyAnswer?1?1?1?1-?1?1?1?1?1
hashcat -a 3 -m 0 md5hashes.txt -1 ?l?u?d MGCopyAnswerDeviceSupports?1?1?1?1

The last example would give back:

a961958e794dff058c8655a07cd71206:MGCopyAnswerDeviceSupports9Pin
8e2e7a04ed6651e4fb420f513bb12bf7:MGCopyAnswerDeviceSupportsASTC
abaf6f6aea8af5d8e73e5119045055e0:MGCopyAnswerDeviceSupportsSiDP
9701d14d934ee49abcee9565cdd34620:MGCopyAnswerDeviceSupports720p
5e47c655896b90140981a19a6c711225:MGCopyAnswerDeviceSupportsDClr

Dictionary attack

With mask attacks I quickly recovered simple keys (and later keys for which I could guess the format). Recovering more complex keys is inefficient and I switch to a dictionary attack. A dictionary attack (also known as wordlist attack) consists of trying all words from a list.
Using a simple English dictionary, I could recover a couple of keys but obviously the words in the dictionary are less than ideal.

I built a much better dictionary by extracting all the strings from iOS. This can be achieved with the following bash script ( this script can be downloaded here ExtractStrings.sh ):

#!/bin/bash

#---------------------------------------------------------------------
# Bash script that loops through all the files of a folder
# and extract the strings.
# Created by Alexandre Colucci on 16.01.2017
# http://blog.timac.org/?p=1570
#---------------------------------------------------------------------


#---------------------------------------------------------------------
# Force expand a wildcard pattern into the list of matching pathnames
#---------------------------------------------------------------------
shopt -s nullglob

#---------------------------------------------------------------------
# Function to print the usage
#---------------------------------------------------------------------
printUsage ()
{
	echo "Usage: ExtractStrings.sh IN_FOLDER_PATH OUT_FILE"
	echo "IN_FOLDER_PATH: Folder to extract strings from"
	echo "OUT_FILE: All the strings found will be saved to this text file"
	echo ""
	echo "Examples:"
	echo "  ExtractStrings.sh /System/Library /tmp/output.txt"
	echo "  ExtractStrings.sh /System /tmp/output.txt"
	echo "  ExtractStrings.sh / /tmp/output.txt"
	echo ""
	echo "Note: run as root in order to avoid permission issues."
	echo ""
}

#---------------------------------------------------------------------
# Check if the script was called with the expected usage
#---------------------------------------------------------------------
PARAMETER_NUMBER=$#
PARAMETER_REQUIRED=2
if [ $PARAMETER_NUMBER != $PARAMETER_REQUIRED ];
then
	printUsage
	exit 1
fi


#---------------------------------------------------------------------
# Get the folder path
#---------------------------------------------------------------------
PATH_TO_CHECK=$1
OUTPUT_TXT_FILE=$2

echo ""
echo "Start time:"
date
echo ""
echo "Extract strings from ${PATH_TO_CHECK}"
echo "Save strings to ${OUTPUT_TXT_FILE}"


#---------------------------------------------------------------------
# Find all the files in all subdirectories and extract the strings
#---------------------------------------------------------------------

find ${PATH_TO_CHECK} -type f -exec strings {} \; >> "${OUTPUT_TXT_FILE}"


#---------------------------------------------------------------------
# Finalizing
#---------------------------------------------------------------------
echo ""
echo "Completed at:"
date
echo ""

A bunch of keys can be recovered with this dictionary by running hashcat -a 0 -m 0 md5hashes.txt dictionary.txt:

  • -a 0: set the attack mode to straight
  • -m 0: set the hash type to MD5
  • md5hashes.txt: the list of MD5 hashes to brute force
  • dictionary.txt: the dictionary containing all the words to check

Improved dictionary with regular expressions

The dictionary built by extracting the iOS strings contain a lot of duplicates. There are also Objective-C methods names which are probably not valid keys. The strings can be reformatted using regular expressions to get a better attack dictionary. I wrote several scripts to improve the dictionary. One example that you can download is the bash script ImproveDictionary.sh. What it does:

  • Remove duplicated strings
  • Replace characters other than a-z, A-Z, 0-9 by a return line
  • Uppercase the first letter of the lines
  • Split words by looking at the last uppercase character: ‘AnExampleOfWord’ -> ‘AnExampleOf’ and ‘Word’
  • Split words by looking at the first uppercase character: ‘AnExampleOfWord’ -> ‘An’ and ‘ExampleOfWord’

Note the ugly syntax for the regular expressions in this script. The reason is that I wanted the script to run out-of-the-box with sed built in macOS 10.12. Using GNU sed would have resulted in a much cleaner script.

Also note that the dictionary only targets the keys with the format Word1Word2…Wordn (camel case words combination). I made a separate script to convert this dictionary to a dash separated dictionary in order to specifically target the keys with the format word1-word2-…-wordn (dash separated lowercase words).

Running hashcat on this improved dictionary recovered some complex keys.

Combinator Attack

The dictionary attack recovered a lot of keys. But we can recover even more keys with a combinator attack. This attack uses 2 dictionaries and tries all combinations of a word from the first dictionary appended to a word from the second dictionary. For a combinator attack, the first dictionary could contain strings like:

MGCopyAnswerWord1
MGCopyAnswerWord2
MGCopyAnswerWord3

and the second dictionary strings like:

WordA
WordB
WordC

In practice I used my previously generated dictionary as both left and right dictionaries and patched hashcat to always add the prefix “MGCopyAnswer” to each combined word candidate. Running this attack was perform with the command: hashcat -a 1 -m 0 md5hashes.txt dictionary.txt dictionary.txt:

  • -a 1: set the attack mode to combination
  • -m 0: set the hash type to MD5
  • md5hashes.txt: the list of MD5 hashes to brute force
  • dictionary.txt: the left dictionary
  • dictionary.txt: the right dictionary. As previously mentioned I used the same dictionary as both left and right dictionaries and modified hashcat.

I ran a similar combinator attack to specifically target the dash separated words format: hashcat -a 1 -m 0 md5hashes.txt dictionary.txt dictionary.txt -j ‘$-‘. Note the extra option -j ‘$-‘ to append the dash character at the end of each word of the left dictionary.

List of all keys

After running all these different attacks, I managed to recover 564 out of 646 keys (87%). Here is the complete list of obfuscated key / key:

struct tKeyMapping
{
	const char *	obfuscatedKey;
	const char *	key;
};

static const struct tKeyMapping keyMappingTable[] =
{
	"+3Uf0Pm5F8Xy7Onyvko0vA", "DeviceClass",
	"+Ce1uSqGUXaJPl/uT6ur8g", "SDIOProductInfo",
	"+U0jSj4F2EfE+Vqj22IavA", "tnr-mode-back",
	"+VIu65zA5EW4ztayJXvOUg", "device-name-localized",
	"+bL/lKwaIAv+fzmjsHYZdw", "N78aHack",
	"+fgL2ovGydvB5CWd1JI1qg", "has-sphere",
	"+zD41v0XRR72ItZHfisZuQ", NULL,
	"/2V8H9h/+z0UxNUr9aRLeQ", "boot-nonce",
	"/6FWCRjN1yRdUABG9vF8ow", "WiFiCallingCapability",
	"/9luHerXthRoPoNt/PVkTg", "VibratorCapability",
	"/GK+yfRFY/b5ZDIDpdVImg", "hardware-keyboard",
	"/Pop5T2XQdDA60MRyxQJdQ", "hall-effect-sensor",
	"/YYygAofPDbhrwToVsXdeA", "HWModelStr",
	"/bSMNaIuUT58N/BN1nYUjw", NULL,
	"/cMWdoU/88pcjJ1egxmIYw", "wlan.background-scan-cache",
	"/ej/HWmqnKV/QQptXhUZmg", "no-coreroutine",
	"/l0Kz2akvSvEHTNmZeY0nQ", "chip-id",
	"0/2HluYMd/whD80Hua4Rpw", "io-surface-backed-images",
	"0/7QNywWU4IqDcyvTv9UYQ", NULL,
	"0/VAyl58TL5U/mAQEJNRQw", NULL,
	"03hWmMtMs+4nzama4/PzHQ", "CameraLiveEffectsCapability",
	"0AFeHRmliNJ4pSlVb8ltZA", NULL,
	"0L5PkT61qoH1b/B1USWqjQ", "RegionalBehaviorChinaBrick",
	"0R2aiV2nJVu/v8I7Ex2GcQ", "RegionalBehaviorNoPasscodeLocationTiles",
	"0VkTunHOJrrZdolQXR5gCg", NULL,
	"0Y4fmR6ZHZPxDZFfPtBnRQ", "SysCfg",
	"0Yu30fwSQVPKvHVla17kXw", "umts-device",
	"0dnM19zBqLw5ZPhIo4GEkg", "SecureElement",
	"0jjK6IVSQzA8doQeSwmujA", "software-bundle-version",
	"0l4wqBtWEAK1tOkeBHkU6Q", "main-screen-pitch",
	"0pY9r1XBV1duZ8HO3tBvFg", "location-services",
	"0uthiXrHZ212KvcJizKHEw", "BoardId",
	"0uyHvVqOLpJQBpSl/rF3Vg", "kSimultaneousCallAndDataSupported",
	"16N2bLOzcgJEsZToEX21Zg", "accessibility",
	"1DQNgySZSIjPqLWroIzfiQ", "BacklightCapability",
	"1N14oS9TeyskaTU1DxpwoQ", "load-thumbnails-while-scrolling",
	"1Rm/mWYEI5ttaC0dJ3sHBQ", "BootNonce",
	"1X0zc2JwBdYOQrMAyP81DQ", "lte-device",
	"1gsBzuZsXu2rXZJBE01M0w", "FrontFacingCameraHFRCapability",
	"1oMPwMsqxTa9BJxUs8v06w", "PlatinumCapability",
	"1qDdT/85SS7sxriK0wIbbg", "main-screen-orientation",
	"1qJmMHedWOh43VwRKPdDrw", "iTunesFamilyID",
	"1rf3rZXIZFgznqrHlPehuQ", "FaceTimeBitRate3G",
	"1uZbhSbBhsNCsVSsopZ4qg", "dictation",
	"1z6Kk4xUAVLdaBPGugsDSA", "navigation",
	"2IDxmg5KyAMBBi/b0rojgQ", "telephony-maximum-generation",
	"2OK50OGmkXM1ospsh766WQ", NULL,
	"2aIAScwtFNCz+Y7WesMOCA", NULL,
	"2lNKobEIQqX50ohy1JBqCA", "no-hi-res-buildings",
	"2pxKjejpRGpWvUE+3yp5mQ", "cameraRestriction",
	"2sWGezz2RezScIJJgiIYQg", NULL,
	"38C0kq9NiVaMsqjlUsCHcQ", "ota-activation",
	"39ZkJVEsL4pmCXbg+89QmQ", "accelerometer",
	"3kmXfug8VcxLI5yEmsqQKw", NULL,
	"3m1Q0AXlqeA2C/LmqdTndQ", NULL,
	"3sF/uRq+X+mZ2zGHSJOwpw", "crypto-hash-method",
	"3yzXj0lJhQi+r3kgQlwiOg", NULL,
	"4+qmMh9JBDh72Nq6fD64RQ", "gyroscope",
	"475wW3fne+tyzGr4wleUSQ", "CarrierBundleInfoArray",
	"4I0hOaR3n80379Vka7u+Xg", "volume-buttons",
	"4Jfu4lqX8dzru4Z+ONQ1rQ", NULL,
	"4RwhtNOmePfUXmu57rh+KA", "LisaCapability",
	"4W7X4OWHjri5PGaAGsCWxw", NULL,
	"4fT83+9coO3VAUnlxuOOcw", NULL,
	"4k6Wv56SWfITjzet+hIHMQ", "multi-touch",
	"4snMZS8LJkSctKypt2m+xA", "not-green-tea",
	"4uzgAFPkzKUmlZG5HpFIkg", "RegionalBehaviorGoogleMail",
	"50/CmBTX6jhkb8Z61hzwhQ", "class",
	"566JrJVMlDfnslGpwUzNlQ", "ChipID",
	"57eLnXynqDlQaGEi+9JAtQ", "call-forwarding",
	"5MSZn7w3nnJp22VbpqaxLQ", "venice",
	"5MXFoiW2zgxfIbaaTb/wvA", "SecondaryEthernetMacAddressData",
	"5QM8apssQbhm2ZrUx5g5Tw", "pipelined-stillimage-capability",
	"5dyhCh3dm1vSOaNK+US1Qw", "euicc-chip-id",
	"5lAK1Xp+ezh1Qu+4jnHAOg", "SupportsSOS",
	"5mvQIwu3Mqqw/zOKmwGkWw", "ProximitySensorCalibrationDictionary",
	"5pYKlGnYYBzGvAlIU8RjEQ", "HardwarePlatform",
	"5tnvmEsHQKfCoieLEYpnvg", "RFExposureSeparationDistance",
	"5v2p6i7PyIMdWOK4n/+G4A", "proximity-sensor",
	"5y8gwXr/HXkhryza4xQeFg", NULL,
	"61xs1bQ+9eTk8tlRvG9UKw", "MicrophoneCount",
	"67x5O+zO+JwnGgmKlq+qdA", "DiagData",
	"6MnVtR+c9LeR46bMxvR5Yw", "RegionalBehaviorNoVOIP",
	"6PkKE66MnKm0yiOIQLknEg", "allow-32bit-apps",
	"6RrxXzvfw2GZeUPLKXxrmA", "RearFacingCamera60fpsVideoCaptureCapability",
	"6S9CvPHPtzHQqKudHSfsag", "haptics",
	"6UUmcaeT7rJoyUVmoPJd4A", "ProximitySensorCalibration",
	"6iI7/9cVUGIjdrSvIXEt4A", "RearCameraCapability",
	"6k70IxahfOQTZbGwu++QwA", "additional-text-tones",
	"6pjDdEw65TFyL1FmIdszXw", "hd-video-capture",
	"7D54DikSnFQnbDEBwlKQTQ", "DevicePrefersCheapTrafficShaders",
	"7DfjbzhvH/GDkhio1dv8fA", "HasSEP",
	"7IgVvZZLtNjMFdInQlKg6A", "SoftwareBehavior",
	"7VoVaBmSuokzovhUkiDx6Q", "SecondaryWifiMacAddress",
	"7W2eNk/f6uewC8N58mlRrQ", "FrontFacingCameraHDRCapability",
	"7l0BaQsNxJCanoeHMJ2huA", "AllowYouTube",
	"7mV26K/1a+wTtqiunvHMUQ", "PhosphorusCapability",
	"7ot70MKj7EdRIEEi91jlcg", "bitrate-3g",
	"7qHcAWI5X9b1SiyYIg/Byw", "ui-background-quality",
	"7yzVesPANxqKQ+oqNPhTwg", "applicationInstallation",
	"8/HMvzDR3J6m0aY3NYeqcg", "bluetooth-le",
	"8/tysfSvORoyVg9IE901oQ", "DeviceRGBColor",
	"81Zj1535/jeXbmfOndlIVA", "youtubePlugin",
	"82Ono2SP03rNGkhOc5O1Mw", NULL,
	"84iheBmhAmsxIlcxG4a0zA", NULL,
	"86GizkmSK+IxgCtUMOp2NA", "front-max-video-fps-720p",
	"87sSAh2rboMI2TDvFBimkg", "DeviceColorMapPolicy",
	"8DHlxr5ECKhTSL3HmlZQGQ", "RestoreOSBuild",
	"8QNz35Yxm0KqxP1JiE0HIw", "PintoMacAddressData",
	"8Shl+AdVKo09f1Sldkb0kA", "touch-id",
	"8Wunmi1SpU1MxfBxkv3KOw", "dali-mode",
	"8bOgXKgqoLvqV/XeSomAfA", "SecondaryBluetoothMacAddress",
	"8bY/L3i3rmxrl4ZjFZZpgQ", "siri-gesture",
	"8vIFqHe5lcMGo7TvbNLmyg", "home-button-type",
	"9/J7LY7zuYSGW1BcSTRpOw", "SysCfgDict",
	"91LyMcx4z1w3SGVeqteMnA", "BasebandRegionSKU",
	"96GRvvjuBKkU4HzNsYcHPA", "MinimumSupportediTunesVersion",
	"97JDvERpVwO+GHtthIh7hA", "RegulatoryModelNumber",
	"9MZ5AdH43csAUajl/dU+IQ", "SupportedDeviceFamilies",
	"9N7qIucqhr0Cy2/Tk27/hw", "DeviceCoverGlassColor",
	"9RreaA6rTvewPbqQy5ldRg", "front-auto-hdr",
	"9UCjT7Qfi4xLVvPAKIzTCQ", "ReleaseType",
	"9ZqSL68MJyQESzQFDvKqXA", "voip",
	"9n2qz3uDC5nSe1xZG1/Bkw", "CarrierInstallCapability",
	"9s45ldrCC1WF+7b6C4H2BA", "GSDeviceName",
	"A8aFtN08Oqt21846jqnftQ", NULL,
	"AFXhxraF1bvyaCMlBIOZPA", "RequiredBatteryLevelForSoftwareUpdate",
	"AJFQheZDyUbvI6RmBMT9Cg", "HasBaseband",
	"AOIh1l3cIyDXlP4KB/084A", "iap2-protocol-supported",
	"APeknA55ZAcu0FcufqVN4Q", NULL,
	"AQiIpW0UeYQKnhy2da7AXg", "EffectiveProductionStatusAp",
	"AWEfP3xWh0q1MjO3JAy/AA", "CPUSubType",
	"Ah5yfSlY2yycIQb92HbmrA", "function-button_ringerab",
	"Ai0zsJQ3+sTFkU6/lLbd5A", "opal",
	"Aixt/MEN2O2B7f+8m4TxUA", "HasExtendedColorDisplay",
	"AklmqJyJMChzHsYT0aiBbw", NULL,
	"AthxlkPBk46HtzM9AxK9vg", "explicitContentRestriction",
	"AtmPEO/j+Pdr8+WKxv4Aaw", "DeviceEnclosureMaterial",
	"BOPZue5C0v42pU9iJFYE3A", "location-reminders",
	"BOYfUi496moe56A0RWFbqQ", "sensitive-ui",
	"BQwz+BT9b5mS7OPh2WGD6A", "SecondaryEthernetMacAddress",
	"BYYil6kIk8Hm5lRuA1k8Tw", "prox-sensor",
	"BhXj+5n3+0HcPoSArDGX7g", "EffectiveSecurityMode",
	"Birtx7GxrxCCUzsE1JQO8Q", NULL,
	"BoNz1QXiAEUgic9RdMVLIg", "FaceTimeEncodings",
	"BstyjvaCtwqls0MfbkGTSg", NULL,
	"CJcvxERO5v/3IWjDFKZKRw", "DeviceBackingColor",
	"CK3I7fFGkgeqzKEhGew9rQ", "FaceTimeFrontCameraTemporalNoiseReductionMode",
	"CN/XFuy/9Fdv0yE+28kwRQ", "cell-broadcast",
	"CN64p1hw1JVdTHCfBdgPLQ", "BasebandStatus",
	"CQ6gFmgMhpnnISvG6VakBQ", "MobileSubscriberCountryCode",
	"ChBMzkxYdT9Xmw3QN5kMWA", "DeviceSupportsSimplisticRoadMesh",
	"CpVSHukvtqlJzCgSdoHW5w", "SBAllowSensitiveUI",
	"CzGP5+8jQECJMH4h+z4TYA", "offline-dictation",
	"D0cJ8r7U5zve6uA6QbOiLA", "ModelNumber",
	"D3LeXyjrxDFYSi6pWFEL4A", NULL,
	"D4AU4tOIuGKN3G/uix65cQ", "RegionalBehaviorAll",
	"D6PT05dEJ0f9Ayk7Yi92RA", "front-max-video-fps-1080p",
	"DGBWzPMdVuqPxgH7iSz3SA", "3Gvenice",
	"DIXX7JMbm7glu49f+xi4zQ", "live-effects",
	"DViRIxZ/ZwO007CLcEYvZw", "SoftwareBundleVersion",
	"DWrhyh1BwYypYmW5q78Wuw", "armv7",
	"DdNpmCCXbeMGbqj0kAMCdw", "piezo-clicker",
	"Djv9tHz6MLdTUDjnkq0obQ", "BasebandFirmwareUpdateInfo",
	"DrSqlXYNVfYXCvAsuUrUDA", "DebugBoardRevision",
	"DzLC4o1jZ4hWtP8aB6An6g", "SDIOManufacturerTuple",
	"E2iZGHvwvi387UKi9wC2Mg", NULL,
	"EImfMz+bzJrUkVQKyY6tEg", "BasebandSecurityInfoBlob",
	"EJRyIpTkLz2+Lb6XWy10bQ", "panorama",
	"ELLSWiPOyh0roYBypZFHFA", "magnetometer",
	"ESA7FmyB3KbJFNBAsBejcg", "ui-pip",
	"Eavu9TP+iZ0Lzlk7FU6w6Q", "ActiveWirelessTechnology",
	"Ecx7M8v2wk05Fch3pFE/GA", NULL,
	"EqrsVvjcYDdxHBiQmGhAWw", "apple-internal-install",
	"ErupMbaQrM6KypD4K0kTDQ", "OpenGLESVersion",
	"Ex6ChutQnIx5Zm6c5uwYuw", NULL,
	"ExSUJyf7MblY5nBQx2OaRw", "ScreenRecorderCapability",
	"F1Xz9g1JORibBS9DYPUPrg", "BlueLightReductionSupported",
	"F2M6lgy8EHCyR6hc00hMcg", "effective-security-mode",
	"F6wqOqCR9tpYWyB1taxxnw", "board-id",
	"FDsm68UVR7l3wErusGLgKg", "hw-snapshots-need-purplegfx",
	"FOs+LbLUs+TajsEE4xkbrw", "gas-gauge-battery",
	"Fam17Ufz3CiHdZPcma0AeQ", "regulatory-model-number",
	"FgjnMkPJPpI4C38dWETwtw", "flash",
	"Fh2Ga0/Sj4T3Qn5Z9A9BMw", "DeviceSupports4k",
	"FkD7K642S082lnfw/ohHzg", "BasebandFirmwareManifestData",
	"Fralg2R4+pkggafylKbVgw", NULL,
	"FuR7SfqQmxpRW5MyqMm7FQ", "low-power-wallet-mode",
	"GO5/TJivIXtQkTkFWkRc9A", "certificate-production-status",
	"GdXjx1ixZYvN9Gg8iSf68A", NULL,
	"Glo+aTkt0Uw31BghCxnsyQ", "BridgeRestoreVersion",
	"GnhnHyRVCC8LUClgElhKXA", "effective-security-mode-ap",
	"GvmsjQ/68T7do2CJxUhMig", NULL,
	"GxXmRWHjsY5yAVhMfCH6Lg", "BridgeBuild",
	"H5HW20mJr/djc40tAehkww", "BasebandKeyHashInformation",
	"H5TSt7Pu4zNCD5RvHuk5CQ", "PhoneNumber",
	"H8Pi7AthQFVZ0B6A1J5OTw", "photo-adjustments",
	"H97G3GzDYb4wY5kwJ0AKfQ", "ForwardCameraCapability",
	"HHF6YgqEQ9Kd7MBSVnLsgg", "DeviceSupportsAOP",
	"HIaq6xVZ/V8B9pnigcvqCA", "DeviceSupports3DMaps",
	"HMKkoKYsMmBBSN6ozOtw/w", "stand-alone-contacts",
	"HV7WDiidgMf7lwAu++Lk5w", "HasMesa",
	"HXTqT3UXOKuTEklxz+wMAA", "BasebandAPTimeSync",
	"HdWhWK8BN8j/O9k8/OHblQ", "supports-always-listening",
	"HkXhfA7q9eBKIU2+6yTgQg", "screen-dimensions",
	"HnHX0gXt8RvhMQzIVMM7hw", "FrontFacingCameraHDROnCapability",
	"Ht1HDxwTOy2gyY+THjbd6w", "peer-peer",
	"HxTvMvHnum5rI8d0Nr4xBw", "RegionalBehaviorVolumeLimit",
	"HzddeW2/HtdBNAc5tsFtDg", NULL,
	"I+ptihXW+rMeySVUWURNiw", NULL,
	"I2IvpG8yJdNpvO4csuB9EA", NULL,
	"I32sGclpgl5VujQRJxyhKQ", "IsUIBuild",
	"I83EgnDEGxinSKU4QAykmA", "rear-max-video-frame_rate",
	"IAJzgzhEVk3SMNuEhChs2w", "RemoteBluetoothAddressData",
	"IBqcPacFMPIX8HMWob444A", "AirDropCapability",
	"IFBSPGnQVFrGFW+ujtZu6Q", "RegionalBehaviorNTSC",
	"IFHQSJ65DoElWQl/+eCfNQ", "fast-switch-options",
	"IGYvMgBnOsdJjgmSh7Pe1A", "SEPNonce",
	"IIYjwu1lbAyGz5t0c4ECoA", "MainDisplayRotation",
	"ILaGO+KV5JAOq7Q5GEwbWQ", NULL,
	"IMLaTlxS7ITtwfbRfPYWuA", "DeviceVariantGuess",
	"IMlsLCL69XUZau9QyPnxeQ", "rear-slowmo",
	"IUvPFaILUl3l0684dR0AlA", "front-max-video-zoom",
	"Ini7+h7Q4ZZctfFM9+KTBw", "peek-ui-width",
	"IweaHIDpz+rknAcb3+xg9g", NULL,
	"J/a5Y6rhDH0gVkYtWUylOA", NULL,
	"J912s3mVzhReVtPv4HwqNQ", "FaceTimeCameraRequiresFastSwitchOptions",
	"JLP/IinyzetEPztvoNUNKg", NULL,
	"JOlwW/P8Cw3CDCoFunq8og", "platinum",
	"JQr1mcESYcN648vrcZPJEA", "front-flash-capability",
	"JUWcn+5Ss0nvr5w/jk4WEg", "device-name",
	"JXmZWYUbLoumvz7hu/GL0A", "FaceTimeBackCameraTemporalNoiseReductionMode",
	"JhEU414EIaDvAz8ki5DSqw", "DeviceEnclosureColor",
	"Jq+xaurJgFzSwxOfTqtBGw", NULL,
	"Js8HVdVGRs8m5v94pMjkRw", "enforce-googlemail",
	"JwLB44/jEB8aFDpXQ16Tuw", "HomeButtonType",
	"K0tZN4PayAx7RgB0M+oohw", "bitrate-lte",
	"KGlZoljMyZQSxfhROj0IFg", "data-plan",
	"KLB4sM/KC38QT+dTuDC/aA", "rear-burst",
	"KMgjmT+dsqBCXu1YQEcOFg", "RegionalBehaviorValid",
	"KN7t4gQkyj5X66dBpmh9HQ", "large-format-phone",
	"KWr9OM2iqeLQEhaHS0UshQ", NULL,
	"KXUnLpPZ6IZSE+As45CkhA", "SoftwareDimmingAlpha",
	"L+KOzmOzO5DiJUZl21QGVg", "StarkCapability",
	"L2Oq7vNNUKuv+iJ4m9xtiw", "SIMTrayStatus",
	"L47fh6KehOmR+AseqK2Xsw", "DeviceSupportsCCK",
	"L5al7b+7JATD/izSJeH0aQ", "cellular-data",
	"LAB8o3Bxs3CgNuzDawjRdw", "opengles-3",
	"LBJfwOEzExRxzlAnSuI7eg", "InternalBuild",
	"LWxSM4CmFZMwzYclSh43gg", "rear-hdr",
	"LXP9TbNYtZrIKOktGXez2Q", "3d-maps",
	"LcUv5nw5flxnHlxWu9sJvw", "NavajoFusingState",
	"LeSRsiLoJCMhjn6nd6GWbQ", "FirmwareVersion",
	"Leuy56dCZmAMYoVCQGTfPA", "DeviceSupportsPeriodicALSUpdates",
	"Lg1EJX11Jb7EbveB6+YgVQ", "720p",
	"LkWb+FyA1+ef2UD1Fx+kAw", "RearFacingCameraHDROnCapability",
	"Lrs7l5cKWJ1Gk5ZzgMAKyQ", "sandman-support",
	"Lu6Mgo1O0+EoGMk1OtnMRg", "rear-max-video-fps-1080p",
	"LvCIFE6lOM10QDqIEyYWRA", "PeekUICapability",
	"M+eWZ6Zk/aJIsnIrv4zdAg", "unique-chip-id",
	"MTa8c+pEdbK0tHGXP06xOw", "AllowYouTubePlugin",
	"MW1p1oJH8nDJc6igOb8G4g", "IcefallInfo",
	"MWJNrFKpHkBEm8jAdJf1xw", NULL,
	"MWduuAGptrl7qIzWqBmOqQ", "AWDID",
	"MWpHV1VYKXmaKqhgbmTWCg", "ptp-large-files",
	"MXZ7vg7hul895QdsLUBJFA", "boot-manifest-hash",
	"MYKMJDMFE/lhvOVXgtDNuw", NULL,
	"Mgwtle8wzQEz/0vzBk47FQ", "DeviceSupportsLineIn",
	"Mh+drGtyBfLYKN02sROzxg", "delay-sleep-for-headset-click",
	"MjqwTHDneTCNeqhZ7vCvUw", "DeviceSupportsHiResBuildings",
	"Mk4ZslaChmO+6s3h7L1w6Q", "DeviceSupports1080p",
	"MulRZdIO3jyzkPar/CuDXA", NULL,
	"MvBKQ+GSnR3DjkovgNL+3w", "airplay-no-mirroring",
	"MzxVeXMzucmEMx2lw8Pg1Q", "opposed-power-vol-buttons",
	"ND6ZSbBBgMgwtMfh+OL5Wg", "HighestSupportedVideoMode",
	"NJsxTSI2WuD+13rxShXX9w", "DeviceHousingColor",
	"NPzjaX07XnS4KcMZ+l8ymA", "ExternalChargeCapability",
	"NUYAz1eq3Flzt7ZQxXC/ng", NULL,
	"NXJOYK7VhNn7ugbF2kx0zg", NULL,
	"NaA/zJV7myg2w4YNmSe4yQ", "WifiChipset",
	"Nhm02nvVOaQPimpOshlO1g", "FaceTimeBitRate2G",
	"NkQOJZ1xdFk5SV55PFKlIg", "wlan",
	"Nmhz54v5ZLqj2I4NPFIFqQ", "BasebandSerialNumber",
	"NrXe/KHDNhJ4r2SC2bMQyA", "any-telephony",
	"Nzu4E/VsXjEIa83CkRdZrQ", "Image4CryptoHashMethod",
	"OBqqs000I0SR+EbJ7VO8UQ", "HasSpringBoard",
	"OPzhvROZUqCZhgYMyve5BA", "sms",
	"OWLyWlUOIkl+eQB7Iq37xQ", "DesenseBuild",
	"Oji6HRoPi7rH7HPdWVakuw", "HasInternalSettingsBundle",
	"OjzOua0LkOegX7pQdgMksw", "main-screen-height",
	"OoFyZnd3oLS2Lw/KQTccGA", "SupportsTouchRemote",
	"Ov9G2lRzQYbUyBYJ0KCMhA", NULL,
	"P+UqVuzQzn3nwHSiSeDmyw", "live-photo-capture",
	"P1djMN/L3B6otgGpO9WYkw", NULL,
	"P6z8eNrRPcv0AcKPML0iow", "wi-fi",
	"PLQ6xgfGji63NbFu+sjeYg", "WLANBkgScanCache",
	"PNexcW/LBlPgAm+Skp2EAg", "EffectiveProductionStatusSEP",
	"PQzmRjKVMistuIVsqs6QXA", "BasebandFirmwareVersion",
	"PTfO3r9syJ45k+OItTlD3Q", "ui-no-procedural-wallpaper",
	"PUMArrha4PFeOqINeQRM3A", "sim",
	"PUY/n3uJEk8GSE+RjkHHAA", "video-cap",
	"Po0s2Vf6g2ZqymKGNLFxeQ", "FaceTimeCameraSupportsHardwareFaceDetection",
	"PpmzzBVLpZVubmP0tCIymg", NULL,
	"PxEDp0oOasJ92F/V7YBa8A", "RawPanelSerialNumber",
	"PxLTGkQx9GkeYcJKOaZguA", "video-stills",
	"Q/BI7GKNZY13TpxbqA8nhQ", "rear-max-video-fps-720p",
	"Q1Ty5w8gxMWHx3p4lQ1fhA", "MLBSerialNumber",
	"Q4b8YIwPgnznT5hs4qXjaA", "rear-burst-image-duration",
	"Q5QHkCRPRmiX3L/5xxKrRg", "BasebandCertId",
	"QFnvO2shAYI+d4bj3qXuFQ", "DevicePrefersBuildingStrokes",
	"QGmb9t2ZMFVwOImO6fewgQ", "all-features",
	"QJSuJ2zhdxYX/7DUA2JtUw", "EffectiveSecurityModeSEP",
	"QZgogo2DypSAZfkRW4dP/A", "InternationalMobileEquipmentIdentity",
	"QbQzuIbef01P4JeoL9EmKg", NULL,
	"QdL5XM6PGBrjvJ/k187Ueg", "IDAMCapability",
	"Qq9/Mya05P4ToEr1pMpGGg", "BootManifestHash",
	"QtLcewkuPtPV0RpO+i0Zzw", "MarketingVersion",
	"RA3I5nhSK65i1ZxkRxQKfg", "HasThinBezel",
	"RECLuzbJ6oh8q4NKR8RtNg", "multitasking",
	"RLlZndRrTB3oIDuZEihtpQ", "RearFacingCameraAutoHDRCapability",
	"RXyKSjeF239SL2vOcru01A", "MobileEquipmentInfoBaseVersion",
	"RYO2N0gqp5hHCik2TEiSVA", "armv7s",
	"RYZZuAFEfSNnEKEzwzRnqw", "photo-stream",
	"RaX3KBmG7H9fUOEtLK/I6w", "stockholm",
	"RgoxDxYGuZ0GzijFt6kSQQ", NULL,
	"RrhB72r1de9N65EG4pgqJw", "tnr-mode-front",
	"RyXm3yMC4ejlFvwlEI509w", "hearingaid-low-energy-audio",
	"S5Bf9bF00BTHrySCydAkdg", "bitrate-2g",
	"SMgTCc2v9AU2ziIHRX8qww", "hearingaid-audio-equalization",
	"SNfDJgQFV2Xj7+WnozcJPw", "main-screen-scale",
	"SjED0v6tcI1c4fqvuUYAqQ", "EffectiveProductionStatus",
	"SmUPjD77AHIMCLny9nawdw", "ConfigNumber",
	"Sr1Bmb3uoIfgKyaZguG0Gw", "front-max-video-fps-4k",
	"SvI9oDkzw4XJFd+dKen/2Q", "DeviceVariant",
	"T9MMpvl0fu59PO8lXi/Cxg", "effective-production-status",
	"TDM8SEI14n2KE9PGHO0a4A", NULL,
	"TF31PAB6aO8KAbPyNKSxKA", "UniqueChipID",
	"TTZrMo1OOEUELa7asaQ7xg", "RearFacingCameraHDRCapability",
	"TXZxlSojLMQyLqusm9aa/g", "DeviceEnclosureRGBColor",
	"TZ/0j62wM3D0CuRt+Nc/Lw", "ProductHash",
	"ToJGxfcjkIerYyeL2e8c4A", "BasebandBoardSnum",
	"TqrlqJOZiAuRx8Qu3SVr+Q", NULL,
	"Tr9qG122eEQiKGfr6EGRdQ", "RegionalBehaviorEUVolumeLimit",
	"TucF/tpjeAln1I0f3g0K3w", "does-not-support-gamekit",
	"Ty5/C8UDfdjcdR853kulmA", "FrontFacingCameraBurstCapability",
	"U+73bmG4kBGj6kpreQXUTQ", NULL,
	"U1fcnNYCEu9uH1bg3/6PKQ", "image4-supported",
	"UCG5MkVahJxG1YULbbd5Bg", NULL,
	"UF3CoK9RCYXfTyzttoxNDQ", NULL,
	"UFqkf9tcH1ltsOMzpdwSUw", "multitasking-gestures",
	"UYZtXbMcIyMRZQ9pjDxRvA", "ui-weather-quality",
	"UZyrJHlX635ocWEjBkt9YA", "UIProceduralWallpaperCapability",
	"Ue0GVAyEOkP5kyQgcXKlxg", NULL,
	"V2Ykm/0M3CA6nyNhwNInsg", "64-bit",
	"V5QFNbWGgrw+UZPvgIbDvQ", NULL,
	"VG9TCKNqNLCHk0J6zTkuVQ", "EthernetMacAddress",
	"VHTcx7WQq0V7YgGKZisRWA", "FDRSealingStatus",
	"VLfT+eziZYKNjRASM6ntnQ", "FirmwareNonce",
	"VasUgeSzVyHdB27g2XpN0g", "SerialNumber",
	"VrWzQGQK9Fbp/RqeQ08VzA", "car-integration",
	"W5kTfIuxkKpHVdWTk42C9A", "n78a-mode",
	"W7MyZ3Yxoy1qD6FrI0mLUQ", "RF-exposure-separation-distance",
	"WC6wwFV23k19BlUQIAwDTg", "RearFacingCameraMaxVideoZoomFactor",
	"WbcphnnzI6Yb5r/AzwiyUA", "mix-n-match-prevention-status",
	"X9NA3D+PguwY0i0Uffl07Q", "camera-rear",
	"XACgWnmwo1t6swUPu+/UUQ", NULL,
	"XEoV4os3FAUL7yHDxWmSMw", "AppStore",
	"XEp4h49dagkYL6YrtjW1Kw", NULL,
	"XEzIXVPlevxuEIpZrMY+8A", "Skey",
	"XFtUsQP3AyqT4CazSb5VCw", "DeviceSupportsCarIntegration",
	"XFx5cRZ0tJYl+xJUCEgjnQ", NULL,
	"XI87Zkcr5j1B/p2dom/B6A", "AWDLCapability",
	"XIcF5FOyQlt/H79oFw9ciA", NULL,
	"XKpK5v7PGzbe7igjloNBpQ", "closed-loop",
	"XQBHOWjPt2P+uNqlLm1P7A", "BasebandClass",
	"XSLlJd/8sMyXO0qtvvUTBQ", "bluetooth",
	"Xa9nxhMDoHTdmrn/FufA3g", NULL,
	"XellXEQUbOIgUPoTrIj5nA", NULL,
	"XkfGVYlrkBQJgaGabHESJQ", "DeviceSupportsDClr",
	"XrPbSCNx9X7Lyw9oGPgMDQ", "WirelessBoardSnum",
	"XxnEk9uiIk5vCdbWEGt7lA", NULL,
	"Y2TwC8z+XeBBBswnLf7JsQ", "PeekUIWidth",
	"Y2Y67z0Nq/XdDXgW2EeaVg", "FMFAllowed",
	"YH5LeF090QGZQTvT76qcBg", NULL,
	"YUobJKXH3+ukrUe13TXL3Q", "BasebandPostponementStatusBlob",
	"YVNo6vlMjhgQ9yGYV8gatw", "PanelSerialNumber",
	"YcNAX0Gc6KejQPKSrA9kvg", "front-burst",
	"YdPNjYPBzyE0jJl2X/CayQ", "RotateToWakeStatus",
	"Yk5H+MlMreeaBLjv6PPFDw", "camera-front",
	"YzrS+WPEMqyh/FBv/n/jvA", NULL,
	"Z/TJS0IaLyq10dcSvUTGPg", "DieId",
	"Z/dqyWS6OZTRy10UcmUAhw", "marketing-name",
	"Z3gOHeppbL6+rblIe8H5Ag", "BasebandRegionSKURadioTechnology",
	"ZApuwHXWV8RCz0iVzMnqLw", "telephony",
	"ZEF0po63sTgpVrc9Ce7YNQ", "DMin",
	"ZYqko/XM5zD3XBfN5RmaXA", NULL,
	"ZeGw3VKUymUAbp4noKsxoQ", "FrontFacingCameraMaxVideoZoomFactor",
	"ZepchaN1K8XQJaBUMMlV5w", "iAP2Capability",
	"ZgIjA7Nwd2jSo13lhDO1Iw", "RegionalBehaviorShutterClick",
	"ZiSlYxYSkyaYImU3lrSXWw", "gps",
	"a/mex6YNO6gJ8N8SxAA71A", "DeviceSupportsCrudeProx",
	"a13V9f9x26JcQCfczZAVAw", "ui-traffic-cheap-shaders",
	"a5BRUxn1QBPXkAnbAHbmeg", "SigningFuse",
	"a6vjPkzcRjrsXmniFsm0dg", "ShouldHactivate",
	"aCQx2Qq/TChnNAq1rr6Egw", "DeviceSupportsAlwaysOnCompass",
	"aCuWsar9Ayou7Vfkh7fdLw", "front-slowmo",
	"aH78kNnsHDm9yHe6vSJYNw", "builtin-mics",
	"aHrkhDFY/f2ophZ5/MqX0w", "face-detection-support",
	"aIJva0DAnD6KdrSpPF11xQ", NULL,
	"aNZeCyuWxI6SE/KwZ129wA", "name",
	"aOq/O8u9f/bpWUnKco+xgA", "EthernetMacAddressData",
	"aoAKcHLuTUp/o3squcJkhA", "CompassCalibrationDictionary",
	"b/KizANb5o/dWqSP2GC23g", "public-key-accelerator",
	"b/k0ZT2f/WGV2qJSyPJHoQ", "config-number",
	"b5K3g59Aj+Cc982n9FQv8A", "display-rotation",
	"bUJD9zcOcitJwFA0ieIkxA", "DeviceBackGlassMaterial",
	"bbyFCcrPE+k6ZXIVbXSFUw", NULL,
	"bhPjDx/0UDk9mzia6ksZ+A", "nike-support",
	"bl+nF6e86pLBiPP4pVJ24g", "PhotoCapability",
	"bxQyyA/qJ3QQXTiHBsW2eg", NULL,
	"bysMryc4yLwQjKvUQGGXXQ", "DevicePrefersProceduralAntiAliasing",
	"c5uqoV7Z9ly+f4c5mYXILg", "OfflineDictationCapability",
	"c7fCSBIbX1mFaRoKT5zTIw", "WifiVendor",
	"cBy4BcYs5YWtFHbBpt4C6A", "DeviceSupportsHaptics",
	"cHla4KIe1wv0OvpRVrzy/w", "hide-non-default-apps",
	"cRjPy4Ef+KZwJ+nfPeBV5Q", NULL,
	"cX1+ZsVacGTXWVKB9enYow", "shoebox",
	"cZflGJ39lJHTCPy35/N14Q", NULL,
	"ce5pjDJVSOxjcg1HwmAezA", "opengles-2",
	"cganRwxlDnONJx4WeDI0kQ", "firmware-version",
	"cmkS/KVB6ubxH76sLbumbw", "rear-max-slomo-video-fps-1080p",
	"ct5Dh6u0D6WDJKg2PrMFVQ", NULL,
	"cux58RcuSiBhpxWnT3pE4A", NULL,
	"d27R2IjPvpwp+MX/kUbJ2w", "PintoMacAddress",
	"diS7AlmwFZz6NyF7CY97sA", NULL,
	"dp7SlZZQotrh8McQoH1xFA", "rear-facing-camera",
	"drPpRw0Jmqcxv1XQPn/q/Q", NULL,
	"e9aZViEIJ/riA4pRfg1ihg", "device-color-policy",
	"eH9J8yYIjbRNxg2EeYvNFg", "UIBackgroundQuality",
	"eKgHzGQ9HnWdPKX7W16OAg", "ui-reachability",
	"eLfYx8jpSlim2NZFIonPzA", "WifiCallingSecondaryDeviceCapability",
	"eNgz35a7iZnVeEMwsBQZew", "BasebandChipId",
	"eQd5mlz0BN0amTp/2ccMoA", "SupportsForceTouch",
	"eXCYx/SHTZIn5LInWvZByw", "call-waiting",
	"eZS2J+wspyGxqNYZeZ/sbA", "WifiAddressData",
	"ebyBs0j3KAquBsgcfrNZIg", "CellularTelephonyCapability",
	"edlvEg0UXOGErRDpk7O5Fg", "calibration",
	"ee9YfVjjsbVte45bYSt4Wg", "DeviceSupportsNavigation",
	"eg8KDO//lXaLwp+URGP6DA", "CertificateSecurityMode",
	"emXA9B552rnSoI7xXE91DA", NULL,
	"eu8pUYR7yo+AlS9aojlgwg", "DeviceSupports4G",
	"euampscYbKXqj/bSaHD0QA", NULL,
	"f+PE44W6AO2UENJk3p2s5A", "SupportsLowPowerMode",
	"f2DlVMUVcV+MeWs/g2ku+g", "BatteryCurrentCapacity",
	"f8peylp799CJta4Ev/vz8A", "hiccough-interval",
	"fAwIjGT2efY3MHaGNHbCeQ", NULL,
	"fGpT09KNGDBjFXnqcVbgbw", "RearFacingCameraHFRCapability",
	"fJZs6N8SqTS4RuQVh3szxA", "camera-front-flash",
	"fW9C1U4C1FR8bwe1VqEWug", "full-6",
	"fdh+s6j3VijuyrK7xLjd7g", "main-screen-class",
	"fh6DnnDGDVZ5kZ9nYn/GrQ", "hdr-image-capture",
	"fkWvcjYnYzGRhVKiBoYzgA", "HasPKA",
	"fqNtLlgbYfa9gSNrhg7VGQ", "encode-aac",
	"frZQaeyWLUvLjeuEK43hmg", "InverseDeviceID",
	"fuKL2rMywRgQF1wowOA/cg", "DeviceBrand",
	"fucd7llSuoCNHrrvLS1QQg", "watch-companion",
	"fv8ZXM/NhUHQBQqCSk19cA", "FrontFacingCameraAutoHDRCapability",
	"g+9NpjmSVwtomd8nyNJimg", "armv6",
	"g1gP4TOlkv84ezeaZrUgFg", "thin-bezel",
	"g7YQ1Djxh4YiKlEeaoGhzg", "main-screen-width",
	"g7vU4YF+9Z+wkSvw/Cm8Dg", "CoreRoutineCapability",
	"g7yZjVHqRxbfXOqns+Sm9w", "front-hdr",
	"gI6iODv8MZuiP0IA+efJCw", "WifiAddress",
	"gKzNJcweSCWA+gIGiUQJ5w", "mms",
	"gPoIZFd4NhmSKrk67qH80w", "SBCanForceDebuggingInfo",
	"ghpAuGJlPoauWijdtPi7sQ", "UserAssignedDeviceName",
	"gk8sn5Vi0s088gEvssfbOg", "front-hdr-on",
	"gnQwi8RnEeMG9qBe3IUKrg", "DeviceCoverGlassMaterial",
	"gq0j1GmcIcaD4DjJoo9pfg", NULL,
	"gqDnklGQnpv5ilgh5uHckw", NULL,
	"grEfqkFsEkgnJH1nl9sodw", "effective-production-status-sep",
	"gukw/2mRLE2GyqXJFEu7ng", "rear-hdr-on",
	"guykxGaRwHdenUK8fJRl8w", "gamekit",
	"h0OUwg53vKp+IPdzLG4NrA", "mesa",
	"h63QSdBCiT/z0WU6rdQv6Q", "RegionCode",
	"h8xonkkn/NzDMvvCXLw8cQ", "FaceTimeBitRateWiFi",
	"h9jDsbgj7xIVeIQ8S3/X3Q", "ProductType",
	"hK/qlAUuu8u6SvIRkKmjQQ", "gps-capable",
	"hLzlRnTuKAcQLWtNwCFSfg", "nfcWithRadio",
	"hOkus/A6lBEF6Ar3jV7LrQ", "DeviceSupportsRGB10",
	"heP+NTlvkhJ2zzWIUznawA", "MobileEquipmentInfoBaseProfile",
	"hfs43coKE3iWlCwnqPgBpg", "IceFallID",
	"hh/NoWpEoq1VF4lGDdPUpw", "role",
	"hiHut/WR+B9Lx/vd0WyeNg", "wapi",
	"htWSrEg/cfn3squdzvER/w", NULL,
	"hwd9ipb6eezNleN59+6n1Q", "metal",
	"hx2qJfJRLZ9Sseb37IcQow", "ringer-switch",
	"hykQtM0zkNe2/IY69+3PPQ", "ApNonce",
	"i8+iwUtLtB5jT+WNvqwrEA", "encrypted-data-partition",
	"iBLsDETxB4ATmspGucaJyg", "IsLargeFormatPhone",
	"iFOX66VmcijipO3YRc+AXg", "display-mirroring",
	"iaegRQa4jNGOuTA6hnZmcQ", "DeviceCoverMaterial",
	"ibhfX8FQ6b809N632Ey98g", NULL,
	"iifCuJmggYlB4hLzc0Zoiw", "rear-max-slomo-video-fps-720p",
	"inECTnNyR97XWxm7jU8uqA", "MobileEquipmentInfoBaseId",
	"inLiSl5OQHJ1stAIvKH8wg", "RegionalBehaviorGB18030",
	"is3zjHrEdiF6J/boqghy9A", NULL,
	"ivIu8YTDnBSrYv/SN4G8Ag", "ProductName",
	"iyfxmLogGVIaH7aEgqwcIA", "green-tea",
	"izFv/qj3IUhqAIiEuYH6xw", "MusicStore",
	"j4dedPnpeXouudM1+j3dsQ", "IntegratedCircuitCardIdentifier",
	"j9Th5smJpdztHwc+i39zIg", "MarketingProductName",
	"jBGZJ71pRJrqD8VZ6Tk2VQ", NULL,
	"jJ+5tnncQBcHo5T26MI5jA", "debug-board-revision",
	"jKFTzVOYcfTfNBh+yDrprw", NULL,
	"jMiqevikb6QWeHOhvLsw6A", NULL,
	"jPfKgbKUk+Vl6s7DaotqIA", NULL,
	"jSDzacs4RYWnWxn142UBLQ", "BluetoothAddressData",
	"jWdMTTxiAZc+KNO6Bz2jNg", "MesaSerialNumber",
	"jdLgKT+0BZmGrzd9J0cuPA", "camera-flash",
	"jewva1LRTg17HDPWdj+TLw", NULL,
	"jgE7MmmkZAG0BiWVqD7bMQ", "BatteryIsFullyCharged",
	"ji56BO1mUeT7Qg9RO7Er9w", "DeviceSupportsASTC",
	"jyEyRLza0L3StNXgFUCoTw", NULL,
	"k5lVWbXuiZHLA17KGiVUAA", "BluetoothAddress",
	"k7QIBwZJJOVw+Sej/8h8VA", "CPUArchitecture",
	"kKgJsWN/rBUAkimOtm/wbA", "arm64",
	"kMHGt7N4hx12NopZFcIz6Q", NULL,
	"kQ8nm82jb5iTBUwT2M3aIQ", NULL,
	"kWVFqaGBc3nOGmfM+ZpoEg", "tv-out-settings",
	"kc+QzHP4Frf2NvP+mclQ2A", "wifi-chipset",
	"kjKnJNt7HY90iN6rpbSeFQ", "RegionalBehaviorNoWiFi",
	"kkSkHTEei96N1ZehicOgoA", NULL,
	"knoZzQDWpu6OQWS7wgRWLg", "rear-max-video-zoom",
	"kt7gXeIiU0dLEKrgUSsLVw", "opengles-1",
	"kyszW/uUGJFTVNQwFaf6og", NULL,
	"kyxFFGn+VS4L9a/bsvm19Q", "Image4Supported",
	"l/n0Z7pMB8k0GyTKz3v3Tw", "AirplaneMode",
	"lM8BH5myz/qFGeIYnsiEoQ", NULL,
	"lMKshPs7fX9YxDSOEXnoiw", "effective-security-mode-sep",
	"lR7sjp4tOz3cMWoEMlZrLA", NULL,
	"lSpe1QHIya0aeNrjLTtaJA", "hidpi",
	"lUryPpLkvlffpEKiNnEchA", "slow-letterpress-rendering",
	"lY6RKv6ri6kfBeJCWilmmQ", "front-burst-image-duration",
	"ld2eewXs5StVwdRtwYT8sw", NULL,
	"lo3szoQ4sLy7o3+ZD0GcAQ", "ambient-light-sensor",
	"lvmEUCUwik8sO0yGU1rBOA", "rear-max-video-fps-4k",
	"lwHRTZNO5Jq87pVlzdNGIA", "DeviceSupports720p",
	"m+FD6mX8VZzP95hOhM+jow", "hw-encode-snapshots",
	"m4UsCAgXhbdnwLebiyKMiw", "UIReachability",
	"mAAbkChrX3bpxPIffHG1BQ", "front-facing-camera",
	"mVenV0u+B3ShrqRddinaFQ", "homescreen-wallpaper",
	"mZfUC7qo4pURNhyMHZ62RQ", "BuildVersion",
	"mm4/5+X4Z+eStXyipfwWVQ", "rear-cam-telephoto-capability",
	"mmu76v66k1dAtghToInT8g", "UIParallaxCapability",
	"mtHZd1H8XJ2DMVtNVUSkag", "wifi",
	"mtrAoWJ3gsq+I90ZnQ0vQw", "DeviceClassNumber",
	"mug/QuG6jZ3CYR9p7OWQaw", NULL,
	"mumHZHMLEfAuTkkd28fHlQ", "DeviceColor",
	"n/G0fQIQiom+pb4tHA4Mmw", "device-colors",
	"n/aVhqpGjESEbIjvJbEHKg", "SphereCapability",
	"nFRqKto/RuQAV1P+0/qkBA", "UniqueDeviceIDData",
	"nSo8opze5rFk+EdBoR6tBw", "RestrictedCountryCodes",
	"nVh/gwNpy7Jv1NOk00CMrw", "MedusaPIPCapability",
	"nZUUCFZgomfWUIPGGzNAqg", "SecureElementID",
	"na6PSBfq05lkAfWkwAwaGg", "ExternalPowerSourceConnected",
	"na77zbwlhy0V7shc4ORRgA", "post-effects",
	"nmOy2K5HzAAs2QNAi8wR+Q", "SupportsRotateToWake",
	"nteaxwXwZWYUI9z46VDRnA", "video-camera",
	"nudr7/i2XcxAX6widrWShg", "certificate-security-mode",
	"nv4RoLkNoPT0/rsO8Yaiew", "still-camera",
	"o/mXrucvBSYUXqq7K3UzKA", "IsThereEnoughBatteryLevelForSoftwareUpdate",
	"o0axLo6LGt8HbuEWdLZ92Q", "auto-focus-camera",
	"o60T6wXe1DDaO4a4gw10TA", "TristarID",
	"oBbtJ8x+s1q0OkaiocPuog", "MainScreenStaticInfo",
	"oJGeec0N+MudCr0LsdtbHw", "MobileSubscriberNetworkCode",
	"oPeik/9e8lQWMszEjbPzng", "ArtworkTraits",
	"oTuH4/axV9s11/jKxB2z2A", "ui-no-parallax",
	"ohnQBWkVQf2nu9Vr/9uLug", "DeviceSupports3DImagery",
	"ol92SaBpqIvQs+KBljuwGA", "kConferenceCallType",
	"oxH8p7+EaUzhkc2edrXsQQ", "aggregate-cam-photo-zoom",
	"pB5sZVvnp+QjZQtt2KfQvA", "BasebandChipset",
	"pCbWB0w5vhsKbGJHs/c1jQ", "youtube",
	"pLzf7OiX5nWAPUMj7BfI4Q", "SupportsIrisCapture",
	"pX2TxZTxWKS7QSXZDC/Z6A", "HasBattery",
	"paR6NqTecAD44x45kzV87g", "AudioPlaybackCapability",
	"pdFo85PUvIiT4FjAT6Amcw", "baseband-chipset",
	"plaYa8bKJaAF5Erc5nvZ+g", "RearFacingCameraBurstCapability",
	"po7g0ATDzGoVI1DO8ISmuw", NULL,
	"pxqIJ789zCoOILWO6cQ52Q", "no-simplistic-road-mesh",
	"q4cLktMwtrx8dCJAQTeqTg", "PanoramaCameraCapability",
	"q69vauqK9djnPlEZBFBV4A", "DeviceSupportsSiDP",
	"qHVhw5NhezD+ljFUPvQb4g", "nike-ipod",
	"qNNddlUK+B/YlooNoymwgA", "ProductVersion",
	"qOwiNS0eFEq9oi3MNsgxWg", "FirmwarePreflightInfo",
	"qWG594bTi87edQCSYxlLeA", "EUICCChipID",
	"qWGVjnlN/wWMhlWgfNcSBg", "DeviceSupports9Pin",
	"qb//mYg6KeTmjv8w4ZAMIg", "CompassCalibration",
	"r/++Z94rbTcHrTtZ/rCU4w", NULL,
	"re6Zb+zwFKJNlkQTUeT+/w", "UniqueDeviceID",
	"rkFHO5dZmWxy3QdOx7r7kA", "MobileEquipmentInfoCSN",
	"rkqlwPcRHwixY4gapPjanw", "DeviceName",
	"rxUlSnmihTL8oDg9Hrgq/A", "MixAndMatchPrevention",
	"s+gaKNe68Gs3PfqKrZhi1w", "MonarchLowEndHardware",
	"s2UwZpwDQcywU3de47/ilw", "microphone",
	"sJ0n0UZHSUVJbmyy2p54Cw", "unified-ipod",
	"sLe8lqXRlqZM74MNUoVcyQ", "BatteryIsCharging",
	"sYxZdpH3i8nwjZNet0QuAw", "fcm-type",
	"spGVujDEmyCzDznXozB3oA", "apn",
	"tOLVnZop4m/g5/iuC7zlUw", "effective-production-status-ap",
	"tUIqcYyzHuWBvBQHsLk8IQ", "international-settings",
	"tYqUcLmLfhmk7vOgdFvURg", "sim-phonebook",
	"tad3RCjcWdkyLSVI8kUBtA", "caller-id",
	"tdUWKiiM7JdctnzQuvaVVA", "c2k-device",
	"tuwdHA2NDGnLajCo5K3UUA", "voice-control",
	"u3c0R+31Df4SUTHrICQkTg", "hearingaid-power-reduction",
	"uAIY4Jb2A7Fy2aLrlDU1gg", "RemoteBluetoothAddress",
	"uB6I2WImAHd8DEGuqYcMbw", "WifiFirmwareVersion",
	"uKc7FPnEO++lVhHWHFlGbQ", "ipad",
	"uO3aPe7lfB1XxSiz/1xBvA", "CertificateProductionStatus",
	"ueuuYQk48HGWm/cJlHq/Dw", "fcc-logos-via-software",
	"ulMliLomP737aAOJ/w/evA", "IsSimulator",
	"ulPs+OBjapRJaJ6Ech3OFA", "h264-encoder",
	"uyejyEdaxNWSRQQwHmXz1A", "DiskUsage",
	"v/BP9Nx/zfo9bKi9JR2p+g", "3d-imagery",
	"v2Q3tLoD4+o/XazHC/0FyA", NULL,
	"v5YVEwERRin1v+reUNjJ5w", "ComputerName",
	"v9YZN998zL0OLA3q6SpPQA", "HasIcefall",
	"vENa/R1xAXLobl8r3PBL6w", "EffectiveSecurityModeAp",
	"vIccod02kDxScKF5s2h6OA", "BasebandUniqueId",
	"vaiFeAcMTIDXMSxTr8JwCw", "BasebandPostponementStatus",
	"vl45ziHlkqzh1Yt6+M9vBA", "displayport",
	"vmZuX/fdqt3gKhonHYLyUw", "aggregate-cam-video-zoom",
	"vwZ4ohiPF3w3M1jzHbP30g", NULL,
	"wAbB2fAjUqUc6lNBelfWMA", NULL,
	"wBVgxg3VYUU5gawcgq7MXg", "SupportedKeyboards",
	"wOVK1nhmiAawowdbIwgyaQ", NULL,
	"whbsdxpLirBFgUbLH3+0JA", NULL,
	"wlxZYdEZITDTzgs/OnnV+Q", "personal-hotspot",
	"wtUF1NceYeLT6IHovZvocw", "DeviceSubBrand",
	"xDg5n/9rR2cMhp7MK0irBA", "healthkit",
	"xJUG7IKySthRrPcxII184g", "enforce-shutter-click",
	"xOEH0P1H/1jmYe2t54+5cQ", "MobileEquipmentIdentifier",
	"xOJfWykLmQCc8lKlzMlrLA", "assistant",
	"xSh3mf5+Zuoz6xhxEah0zQ", "DeviceSupportsTethering",
	"xU1eZLRifcixnyDzjo52DQ", "tv-out-crossfade",
	"xUHcyT2/HE8oi/4LaOI+Sw", "PartitionType",
	"xXBT4e92qXwQo3SYmACj3w", "die-id",
	"xYu8vn4nnbLnNTbBe0FT+w", NULL,
	"xZm4Ky2/qswyf7ykvlchYg", "CPUType",
	"xbNo7dj2oAnz92JhEOn9tw", "DevicePrefers3DBuildingStrokes",
	"xleedMDMw0UV3fSgmHIoaQ", "kSimultaneousCallAndDataCurrentlySupported",
	"xsaMbRQ5rQ+eyKMKG+ZSSg", "PasswordConfigured",
	"xunfK8NYNCS75N2z2buKWQ", "FaceTimeBitRateLTE",
	"y0jtYciPmcx3ywPM582WZw", "ContinuityCapability",
	"yMmSdMRKEHRTCQ72ltCH1w", "airplay-mirroring",
	"yNesiJuidlesNpI/K5Ri4A", "PasswordProtected",
	"yPSUYPhrVLHnvX0TUugiwg", "rear-auto-hdr",
	"yRZv0s7Dpj8ZBk0S+0+nMA", "contains-cellular-radio",
	"yUCaqT4KOwJpYEb+XDPq7g", "SIMStatus",
	"ybGkijAwLTwevankfVzsDQ", "MainScreenCanvasSizes",
	"yeQy+rgNoD7+YIY6mSVOhg", NULL,
	"yeaE9+OrN2WJlWkDroMtZg", "bitrate-wifi",
	"yhHcB0iH0d1XzPO/CFd3ow", "DeviceSupportsApplePencil",
	"yl8qmYPdAhFLeDBho10sdQ", NULL,
	"z+5gEULGC7aEYopBd4ggpA", NULL,
	"zDBaE8nqtDP8hY4pOa6iMw", NULL,
	"zHeENZu+wbg7PUprwNwBWg", "RegionInfo",
	"zJUWenIp94snlzBD1cub3g", "function-button_halleffect",
	"zP3kBA1Biwz2d6PTIIbmUQ", "ActivationProtocol",
	"zPSNnYDFk+x5ebOtenb3Eg", "auto-focus",
	"znvmheFkjr6hiqIK9TrCVw", "pressure",
	"zxMIgVSILN6S5ee6MZhf+Q", "NFCRadio",
	NULL, NULL
};

MGCopyAnswerTable

Having the list of keys, I created a simple iOS app that displays all the key/value pairs of libMobileGestalt:


MGCopyTableScreenshot

This app runs on iOS 10.2 – jailbreak is not required. Note that it relies on private APIs and as such you shouldn’t use such code in shipping apps. You can download the source code here: MGCopyAnswerTable source

Conclusion

The libMobileGestalt library gives access to an incredible amount of useful data:

  • iOS information: DeviceName, ProductVersion, BuildVersion, DiskUsage, FirmwareVersion, …
  • Device capabilities: DeviceSupports4k, DeviceSupportsCarIntegration, DeviceSupportsHaptics, DeviceSupportsApplePencil, VibratorCapability, …
  • Camera capabilities: CameraLiveEffectsCapability, FrontFacingCameraHDRCapability, FaceTimeCameraSupportsHardwareFaceDetection, …
  • Device materials: DeviceRGBColor, DeviceCoverGlassColor, DeviceBackGlassMaterial, DeviceEnclosureMaterial, …
  • And a lot more: AirplaneMode, InternalBuild, FaceTimeBitRateLTE, MicrophoneCount, MinimumSupportediTunesVersion, …

It is strange that Apple only protected some of the key/value pairs behind an XPC service and not most of them. For the protected keys (like the “BluetoothAddress”), you will get a nil value and see a warning in the logs:

MobileGestalt.c:549: no access to k5lVWbXuiZHLA17KGiVUAA (see <rdar://problem/11744455>)

Due to the use of a weak algorithm, it was possible to deobfuscate most of the keys. With more GPU computing power and/or more time, it should be possible to recover the missing keys. Note that some keys did not match the formats I targeted:

3Gvenice
applicationInstallation
cameraRestriction
explicitContentRestriction
function-button_halleffect
function-button_ringerab
kConferenceCallType
kSimultaneousCallAndDataCurrentlySupported
kSimultaneousCallAndDataSupported
nfcWithRadio
rear-max-video-frame_rate
RF-exposure-separation-distance
wlan.background-scan-cache
youtubePlugin

Note: Before publishing this post, I discovered an excellent article from Jonathan Levin about libMobileGestalt.dylib. It provides a good overview and other details about libMobileGestalt.dylib and might be a good complement to this post.

Update 29.01.2017:
I updated the list of obfuscated keys to match the latest iOS release and to include some obfuscated keys I somehow missed. There are now 673 known obfuscated keys. I did not run a brute force to resolve the keys.


3 Comments on “Deobfuscating libMobileGestalt keys”

  1. 1 Deobfuscating libMobileGestalt keys – sec.uno said at 9:52 am on January 25th, 2017:

    […] by /u/secaggr [link] […]

  2. 2 iMokhles said at 11:53 pm on January 27th, 2017:

    very well documented and explained ( THANKS )
    but you just forget to mention that

    UIDevice class has private method named : _deviceInfoForKey:

    which call directly MGCopyAnswer without need extra unwanted code

    here’s my example https://github.com/iMokhles/MGCopyAnswer-From-UIDevice/blob/master/Tweak.xm

    simple just call it like that

    UIDevice *device = [UIDevice currentDevice];
    NSString *UDID = [device _deviceInfoForKey:@”UniqueDeviceID”];

    or for other values from your keys table list

    NSString *gotValue = [device _deviceInfoForKey:@”KEY_HERE”];

    and UIKit framework uses this private method often specially in [UIDevice systemVersion]
    [UIDevice buildVersion]
    [UIDevice localizedModel]
    [UIDevice model]

    you may aware of that
    anyway thanks away for such useful article

  3. 3 Timac said at 3:38 pm on January 28th, 2017:

    Thanks for the comment.

    In the first section of this post, I present some MGCopyAnswer examples in order to introduce the concept of obfuscated key as well as the different key formats I later targeted. I chose 4 examples from UIKit but I could have chosen any other framework. Since the goal of this article was to explain libMobileGestalt, I simplified the examples and did not mention -[UIDevice _deviceInfoForKey:]. As you noted, this private UIKit method is just a wrapper around MGCopyAnswer so mentioning it would not have helped understanding libMobileGestalt.

    As you saw in the sample app ‘MGCopyAnswerTable’ I also directly call MGCopyAnswer. To do so, I simply use dlsym to locate the function inside libMobileGestalt.dylib. It is indeed possible to replace these lines of code and use instead -[UIDevice _deviceInfoForKey:]. However doing so would:

    – introduce a dependency to UIKit. In this example it really doesn’t matter but if you were writing a command line tool, this would be a no-go.

    – have more risks of breaking in the future. -[UIDevice _deviceInfoForKey:] is a private method of UIKit and as far as I know only a couple of methods are using it. Apple could easily rename or remove this method. Changing MGCopyAnswer would be much more complicated as it is basically used by all frameworks/libraries on iOS.

    So yes you can use -[UIDevice _deviceInfoForKey:] but I personally prefer to explicitly use MGCopyAnswer – even if it requires 20 extra lines of code.


Leave a Reply