一、背景 & 场景
1.1 环境
设备型号:iphone 14、iOS 版本:16.4.1、越狱方案:Dopamine
工具链:Frida16.1.4、IDA pro 9.2
1.2 引言
对于大多数互联网风控攻防业务来说,真正棘手的往往不是单个请求本身,而是背后那一整套“批量造设备、批量刷行为”的自动化体系。正是在这样的背景下,从最初的简单模拟请求,到如今的设备指纹伪造、群控刷量,攻防对抗从未停止。在这一背景下,Apple 推出的 DeviceCheck(以及后续的 App Attest)成为了 iOS 平台上反作弊与反爬虫的重要防线。
DeviceCheck 的核心目标是在保护用户隐私的前提下,为开发者提供一种持久化的设备标记能力。即使 App 被卸载重装,甚至设备被恢复出厂设置(在某些条件下),DeviceCheck 存储的 2-bit 状态依然可以被保留。这使得它成为了对抗“新用户薅羊毛”、“设备封禁”等场景的利器。
然而,对于安全研究人员和黑灰产从业者而言,DeviceCheck 也是一个必须攻克的堡垒。本文将基于逆向工程视角,简单剖析 DeviceCheck 的底层实现,揭示其加密流程,并探讨在越狱环境下进行攻防对抗的可行性。
1.3、研究动机与目标
验证通过改机(UniqueChipID / ECID/SerialNumber等)为什么不能激活设备?
想搞清楚:苹果到底在检验什么?哪些字段是“硬绑定”的?
从攻击与防护视角学习如何应用好DeviceCheck?
1.4、整体流程与框架
还是老规矩,先上整体框架图以方便理解整体,激活流程:
二、mobileactivationd 激活流程分析
2.1、什么时候会激活?
这里说的激活,就是由 mobileactivationd + Apple 服务器 参与的那种“和苹果聊一聊,我是谁、能不能用”的流程,而不是普通 App 级别的登录。
首次开箱 / 刷机之后第一次开机
全新 iPhone、刚刷完原版 IPSW、DFU 恢复之后第一次进开机向导。
这时候本地没任何“激活凭据”,系统必须:
收集硬件指纹(ECID、ChipID、BoardId、SerialNumber…)
跟 Apple 服务器谈一轮,生成 / 刷新 uik.pem / ucrt.pem、设备证书等。
你能看到的表现就是:
恢复出厂设置 / 抹掉所有内容之后
在设置 → 通用 → 传输或还原 iPhone → 抹掉所有内容和设置,或者用 Finder/iTunes 恢复。
抹掉后再次启动,和第一次开箱本质一样,也要重新激活。
这时 mobileactivationd 会:
检查旧的激活票据是否还有效
一般还是会重新向服务器请求新的激活证书(你抓到的 RKCertification 就是这类东西)。
硬件变化比较大时(换本板 / 基带 / 改机)
主板更换、严重“硬改机”、某些基带相关硬件变化,会导致:
UniqueChipID(ECID)、ChipID、BoardId、SecurityDomain 组合发生改变。
Apple 服务器视角:这是“另一台设备”,必须重新审查:
有没有被报失
有没有被运营商锁 / 黑名单
所以一旦检测到这种变化,系统会强制重新走激活流程。
你的 hook 里如果把 UniqueChipID 换成别的机器的 ECID,就会看到服务器直接回:
某些大版本升级 / 本地激活证书过期异常
和运营商 / 区域相关的情况
小结一句:
只要 Apple 觉得“我有理由重新确认你这台机器的身份/状态”,就会触发 mobileactivationd 跑激活。
2.2、为什么要激活?
从苹果的角度,这一整套“激活”设计,主要是为了解决三大问题:防伪造、防偷盗、统一发证。DeviceCheck / AppAttest 其实都是站在这套基础设施上实现的。
确认“这是一台真机,而不是山寨/模拟设备”
激活时上传的 RKCertification 里,包含:
从 Secure Enclave 拿到的真·硬件密钥的 attestation
ECID / ChipID / BoardId / SerialNumber / SecurityDomain 等指纹
苹果在服务器上用自己的 CA 体系校验证书链:
证书是不是 Apple 自己签出来的
硬件签名是不是由安全芯片里那把私钥算出来的
结论:
防丢失、防盗机、控制设备生命周期
激活是苹果“设备生命周期管理”的关键环节:
防盗 / 查找我的 iPhone:
被“查找”绑定过的机器,如果被抹掉再激活,Apple 会要求输入原 Apple ID 才能继续。
黑名单 / 封禁:
被判定为重大违规(盗刷、欺诈)的 ECID/序列号,可以在服务器侧直接标记,下一次激活就直接拒绝。
区域控制:
比如某些功能/频段只在特定地区开放,也可以通过激活阶段写入策略。
为上层安全服务“铺路”(你现在在玩的部分)
激活完成后,mobileactivationd 会产出一套“设备根身份”:
系统组文件:uik.pem / ucrt.pem
Keychain 里的:
这些东西后面会被谁用?
devicecheckd 生成 DeviceCheck Token
AppAttest 做应用级 attestation
各种安全相关 daemon(FairPlay、Apple Pay、Find My…)
2.3、激活流程逆向分析
主要通过copyAnswer:方法采集设备唯一性相关信息
UniqueChipID: "6871544955xxxxxx", ChipID: "33040",BoardId: "24",SecurityDomain: "1",SerialNumber: "F6X439xxxxxx",BuildVersion: "20E252",UniqueDeviceID: "00008110-303C30C91A0xxxxxx"
// 获取设备信息void __fastcall create_baa_info_sub_1000EEDCC(__SecKey *a1, id a2, _QWORD *a3){ id v4; // x25 id v5; // x20 void *v6; // x21 id v7; // x20 int v8; // w5 int v9; // w6 int v10; // w7 id v11; // x19 NSArray *v12; // x21 void *v13; // x27 NSNumber *v14; // x0 int v15; // w5 int v16; // w6 int v17; // w7 NSNumber *v18; // x24 void *v19; // x22 id v20; // x23 void *v21; // x27 void *v22; // x22 char *v23; // x0 char *v24; // x23 __int64 v25; // x25 char *i; // x28 __SecKey *v27; // x24 int v28; // w5 int v29; // w6 int v30; // w7 const void *v31; // x9 void *v32; // x27 void *v33; // x26 void *v34; // x23 void *v35; // x19 _BOOL4 v36; // w9 __SecKey *v37; // x20 void *v38; // x23 _BOOL4 v39; // w24 _BOOL4 v40; // w19 NSNumber *v41; // x26 id v42; // x22 int v43; // w1 __SecKey *v44; // x21 int v45; // w5 int v46; // w6 int v47; // w7 id v48; // x20 __SecKey *v49; // x0 int v50; // w5 int v51; // w6 int v52; // w7 CFDataRef v53; // x21 int v54; // w5 int v55; // w6 int v56; // w7 __int64 v57; // x0 int v58; // w5 int v59; // w6 int v60; // w7 char v61; // w22 int v62; // w24 int v63; // w5 int v64; // w6 int v65; // w7 __SecKey *v66; // x19 int v67; // w5 int v68; // w6 int v69; // w7 unsigned int v70; // w28 void *v71; // x21 __SecKey *v72; // x22 int v73; // w5 int v74; // w6 int v75; // w7 int v76; // w5 int v77; // w6 int v78; // w7 id v79; // x19 int v80; // w5 int v81; // w6 int v82; // w7 void *v83; // x21 id v84; // x22 NSNumber *v85; // x25 NSNumber *v86; // x19 NSNumber *v87; // x21 unsigned __int8 v88; // w22 int v89; // w5 int v90; // w6 int v91; // w7 NSNumber *v92; // x19 unsigned int v93; // w20 int v94; // w5 int v95; // w6 int v96; // w7 const __CFString *v97; // x4 int v98; // w1 int v99; // w2 id v100; // x20 int v101; // w5 int v102; // w6 int v103; // w7 __SecKey *v104; // x0 int v105; // w5 int v106; // w6 int v107; // w7 NSFileManager *v108; // x20 NSFileManager *v109; // x21 void *v110; // x22 unsigned __int8 v111; // w23 int v112; // w5 int v113; // w6 int v114; // w7 id v115; // x20 id v116; // x20 int v117; // w5 int v118; // w6 int v119; // w7 id v120; // x20 void *v121; // x21 id v122; // x20 int v123; // w5 int v124; // w6 int v125; // w7 id v126; // x20 void *v127; // x21 id v128; // x20 int v129; // w5 int v130; // w6 int v131; // w7 id v132; // x20 __SecKey *v133; // x21 id v134; // x20 int v135; // w5 int v136; // w6 int v137; // w7 id v138; // x20 __SecKey *v139; // x21 id v140; // x20 int v141; // w5 int v142; // w6 int v143; // w7 id v144; // x21 void *v145; // x26 int v146; // w5 int v147; // w6 int v148; // w7 __SecKey *v149; // x0 int v150; // w5 int v151; // w6 int v152; // w7 CFDataRef v153; // x0 int v154; // w5 int v155; // w6 int v156; // w7 CFDataRef v157; // x24 int v158; // w1 id v159; // x26 id v160; // x21 int v161; // w5 int v162; // w6 int v163; // w7 __SecKey *v164; // x19 __CFString **v165; // x8 CFDataRef v166; // x26 CFDataRef v167; // x2 void *v168; // x20 id v169; // x21 void *v170; // x20 void *v171; // x21 void *v172; // x0 void *v173; // x23 int v174; // w5 int v175; // w6 int v176; // w7 void *v177; // x20 int v178; // w5 int v179; // w6 int v180; // w7 void *v181; // x20 void *v182; // x21 void *v183; // x0 void *v184; // x20 int v185; // w5 int v186; // w6 int v187; // w7 void *v188; // x20 int v189; // w5 int v190; // w6 int v191; // w7 void *v192; // x20 void *v193; // x21 void *v194; // x0 void *v195; // x20 int v196; // w5 int v197; // w6 int v198; // w7 int v199; // w5 int v200; // w6 int v201; // w7 int v202; // w5 int v203; // w6 int v204; // w7 __SecKey *v205; // x0 void *v206; // x20 id v207; // x21 void *v208; // x20 void *v209; // x21 id v210; // x22 void *v211; // x21 unsigned int v212; // w19 void *v213; // x22 id v214; // x23 void *v215; // x21 void *v216; // x22 id v217; // x23 void *v218; // x21 void *v219; // x22 id v220; // x23 void *v221; // x21 void *v222; // x22 id v223; // x23 void *v224; // x23 int v225; // w5 int v226; // w6 int v227; // w7 void *v228; // x22 id v229; // x23 __SecKey *v230; // x21 __SecKey *v231; // x24 void *v232; // x28 id v233; // x27 void *v234; // x25 void *v235; // x26 __SecKey *v236; // x23 void *v237; // x22 id v238; // x19 const void *v239; // x20 __SecKey *v240; // x21 __SecKey *v241; // x0 id v242; // x19 NSDictionary *v243; // x22 void *v244; // x24 __CFString **v245; // x8 void *v246; // x0 id v247; // x0 void *v248; // x22 char v249; // w23 id v250; // x19 id v251; // x23 int v252; // w5 int v253; // w6 int v254; // w7 id v255; // x19 id v256; // x24 int v257; // w5 int v258; // w6 int v259; // w7 char is_darwinos; // w0 id v261; // x19 id v262; // x21 int v263; // w5 int v264; // w6 int v265; // w7 id v266; // x24 NSData *v267; // x24 int v268; // w5 int v269; // w6 int v270; // w7 CFDataRef v271; // x2 int v272; // w5 int v273; // w6 int v274; // w7 char v275; // [xsp+0h] [xbp-3B0h] char v276; // [xsp+0h] [xbp-3B0h] void *v277; // [xsp+8h] [xbp-3A8h] __SecKey *v278; // [xsp+18h] [xbp-398h] __SecKey *v279; // [xsp+20h] [xbp-390h] void *v280; // [xsp+28h] [xbp-388h] void *v281; // [xsp+30h] [xbp-380h] void *v282; // [xsp+38h] [xbp-378h] __SecKey *v283; // [xsp+40h] [xbp-370h] __SecKey *v284; // [xsp+48h] [xbp-368h] __SecKey *cf; // [xsp+50h] [xbp-360h] id v286; // [xsp+58h] [xbp-358h] id v287; // [xsp+58h] [xbp-358h] char v288[8]; // [xsp+60h] [xbp-350h] __SecKey *v289; // [xsp+68h] [xbp-348h] __SecKey *v290; // [xsp+70h] [xbp-340h] const void *v291; // [xsp+78h] [xbp-338h] id v292; // [xsp+80h] [xbp-330h] id v293; // [xsp+80h] [xbp-330h] __SecKey *v294; // [xsp+88h] [xbp-328h] __SecKey *v295; // [xsp+88h] [xbp-328h] CFDataRef v296; // [xsp+90h] [xbp-320h] unsigned int v297; // [xsp+98h] [xbp-318h] NSData *v298; // [xsp+98h] [xbp-318h] CFDataRef v299; // [xsp+A0h] [xbp-310h] id v300; // [xsp+A8h] [xbp-308h] id v301; // [xsp+B0h] [xbp-300h] id v302; // [xsp+B8h] [xbp-2F8h] _BOOL4 v303; // [xsp+C0h] [xbp-2F0h] _BOOL4 v304; // [xsp+C0h] [xbp-2F0h] id v305; // [xsp+C0h] [xbp-2F0h] id v306; // [xsp+C8h] [xbp-2E8h] id v307; // [xsp+D0h] [xbp-2E0h] NSNumber *v308; // [xsp+D8h] [xbp-2D8h] NSNumber *v309; // [xsp+E0h] [xbp-2D0h] id v310; // [xsp+E8h] [xbp-2C8h] id v311; // [xsp+F0h] [xbp-2C0h] id v312; // [xsp+F8h] [xbp-2B8h] NSNumber *v313; // [xsp+100h] [xbp-2B0h] id v314; // [xsp+108h] [xbp-2A8h] id v315; // [xsp+110h] [xbp-2A0h] __SecKey *v316; // [xsp+118h] [xbp-298h] unsigned int v317; // [xsp+118h] [xbp-298h] id v318; // [xsp+120h] [xbp-290h] id v319; // [xsp+128h] [xbp-288h] CFDataRef v320; // [xsp+130h] [xbp-280h] id v321; // [xsp+138h] [xbp-278h] NSNumber *v322; // [xsp+140h] [xbp-270h] __SecKey *v323; // [xsp+148h] [xbp-268h] id v324; // [xsp+148h] [xbp-268h] id v325; // [xsp+148h] [xbp-268h] id v327; // [xsp+158h] [xbp-258h] BYREF id v328; // [xsp+160h] [xbp-250h] BYREF id v329; // [xsp+168h] [xbp-248h] BYREF id v330[2]; // [xsp+170h] [xbp-240h] BYREF id v331; // [xsp+180h] [xbp-230h] BYREF id v332; // [xsp+188h] [xbp-228h] BYREF id v333; // [xsp+190h] [xbp-220h] BYREF id v334[3]; // [xsp+198h] [xbp-218h] BYREF id v335[2]; // [xsp+1B0h] [xbp-200h] BYREF id v336[2]; // [xsp+1C0h] [xbp-1F0h] id v337[2]; // [xsp+1D0h] [xbp-1E0h] id v338[2]; // [xsp+1E0h] [xbp-1D0h] CFErrorRef error; // [xsp+1F0h] [xbp-1C0h] BYREF id v340[12]; // [xsp+1F8h] [xbp-1B8h] BYREF _QWORD v341[12]; // [xsp+258h] [xbp-158h] BYREF char v342[8]; // [xsp+2B8h] [xbp-F8h] BYREF _QWORD v343[3]; // [xsp+338h] [xbp-78h] BYREF __int64 vars8; // [xsp+3B8h] [xbp+8h] v4 = objc_retain(a2); error = 0; v5 = objc_retainAutoreleasedReturnValue(+[GestaltHlpr getSharedInstance](&OBJC_CLASS___GestaltHlpr, "getSharedInstance")); v6 = objc_msgSend(v5, "copyAnswer:", CFSTR("s7nuHoZIYNoOHCqT9iyZkQ")); objc_release(v5); v319 = v6; v7 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v6)); objc_release(v7); if ( !v7 ) { v322 = 0; v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 244, -1, 0, (int)CFSTR("Failed to retrieve %@."), v8, v9, v10, (char)CFSTR("s7nuHoZIYNoOHCqT9iyZkQ"))); v302 = 0; v31 = 0; v306 = 0; v307 = 0; v315 = 0; v299 = 0; v300 = 0; v310 = 0; v311 = 0; v313 = 0; v308 = 0; v309 = 0; v318 = 0; v321 = 0; v27 = 0; a1 = 0; v32 = 0; v33 = 0; v34 = 0; v35 = 0;LABEL_18: v320 = 0; v316 = 0;LABEL_46: v296 = 0; v298 = 0; v312 = 0; v314 = 0; v44 = 0;LABEL_47: v72 = 0; v301 = 0; v305 = 0; goto LABEL_180; } v11 = objc_alloc((Class)&OBJC_CLASS___NSMutableArray); v343[0] = CFSTR("1.2.840.113635.100.8.4"); v343[1] = CFSTR("1.2.840.113635.100.8.5"); v343[2] = CFSTR("1.2.840.113635.100.8.7"); v12 = objc_retainAutoreleasedReturnValue(+[NSArray arrayWithObjects:count:](&OBJC_CLASS___NSArray, "arrayWithObjects:count:", v343, 3)); v13 = objc_msgSend(v11, "initWithArray:", v12); objc_release(v12); v14 = objc_retainAutoreleasedReturnValue(+[NSNumber numberWithUnsignedInt:](&OBJC_CLASS___NSNumber, "numberWithUnsignedInt:", 0)); v322 = v14; if ( !v4 ) { v36 = 0; v297 = 0; v37 = 0; v320 = 0; v38 = 0; v310 = 0; v311 = 0; v300 = 0; v315 = 0; v306 = 0; v39 = 0; v40 = 1; v41 = (NSNumber *)&off_100E66CB8; v308 = (NSNumber *)&off_100E66CB8; v309 = (NSNumber *)&off_100E66CA0; goto LABEL_20; } v18 = v14; v323 = a1; v19 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v20 = objc_retainAutoreleasedReturnValue((id)isKindOfClass()); objc_release(v20); objc_release(v19); if ( v20 ) { v321 = v13; *(_OWORD *)v337 = 0u; *(_OWORD *)v338 = 0u; *(_OWORD *)v335 = 0u; *(_OWORD *)v336 = 0u; v21 = v4; v22 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v23 = (char *)objc_msgSend(v22, "countByEnumeratingWithState:objects:count:", v335, v342, 16); if ( v23 ) { v24 = v23; v25 = *(_QWORD *)v336[0]; while ( 2 ) { for ( i = 0; i != v24; ++i ) { if ( *(_QWORD *)v336[0] != v25 ) objc_enumerationMutation(v22); v27 = (__SecKey *)objc_retainAutoreleasedReturnValue((id)isKindOfClass_1(*((_QWORD *)v335[1] + (_QWORD)i))); objc_release(v27); if ( !v27 ) { v4 = v21; v277 = objc_retainAutoreleasedReturnValue(objc_msgSend(v21, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 263, -2, 0, (int)CFSTR("Invalid options (%@): %@"), v76, v77, v78, (char)CFSTR("OIDSToInclude"))); objc_release(v277); objc_release(v22); v302 = 0; v31 = 0; v306 = 0; v307 = 0; v315 = 0; v300 = 0; v310 = 0; v311 = 0; v318 = 0; goto LABEL_93; } } v24 = (char *)objc_msgSend(v22, "countByEnumeratingWithState:objects:count:", v335, v342, 16); if ( v24 ) continue; break; } } objc_release(v22); v4 = v21; v13 = objc_retainAutoreleasedReturnValue(objc_msgSend(v21, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); objc_release(v321); v18 = v322; } v321 = v13; if ( (unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.1")) && ((sub_100C87320() & 1) != 0 || (unsigned int)sub_100C87330()) ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 276, -2, 0, (int)CFSTR("Boot manifest not available in rOS or diagnosticsOS."), v28, v29, v30, v275)); v302 = 0; v31 = 0; v306 = 0; v315 = 0; v300 = 0; v310 = 0; v311 = 0; v318 = 0; goto LABEL_92; } v304 = ((unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.1")) & 1) != 0 || ((unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.7")) & 1) != 0 || ((unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.10.1")) & 1) != 0 || ((unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.10.2")) & 1) != 0 || (unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.10.3")); v70 = (unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.7")); if ( ((unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.2")) & 1) != 0 || (unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.8.11.1")) ) { v71 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("nonce"))); v72 = (__SecKey *)objc_retainAutoreleasedReturnValue((id)isKindOfClass_2()); objc_release(v72); objc_release(v71); if ( !v72 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 295, -2, 0, (int)CFSTR("Missing required option: %@"), v73, v74, v75, (char)CFSTR("nonce"))); v302 = 0; v31 = 0; v306 = 0; v307 = 0; v315 = 0; v316 = 0; v299 = 0; v300 = 0; v310 = 0; v311 = 0; v318 = 0; v27 = 0; a1 = 0; v32 = 0; v33 = 0; v34 = 0; v35 = 0; v7 = 0; v320 = 0; v296 = 0; v298 = 0; v312 = 0; v314 = 0; v44 = 0;LABEL_96: v301 = 0; v305 = 0; v313 = (NSNumber *)&off_100E66CB8; v308 = (NSNumber *)&off_100E66CB8; v309 = (NSNumber *)&off_100E66CA0; goto LABEL_180; } v318 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("nonce"))); } else { v318 = 0; } v83 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("CertType"))); v84 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v83)); objc_release(v84); objc_release(v83); v293 = v4; if ( v84 ) { v85 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("CertType"))); objc_release(v18); v86 = objc_retainAutoreleasedReturnValue(+[NSNumber numberWithUnsignedInt:](&OBJC_CLASS___NSNumber, "numberWithUnsignedInt:", 0)); if ( -[NSNumber isEqualToNumber:](v85, "isEqualToNumber:", v86) ) { objc_release(v86); v18 = v85; } else { v87 = objc_retainAutoreleasedReturnValue(+[NSNumber numberWithUnsignedInt:](&OBJC_CLASS___NSNumber, "numberWithUnsignedInt:", 1)); v88 = -[NSNumber isEqualToNumber:](v85, "isEqualToNumber:", v87); objc_release(v87); objc_release(v86); v18 = v85; if ( (v88 & 1) == 0 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 306, -2, 0, (int)CFSTR("Invalid value for option (%@): %@"), v89, v90, v91, (char)CFSTR("CertType"))); v302 = 0; v31 = 0; v306 = 0; v307 = 0; v315 = 0; v316 = 0; v299 = 0; v300 = 0; v310 = 0; v311 = 0; v27 = 0; a1 = 0; v32 = 0; v33 = 0; v34 = 0; v35 = 0; v7 = 0; v320 = 0; v296 = 0; v298 = 0; v314 = 0; v44 = 0; v72 = 0; v301 = 0; v305 = 0; v322 = v85; v312 = 0; v313 = (NSNumber *)&off_100E66CB8; v308 = (NSNumber *)&off_100E66CB8; v309 = (NSNumber *)&off_100E66CA0; v4 = v293; goto LABEL_180; } } } v92 = objc_retainAutoreleasedReturnValue(+[NSNumber numberWithUnsignedInt:](&OBJC_CLASS___NSNumber, "numberWithUnsignedInt:", 1)); v93 = -[NSNumber isEqualToNumber:](v18, "isEqualToNumber:", v92); objc_release(v92); v322 = v18; if ( v93 ) { v4 = v293; if ( ((unsigned int)objc_msgSend(v319, "boolValue") & 1) == 0 ) { v97 = CFSTR("Certificate type not supported on this platform: %@"); v276 = (char)v18; v98 = 313; v99 = -3; goto LABEL_89; } if ( ((unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.6.71.1")) & 1) == 0 ) { v97 = CFSTR("Missing required OID for certificate type (%@): %@"); v276 = (char)v18; v98 = 318;LABEL_66: v99 = -2;LABEL_89: v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", v98, v99, 0, (int)v97, v94, v95, v96, v276));LABEL_90: v302 = 0; v31 = 0; v306 = 0; v315 = 0; v300 = 0; v311 = 0;LABEL_91: v310 = 0;LABEL_92: v307 = 0; v27 = 0;LABEL_93: a1 = 0; v32 = 0; v33 = 0; v34 = 0; v299 = 0; v35 = 0; goto LABEL_94; } } else { v4 = v293; if ( ((unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.6.71.1")) & 1) != 0 || ((unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.6.71.2")) & 1) != 0 || (unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.6.71.3")) ) { v97 = CFSTR("Invalid OID(s) for requested certificate type: %@"); v276 = (char)v18; v98 = 325; goto LABEL_66; } } if ( (unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.6.71.1")) && (v168 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiProperties"))), v169 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_2()), objc_release(v169), objc_release(v168), v169) ) { v170 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiProperties"))); v171 = objc_msgSend(v170, "length"); objc_release(v170); v172 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiProperties"))); v173 = v172; if ( v171 != (void *)32 ) { objc_msgSend(v172, "length"); v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 333, -2, 0, (int)CFSTR("Invalid value for option (%@): unexpected size (%lu)"), v174, v175, v176, (char)CFSTR("MFiProperties"))); objc_release(v173); goto LABEL_90; } } else { v173 = 0; } v311 = v173; if ( (unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.6.71.2")) ) { v177 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiPPUID"))); v44 = (__SecKey *)objc_retainAutoreleasedReturnValue((id)isKindOfClass_1(v177)); objc_release(v44); objc_release(v177); if ( !v44 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 343, -2, 0, (int)CFSTR("Missing required option: %@"), v178, v179, v180, (char)CFSTR("MFiPPUID"))); v302 = 0; v31 = 0; v306 = 0; v315 = 0; v300 = 0;LABEL_135: v310 = 0; v307 = 0; v27 = 0; a1 = 0; v32 = 0; v33 = 0; v34 = 0; v298 = 0; v299 = 0; v35 = 0; v7 = 0; v320 = 0; v316 = 0; v296 = 0; v312 = 0; v314 = 0; goto LABEL_95; } v181 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiPPUID"))); v182 = objc_msgSend(v181, "length"); objc_release(v181); v183 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiPPUID"))); v184 = v183; if ( (unsigned __int64)v182 >= 0x25 ) { objc_msgSend(v183, "length"); v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 348, -2, 0, (int)CFSTR("Invalid value for option (%@): unexpected size (%lu)"), v185, v186, v187, (char)CFSTR("MFiPPUID"))); objc_release(v184); v302 = 0; v31 = 0; v306 = 0; v315 = 0; v300 = 0; goto LABEL_91; } v35 = objc_retainAutoreleasedReturnValue(objc_msgSend(v183, "stringByPaddingToLength:withString:startingAtIndex:", 36, &stru_100E61E50, 0)); objc_release(v184); if ( !v35 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 357, -2, 0, (int)CFSTR("Failed to pad string."), v199, v200, v201, v275)); v302 = 0; v31 = 0; v306 = 0; v307 = 0; v315 = 0; v299 = 0; v300 = 0; v310 = 0; v27 = 0; a1 = 0; v32 = 0; v33 = 0; v34 = 0;LABEL_94: v7 = 0; v320 = 0; v316 = 0; v296 = 0; v298 = 0; v312 = 0; v314 = 0; v44 = 0;LABEL_95: v72 = 0; goto LABEL_96; } v315 = objc_retainAutoreleasedReturnValue(objc_msgSend(v35, "dataUsingEncoding:", 4)); if ( !v315 ) { v300 = v35; v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 363, -2, 0, (int)CFSTR("Failed to convert string to data."), v202, v203, v204, v275)); v302 = 0; v31 = 0; v306 = 0; v315 = 0; goto LABEL_91; } } else { v35 = 0; v315 = 0; } v300 = v35; if ( !(unsigned int)objc_msgSend(v13, "containsObject:", CFSTR("1.2.840.113635.100.6.71.3")) ) { v306 = 0; goto LABEL_137; } v188 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiData"))); v44 = (__SecKey *)objc_retainAutoreleasedReturnValue((id)isKindOfClass_2()); objc_release(v44); objc_release(v188); if ( !v44 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 370, -2, 0, (int)CFSTR("Missing required option: %@"), v189, v190, v191, (char)CFSTR("MFiData"))); v302 = 0; v31 = 0; v306 = 0; goto LABEL_135; } v192 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiData"))); v193 = objc_msgSend(v192, "length"); objc_release(v192); v194 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("MFiData"))); v195 = v194; if ( (unsigned __int64)v193 >= 0x4B0 ) { objc_msgSend(v194, "length"); v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 375, -2, 0, (int)CFSTR("Invalid value for option (%@): unexpected size (%lu)"), v196, v197, v198, (char)CFSTR("MFiData"))); objc_release(v195); v302 = 0; v31 = 0; v306 = 0; goto LABEL_91; } v306 = v194;LABEL_137: v206 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("UseRKSigningInterface"))); v207 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v206)); objc_release(v207); objc_release(v206); if ( v207 ) { v208 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("UseRKSigningInterface"))); v317 = (unsigned int)objc_msgSend(v208, "boolValue"); objc_release(v208); } else { v317 = 0; } v209 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("UseSoftwareGeneratedKey"))); v210 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v209)); objc_release(v210); objc_release(v209); if ( v210 ) { v211 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("UseSoftwareGeneratedKey"))); v212 = (unsigned int)objc_msgSend(v211, "boolValue"); objc_release(v211); } else { v212 = 1; } v213 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("Validity"))); v214 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v213)); objc_release(v214); objc_release(v213); if ( v214 ) { v215 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("Validity"))); v309 = objc_retainAutoreleasedReturnValue( +[NSNumber numberWithUnsignedInteger:]( &OBJC_CLASS___NSNumber, "numberWithUnsignedInteger:", objc_msgSend(v215, "unsignedIntegerValue"))); objc_release(v215); } else { v309 = (NSNumber *)&off_100E66CA0; } v216 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("CACert"))); v217 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v216)); objc_release(v217); objc_release(v216); if ( v217 ) { v218 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("CACert"))); v308 = objc_retainAutoreleasedReturnValue( +[NSNumber numberWithUnsignedInteger:]( &OBJC_CLASS___NSNumber, "numberWithUnsignedInteger:", objc_msgSend(v218, "unsignedIntegerValue"))); objc_release(v218); } else { v308 = (NSNumber *)&off_100E66CB8; } v219 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("scrtAttestation"))); v220 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v219)); objc_release(v220); objc_release(v219); if ( v220 ) { v221 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("scrtAttestation"))); v41 = objc_retainAutoreleasedReturnValue( +[NSNumber numberWithUnsignedInteger:]( &OBJC_CLASS___NSNumber, "numberWithUnsignedInteger:", objc_msgSend(v221, "unsignedIntegerValue"))); objc_release(v221); } else { v41 = (NSNumber *)&off_100E66CB8; } v222 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("ClientAttestationData"))); v223 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_2()); objc_release(v223); objc_release(v222); if ( !v223 ) { v37 = 0; v320 = 0; goto LABEL_156; } v224 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("ClientAttestationPublicKey"))); v27 = (__SecKey *)objc_retainAutoreleasedReturnValue((id)isKindOfClass_2()); objc_release(v27); objc_release(v224); if ( !v27 ) { v313 = v41; v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 412, -2, 0, (int)CFSTR("Missing required option for %@."), v225, v226, v227, (char)CFSTR("ClientAttestationPublicKey"))); v302 = 0; v31 = 0; v310 = 0; v307 = 0; a1 = 0; v32 = 0; v33 = 0; v34 = 0; v299 = 0; v35 = 0; v7 = 0; goto LABEL_18; } v37 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("ClientAttestationData"))); v320 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("ClientAttestationPublicKey")));LABEL_156: v297 = v70; v228 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("AppID"))); v229 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_1(v228)); objc_release(v229); objc_release(v228); v39 = v317 != 0; v40 = v212 != 0; if ( v229 ) v310 = objc_retainAutoreleasedReturnValue(objc_msgSend(v4, "objectForKeyedSubscript:", CFSTR("AppID"))); else v310 = 0; v38 = v318; a1 = v323; v36 = v304;LABEL_20: v321 = v13; v318 = v38; v313 = v41; if ( !a1 ) { v316 = v37; v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 467, -2, 0, (int)CFSTR("Invalid input."), v15, v16, v17, v275)); v302 = 0; v31 = 0; v307 = 0; v27 = 0;LABEL_45: v32 = 0; v33 = 0; v34 = 0; v299 = 0; v35 = 0; v7 = 0; goto LABEL_46; } v42 = 0; v303 = v36; if ( !v39 || v37 ) { v291 = 0; v289 = 0; v294 = 0;LABEL_49: v316 = v37; v333 = v42; v334[0] = 0; v27 = security_copy_system_key(0, v334, &v333); v7 = objc_retain(v334[0]); v79 = objc_retain(v333); objc_release(v42); if ( !v27 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 519, -1, error, (int)CFSTR("Failed to copy SIK attestation key."), v80, v81, v82, v275)); objc_release(v79); v302 = 0; v305 = 0; v301 = 0; v72 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v35 = 0; v299 = 0; v34 = 0; v33 = 0; v32 = 0; a1 = 0; v307 = 0; v290 = 0; goto LABEL_173; } *(_QWORD *)v288 = v7; if ( -[NSNumber boolValue](v41, "boolValue") ) { v292 = v4; v286 = 0; v284 = 0; } else { v331 = v79; v332 = 0; v72 = security_copy_system_key(2, &v332, &v331); v286 = objc_retain(v332); v100 = objc_retain(v331); objc_release(v79); if ( !v72 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 528, -1, v100, (int)CFSTR("Failed to copy UIK attestation key."), v101, v102, v103, v275)); objc_release(v100); CFRelease(v27); v302 = 0; v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; v34 = 0; v33 = 0; v32 = 0; a1 = 0; v27 = 0; v307 = 0; v290 = 0; v35 = v286; v7 = *(id *)v288; goto LABEL_173; } v284 = v72; v292 = v4; v79 = v100; v7 = *(id *)v288; } cf = v27; v104 = (__SecKey *)objc_alloc_init((Class)&OBJC_CLASS___NSMutableDictionary); v72 = v104; if ( !v104 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 536, -1, 0, (int)CFSTR("Failed to allocate dictionary."), v105, v106, v107, v275)); objc_release(v79); v302 = 0; v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; v34 = 0; v33 = 0; v32 = 0; a1 = 0; v27 = 0; v307 = 0; v290 = 0; v4 = v292; v35 = v286; goto LABEL_171; } v283 = v104; if ( -[NSNumber boolValue](v41, "boolValue") || (v108 = objc_retainAutoreleasedReturnValue(+[NSFileManager defaultManager](&OBJC_CLASS___NSFileManager, "defaultManager")), v109 = objc_retainAutoreleasedReturnValue(objc_retainAutoreleaseReturnValue(v108)), v110 = objc_retainAutoreleasedReturnValue( -[NSFileManager stringByAppendingPathComponent:]( v109, "stringByAppendingPathComponent:", CFSTR("ucrt.pem"))), v111 = -[NSFileManager fileExistsAtPath:](v108, "fileExistsAtPath:", v110), objc_release(v110), objc_release(v109), objc_release(v108), (v111 & 1) != 0) ) { v115 = objc_retainAutoreleasedReturnValue(+[GestaltHlpr getSharedInstance](&OBJC_CLASS___GestaltHlpr, "getSharedInstance")); v34 = objc_msgSend(v115, "copyAnswer:", CFSTR("UniqueChipID")); objc_release(v115); v116 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v34)); objc_release(v116); if ( v116 ) { v281 = v34; v120 = objc_retainAutoreleasedReturnValue(+[GestaltHlpr getSharedInstance](&OBJC_CLASS___GestaltHlpr, "getSharedInstance")); v121 = objc_msgSend(v120, "copyAnswer:", CFSTR("ChipID")); objc_release(v120); v282 = v121; v122 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v121)); objc_release(v122); if ( !v122 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 588, -1, 0, (int)CFSTR("Failed to retrieve %@."), v123, v124, v125, (char)CFSTR("ChipID"))); objc_release(v79); v302 = 0; v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; v32 = 0; a1 = 0; v27 = 0; v307 = 0; v290 = 0; v4 = v292; v35 = v286; v7 = *(id *)v288; v33 = v282; v72 = v283; goto LABEL_171; } v126 = objc_retainAutoreleasedReturnValue(+[GestaltHlpr getSharedInstance](&OBJC_CLASS___GestaltHlpr, "getSharedInstance")); v127 = objc_msgSend(v126, "copyAnswer:", CFSTR("BoardId")); objc_release(v126); v280 = v127; v128 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v127)); objc_release(v128); if ( !v128 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 594, -1, 0, (int)CFSTR("Failed to retrieve %@."), v129, v130, v131, (char)CFSTR("BoardId"))); objc_release(v79); v302 = 0; v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; a1 = 0; v27 = 0; v307 = 0; v290 = 0; v4 = v292; v35 = v286; v7 = *(id *)v288; v33 = v282; v72 = v283; v32 = v280; goto LABEL_171; } v132 = objc_retainAutoreleasedReturnValue(+[GestaltHlpr getSharedInstance](&OBJC_CLASS___GestaltHlpr, "getSharedInstance")); v133 = (__SecKey *)objc_msgSend(v132, "copyAnswer:", CFSTR("SecurityDomain")); objc_release(v132); v279 = v133; v134 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_0(v133)); objc_release(v134); if ( !v134 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 600, -1, 0, (int)CFSTR("Failed to retrieve %@."), v135, v136, v137, (char)CFSTR("SecurityDomain"))); objc_release(v79); v302 = 0; v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; v27 = 0; v307 = 0; v290 = 0; v4 = v292; v35 = v286; v7 = *(id *)v288; v33 = v282; v72 = v283; v32 = v280;LABEL_133: a1 = v279; goto LABEL_171; } v138 = objc_retainAutoreleasedReturnValue(+[GestaltHlpr getSharedInstance](&OBJC_CLASS___GestaltHlpr, "getSharedInstance")); v139 = (__SecKey *)objc_msgSend(v138, "copyAnswer:", CFSTR("SerialNumber")); objc_release(v138); v278 = v139; v140 = objc_retainAutoreleasedReturnValue((id)isKindOfClass_1(v139)); objc_release(v140); if ( v140 ) { v144 = objc_retainAutoreleasedReturnValue(+[GestaltHlpr getSharedInstance](&OBJC_CLASS___GestaltHlpr, "getSharedInstance")); v145 = objc_msgSend(v144, "copyAnswer:", CFSTR("BuildVersion")); objc_release(v144); v307 = v145; v44 = (__SecKey *)objc_retainAutoreleasedReturnValue((id)isKindOfClass_1(v145)); objc_release(v44); if ( v44 ) { v149 = SecKeyCopyPublicKey(a1); if ( v149 ) { v290 = v149; v153 = SecKeyCopyExternalRepresentation(v149, &error); v7 = *(id *)v288; if ( v153 ) { v157 = v153; if ( -[NSNumber boolValue](v313, "boolValue") ) v158 = 0; else v158 = 2; v330[1] = v79; v159 = objc_retainAutoreleasedReturnValue((id)security_create_system_key_attestation( (int)a1, v158, v318)); v160 = objc_retain(v79); objc_release(v79); v312 = v159; v299 = v157; if ( v159 ) { v325 = v160; if ( v316 ) { v164 = v283; -[__SecKey setObject:forKeyedSubscript:]( v283, "setObject:forKeyedSubscript:", v316, CFSTR("RKCertification")); -[__SecKey setObject:forKeyedSubscript:]( v283, "setObject:forKeyedSubscript:", v159, CFSTR("RKSigning")); v165 = off_100E52138; v166 = v157; v167 = v157; } else { v165 = off_100E51E10; v167 = (CFDataRef)v159; v164 = v283; v166 = v157; } -[__SecKey setObject:forKeyedSubscript:](v164, "setObject:forKeyedSubscript:", v167, *v165); v242 = objc_alloc((Class)&OBJC_CLASS___NSMutableDictionary); v340[0] = CFSTR("UniqueChipID"); v340[1] = CFSTR("ChipID"); v341[0] = v34; v341[1] = v282; v340[2] = CFSTR("BoardId"); v340[3] = CFSTR("SecurityDomain"); v341[2] = v280; v341[3] = v279; v340[4] = CFSTR("SerialNumber"); v340[5] = CFSTR("OsBuildVersion"); v341[4] = v278; v341[5] = v307; v340[6] = CFSTR("scrtAttestation"); v340[7] = CFSTR("CertType"); v341[6] = v313; v341[7] = v322; v340[8] = CFSTR("Validity"); v340[9] = CFSTR("CACert"); v341[8] = v309; v341[9] = v308; v340[10] = CFSTR("OIDSToInclude"); v340[11] = CFSTR("SIKPub"); v341[10] = v13; v341[11] = *(_QWORD *)v288; v243 = objc_retainAutoreleasedReturnValue( +[NSDictionary dictionaryWithObjects:forKeys:count:]( &OBJC_CLASS___NSDictionary, "dictionaryWithObjects:forKeys:count:", v341, v340, 12)); v244 = objc_msgSend(v242, "initWithDictionary:", v243); objc_release(v243); v245 = off_100E52130; if ( v316 ) { objc_msgSend(v244, "setObject:forKeyedSubscript:", v320, CFSTR("RKCertificationPub")); v245 = off_100E52138; } v35 = v286; v246 = objc_msgSend(v244, "setObject:forKeyedSubscript:", v166, *v245); if ( v286 ) v246 = objc_msgSend(v244, "setObject:forKeyedSubscript:", v286, CFSTR("UIKPub")); v247 = objc_retainAutoreleasedReturnValue((id)IORegistryEntry_sub_10052290C(v246)); v314 = v244; if ( !v247 ) goto LABEL_201; v248 = v247; if ( (sub_100C87330() & 1) != 0 ) { objc_release(v248);LABEL_201: v302 = 0;LABEL_207: if ( v303 && (sub_100C87320() & 1) == 0 ) { if ( (sub_100C87330() & 1) != 0 ) { v301 = 0; } else { v329 = v325; v255 = objc_retainAutoreleasedReturnValue((id)sub_100C75830(2, &v329)); v256 = objc_retain(v329); objc_release(v325); v301 = v255; if ( !v255 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 735, -1, v256, (int)CFSTR("Failed to load boot manifest."), v257, v258, v259, v275)); objc_release(v256); v305 = 0; v301 = 0;LABEL_240: v44 = 0; v296 = 0; v298 = 0; goto LABEL_168; } objc_msgSend(v314, "setObject:forKeyedSubscript:", v255, CFSTR("Image4Manifest")); v325 = v256; } v35 = v286; v7 = *(id *)v288; v34 = v281; } else { v301 = 0; } if ( (sub_100C87330() & 1) != 0 ) { v305 = 0;LABEL_221: v4 = v292; v266 = v306; v72 = v283;LABEL_222: v33 = v282; v262 = v325; goto LABEL_223; } is_darwinos = os_variant_is_darwinos(objc_msgSend(CFSTR("com.apple.mobileactivationd"), "UTF8String")); v305 = 0; if ( !v297 ) goto LABEL_221; if ( (is_darwinos & 1) != 0 ) { v4 = v292; v266 = v306; v35 = v286; v7 = *(id *)v288; v72 = v283; v34 = v281; goto LABEL_222; } v328 = v325; v261 = objc_retainAutoreleasedReturnValue((id)sub_100C75830(10, &v328)); v262 = objc_retain(v328); objc_release(v325); v305 = v261; if ( v261 ) { objc_msgSend(v314, "setObject:forKeyedSubscript:", v261, CFSTR("Cryptex1Image4Manifest")); v4 = v292; v266 = v306; v35 = v286; v7 = *(id *)v288; v33 = v282; v72 = v283; v34 = v281;LABEL_223: v32 = v280; if ( v310 ) objc_msgSend(v314, "setObject:forKeyedSubscript:", v310, CFSTR("AppID")); if ( v311 ) objc_msgSend(v314, "setObject:forKeyedSubscript:", v311, CFSTR("MFiProperties")); if ( v315 ) objc_msgSend(v314, "setObject:forKeyedSubscript:", v315, CFSTR("MFiPPUID")); if ( v266 ) objc_msgSend(v314, "setObject:forKeyedSubscript:", v266, CFSTR("MFiData")); v327 = 0; v267 = objc_retainAutoreleasedReturnValue( +[NSPropertyListSerialization dataWithPropertyList:format:options:error:]( &OBJC_CLASS___NSPropertyListSerialization, "dataWithPropertyList:format:options:error:", v314, 100, 0, &v327)); v287 = objc_retain(v327); objc_release(v262); if ( v267 ) { -[__SecKey setObject:forKeyedSubscript:]( v72, "setObject:forKeyedSubscript:", v267, CFSTR("RKProperties")); v298 = v267; v271 = SecKeyCreateSignature( a1, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (CFDataRef)v267, &error); v27 = v278; if ( v271 ) { v296 = v271; -[__SecKey setObject:forKeyedSubscript:]( v72, "setObject:forKeyedSubscript:", v271, CFSTR("RKPropertiesSignature")); v44 = objc_retain(v72); v324 = v287; } else { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 810, -1, error, (int)CFSTR("Failed to sign data with ref key."), v272, v273, v274, v275)); objc_release(v287); v44 = 0; v296 = 0; } goto LABEL_133; } v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 799, -1, v287, (int)CFSTR("Could not convert dictionary to xml data."), v268, v269, v270, v275)); objc_release(v287); v44 = 0; v296 = 0; v298 = 0;LABEL_170: v27 = v278; a1 = v279;LABEL_171: CFRelease(cf); if ( v284 ) CFRelease(v284);LABEL_173: if ( v289 ) CFRelease(v289); v205 = v294; if ( !v294 ) goto LABEL_177; goto LABEL_176; } v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 770, -1, v262, (int)CFSTR("Failed to load cryptex1 manifest."), v263, v264, v265, v275)); objc_release(v262); v305 = 0; goto LABEL_240; } v249 = os_variant_is_darwinos(objc_msgSend(CFSTR("com.apple.mobileactivationd"), "UTF8String")); objc_release(v248); if ( (v249 & 1) != 0 ) { v302 = 0;LABEL_206: v34 = v281; goto LABEL_207; } v330[0] = v160; v250 = objc_retainAutoreleasedReturnValue((id)sub_100C75830(9, v330)); v251 = objc_retain(v330[0]); objc_release(v160); v302 = v250; if ( v250 ) { objc_msgSend(v244, "setObject:forKeyedSubscript:", v250, CFSTR("LocalPolicy")); v325 = v251; v35 = v286; v7 = *(id *)v288; goto LABEL_206; } v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 719, -1, v251, (int)CFSTR("Failed to load cryptex1 local policy."), v252, v253, v254, v275)); objc_release(v251); v305 = 0; v301 = 0; v44 = 0; v296 = 0; v298 = 0;LABEL_167: v302 = 0;LABEL_168: v4 = v292; v7 = *(id *)v288;LABEL_169: v35 = v286; v33 = v282; v72 = v283; v32 = v280; v34 = v281; goto LABEL_170; } v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 637, -1, v160, (int)CFSTR("Failed to create reference key attestation (nonce: %@)."), v161, v162, v163, (char)v318)); objc_release(v160); v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; } else { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 628, -1, 0, (int)CFSTR("Failed to encode RK public key as data."), v154, v155, v156, v275)); objc_release(v79); v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; } v302 = 0; v4 = v292; goto LABEL_169; } v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 622, -1, 0, (int)CFSTR("Failed to copy RK public key."), v150, v151, v152, v275)); objc_release(v79); v305 = 0; v301 = 0; v44 = 0; } else { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 612, -1, v79, (int)CFSTR("Failed to retrieve %@."), v146, v147, v148, (char)CFSTR("BuildVersion"))); objc_release(v79); v305 = 0; v301 = 0; } v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; } else { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 606, -1, 0, (int)CFSTR("Failed to retrieve %@."), v141, v142, v143, (char)CFSTR("SerialNumber"))); objc_release(v79); v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; v307 = 0; } v290 = 0; goto LABEL_167; } v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 582, -1, 0, (int)CFSTR("Failed to retrieve %@."), v117, v118, v119, (char)CFSTR("UniqueChipID"))); objc_release(v79); v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; } else { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 543, -4, 0, (int)CFSTR("UCRT is unavailable."), v112, v113, v114, v275)); objc_release(v79); v305 = 0; v301 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v299 = 0; v34 = 0; } v33 = 0; v32 = 0; a1 = 0; v27 = 0; v307 = 0; v290 = 0; v302 = 0; v4 = v292; v35 = v286; v7 = *(id *)v288; v72 = v283; goto LABEL_171; } if ( -[NSNumber boolValue](v41, "boolValue") ) v43 = 0; else v43 = 2; v334[2] = 0; v44 = (__SecKey *)objc_retainAutoreleasedReturnValue((id)security_create_system_key_attestation((int)a1, v43, v38)); v48 = objc_retain(0); if ( !v44 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 477, -1, v48, (int)CFSTR("Failed to create reference key attestation."), v45, v46, v47, v275)); objc_release(v48); v302 = 0; v31 = 0; v307 = 0; v27 = 0; a1 = 0; v32 = 0; v33 = 0; v34 = 0; v298 = 0; v299 = 0; v35 = 0; v7 = 0; v316 = 0; v296 = 0; v312 = 0; v314 = 0; goto LABEL_47; } v316 = v44; v49 = SecKeyCopyPublicKey(a1); if ( !v49 ) { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 483, -1, 0, (int)CFSTR("Failed to copy RK public key."), v50, v51, v52, v275)); objc_release(v48); v302 = 0; v31 = 0; v307 = 0; v27 = 0; a1 = 0; goto LABEL_45; } v294 = v49; v53 = SecKeyCopyExternalRepresentation(v49, &error); objc_release(v320); if ( v53 ) { v57 = SecAccessControlCreate(0, &error); if ( v57 ) { v61 = kSecAttrAccessibleUntilReboot; v62 = v57; v291 = (const void *)v57; if ( (SecAccessControlSetProtection(v57, kSecAttrAccessibleUntilReboot, &error) & 1) != 0 ) { v334[1] = v48; v66 = (__SecKey *)sub_100C6E934(v62, v40, v4); v42 = objc_retain(v48); objc_release(v48); if ( v66 ) { v320 = v53; a1 = v66; v289 = v66; v37 = v316; goto LABEL_49; } v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 508, -1, v42, (int)CFSTR("Failed to create reference key."), v67, v68, v69, v275)); v48 = v42; } else { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 502, -1, error, (int)CFSTR("Failed to set ACL protection to %@."), v63, v64, v65, v61)); } } else { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 497, -1, error, (int)CFSTR("Failed to create access control."), v58, v59, v60, v275)); v291 = 0; } v320 = v53; } else { v324 = objc_retainAutoreleasedReturnValue((id)com_apple_MobileActivation_ErrorDomain( (int)"create_baa_info", 489, -1, error, (int)CFSTR("Failed to encode RK public key as data."), v54, v55, v56, v275)); v320 = 0; v291 = 0; } objc_release(v48); v302 = 0; v305 = 0; v301 = 0; v72 = 0; v44 = 0; v314 = 0; v296 = 0; v298 = 0; v312 = 0; v7 = 0; v35 = 0; v299 = 0; v34 = 0; v33 = 0; v32 = 0; a1 = 0; v27 = 0; v307 = 0; v290 = 0; v205 = v294;LABEL_176: CFRelease(v205);LABEL_177: if ( v290 ) CFRelease(v290); v31 = v291;LABEL_180: if ( error ) { v295 = v44; v230 = v27; v231 = a1; v232 = v32; v233 = v4; v234 = v33; v235 = v34; v236 = v72; v237 = v35; v238 = v7; v239 = v31; CFRelease(error); v31 = v239; v7 = v238; v35 = v237; v72 = v236; v34 = v235; v33 = v234; v4 = v233; v32 = v232; a1 = v231; v27 = v230; v44 = v295; } error = 0; if ( v31 ) CFRelease(v31); if ( a3 && !v44 ) *a3 = objc_retainAutorelease(v324); v240 = objc_retain(v44); objc_release(v302); objc_release(v324); objc_release(v306); objc_release(v315); objc_release(v300); objc_release(v311); objc_release(v310); objc_release(v322); objc_release(v313); objc_release(v308); objc_release(v309); objc_release(v318); objc_release(v321); objc_release(v307); objc_release(v27); objc_release(a1); objc_release(v32); objc_release(v33); objc_release(v34); objc_release(v299); objc_release(v35); objc_release(v7); objc_release(v320); objc_release(v316); objc_release(v296); objc_release(v312); objc_release(v298); objc_release(v314); objc_release(v240); objc_release(v72); objc_release(v301); objc_release(v319); objc_release(v305); objc_release(v4); if ( ((vars8 ^ (2 * vars8)) & 0x4000000000000000LL) != 0 ) __break(0xC471u); v241 = objc_autoreleaseReturnValue(v240);}
用 SE 里封装的密钥 + 苹果预置的证书链,生成了一份 attestation(证明)blob,这个 blob 里面带着证书和签名,对“某些设备硬件字段 + 公钥”做了绑定。
这个“证书/attestation blob”是 依赖安全硬件(Secure Enclave / Apple KeyStore)生成的,而且签名覆盖了与这台硬件绑定的一些信息。
格式如下:
SEQUENCE INTEGER 02 SEQUENCE OCTETSTRING xxxxdeca90b4fd52da1c016730a81dcb281f6c4dbb973e6b8438e6827530a177 OCTETSTRING xxxx980ea0e8b0211cc342dc42067f1b..(total 65bytes)..2c8c482afb33b9e84221b49ffd1d81fa OCTETSTRING xxxx730da8259089a9b9b02bd4a455fd OCTETSTRING xxxxce59b8232b317ff32beb21237051 OCTETSTRING xxxx56c0b70138d40071067ee100013f..(total 1074bytes)..4b70f5283c1085f6a8d25107d6b9a94b
将采集的硬件信息与证书签名信信息组合成 plist格式数据上报到服务器端
[*] URL : https://humb.apple.com/humbug/baa[*] Method : POST 0 : User-Agent = {contents = "iOS Device Activator (MobileActivation-834.100.27) - devicecheckd"} 3 : Content-Type = {contents = "application/xml"} 4 : Content-Length = 9822 6 : x-jmet-deviceid = {contents = "00008110-303C30C91A06484E"}}
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plistPUBLIC"-//Apple//DTD PLIST 1.0//EN""http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plistversion="1.0"><dict> <key>RKCertification</key> <data> MIIExQIBAjxxxxxxxxP4C3sqQtP1S2hwBZzCoHcsoH2xNu5c+a4Q45oJ1MKF3BEEEiTxl 3JiRx7vW49DhREeRVU04QQBLnB7Lm7nI8+D2ayS/PMZ7rcmhC89px3xHSlAvDl2MQopT SHXxnC/0Bs/6KgQQ1SciqWRdHp3U/vxi/S1O/wQQNpOm/5v25ojsX99XACzgpwSCBDHO l9izvodcLU0pQSlaNXHlIp7nMLqh/QkyEI+a/YlGFaqTR/PgZbq4o37Rw6SCZQ+MjU2F uzuq9O6sTaKVBcw4aDW0oPDmZgH5m1ZlDwvUqQFAy+OvNrO8L4D4zSo2lW8BRqR89jkx WAixq12iERj/4+orIFAFGG86P/PnRRUsC8uR1tkqM4NpjXiLNUlO/X7VF1iY7g3nf5JS uxAqGMNZ8eEXXHJ9I5XuPDC/B1BvpoM/Pk65CPRbaw5ojMr+McZ+IsuWQBb21dxMldAy MMg5sFEt5+uIqWFaVyjFMfFCqYTfSofsyFQO8woaPegrmqFBVJRTGbbPkEDEVaWgLprd VuoE8hkSvecWaBwsyNH0UmTLMOwrMHF12RLVPc6qChr4ki0FkIP9crLHhQwxVYeXgRpA ClcA6uNFFa412RdhRhv5T88NBVRNu9ewCm3gWBnhMF10PltNVGJ1ZRjhZS0ghaVnqHpj DA+2pnObaocLzgC9bOl0RExDwVwxLp7/hD/0jqZ+GqGSPgXYGY3FxnIB9n1e35KNjWaV ur1WgHps5TEdi9LHxur2iqv5IkmxXNojxUoWprRc36RCBkurDLJiCM6Es8/63z1mZQ9h a4iA5+u0PStVpCSjOJ/0gn01pIxxxeppomCsT6980+l1HYi7zsD/tBkOznpFwGS5Ki9h RErTaCc2/9YGjgWVOBv1w5dEnBnwb1P59Qgpmnx3k9eyczaxt3OXOnKVwzYKtowI0OeD F9jM1yN9KZVtAqQJM4H8N+W3f0w8x+PwYHUf/0AHdAK/WyUHObDkoPzZOY+N7aFvkSf8 aVcxC5MMCM6YFGpeDN9yoroti2mxxxelwDYx7Q8wuIeBBDiJfHRMWXxQEbej2XoYxGs4 tz8Qh0z5p0kL5bb5MERKHPkaIg+slVxEpoCAxCnNHiTHjK3gEXhgyxkiBmLO4ENSGDTp +5PX64sez9Sb95ua6PhFFJYRXFgnp2IqffOoxx9Pxtxf7aKvpmlhPu+YGfbpz+mF+BSQ Y0a/ybU0xySRCKfTlepT8J+3HGNGl6HmjKPMDgj1SIloAoNR+VATnMs0THe7ZZTYLI+m bghSAHqDcjZCOWbRp19gSbUz71WU/sDAbN477biemxOYszVzS6cckGmmoDSLuav8RCSH 9h254xTGB5VzEjT5lqpsWJ0u+IJUW7gfCbkq1IGer5PdmVrzAluNTS4G85iHnXi3EKJB wJ1upCRMjwlQRFlKP/SDo1TTQUa1kX0x+o1bFjvroyNKq+wL56PRQex22FzN00gsursF dstdB+WPHde2jfeVmielZ+wxw59wEuE2CLeS5D1CLIEGYgsTyoLxl6QQ80UjaphhAuVA A7HqcmXNe/6AOGdL42LHUhF23K5Fd55i8yaJP0sMwzY1e3nPbeunZmIiL1KiAFcKLzpm cg== </data> <key>RKProperties</key> <data> ff94bfwgfmVyc2lvbjxxxxxwIiBlbmNvZGluZz0iVVRGLTgiPz4KPCFET0NUWVBFIHBs aXN0IFBVQkxJQyAiLSxxxxxwbGUvL0RURCBQTElTVCAxLjAvL0VOIiAiaHR0cDovL3d3 dy5hcHBsZS5jb20vRFREcy9Qcm9wZXJ0eUxpc3QtMS4wLmR0ZCI+CjxwbGlzdCB2ZXJz aW9uPSIxLjAiPgo8ZGljdD4KCTxrZXk+QXBwSUQ8L2tleT4KCTxzdHJpbmc+Y29tLmFw cGxlLmRldmljZWNoZWNrZDwvf3RyaW5nPgoJPGtleT5Cb2FyZElkPC9rZXk+Cgk8aW50 ZWdlcj4yNDwvaW50ZWdlcj4KffxrZXk+QfFfZXffPC9rZXk+Cgk8aW50ZWdlcj4wPC9p bnRlZ2VyPgoJPGtleT5DZXJ0VHlwZTwva2V5PgoJPGludGVnZXI+MDwvaW50ZWdlcj4K CTxrZXk+Q2hpcElEPC9rZXk+Cgk8aW50ZWdlcj4zMzA0MDwvaW50ZWdlcj4KCTxrZXk+ TG9jYWxQb2xpY3k8L2tleT4KCTxkYXRhPgoJTUlJTVFCWUVTVTFITkRBVUZnUkpUVFJR RmdSc2NHOXNGZ014TGpBRUFRQ2dnZfdfTUfJfUhCWUVTVTAwVFFJQkFER0MKCUFpUC9o T3FGbkVLQ0Fob3dnZ0lXRmdSTlFxxUNNWUlDRFArRTZvV2NVSUlCbnpDQ0Fac1dCRTFC VGxBeGdnR1IvNFNTCgl2YVJFQ3pBSkZnUkNUMUpFQWdFWS80U2FsYUJQQ3pBSkZnUkRS VkJQQWdFQi80U2FvWkpRRFRBTEZnUkRTRWxRQWdNQQoJZ1JEL2hKckJwRThMTUFrV0JF TlFVazhCQWYvL2hKck5pa01MTUFrV0JFTlRxVU1CQfWYvL2hLcU5ra1FSTUE4V0JFVkQK CVNVUUNCeGhwb2p3Z0lCNy9oWnFSbmswTE1Ba1dCRk5FVDAwQ0FRSC9odU85eEc4TE1B a1dCR3h2WW04QkFmLy9odlBOCgkwbWc2TURnV0JHNXphV2dFTUlQc0gwYlAybmtaaDNo NVF3U2RXUU1CL0NoekZrWlMyczE0SxlWxnJTdDZwR2RlaDIvSgoJd3VnR2V4dFU5cWNm Uy8rSGs3M2NhQ293S0JZRWNtOXVhQVFnU2srUmVVVnd1QWlCeEw0cWM5WmlZZUFFQ3Y1 OVN2dmwKCXk4SWhTM2ZaK2k3L2g1dkIwbWc2TURnV0JITndhV2dFTUo3V1ZSSWhWNU13 ZXlXa2VHdVo5STVSbUFSNGQycm9aZnFQCglmOE92aXljRkFjUEs0cHJDUXVTN3BSa3lB WDQxVi8rSG04bnNiaDR3SEJZRWMzSjJiZ1FVRzIrWkp3aXFselVHSUkzQQoJVmZMcklJ L3RkMGYvaDdQVjBtUWFNQmdXQkhaMWFXUUVFQUFBQUFBQUFBQUFBQUFBQUFBQUFBRC9o dVBCM214ZE1Gc1cKCUJHeHdiMnd4VS8rRW9wMm1WRG93T0JZRVJFZFRWQVF3MFFGVU9N U29rWEtqQkkxZXJyeXkzbVYzZGNacStHaVJhcWVXCglHUUk5Z29haFJoREhKZVNSem1m MERMMVl0M2h5LzRTcXJZcFpDekFKRmdSRlMwVlpBUUgvQklJQ0FFRmdqK1krQkpheAoJ MU1jS3dGQkdFMHpvcElKZkJWY2dKcG5MeDV2MFA2L1VsbG1jWmZYcnVYK2t1K2xRYm9H UXBkQ3ZZcnp6K3l4bXVjS00KCWtDOXlJdlpzMndjMldrMzdDeHl4a1lXZ2UvckZmSERC WFpQS3hTc1hIRFpkVXVjanFQbGlqVkJGV1pXekJjc0hQd2M3CgkyOFJUcTNWQU9aeG0x RXo3RVFlVHRmUDFocDN0WEdic0xaMlZ0aVcyWG12VDFDeCsvajNCbnhnNGNtQy9EUjJW SmpZaQoJUUx2V0dJSTNSVUY5cUEwL3BBeGcvQ3JCeXI4Zkx3Uk5QV2haOGMwRW04eVhi U2MxZ1h2K0NlUnJJcVBNZXFWU1o3cGoKCXdGamlhTWlwRXEwRUJhQkcyOG9xNkNCZE9E K1ZDUWxYSzBNOEdqUXZXc3FpcS9UVDRlQkVGV0NQTzRKLzU2bzE4WkxpCgk5OFdZaTQy RVBLb0RHM0ZyTFhreWNWR0E0QTdnVlhIczBnS25TeWJEKzZmYlk0SGF5cWtpUEM4ZHl1 QWlUNXF5WThwUwoJdVp5TTY5aEs4dEJleFpiWDdiOFdEd29HVElzd3RST0d1SGZJbEpS bXBIVXF2YnRUcWs4Qk42cFBwaHlNMlJqb1p4QmgKCXlBdzdEQ0M5Y0tuTkpnamhQTE91 aFRaUlU0aCtqMXo5WnY2UmdpSU44L21wTkxZV2pNMmtFWEw1eVRKbVhYVnBOcThICgll UGx5VUF4TnF6dkFLVFpZQjMrODROOFF4ekF4bVk4eFFBcUpVb1ROWWVZSjZnSWZXcnFM VktsRFdDcy9kUE5kc2xndwoJNHN4ci9xS09kcDI1cm5ST1hyK21Kc080Qm4rNkI2Vmhm WndWWnpmT2VkN0toZ3dMaGxrSXRYY25UbEN0TUlJSDVEQ0MKCUIrQXdnZ1hJb0FNQ0FR SUNFRDM5ajV5cU5WOXZVQ0xzTjAyRWRCOHdEUVlKS29aSWh2Y05BUUVNQlFBd1N6RW5N Q1VHCglBMVVFQXd3ZVFYQndiR1VnVTJWamRYSmxJRUp2YjNRZ1VtOXZkQ0JEUVNBdElF YzJNUk13RVFZRFZRUUtEQXBCY0hCcwoJWlNCSmJtTXVNUXN3Q1FZRFZRUUdFd0pWVXpB ZUZ3MHlNREEzTWpJeE9EQTJORGhhRncwek1EQTNNak14T0RBMk5EaGEKCU1GSXhMakFz QmdOVkJBTU1KVlE0TVRFd0xWTkVUMDB4TFZKbFkyOTJaWEo1UW05dmRDMVNaWFpCTFVa aFkzUnZjbmt4CglFekFSQmdOVkJBb01Da0Z3Y0d4bElFbHVZeTR4Q3pBSkJnTlZCQVlU QWxWVE1JSUNJakFOQmdrcWhraUc5dzBCQVFFRgoJQUFPQ0FnOEFNSUlDQ2dLQ0FnRUF5 aVFHMk1leXZJeFlCQThJdis1bVd0cG83SHJ6ZUdvdU1sSlR1SHFqbmNUYzdDVEYKCUlp WlUvT1RMaVRoT2FsdS85L29rQnBqY2MyY0hVdXV6NFlMeUhRYkNFYzllam5MdTFhY2lY Q3MvVHZaZmoyTFpScnZsCgk4Tk1xaTBrNUE5RHlUVGxzYnZWRDhXQmdIZ3VUN2MySjh2 N0tpUnM5MkZUWjZ6OGROK0ZPa1VjM3dTUnRiOFBaQ2QrWgoJREdXblpDYzZyZFlkOFRJ WDhNK0dCYzhGeUVEaXFhUmNONmpNNzJkRkRDL0NCQjZxcmFKZDlEQ1VzRTdDVXJ5Zk02 VWYKCXpqbVNyTGNnSkZYSjhZK3k0N2VjaGcrY2RDTytOQThBYjQzL2E1N0xJaTBtT0JI V2FIUytHTkExR3c3WkpqdHdNQXcvCgllbW9heXVNYXB6d1RlRjFNTW1qKzNTa0h2WEdT T0JtcU5SYVBoT2hRd1p3bkpsaEhpSkNzaVl1dWJ3N3Bxa0MycytiYgoJekx3MkxNakEy UUppQWdDOHJmU3VYb2RUT2EzRkxhK1RmSlJ4TjhoL3p2aEU5Wmk0RDNBeC8xQ2dBS1Qx bTNXT3JtQ1AKCURVZDZKOXZ5c3plTWdlZ3RTWldHdU9oL1o1OGFDR1lROTFoMVdpYSt5 VHdvU1J4c1lYdTR5ZldkT0ZlelpYQjlzMmFqCglWUEFRKzI2eE8xWlRsR29CWXVHcU1y TGEvaUV5S1J1UHpzZDVzcC9uU29wdE43dDQwS0h5Uy9KL1luT2RoZTltREdqUwoJMTZE aFJBSjRWdHBubDFmeHhubFdNcXpJeUNTMWxtTDdWeWxMdkF1YkpKZTF6MGtaTm9CNWln SFB5Q3V2ZW5FUVpSVkQKCUlBcFJ5YlpqSk9Pc1FoVUY3dGFYVUQwQ0F3RUFBYU9DQXJj d2dnS3pNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqCglCQmd3Rm9BVVU3ZUV0TEhv T0R5Vzc2UldMdm96M1BFUWtPQXdIUVlxxlIwT0JCWUVGRlhYTkNqTWlaMzlYVFlGU3B0 TgoJTXFNRlNwcWNNQTRHQTFVZER3RUIvd1FFQXdJSGdEQ0NBbEVHQ2lxR1NJYjNZMlFH QVE4QkFmOEVnZ0krTVlJQ092K0UKCTZvV2NVSUlCd1RDQ0FiMFdCRTFCVGxBeGdnR3ov NFNTdVlaSUREQUtGZ1JDVGtOSW9RSUZBUCtFa3Iya1JBd3dDaFlFCglRazlTUktBQ0JR RC9oSnFWb0U4TE1Ba1dCRU5GVUU4Q0FRSC9oSnFoa2xBTk1Bc1dCRU5JU1ZBQ0F3Q0JF UCtFbXNHawoJVHd3d0NoWUVRMUJTVDZBQ0JxRCxxSnJxxWtNTU1Bb1dCRU5UUlVPZ0Fn VUEvNFNxalpKRUREQUtGZ1JGUTBsRW9BSUYKCUFQK0ZtcEdlVFFzd0NSWUVVMFJQVFFJ QkFmK0dpOVh3YVF3d0NoWUVZWFY0YWFFQ0JRRC9ob3ZWOEhBTU1Bb1dCR0YxCgllSENo QWdVQS80Ymp2Y1J2Q3pBSkZnUnNiMkp2QVFILy80Ymp3ZHhvRERBS0ZnUnNjRzVvb1FJ RkFQK0c4ODNTYUF3dwoJQ2hZRWJxxxBxS0FDQlFEL2g1TzkzR2dNTUFvV0JISnZibWln QWdVQS80ZVR3ZHhvRERBS0ZnUnljRzVvb1FJRkFQK0gKCW02WGdNQXd3Q2hZRWMybHdN S0VDQlFEL2g1dWw0REVNTUFvV0JITnBjREdoQWdVQS80ZWJwZUF5RERBS0ZnUnphWEF5 CglvUUlGQVArSG02WGdNd3d3Q2hZRWMybHdNNkVDQlFEL2g1dTF4REFNTUFvV0JITnRZ akNoQWdVQS80ZWJ0Y1F4RERBSwoJRmdSemJXSXhvUUlGQVArSG03WEVNZ3d3Q2hZRWMy MWlNcUVDQlFEL2g3UFYwbVFNTUFvV0JIWjFhV1NnQWdVQS80VDYKCWlaUlFhVEJuRmdS UFFrcFFNVi8vaEtLZHBsUU1NQW9XQkVSSFUxU2dBZ1VBLzRTaXdhUlBEREFLRmdSRVVG SlBvUUlGCglBUCtFb3MyS1F3d3dDaFlFUkZORlE2RUNCUUQvaEtyQnBFOE1NQW9XQkVW UVVrK2hBZ1VBLzRTcXpZcEREREFLRmdSRgoJVTBWRG9RSUZBREFOQmdrcWhraUc5dzBC QVF3RkFBT0NBZ0VBalRUWGVyeE9pMnRWbkNUdXBYR3ZJZW5FQWRLNnZKZ28KCVJaTFNo TFo0NGFqNnYySS93V1NKblE1T1VBdGJaNEdiL1RSblZIOUV1dEtZZks0cC9GVlJOZVUv c0w2UjRHZEI2TGV0CgkwbWNKWkpSN2xtaUtUQmtMaFBYcnZsaU9qM2hQRlMxWHhCNDBT YzU2SlJ6L3REMlpjM1VPSmFNZDZza2YxR3FRd3BUaQoJUzgxVU5zS3JNVmtpc0R5YXYv VWxTQmpKM1hyazBCMmN1YVNpVjRaUXhZaSs0ZjRaSXUyZDQ2Y3lBMEJ3YXhBd0UwNFkK CU1OdDZVUXl2Y0R4VUxrMU5oUzhUbEtvMVJLczM3UWJxY2k4bUdMOU52M2N4NThjN3B4 czBNT2VKMVY1UmNtRGxxZWVLCgliTEtTc3BnUTRLNkFHaTJwL3VsckI0YWsxU3lZZGky UVlMUUw5TmU3dHhlMXE3c0Zlcmw0RnluOVZGZ2F1aVIreGlvQgoJaXpMcFZWblNPa1RR SGgzVEtNbVpEUS9MUDdscUNrcnVCOHZPRGYxV3dITzNOQityVTRXZlBZeERyazJqOWln a1pDdzEKCStjVFdWMmozU2lIekk1WUQ5WGRWZmNpZklOTktiNnhhckhuODdpQkh2Rmgv M3hKekVqUzZTclI2WEpRTi9RU0FTTXpMCglnVkZRUXFxaHM0N1ZRNmlOS0NjZnZpR21U aXFoOE5vWVh1ZXUrME1Rdm5kb3NtcjUzelQzMEFTVWt0TTJnNFBKeDBuawoJUHN1dTVy SVVaK3pKeWd6YjVmKzlhSXRHYkNUZEdwajM4YldYR0U3aWRXYTJuQlh6bnBVbDgyd3Fh MlpWMHE1OFp2N20KCTBXY09ZWlRxcnVOSTcxRTVXd1duMWFCdzZQRlFOeG0xQlBOcFhS MD0KCTwvZGF0YT4KCTxrZXk+T0lEU1RvSW5jbHVkZTwva2V5PgoJPGFycmF5PgoJCTxz dHJpbmc+MS4yLjg0MC4xMTM2MzUuMTAwLjEwLjE8L3N0cmluZz4KCTwvYXJyYXk+Cgk8 a2V5Pk9zQnVpbGRWZXJzaW9uPC9rZXk+Cgk8c3RyaW5nPjIwRTI1Mjwvc3RyaW5nPgoJ PGtleT5SS0NlcnRpZmljYXRpb25QdWI8L2tleT4KCTxkYXRhPgoJQkgvL3VxQ1FzNEE0 VElCdm1ZTWNJQkhiaGo1d0ZURkJaaDU3d2JkL0hTU25aSi9ZeE5YandIZ1FhZzlkandM Vk84VjkKCS9DUHk2dDhmbURvbXM1TFpmYVE9Cgk8L2RhdGE+Cgk8a2V5PlNJS1B1Yjwv a2V5PgoJPGRhdGE+CglCUHpXTnFSZk1MYmZCNTE0ZXorMWdXNG5vRzZxWGRMa3VySTYz Y0NXSlRaall5cHVQVWIvUVZnNmJySUg5M2VUREd3QwoJMFJHTERuYjF3VjlPOHhSWkxM ODVSNGdZMVJMeGw0ZnlmYkxLbzUrVHNoQk01bkYyckRlU0hMOG43cEFVOGc9PQoJPC9k YXRhPgoJPGtleT5TZWN1cml0eURvbWFpbjwva2V5PgoJPGludGVnZXI+MTwvaW50ZWdl cj4KCTxrZXk+U2VyaWFsTnVtYmVyPC9rZXk+Cgk8c3RyaW5nPkY2WDQzOU5IRjk8L3N0 cmluZz4KCTxrZXk+VUlLUHViPC9rZXk+Cgk8ZGF0YT4KCUJEOHVOckcvaWJvL1RzbVg5 a3JlVHZvS1N5WW1pZ2Z4UTJzTndTODVSb20rNy90TDBUM2toMlByTVlhWithZTlidWdq CglNVWxFTkxFOHBGUTFaTjdmSkprPQoJPC9kYXRhPgoJPGtleT5VbmlxdWVDaGlwSUQ8 L2tleT4KCTxpbnRlZ2VyPjY4NzE1NDQ5NTU0MTI1MTA8L2ludGVnZXI+Cgk8a2V5PlZh bGlkaXR5PC9rZXk+Cgk8aW50ZWdlcj40NDExODY8L2ludGVnZXI+Cgk8a2V5PnNjcnRB dHRlc3RhdGlvbjwva2V5PgoJPGludGVnZXI+MDwvaW50ZWdlcj4KPC9kaWN0Pgo8L3Bs aXN0Pgo= </data> <key>RKPropertiesSignature</key> <data> MEYCIQD6alE5at+gOBxxxxxxYAIVZ6QwFJb7Q5lWdv/s95rSZAIhALu+7s0YPJu8LtN9 O19Svcb46Vhw2CKF9Txv7GNheg+6 </data></dict></plist>
即使hook伪造 MGCopyAnswer获取的的设备 ID,也不能伪造成另一台真机,因为底层 attestation 必须由那台真机的 SE 自签。单纯在软件层面篡改 UniqueChipID 时,服务器端会发现 “你上报的设备 ID 和 attestation 里的(或服务器已有记录里的)设备硬件身份对不上”。
服务验签没问题后会返回正常的激活两本证书
-----BEGIN CERTIFICATE-----MIIDQTCCAuagAwIBAgIGAZrdcv7/MAoGCCqGSM49BAMCMFMxJzAlBgNVBAMMHkJhc2ljIEF0dGVzdGF0aW9uIFVzZXIgU3ViIENBMTETMBEGA1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTAeFw0yNTEyMDEwNTA0NTJaFw0yNjA3MzExMTMzNTJaMIGRMUkwRwYDVQQDDEA4YmQzNmIxNWZkNGViODgxZjZlYzNlYzE1MjJhNjlhNzE2ZGY1YTIxNzAxZmZlNTc1NWUwMmQ0MmVjZWRhYTVjMRowGAYDVQQLDBFCQUEgQ2VydGlmaWNhdGlvbjETMBEGx1xECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABAZRvBj8pkr4rDSbr4x137hYn/JvpfSXJpuvcTL0XXwhvK5s/TDrhpp07/n3Vo/1GDz3DyDjGbOdIci26U4h54GjggFlMIIBYTAMBgNVHRMBAf8EAxxAMA4GA1UdDwEB/wQEAwIE8DCCAT8GCSqGSIb3Y2QKAQSCATAEggEsMYIBKP+EmqGsUA0wCxYEQ0hJUAIDAIEQ/4SqjZJEETAPFgRFQ0lEAgcYaaI8ICAe/4SSvaRECzAJFgRCT1JEAgEY/4aTtcJjGzAZFgRibWFjBBFhYzoxNjoxNTo2ZDphNToxZf+Gy7XKaRkwFxYEaW1laQQPMzU2MTI0NzE1MDY4NTU1/4ebydxtFDASFgRzcm5tBApGNlg0MzlOSEY5/4erkdJkIzAhFgR1ZGlkBBkwMDAwODExMC0wMDE4NjlBMjNDMjAyMDFF/4e7tcJjGzAZFgR3bWFjBBFhYzoxNjoxNTo3OTo4ZTpmZf+Hm5XSZDowOBYEc2VpZAQwMDQyRDI3QzU4QTE2OTAwMjIzMzIwMTMxNzI0MDUyMjRGRDE3MkZCRUQxM0VFQzdCMAoGCCqGSM49BAMCA0kAMEYCIQCkVmdn5P6/mipbxpLOX7j9tTZ0ob4x2GzYsMeNF7mnwAIhAJgrskCv3xq9xR/QCaBYl+b8Ju0i2Jk5xxxxxxxxxx=-----END CERTIFICATE----------BEGIN CERTIFICATE-----MIICIzCCAaigAwIBAgIIeNjhG9tnDGgwCxxIKxZIzj0EAwIwUzEnMCUGA1UEAwweQmFzaWMgQXR0ZXN0YXRpb24gVXNlciBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTE3MDQyMDAwNDIwMFoXDTMyMDMyMjAwMDAwMFowUzEnMCUGA1UEAwweQmFzaWMgQXR0ZXN0YXRpb24gVXNlciBTdWIgQ0ExMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoSZ/1t9eBAEVp5a8PrXacmbGb8zNC1X3StLI9YO6Y0CL7blHmSGmjGWTwD4Q+i0J2BY3+bPHTGRyA9jGB3MSbaNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSD5aMhnrB0w/lhkP2XTiMQdqSj8jAdBgNVHQ4EFgQU5mWf1DYLTXUdQ9xmOH/uqeNSD80wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMCA2kAMGYCMQC3M360LLtJS60Z9q3vVjJxMgMcFQ1roGTUcKqvW+4hJ4CeJjySXTgq6IEHn/yWab4CMQCm5NnK6SOSK+AqWum9lL87W3E6AA1f2TvJ/hgok/34jr93nhS87tOQNdxDS8xxxx=-----END CERTIFICATE-----
这两本证书就是后面用于计算DeviceCheck Token的,格式解析如下:
验证证书有效后缓存在本地keychain,后面计算DeviceCheck Token时会有用到。
2.4、修改设备硬件信息激活验证测试
// ========= 0. Hook MGCopyAnswer ========= var g_mgCopyAnswerHooked = false; var mgJsCache = { UniqueChipID: null, ChipID: null, BoardId: null, SecurityDomain: null, SerialNumber: null, BuildVersion: null, UniqueDeviceID: null }; function hookGestatcopyAnswer() { try { if (g_mgCopyAnswerHooked) { console.log("[*] MGCopyAnswer already hooked"); return; } var mgCopyAnswer = Module.findExportByName(null, "MGCopyAnswer"); if (!mgCopyAnswer) { console.error("[-] MGCopyAnswer not found"); return; } console.log("[+] MGCopyAnswer =", mgCopyAnswer); Interceptor.attach(mgCopyAnswer, { onEnter: function (args) { this.keyStr = null; try { var keyObj = new ObjC.Object(args[0]); var ks = keyObj.toString(); this.keyStr = ks; console.log("[MGCopyAnswer] key =", ks); } catch (e) { console.log("[MGCopyAnswer] key (raw) =", args[0], "err:", e); } }, onLeave: function (retval) { var keyStr = this.keyStr; var origDesc; try { var origObj = new ObjC.Object(retval); origDesc = origObj.toString(); } catch (e) { origDesc = "<raw> " + retval; } console.log("[MGCopyAnswer] orig =>", origDesc); if (!CONFIG.patchMGCopyAnswer || !keyStr) { return; } try { var NSString = ObjC.classes.NSString; var NSNumber = ObjC.classes.NSNumber; var NSUUID = ObjC.classes.NSUUID; var fakeObj = null; var fixed = CONFIG.fixedMG || {}; var useFixed = CONFIG.useFixedMGValues === true; switch (keyStr) { case "UniqueChipID": case "Uniquechipid": { var v; if (useFixed && fixed.UniqueChipID !== undefined) { v = Number(fixed.UniqueChipID); } else { if (mgJsCache.UniqueChipID === null) { mgJsCache.UniqueChipID = (Math.floor(Math.random() * 0xFFFFFFFF) >>> 0); } v = mgJsCache.UniqueChipID; } fakeObj = NSNumber.numberWithLongLong_(v); fakeObj.retain(); console.log("[*] override UniqueChipID =>", fakeObj.toString()); retval.replace(fakeObj.handle); break; } case "ChipID": case "Chipid": { var cVal; if (useFixed && fixed.ChipID !== undefined) { cVal = Number(fixed.ChipID); } else { if (mgJsCache.ChipID === null) { mgJsCache.ChipID = (0x2000 + Math.floor(Math.random() * 0x1000)) >>> 0; } cVal = mgJsCache.ChipID; } fakeObj = NSNumber.numberWithUnsignedInt_(cVal >>> 0); fakeObj.retain(); console.log("[*] override ChipID =>", fakeObj.toString()); retval.replace(fakeObj.handle); break; } case "BoardId": case "BoardID": { var bVal; if (useFixed && fixed.BoardId !== undefined) { bVal = Number(fixed.BoardId); } else { if (mgJsCache.BoardId === null) { mgJsCache.BoardId = 10 + Math.floor(Math.random() * 20); } bVal = mgJsCache.BoardId; } fakeObj = NSNumber.numberWithUnsignedInt_(bVal >>> 0); fakeObj.retain(); console.log("[*] override BoardId =>", fakeObj.toString()); retval.replace(fakeObj.handle); break; } case "SecurityDomain": case "Securitydomain": { var sVal; if (useFixed && fixed.SecurityDomain !== undefined) { sVal = Number(fixed.SecurityDomain); } else { if (mgJsCache.SecurityDomain === null) { mgJsCache.SecurityDomain = 1; } sVal = mgJsCache.SecurityDomain; } fakeObj = NSNumber.numberWithUnsignedInt_(sVal >>> 0); fakeObj.retain(); console.log("[*] override SecurityDomain =>", fakeObj.toString()); retval.replace(fakeObj.handle); break; } case "SerialNumber": case "Serialnumber": { var sn; if (useFixed && fixed.SerialNumber) { sn = fixed.SerialNumber.toString(); } else { if (mgJsCache.SerialNumber === null) { mgJsCache.SerialNumber = "F" + randHex(11); } sn = mgJsCache.SerialNumber; } var snCStr = Memory.allocUtf8String(sn); fakeObj = NSString.stringWithUTF8String_(snCStr); fakeObj.retain(); console.log("[*] override SerialNumber =>", fakeObj.toString()); retval.replace(fakeObj.handle); break; } case "BuildVersion": case "Buildversion": { var bv; if (useFixed && fixed.BuildVersion) { bv = fixed.BuildVersion.toString(); } else { if (mgJsCache.BuildVersion === null) { mgJsCache.BuildVersion = "20" + randHex(4); } bv = mgJsCache.BuildVersion; } var bvCStr = Memory.allocUtf8String(bv); fakeObj = NSString.stringWithUTF8String_(bvCStr); fakeObj.retain(); console.log("[*] override BuildVersion =>", fakeObj.toString()); retval.replace(fakeObj.handle); break; } case "UniqueDeviceID": { var udid; if (useFixed && fixed.UniqueDeviceID) { udid = fixed.UniqueDeviceID.toString(); } else { if (mgJsCache.UniqueDeviceID === null) { var uuidObj = NSUUID.UUID(); mgJsCache.UniqueDeviceID = uuidObj.UUIDString().toString(); } udid = mgJsCache.UniqueDeviceID; } var udidCStr = Memory.allocUtf8String(udid); fakeObj = NSString.stringWithUTF8String_(udidCStr); fakeObj.retain(); console.log("[*] override UniqueDeviceID =>", fakeObj.toString()); retval.replace(fakeObj.handle); break; } default: break; } } catch (e) { console.log("[-] MGCopyAnswer patch error:", e); } } }); g_mgCopyAnswerHooked = true; console.log("[+] Hooked MGCopyAnswer (patch =", CONFIG.patchMGCopyAnswer, ", useFixed =", CONFIG.useFixedMGValues, ")"); } catch (e) { console.error("[-] hookGestatcopyAnswer failed:", e.stack || e); } }
全部更改设备信息服务器会返回错误
-----BEGIN ERROR-----93:UCRT SCRT SEAL from tabasco is null.-----END ERROR-----
站在苹果服务器的角度,它收到这些东西之后,大概会做这样几步检测:
1. 验证 SE attestation(由 Apple 根证书/中间证书链签的): - 检查证书链是否正确、未过期、签名有效 - 从 attestation blob 里取出: * 这个 key 所在的“安全硬件身份”:比如 Secure Enclave 的某个 ID * 跟这一块硬件绑定的标识:UniqueChipID/ChipID/SecurityDomain/...(以某种形式存在)2. 验证 RKPropertiesSignature: - 用 attestation 里证明的那把 refKey 的 “公钥” 去验签 RKPropertiesSignature - 确认:RKProperties 确实是 **同一个 SE 里那把 refKey** 签出来的, 而不是你在用户态自己随便弄的 key。3. 一致性检查: - 从 attestation / 后端数据库里得到的“真实硬件 ID” 记为 H = {U_real, ChipID_real, ...} - 从 RKProperties 里解析出你上报的 ID 记为 S = {U_reported, ChipID_reported, ...} 然后做类似: if U_reported != U_real or ChipID_reported != ChipID_real ... => 认为这是“篡改 / 不一致”,直接拒绝,后面的 UCRT/SCRT/SEAL 都不下发
修改部分真实设备信息
其它字段随机、只保留UniqueChipID、ChipID不改,正常返回证书;
说明SE中对UniqueChipID、ChipID进行了签名,服务器端做检验。
A手机信息替换为B手机
将A手机的UniqueChipID、ChipID替换到B手机,返回如下:
-----BEGIN ERROR-----29:ECC signature verification failed: signature incorrect.-----END ERROR-----
整体流程与修改信息验证流程
从上面验证情况来看,硬ID与SE 里的证书是绑定的。SE 里的“根密钥”和“设备证书”是在出厂生产 / 校准阶段由 Apple 写入硬件安全区的,属于“出厂级”的东西。
我改的 MobileGestalt 层(UniqueChipID/ChipID)只是“软件视角的 ID”,并不会改变 SE 里真实的密钥和它生成的签名,所以软改实现激活大概率是不可行的。
三、DeviceCheck 架构与正向流程
DeviceCheck 的工作流程涉及三方交互:客户端 App、系统守护进程 devicecheckd 以及 Apple 服务器。整体流程如下:
3.1 核心组件
客户端 (App):通过 DCDevice 类发起 Token 生成请求。
守护进程 (devicecheckd):iOS 系统内置的守护进程,负责与硬件安全模块(Secure Enclave)通信,执行核心加密操作。
Apple Server:接收 Token,验证其合法性,并根据 Token 更新或查询设备的 2-bit 状态。
3.2 bit 状态存储机制
DeviceCheck 允许开发者为每个设备-App 组合存储两个二进制位(00, 01, 10, 11)。
3.3 正向调用流程
App 调用 [DCDevice generateTokenWithCompletionHandler:]。
请求通过 XPC(跨进程通信)被转发给系统的 com.apple.devicecheckd 服务。
devicecheckd 调用底层硬件接口生成加密的 Base64 Token。
App 将 Token 发送给开发者的业务服务器。
业务服务器调用 Apple API(update_two_bits 或 query_two_bits),验证 Token 并读写状态。
四、逆向分析:揭秘 devicecheckd
通过对 devicecheckd 二进制文件的静态分析与动态调试,分析其核心加密流程。
4.1 关键函数定位
在 App 二进制中搜索客户端获取DeviceCheckenToken调用的api,定位到 [DCDevice generateTokenWithCompletionHandler:]
然后再一步调试到关键方法,但这种方式比较慢,还有一种更方便的方式,根据日志输出字符串定位,下面是生成token过程中输出的日志:
Generating certificate...Fetched remote public key...Encrypting data...Certificate issued, processing..Using synced timestampReturning cached certificates-[MAAssetQuery getResultsFromMessage:]: Got the query meta data reply for: com.apple.MobileAsset.DeviceCheck, response: 0Falling back to locally cached key... Asset fetch failed: Error Domain=com.apple.twobit.fetcherror Code=-3100
void __fastcall __37__DCCryptoProxyImpl__fetchPublicKey___block_invoke(__int64 a1, void *a2, void *a3){ id v5; // x19 id v6; // x20 void *v7; // x23 __int64 v8; // x0 __int64 v9; // x0 NSObject *v10; // x22 _BOOL4 v11; // w0 __int64 v12; // x22 __int64 v13; // x0 void *v14; // x21 int v15; // [xsp+0h] [xbp-50h] BYREF id v16; // [xsp+4h] [xbp-4Ch] v5 = objc_retain(a2); v6 = objc_retain(a3); v7 = (void *)objc_claimAutoreleasedReturnValue_1330(objc_msgSend(v5, "publicKey")); objc_release(v7); v9 = _DCLogSystem(v8); v10 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v9); v11 = os_log_type_enabled_1518(v10, OS_LOG_TYPE_DEFAULT); if ( v7 ) { if ( v11 ) { LOWORD(v15) = 0; _os_log_impl_1398(&dword_446A2E000, v10, OS_LOG_TYPE_DEFAULT, "Fetched remote public key...", (uint8_t *)&v15, 2u); } objc_release(v10); v12 = *(_QWORD *)(a1 + 32); v13 = objc_claimAutoreleasedReturnValue_1330(objc_msgSend(v5, "publicKey")); } else { if ( v11 ) { v15 = 138412290; v16 = v6; _os_log_impl_1398( &dword_446A2E000, v10, OS_LOG_TYPE_DEFAULT, "Falling back to locally cached key... Asset fetch failed: %@", (uint8_t *)&v15, 0xCu); } objc_release(v10); v12 = *(_QWORD *)(a1 + 32); v13 = objc_claimAutoreleasedReturnValue_1330(objc_msgSend(&OBJC_CLASS___NSData, "dataWithBytes:length:", &fallback_server_pubkey, 65)); } v14 = (void *)v13; (*(void (__fastcall **)(__int64, __int64))(v12 + 16))(v12, v13); objc_release(v14); objc_release(v6); objc_release(v5);}
尝试用 DCAssetFetcher/MobileAsset 拉最新的远程公钥,如果成功就用它;失败就用代码中默认密钥fallback_server_pubkey 常量,然后把选出来的公钥交回后续逻辑(DCCertificateGenerator 那边去做 ECDH)。
pub key0000000A9700B010 04 50 D9 34 FA 67 BC F6 F2 DF BF 960000000A9700B020 62 9E 0A 72 38 E9 20 5D 75 F2 8C FC D8 4F 35 A6 0000000A9700B030 59 2B BE 05 8A 9C 0F 8E DB CA 2A CB 67 EF B7 74 0000000A9700B040 97 1C A4 5F 7D 85 6A 69 4F B1 B9 C4 0B 94 FB 2E 0000000A9700B050 7A 5A 94 98 B0
这张证书属于哪一类身份 & 存在哪个抽屉KeychainLabel = "2bit-identity"KeychainAccessGroup = "2bit-identity"//生成配置信息id +[DCCryptoUtilities identityCertificateOptions](){ void *v0; // x19 __int64 v1; // x0 NSObject *v2; // x20 void *v3; // x22 void *v4; // x23 void *v5; // x24 void *v6; // x21 void *v7; // x22 __CFString *v9; // [xsp+0h] [xbp-A0h] BYREF _QWORD v10[6]; // [xsp+8h] [xbp-98h] BYREF _QWORD v11[6]; // [xsp+38h] [xbp-68h] BYREF __int64 vars8; // [xsp+A8h] [xbp+8h] v0 = objc_msgSend(&OBJC_CLASS___DCCryptoUtilities, "generateTTL"); v1 = _DCLogSystem(v0); v2 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v1); if ( os_log_type_enabled_1518(v2, OS_LOG_TYPE_DEBUG) ) +[DCCryptoUtilities identityCertificateOptions].cold.1(v0, v2); objc_release(v2); v10[0] = CFSTR("Validity"); v3 = (void *)objc_claimAutoreleasedReturnValue_1330(objc_msgSend(&OBJC_CLASS___NSNumber, "numberWithUnsignedInt:", v0)); v11[0] = v3; v11[1] = &__kCFBooleanFalse; v10[1] = CFSTR("scrtAttestation"); v10[2] = CFSTR("KeychainLabel"); v11[2] = CFSTR("2bit-identity"); v11[3] = CFSTR("2bit-identity"); v10[3] = CFSTR("KeychainAccessGroup"); v10[4] = CFSTR("IgnoreExistingKeychainItems"); v11[4] = &__kCFBooleanFalse; v10[5] = CFSTR("OIDSToInclude"); v9 = CFSTR("1.2.840.113635.100.10.1"); v4 = (void *)objc_claimAutoreleasedReturnValue_1330(objc_msgSend(&OBJC_CLASS___NSArray, "arrayWithObjects:count:", &v9, 1)); v11[5] = v4; v5 = (void *)objc_claimAutoreleasedReturnValue_1330(objc_msgSend(&OBJC_CLASS___NSDictionary, "dictionaryWithObjects:forKeys:count:", v11, v10, 6)); v6 = (void *)objc_claimAutoreleasedReturnValue_1330(objc_msgSend(&OBJC_CLASS___NSMutableDictionary, "dictionaryWithDictionary:", v5)); objc_release(v5); objc_release(v4); objc_release(v3); if ( (unsigned int)os_variant_allows_internal_security_policies_55(0) ) { v7 = objc_msgSend( objc_alloc((Class)&OBJC_CLASS___NSUserDefaults), "initWithSuiteName:", CFSTR("com.apple.DeviceCheck")); if ( (unsigned int)objc_msgSend(v7, "boolForKey:", CFSTR("DCIgnoreExistingKeychainItems")) ) objc_msgSend(v6, "setObject:forKeyedSubscript:", &__kCFBooleanTrue, CFSTR("IgnoreExistingKeychainItems")); objc_release(v7); } if ( (DeviceIdentityUCRTAttestationSupported_1() & 1) == 0 ) objc_msgSend(v6, "setObject:forKeyedSubscript:", &__kCFBooleanTrue, CFSTR("scrtAttestation")); objc_msgSend(v6, "setObject:forKeyedSubscript:", &__kCFBooleanTrue, CFSTR("ReturnReferenceDate")); if ( ((vars8 ^ (2 * vars8)) & 0x4000000000000000LL) != 0 ) __break(0xC471u); return objc_autoreleaseReturnValue(v6);}//开始读取void __fastcall __DeviceIdentityIssueClientCertificateWithCompletion_block_invoke(__int64 a1){ __int64 v2; // x5 __int64 v3; // x6 __int64 v4; // x7 NSObject *v5; // x20 dispatch_queue_global_t global_queue_364; // x0 __int64 v7; // x19 __int64 v8; // x5 __int64 v9; // x6 __int64 v10; // x7 __SecTask *v11; // x0 __int64 v12; // x5 __int64 v13; // x6 __int64 v14; // x7 __SecTask *v15; // x23 __int64 v16; // x5 __int64 v17; // x6 __int64 v18; // x7 __int64 v19; // x0 void *v20; // x21 unsigned __int8 v21; // w22 void *v22; // x0 id *v23; // x28 void *v24; // x21 __int64 v25; // x0 void *v26; // x22 void *v27; // x21 void *v28; // x22 __int64 v29; // x0 void *v30; // x22 unsigned __int8 v31; // w25 id MobileActivationError_0; // x0 __int64 v33; // x0 id v34; // x0 id v35; // x21 CFDictionaryRef v36; // x25 CFDataRef v37; // x28 void *v38; // x22 void *v39; // x27 __int64 v40; // x8 void *v41; // x26 void *v42; // x9 __int64 *v43; // x8 const void *v44; // x0 __int64 *v45; // x8 const void *v46; // x0 __int64 *v47; // x8 const void *v48; // x0 __int64 *v49; // x8 const void *v50; // x0 __int64 *v51; // x8 const void *v52; // x0 id v53; // x26 id *v54; // x19 id v55; // x0 CFErrorRef v56; // x21 __int64 v57; // x5 __int64 v58; // x6 __int64 v59; // x7 id v60; // x0 __int64 v61; // x0 __int64 v62; // x8 void *v63; // x9 id v64; // x0 bool v65; // w25 __int64 v66; // x5 __int64 v67; // x6 __int64 v68; // x7 char v69; // w26 __int64 v70; // x0 __int64 v71; // x5 __int64 v72; // x6 __int64 v73; // x7 __int64 v74; // x0 __int64 v75; // x5 __int64 v76; // x6 __int64 v77; // x7 __int64 v78; // x21 __int64 v79; // x0 __int64 v80; // x5 __int64 v81; // x6 __int64 v82; // x7 const __CFData *v83; // x21 SecCertificateRef v84; // x0 __int64 v85; // x5 __int64 v86; // x6 __int64 v87; // x7 const __CFData *v88; // x21 SecCertificateRef v89; // x0 __int64 v90; // x5 __int64 v91; // x6 __int64 v92; // x7 id v93; // x0 CFErrorRef v94; // x19 __int64 v95; // x5 __int64 v96; // x6 __int64 v97; // x7 id v98; // x0 __int64 v99; // x0 __int64 v100; // x8 void *v101; // x9 __int64 v102; // x19 __int64 v103; // x5 __int64 v104; // x6 __int64 v105; // x7 __int64 v106; // x19 void *v107; // x3 id *v108; // x19 void *v109; // t1 id v110; // x0 double v111; // d8 __int64 v112; // x5 __int64 v113; // x6 __int64 v114; // x7 __int64 v115; // x19 void *v116; // x3 id *v117; // x19 void *v118; // t1 id v119; // x0 void *v120; // x25 unsigned __int8 v121; // w26 void *v122; // x21 void *v123; // x22 void *v124; // x25 void *v125; // x26 void *v126; // x27 __int64 v127; // x5 __int64 v128; // x6 __int64 v129; // x7 id v130; // x0 int v131; // w21 void *v132; // x3 id v133; // x0 id v134; // x0 id v135; // x0 id v136; // x0 __int64 v137; // x5 __int64 v138; // x6 __int64 v139; // x7 __int64 v140; // x5 __int64 v141; // x6 __int64 v142; // x7 id v143; // x0 void *v144; // x9 __int64 v145; // x5 __int64 v146; // x6 __int64 v147; // x7 __int64 v148; // x5 __int64 v149; // x6 __int64 v150; // x7 CFDataRef v151; // x21 __int64 v152; // x5 __int64 v153; // x6 __int64 v154; // x7 __int64 v155; // x0 __int64 v156; // x21 char v157; // w22 __int64 v158; // x5 __int64 v159; // x6 __int64 v160; // x7 id v161; // x0 void *v162; // x22 __int64 v163; // x0 void *v164; // x21 __int64 v165; // x22 void *v166; // x21 __int64 v167; // x0 void *v168; // x19 void *v169; // x22 __int64 v170; // x5 __int64 v171; // x6 __int64 v172; // x7 id v173; // x0 __int64 v174; // x0 __int64 v175; // x0 void *v176; // x9 __int64 v177; // x5 __int64 v178; // x6 __int64 v179; // x7 void *v180; // x0 __int64 v181; // x0 __int64 v182; // x0 void *v183; // x9 __int64 v184; // x5 __int64 v185; // x6 __int64 v186; // x7 void *v187; // x0 __int64 v188; // x0 __int64 v189; // x0 void *v190; // x9 void *v191; // x0 id v192; // x0 void *v193; // x0 void *v194; // x9 id v195; // x0 id v196; // x0 id v197; // x0 id v198; // x0 id v199; // x0 void *v200; // x21 __int64 v201; // x0 void *v202; // x22 __int64 v203; // x5 __int64 v204; // x6 __int64 v205; // x7 id v206; // x0 void *v207; // x21 __int64 v208; // x0 void *v209; // x22 __int64 v210; // x0 __CFString *v211; // x0 void *v212; // x21 __int64 v213; // x0 void *v214; // x22 void *v215; // x21 unsigned int v216; // w19 void *v217; // x22 __int64 v218; // x5 __int64 v219; // x6 __int64 v220; // x7 id v221; // x0 void *v222; // x22 __int64 v223; // x0 void *v224; // x25 __int64 v225; // x5 __int64 v226; // x6 __int64 v227; // x7 id v228; // x0 void *v229; // x25 __int64 v230; // x0 void *v231; // x26 __int64 v232; // x5 __int64 v233; // x6 __int64 v234; // x7 id v235; // x0 void *v236; // x22 CFTypeID v237; // x25 CFTypeID TypeID_4; // x26 void *v239; // x22 __int64 v240; // x0 void *v241; // x25 void *v242; // x21 void *v243; // x22 __int64 v244; // x0 void *v245; // x25 void *v246; // x21 void *v247; // x25 __int64 v248; // x0 void *v249; // x26 void *v250; // x21 void *v251; // x21 __int64 v252; // x0 void *v253; // x26 void *v254; // x21 __int64 v255; // x0 void *v256; // x26 __int64 v257; // x5 __int64 v258; // x6 __int64 v259; // x7 void *v260; // x25 __int64 v261; // x0 void *v262; // x26 void *v263; // x21 unsigned int v264; // w27 void *v265; // x25 __int64 v266; // x0 void *v267; // x26 void *v268; // x21 unsigned int v269; // w22 void *v270; // x25 __int64 v271; // x0 void *v272; // x26 void *v273; // x19 __int64 v274; // x26 __int64 v275; // x27 __int64 v276; // x22 __int64 v277; // x19 __int64 v278; // x0 id v279; // x0 void *v280; // x21 __int64 v281; // x0 __int64 v282; // x5 __int64 v283; // x6 __int64 v284; // x7 __int64 v285; // x5 __int64 v286; // x6 __int64 v287; // x7 id v288; // x0 id v289; // x0 id v290; // x0 id v291; // x0 __int64 v292; // x0 __int64 v293; // x8 void *v294; // x9 __int64 v295; // x0 __int64 v296; // x25 __int64 v297; // x21 int valid; // w28 __int64 v299; // x0 __int64 v300; // x21 int v301; // w28 __int64 v302; // x21 char v303; // w28 id v304; // x0 __int64 v305; // x0 __int64 v306; // x8 void *v307; // x9 id v308; // x0 void *v309; // x8 __int64 *v310; // x8 const void *v311; // x0 __int64 *v312; // x8 const void *v313; // x0 __int64 *v314; // x8 const void *v315; // x0 __int64 v316; // x8 void *v317; // x9 double v318; // d0 void *v319; // x0 __int64 v320; // x0 char v321; // w19 void *v322; // x8 __int64 v323; // x0 __int64 v324; // x21 __int64 v325; // x21 double v326; // d8 double v327; // d9 double v328; // d0 int v329; // w25 int v330; // w8 id v331; // x0 __int64 v332; // x0 const void *v333; // x0 __SecKey *v334; // x25 __int64 v335; // x2 __int64 v336; // x26 __int64 v337; // x5 __int64 v338; // x6 __int64 v339; // x7 __SecKey *v340; // x0 __int64 v341; // x5 __int64 v342; // x6 __int64 v343; // x7 __int64 v344; // x5 __int64 v345; // x6 __int64 v346; // x7 CFDictionaryRef v347; // x0 __int64 v348; // x5 __int64 v349; // x6 __int64 v350; // x7 __int64 v351; // x5 __int64 v352; // x6 __int64 v353; // x7 void *v354; // x26 dispatch_queue_global_t v355; // x0 __CFString *v356; // x0 __int64 v357; // x8 id v358; // x0 id v359; // x0 id v360; // x0 id v361; // x0 __int64 v362; // x9 void *v363; // x8 const void *v364; // x0 CFTypeRef v365; // x0 id v366; // x0 void *v367; // x0 void *v368; // x0 void *v369; // x0 __int64 v370; // x19 void *v371; // x0 id v372; // x0 __int64 v373; // x8 id v374; // x19 id v375; // x0 id v376; // x0 id v377; // x0 id v378; // x0 id v379; // x0 id v380; // x0 __int64 v381; // x9 __int64 *v382; // x8 __int64 *v383; // x9 char v384; // [xsp+0h] [xbp-680h] void *v385; // [xsp+18h] [xbp-668h] id v386; // [xsp+20h] [xbp-660h] void *v387; // [xsp+28h] [xbp-658h] id v388; // [xsp+30h] [xbp-650h] __int64 v389; // [xsp+38h] [xbp-648h] void *v390; // [xsp+38h] [xbp-648h] int v391; // [xsp+40h] [xbp-640h] unsigned int v392; // [xsp+40h] [xbp-640h] __int64 v393; // [xsp+40h] [xbp-640h] void *v394; // [xsp+40h] [xbp-640h] _BOOL4 v395; // [xsp+48h] [xbp-638h] void *v396; // [xsp+48h] [xbp-638h] _BOOL4 v397; // [xsp+50h] [xbp-630h] void *v398; // [xsp+50h] [xbp-630h] _BOOL4 v399; // [xsp+58h] [xbp-628h] id v400; // [xsp+58h] [xbp-628h] void *queue; // [xsp+60h] [xbp-620h] _BOOL4 queuea; // [xsp+60h] [xbp-620h] unsigned int queueb; // [xsp+60h] [xbp-620h] NSObject *queuec; // [xsp+60h] [xbp-620h] id queued; // [xsp+60h] [xbp-620h] id v406; // [xsp+68h] [xbp-618h] void *v407; // [xsp+70h] [xbp-610h] id v408; // [xsp+78h] [xbp-608h] void *v409; // [xsp+80h] [xbp-600h] id v410; // [xsp+88h] [xbp-5F8h] id v411; // [xsp+90h] [xbp-5F0h] void *v412; // [xsp+98h] [xbp-5E8h] id v413; // [xsp+A0h] [xbp-5E0h] CFDataRef v414; // [xsp+A8h] [xbp-5D8h] unsigned int v415; // [xsp+A8h] [xbp-5D8h] unsigned int v416; // [xsp+A8h] [xbp-5D8h] id v417; // [xsp+B0h] [xbp-5D0h] id v418; // [xsp+B8h] [xbp-5C8h] id v419; // [xsp+C0h] [xbp-5C0h] unsigned __int8 v420; // [xsp+C0h] [xbp-5C0h] void *v421; // [xsp+C8h] [xbp-5B8h] __CFString *v422; // [xsp+D0h] [xbp-5B0h] void *cf; // [xsp+D8h] [xbp-5A8h] void *cfa; // [xsp+D8h] [xbp-5A8h] id v425; // [xsp+E0h] [xbp-5A0h] _QWORD block[4]; // [xsp+E8h] [xbp-598h] BYREF _QWORD v427[4]; // [xsp+108h] [xbp-578h] BYREF _QWORD v428[4]; // [xsp+128h] [xbp-558h] BYREF id v429; // [xsp+148h] [xbp-538h] BYREF __CFString *v430; // [xsp+150h] [xbp-530h] id v431; // [xsp+158h] [xbp-528h] id v432; // [xsp+160h] [xbp-520h] id v433; // [xsp+168h] [xbp-518h] id v434; // [xsp+170h] [xbp-510h] id v435; // [xsp+178h] [xbp-508h] id v436; // [xsp+180h] [xbp-500h] id v437; // [xsp+188h] [xbp-4F8h] id v438; // [xsp+190h] [xbp-4F0h] id v439; // [xsp+198h] [xbp-4E8h] id v440; // [xsp+1A0h] [xbp-4E0h] id v441; // [xsp+1A8h] [xbp-4D8h] NSObject *v442; // [xsp+1B0h] [xbp-4D0h] id v443; // [xsp+1B8h] [xbp-4C8h] __int64 v444; // [xsp+1C0h] [xbp-4C0h] _QWORD *v445; // [xsp+1C8h] [xbp-4B8h] __int64 *v446; // [xsp+1D0h] [xbp-4B0h] __int64 *v447; // [xsp+1D8h] [xbp-4A8h] __int64 *v448; // [xsp+1E0h] [xbp-4A0h] __int64 *v449; // [xsp+1E8h] [xbp-498h] __int64 *v450; // [xsp+1F0h] [xbp-490h] __int64 *v451; // [xsp+1F8h] [xbp-488h] __int64 *v452; // [xsp+200h] [xbp-480h] __int64 *v453; // [xsp+208h] [xbp-478h] __int64 *v454; // [xsp+210h] [xbp-470h] __int64 *v455; // [xsp+218h] [xbp-468h] __int64 *v456; // [xsp+220h] [xbp-460h] __int64 *v457; // [xsp+228h] [xbp-458h] __int64 *v458; // [xsp+230h] [xbp-450h] __int64 *v459; // [xsp+238h] [xbp-448h] __int64 *v460; // [xsp+240h] [xbp-440h] __int64 *v461; // [xsp+248h] [xbp-438h] bool v462; // [xsp+250h] [xbp-430h] id v463; // [xsp+258h] [xbp-428h] BYREF id v464; // [xsp+260h] [xbp-420h] id v465; // [xsp+268h] [xbp-418h] BYREF id v466; // [xsp+270h] [xbp-410h] BYREF id v467; // [xsp+278h] [xbp-408h] BYREF id obj; // [xsp+280h] [xbp-400h] BYREF id v469; // [xsp+288h] [xbp-3F8h] BYREF id v470; // [xsp+290h] [xbp-3F0h] BYREF id v471; // [xsp+298h] [xbp-3E8h] BYREF __int64 v472; // [xsp+2A0h] [xbp-3E0h] BYREF double *v473; // [xsp+2A8h] [xbp-3D8h] __int64 v474; // [xsp+2B0h] [xbp-3D0h] __int64 v475; // [xsp+2B8h] [xbp-3C8h] __int64 v476; // [xsp+2C0h] [xbp-3C0h] BYREF __int64 *v477; // [xsp+2C8h] [xbp-3B8h] __int64 v478; // [xsp+2D0h] [xbp-3B0h] int v479; // [xsp+2D8h] [xbp-3A8h] int v480; // [xsp+2E4h] [xbp-39Ch] BYREF double v481; // [xsp+2E8h] [xbp-398h] BYREF __int64 v482; // [xsp+2F0h] [xbp-390h] BYREF double *v483; // [xsp+2F8h] [xbp-388h] __int64 v484; // [xsp+300h] [xbp-380h] __int64 v485; // [xsp+308h] [xbp-378h] __int64 v486; // [xsp+310h] [xbp-370h] BYREF __int64 *v487; // [xsp+318h] [xbp-368h] __int64 v488; // [xsp+320h] [xbp-360h] __int64 (__fastcall *v489)(); // [xsp+328h] [xbp-358h] __int64 (__fastcall *v490)(); // [xsp+330h] [xbp-350h] id v491; // [xsp+338h] [xbp-348h] __int64 v492; // [xsp+340h] [xbp-340h] BYREF __int64 *v493; // [xsp+348h] [xbp-338h] __int64 v494; // [xsp+350h] [xbp-330h] __int64 (__fastcall *v495)(); // [xsp+358h] [xbp-328h] __int64 (__fastcall *v496)(); // [xsp+360h] [xbp-320h] id v497; // [xsp+368h] [xbp-318h] __int64 v498; // [xsp+370h] [xbp-310h] BYREF __int64 *v499; // [xsp+378h] [xbp-308h] __int64 v500; // [xsp+380h] [xbp-300h] __int64 (__fastcall *v501)(); // [xsp+388h] [xbp-2F8h] __int64 (__fastcall *v502)(); // [xsp+390h] [xbp-2F0h] id v503; // [xsp+398h] [xbp-2E8h] __int64 v504; // [xsp+3A0h] [xbp-2E0h] BYREF __int64 *v505; // [xsp+3A8h] [xbp-2D8h] __int64 v506; // [xsp+3B0h] [xbp-2D0h] __int64 (__fastcall *v507)(); // [xsp+3B8h] [xbp-2C8h] __int64 (__fastcall *v508)(); // [xsp+3C0h] [xbp-2C0h] id v509; // [xsp+3C8h] [xbp-2B8h] __int64 v510; // [xsp+3D0h] [xbp-2B0h] BYREF __int64 *v511; // [xsp+3D8h] [xbp-2A8h] __int64 v512; // [xsp+3E0h] [xbp-2A0h] __int64 (__fastcall *v513)(); // [xsp+3E8h] [xbp-298h] __int64 (__fastcall *v514)(); // [xsp+3F0h] [xbp-290h] id v515; // [xsp+3F8h] [xbp-288h] __int64 v516; // [xsp+400h] [xbp-280h] BYREF __int64 *v517; // [xsp+408h] [xbp-278h] __int64 v518; // [xsp+410h] [xbp-270h] __int64 (__fastcall *v519)(); // [xsp+418h] [xbp-268h] __int64 (__fastcall *v520)(); // [xsp+420h] [xbp-260h] id v521; // [xsp+428h] [xbp-258h] int v522; // [xsp+434h] [xbp-24Ch] BYREF __int64 v523; // [xsp+438h] [xbp-248h] BYREF __int64 *v524; // [xsp+440h] [xbp-240h] __int64 v525; // [xsp+448h] [xbp-238h] __int64 v526; // [xsp+450h] [xbp-230h] __int64 v527; // [xsp+458h] [xbp-228h] BYREF __int64 *v528; // [xsp+460h] [xbp-220h] __int64 v529; // [xsp+468h] [xbp-218h] __int64 v530; // [xsp+470h] [xbp-210h] CFErrorRef error; // [xsp+478h] [xbp-208h] BYREF __int64 v532; // [xsp+480h] [xbp-200h] BYREF __int64 *v533; // [xsp+488h] [xbp-1F8h] __int64 v534; // [xsp+490h] [xbp-1F0h] __int64 v535; // [xsp+498h] [xbp-1E8h] __int64 v536; // [xsp+4A0h] [xbp-1E0h] BYREF __int64 *v537; // [xsp+4A8h] [xbp-1D8h] __int64 v538; // [xsp+4B0h] [xbp-1D0h] __int64 v539; // [xsp+4B8h] [xbp-1C8h] __int64 v540; // [xsp+4C0h] [xbp-1C0h] BYREF __int64 *v541; // [xsp+4C8h] [xbp-1B8h] __int64 v542; // [xsp+4D0h] [xbp-1B0h] __int64 v543; // [xsp+4D8h] [xbp-1A8h] __int64 v544; // [xsp+4E0h] [xbp-1A0h] BYREF __int64 *v545; // [xsp+4E8h] [xbp-198h] __int64 v546; // [xsp+4F0h] [xbp-190h] __int64 v547; // [xsp+4F8h] [xbp-188h] __int64 v548; // [xsp+500h] [xbp-180h] BYREF id *v549; // [xsp+508h] [xbp-178h] __int64 v550; // [xsp+510h] [xbp-170h] __int64 (__fastcall *v551)(); // [xsp+518h] [xbp-168h] __int64 (__fastcall *v552)(); // [xsp+520h] [xbp-160h] id v553; // [xsp+528h] [xbp-158h] _QWORD v554[5]; // [xsp+530h] [xbp-150h] BYREF id v555; // [xsp+558h] [xbp-128h] uint8_t buf[4]; // [xsp+560h] [xbp-120h] BYREF void *v557; // [xsp+564h] [xbp-11Ch] __int16 v558; // [xsp+56Ch] [xbp-114h] id v559; // [xsp+56Eh] [xbp-112h] __int16 v560; // [xsp+576h] [xbp-10Ah] id v561; // [xsp+578h] [xbp-108h] __int16 v562; // [xsp+580h] [xbp-100h] void *v563; // [xsp+582h] [xbp-FEh] __int16 v564; // [xsp+58Ah] [xbp-F6h] id v565; // [xsp+58Ch] [xbp-F4h] __int16 v566; // [xsp+594h] [xbp-ECh] id v567; // [xsp+596h] [xbp-EAh] __int16 v568; // [xsp+59Eh] [xbp-E2h] __int64 v569; // [xsp+5A0h] [xbp-E0h] __int64 v570; // [xsp+5B0h] [xbp-D0h] _QWORD v571[3]; // [xsp+5B8h] [xbp-C8h] BYREF __int64 v572; // [xsp+5D0h] [xbp-B0h] BYREF __CFString *v573; // [xsp+5D8h] [xbp-A8h] BYREF void *v574; // [xsp+5E0h] [xbp-A0h] BYREF __CFString *v575; // [xsp+5E8h] [xbp-98h] BYREF void *v576; // [xsp+5F0h] [xbp-90h] BYREF v554[0] = 0; v554[1] = v554; v554[2] = 0x3032000000LL; v554[3] = __Block_byref_object_copy__4684; v554[4] = __Block_byref_object_dispose__4684; v555 = 0; v548 = 0; v549 = (id *)&v548; v550 = 0x3032000000LL; v551 = __Block_byref_object_copy__4684; v552 = __Block_byref_object_dispose__4684; v553 = 0; v544 = 0; v545 = &v544; v546 = 0x2020000000LL; v547 = 0; v540 = 0; v541 = &v540; v542 = 0x2020000000LL; v543 = 0; v536 = 0; v537 = &v536; v538 = 0x2020000000LL; v539 = 0; v532 = 0; v533 = &v532; v534 = 0x2020000000LL; v535 = 0; error = 0; v527 = 0; v528 = &v527; v529 = 0x2020000000LL; v530 = 0; v523 = 0; v524 = &v523; v525 = 0x2020000000LL; v526 = 0; v522 = -1; v516 = 0; v517 = &v516; v518 = 0x3032000000LL; v519 = __Block_byref_object_copy__4684; v520 = __Block_byref_object_dispose__4684; v521 = 0; v510 = 0; v511 = &v510; v512 = 0x3032000000LL; v513 = __Block_byref_object_copy__4684; v514 = __Block_byref_object_dispose__4684; v515 = 0; v504 = 0; v505 = &v504; v506 = 0x3032000000LL; v507 = __Block_byref_object_copy__4684; v508 = __Block_byref_object_dispose__4684; v509 = 0; v498 = 0; v499 = &v498; v500 = 0x3032000000LL; v501 = __Block_byref_object_copy__4684; v502 = __Block_byref_object_dispose__4684; v503 = 0; v492 = 0; v493 = &v492; v494 = 0x3032000000LL; v495 = __Block_byref_object_copy__4684; v496 = __Block_byref_object_dispose__4684; v497 = 0; v486 = 0; v487 = &v486; v488 = 0x3032000000LL; v489 = __Block_byref_object_copy__4684; v490 = __Block_byref_object_dispose__4684; v491 = 0; v482 = 0; v483 = (double *)&v482; v484 = 0x2020000000LL; v485 = 0; v481 = 0.0; v480 = 0; v476 = 0; v477 = &v476; v478 = 0x2020000000LL; v479 = 0; v472 = 0; v473 = (double *)&v472; v474 = 0x2020000000LL; v475 = 0; v5 = (NSObject *)objc_retain(*(id *)(a1 + 32)); if ( !v5 ) { global_queue_364 = j__dispatch_get_global_queue_364(0, 0); v7 = objc_claimAutoreleasedReturnValue_556(global_queue_364); objc_release(0); v5 = (NSObject *)v7; } if ( !*(_QWORD *)(a1 + 48) ) { MobileActivationError_0 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 989, -1, 0, CFSTR("Invalid input."), v2, v3, v4, v384); v33 = objc_claimAutoreleasedReturnValue_556(MobileActivationError_0);LABEL_20: v425 = 0;LABEL_21: v35 = 0; v421 = 0; v422 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; v417 = 0; v408 = 0; v409 = 0; v410 = 0; v411 = 0; v412 = 0; v413 = 0; v418 = 0; v419 = 0; cf = 0; v15 = 0;LABEL_22: v406 = 0; v407 = 0;LABEL_23: v40 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v41 = *(void **)(v40 + 40); *(_QWORD *)(v40 + 40) = v33; goto LABEL_24; } v425 = objc_alloc_init((Class)off_41CEDE910); if ( !v425 ) { v34 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 995, -1, 0, CFSTR("Failed to allocate array."), v8, v9, v10, v384); v33 = objc_claimAutoreleasedReturnValue_556(v34); goto LABEL_20; } v11 = SecTaskCreateFromSelf_87(0); v15 = v11; if ( !v11 ) { v55 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1003, -1, 0, CFSTR("Failed to create task."), v12, v13, v14, v384); v33 = objc_claimAutoreleasedReturnValue_556(v55); goto LABEL_21; } v422 = (__CFString *)SecTaskCopySigningIdentifier_25(v11, &error); if ( !v422 ) { v64 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1009, -1, error, CFSTR("Failed to query code signing identifier."), v16, v17, v18, v384); v33 = objc_claimAutoreleasedReturnValue_556(v64); v35 = 0; v421 = 0; v422 = 0;LABEL_47: v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; v417 = 0; v408 = 0; v409 = 0; v410 = 0; v411 = 0; v412 = 0; v413 = 0; v418 = 0; v419 = 0;LABEL_48: cf = 0; goto LABEL_22; } v421 = (void *)SecTaskCopyValueForEntitlement_98(v15, CFSTR("com.apple.mobileactivationd.spi"), &error); v19 = isNSNumber_0(v421); v20 = (void *)objc_claimAutoreleasedReturnValue_556(v19); if ( !v20 || (v21 = (unsigned __int8)objc_msgSend(v421, "boolValue"), objc_release(v20), (v21 & 1) == 0) ) { v56 = error; v575 = CFSTR("com.apple.mobileactivationd.spi"); v576 = &__kCFBooleanTrue; v41 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE908, "dictionaryWithObjects:forKeys:count:", &v576, &v575, 1)); v60 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1015, -7, v56, CFSTR("Missing required entitlement: %@"), v57, v58, v59, (char)v41); v61 = objc_claimAutoreleasedReturnValue_556(v60);LABEL_45: v62 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v63 = *(void **)(v62 + 40); *(_QWORD *)(v62 + 40) = v61; objc_release(v63); v35 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; v417 = 0; v408 = 0; v409 = 0; v410 = 0; v411 = 0; v412 = 0; v413 = 0; v418 = 0; v419 = 0; cf = 0; v406 = 0; v407 = 0; goto LABEL_24; } v23 = (id *)(a1 + 40); v22 = *(void **)(a1 + 40); if ( !v22 ) { queuea = 0; v395 = 0; v418 = 0; v419 = 0; v65 = 0; v399 = 0; v406 = 0; v407 = 0; v412 = 0; v413 = 0; v409 = 0; v410 = 0; v417 = 0; v411 = 0; v408 = 0; cf = 0; v397 = 1; goto LABEL_50; } v24 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(v22, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v25 = isNSArray(); v26 = (void *)objc_claimAutoreleasedReturnValue_556(v25); objc_release(v26); objc_release(v24); if ( v26 ) { v27 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); if ( ((unsigned int)objc_msgSend(v27, "containsObject:", CFSTR("1.2.840.113635.100.10.1")) & 1) == 0 ) { v28 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); if ( !(unsigned int)objc_msgSend(v28, "containsObject:", CFSTR("1.2.840.113635.100.8.1")) ) { v120 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v121 = (unsigned __int8)objc_msgSend(v120, "containsObject:", CFSTR("1.2.840.113635.100.8.3")); objc_release(v120); objc_release(v28); objc_release(v27); if ( (v121 & 1) == 0 ) goto LABEL_71; goto LABEL_15; } objc_release(v28); } objc_release(v27);LABEL_15: queue = (void *)SecTaskCopyValueForEntitlement_98( v15, CFSTR("com.apple.mobileactivationd.device-identifiers"), &error); objc_release(v421); v29 = isNSNumber_0(queue); v30 = (void *)objc_claimAutoreleasedReturnValue_556(v29); if ( !v30 || (v31 = (unsigned __int8)objc_msgSend(queue, "boolValue"), objc_release(v30), (v31 & 1) == 0) ) { v94 = error; v573 = CFSTR("com.apple.mobileactivationd.device-identifiers"); v574 = &__kCFBooleanTrue; v41 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE908, "dictionaryWithObjects:forKeys:count:", &v574, &v573, 1)); v98 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1028, -7, v94, CFSTR("Missing required entitlement: %@"), v95, v96, v97, (char)v41); v99 = objc_claimAutoreleasedReturnValue_556(v98); v100 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v101 = *(void **)(v100 + 40); *(_QWORD *)(v100 + 40) = v99; objc_release(v101); v35 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; v417 = 0; v408 = 0; v409 = 0; v410 = 0; v411 = 0; v412 = 0; v413 = 0; v418 = 0; v419 = 0; cf = 0; v406 = 0; v407 = 0; v421 = queue; goto LABEL_24; } v421 = queue;LABEL_71: v122 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); if ( ((unsigned int)objc_msgSend(v122, "containsObject:", CFSTR("1.2.840.113635.100.8.9.1")) & 1) != 0 ) {LABEL_80: objc_release(v122);LABEL_81: v41 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v130 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1039, -2, 0, CFSTR("This API does not support Enterprise Device Attestation OIDs: %@"), v127, v128, v129, (char)v41); v61 = objc_claimAutoreleasedReturnValue_556(v130); goto LABEL_45; } v123 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); if ( ((unsigned int)objc_msgSend(v123, "containsObject:", CFSTR("1.2.840.113635.100.8.9.2")) & 1) != 0 ) {LABEL_79: objc_release(v123); goto LABEL_80; } v124 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); if ( ((unsigned int)objc_msgSend(v124, "containsObject:", CFSTR("1.2.840.113635.100.8.10.1")) & 1) != 0 ) {LABEL_78: objc_release(v124); goto LABEL_79; } v125 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); if ( ((unsigned int)objc_msgSend(v125, "containsObject:", CFSTR("1.2.840.113635.100.8.10.2")) & 1) != 0 ) {LABEL_77: objc_release(v125); goto LABEL_78; } v126 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); if ( ((unsigned int)objc_msgSend(v126, "containsObject:", CFSTR("1.2.840.113635.100.8.10.3")) & 1) != 0 ) { objc_release(v126); goto LABEL_77; } cfa = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v420 = (unsigned __int8)objc_msgSend(cfa, "containsObject:", CFSTR("1.2.840.113635.100.8.11.1")); objc_release(cfa); objc_release(v126); objc_release(v125); objc_release(v124); objc_release(v123); objc_release(v122); if ( (v420 & 1) != 0 ) goto LABEL_81; v168 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); if ( ((unsigned int)objc_msgSend(v168, "containsObject:", CFSTR("1.2.840.113635.100.8.6")) & 1) != 0 ) { v169 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("AccessControls"))); objc_release(v169); objc_release(v168); if ( !v169 ) { v173 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1044, -2, 0, CFSTR("Missing required option: %@"), v170, v171, v172, (char)CFSTR("AccessControls")); v33 = objc_claimAutoreleasedReturnValue_556(v173);LABEL_139: v35 = 0; goto LABEL_47; } } else { objc_release(v168); } } v200 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("KeychainLabel"))); v201 = isNSString_0(); v202 = (void *)objc_claimAutoreleasedReturnValue_556(v201); objc_release(v202); objc_release(v200); if ( v202 ) { if ( (isRunningInRootLaunchdContext() & 1) != 0 || (isRunningInRecovery() & 1) != 0 || (unsigned int)isRunningInDiagnosticsMode() ) { v206 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1058, -2, 0, CFSTR("Option (%@) not allowed for processes running in the system context or diagnostics mode."), v203, v204, v205, (char)CFSTR("KeychainLabel")); v33 = objc_claimAutoreleasedReturnValue_556(v206); goto LABEL_139; } v222 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("ClientAttestationData"))); v223 = isNSData_0(); v224 = (void *)objc_claimAutoreleasedReturnValue_556(v223); objc_release(v224); objc_release(v222); if ( v224 ) { v228 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1063, -2, 0, CFSTR("Keychain (%@) not supported with %@."), v225, v226, v227, (char)CFSTR("KeychainLabel")); v33 = objc_claimAutoreleasedReturnValue_556(v228); goto LABEL_139; } v418 = (id)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("KeychainLabel"))); v417 = (id)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE948, "stringWithFormat:", CFSTR("%@-rk"), v418)); v412 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE948, "stringWithFormat:", CFSTR("%@-leaf"), v418)); v409 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE948, "stringWithFormat:", CFSTR("%@-intermediate"), v418)); v413 = (id)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE948, "stringWithFormat:", CFSTR("%@-combined"), v418)); v411 = (id)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE948, "stringWithFormat:", CFSTR("%@-monotonic-clock"), v418)); v408 = (id)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE948, "stringWithFormat:", CFSTR("%@-server-timestamp"), v418)); v384 = (char)v418; v410 = (id)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE948, "stringWithFormat:", CFSTR("%@-rtc-reset-count"))); } else { v417 = 0; v418 = 0; v412 = 0; v413 = 0; v409 = 0; v410 = 0; v411 = 0; v408 = 0; } v207 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("KeychainAccessGroup"))); v208 = isNSString_0(); v209 = (void *)objc_claimAutoreleasedReturnValue_556(v208); objc_release(v209); objc_release(v207); if ( v209 ) v210 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("KeychainAccessGroup"))); else v210 = 0; if ( v418 && !v210 ) { v211 = objc_retain(v422); v210 = (__int64)v422; } v419 = (id)v210; v212 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("IgnoreExistingKeychainItems"))); v213 = isNSNumber_0(v212); v214 = (void *)objc_claimAutoreleasedReturnValue_556(v213); objc_release(v214); objc_release(v212); if ( v214 ) { v215 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("IgnoreExistingKeychainItems"))); v216 = (unsigned int)objc_msgSend(v215, "boolValue"); objc_release(v215); } else { v216 = 0; } v217 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("AccessControls"))); objc_release(v217); if ( !v217 ) goto LABEL_163; if ( (isRunningInRootLaunchdContext() & 1) != 0 || (isRunningInRecovery() & 1) != 0 || (unsigned int)isRunningInDiagnosticsMode() ) { v221 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1092, -2, 0, CFSTR("Option (%@) not allowed for processes running in the system context or diagnostics mode."), v218, v219, v220, (char)CFSTR("AccessControls")); v33 = objc_claimAutoreleasedReturnValue_556(v221);LABEL_155: v35 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; goto LABEL_48; } v229 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("ClientAttestationData"))); v230 = isNSData_0(); v231 = (void *)objc_claimAutoreleasedReturnValue_556(v230); objc_release(v231); objc_release(v229); if ( v231 ) { v235 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1097, -2, 0, CFSTR("ACLs (%@) not supported with %@."), v232, v233, v234, (char)CFSTR("AccessControls")); v33 = objc_claimAutoreleasedReturnValue_556(v235); goto LABEL_155; } v236 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("AccessControls"))); v237 = CFGetTypeID_254(v236); TypeID_4 = SecAccessControlGetTypeID_4(); objc_release(v236); if ( v237 == TypeID_4 ) { cf = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("AccessControls"))); objc_release(cf); CFRetain_262(cf); } else {LABEL_163: cf = 0; } v239 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("reuseExistingKey"))); v240 = isNSNumber_0(v239); v241 = (void *)objc_claimAutoreleasedReturnValue_556(v240); objc_release(v241); objc_release(v239); if ( v241 ) { v242 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("reuseExistingKey"))); v415 = (unsigned int)objc_msgSend(v242, "boolValue"); objc_release(v242); } else { v415 = 0; } v243 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("UseSoftwareGeneratedKey"))); v244 = isNSNumber_0(v243); v245 = (void *)objc_claimAutoreleasedReturnValue_556(v244); objc_release(v245); objc_release(v243); if ( v245 ) { v246 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("UseSoftwareGeneratedKey"))); queueb = (unsigned int)objc_msgSend(v246, "boolValue"); objc_release(v246); } else { queueb = 1; } v247 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("scrtAttestation"))); v248 = isNSNumber_0(v247); v249 = (void *)objc_claimAutoreleasedReturnValue_556(v248); objc_release(v249); objc_release(v247); if ( v249 ) { v250 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("scrtAttestation"))); v392 = (unsigned int)objc_msgSend(v250, "boolValue"); objc_release(v250); } else { v392 = 0; } v251 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("ClientAttestationData"))); v252 = isNSData_0(); v253 = (void *)objc_claimAutoreleasedReturnValue_556(v252); objc_release(v253); objc_release(v251); if ( v253 ) { v254 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("ClientAttestationPublicKey"))); v255 = isNSData_0(); v256 = (void *)objc_claimAutoreleasedReturnValue_556(v255); objc_release(v256); objc_release(v254); if ( !v256 ) { v279 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1121, -2, 0, CFSTR("Missing required option for %@."), v257, v258, v259, (char)CFSTR("ClientAttestationPublicKey")); v33 = objc_claimAutoreleasedReturnValue_556(v279); v35 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; goto LABEL_22; } v407 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("ClientAttestationData"))); v406 = (id)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("ClientAttestationPublicKey"))); } else { v406 = 0; v407 = 0; } v260 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("ReturnReferenceDate"))); v261 = isNSNumber_0(v260); v262 = (void *)objc_claimAutoreleasedReturnValue_556(v261); objc_release(v262); objc_release(v260); if ( v262 ) { v263 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("ReturnReferenceDate"))); v264 = (unsigned int)objc_msgSend(v263, "boolValue"); objc_release(v263); } else { v264 = 0; } v265 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("SkipNetworkRequest"))); v266 = isNSNumber_0(v265); v267 = (void *)objc_claimAutoreleasedReturnValue_556(v266); objc_release(v267); objc_release(v265); if ( v267 ) { v268 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("SkipNetworkRequest"))); v269 = (unsigned int)objc_msgSend(v268, "boolValue"); objc_release(v268); } else { v269 = 0; } v270 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("DeleteExistingKeysAndCerts"))); v271 = isNSNumber_0(v270); v272 = (void *)objc_claimAutoreleasedReturnValue_556(v271); objc_release(v272); objc_release(v270); v399 = v415 != 0; v65 = v216 != 0; v397 = queueb != 0; v395 = v264 != 0; queuea = v269 != 0; if ( v272 ) { v273 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("DeleteExistingKeysAndCerts"))); v416 = (unsigned int)objc_msgSend(v273, "boolValue"); objc_release(v273); if ( !v417 ) { v417 = 0; if ( !v416 ) goto LABEL_199;LABEL_194: v35 = 0; if ( v418 && v419 ) { delete_keychain_data(v419, v411, 0); delete_keychain_data(v419, v410, 0); delete_keychain_data(v419, v408, 0); delete_keychain_data(v419, v413, 0); delete_keychain_item(v419, v417, 0); delete_certificate(v419, v412, 0); delete_certificate(v419, v409, 0); v35 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; } else { v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; } goto LABEL_25; } } else { if ( !v417 ) { v417 = 0; goto LABEL_199; } LOBYTE(v416) = 0; } if ( v392 ) { v393 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v417, "stringByAppendingString:", CFSTR("-scrt"))); objc_release(v417); v389 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v412, "stringByAppendingString:", CFSTR("-scrt"))); objc_release(v412); v274 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v409, "stringByAppendingString:", CFSTR("-scrt"))); objc_release(v409); v275 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v413, "stringByAppendingString:", CFSTR("-scrt"))); objc_release(v413); v276 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v411, "stringByAppendingString:", CFSTR("-scrt"))); objc_release(v411); v277 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v408, "stringByAppendingString:", CFSTR("-scrt"))); objc_release(v408); v278 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v410, "stringByAppendingString:", CFSTR("-scrt"))); } else { v393 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v417, "stringByAppendingString:", CFSTR("-ucrt"))); objc_release(v417); v389 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v412, "stringByAppendingString:", CFSTR("-ucrt"))); objc_release(v412); v274 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v409, "stringByAppendingString:", CFSTR("-ucrt"))); objc_release(v409); v275 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v413, "stringByAppendingString:", CFSTR("-ucrt"))); objc_release(v413); v276 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v411, "stringByAppendingString:", CFSTR("-ucrt"))); objc_release(v411); v277 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v408, "stringByAppendingString:", CFSTR("-ucrt"))); objc_release(v408); v278 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v410, "stringByAppendingString:", CFSTR("-ucrt"))); } v280 = (void *)v278; objc_release(v410); v408 = (id)v277; v409 = (void *)v274; v410 = v280; v411 = (id)v276; v417 = (id)v393; v412 = (void *)v389; v413 = (id)v275; if ( (v416 & 1) != 0 ) goto LABEL_194;LABEL_199: if ( v407 ) { if ( cf ) CFRelease_438(cf); v281 = SecAccessControlCreate_3(0, &error); cf = (void *)v281; if ( !v281 ) { v289 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1195, -1, error, CFSTR("Failed to create access control."), v282, v283, v284, v384); v33 = objc_claimAutoreleasedReturnValue_556(v289); v35 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; cf = 0; goto LABEL_23; } if ( (SecAccessControlSetProtection_3(v281, CFSTR("f"), &error) & 1) == 0 ) { v288 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1200, -1, error, CFSTR("Failed to set ACL protection to %@."), v285, v286, v287, (char)CFSTR("f")); v33 = objc_claimAutoreleasedReturnValue_556(v288); goto LABEL_86; } } else { v407 = 0; }LABEL_50: if ( (isRunningInRecovery() & 1) != 0 ) { v69 = 0; } else { v102 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v471 = *(id *)(v102 + 40); v69 = isAutomaticTimeEnabledWithError(&v471); j__objc_storeStrong_550((id *)(v102 + 40), v471); v106 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v109 = *(void **)(v106 + 40); v108 = (id *)(v106 + 40); v107 = v109; if ( (v69 & 1) == 0 && v107 ) { v110 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1212, -1, v107, CFSTR("Failed to query automatic time state."), v103, v104, v105, v384); v33 = objc_claimAutoreleasedReturnValue_556(v110); goto LABEL_86; } v470 = v107; v111 = copyMonotonicClock(&v470); j__objc_storeStrong_550(v108, v470); v483[3] = v111; v115 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v118 = *(void **)(v115 + 40); v117 = (id *)(v115 + 40); v116 = v118; if ( v111 == 0.0 ) { v119 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1218, -1, v116, CFSTR("Failed to query monotonic clock."), v112, v113, v114, v384); v33 = objc_claimAutoreleasedReturnValue_556(v119); goto LABEL_86; } v469 = v116; v131 = copyRTCResetCountWithError(&v469); j__objc_storeStrong_550(v117, v469); *((_DWORD *)v477 + 6) = v131; if ( !v131 ) { v132 = *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL); if ( v132 ) { v133 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1224, -1, v132, CFSTR("Failed to query RTC reset count."), v66, v67, v68, v384); v33 = objc_claimAutoreleasedReturnValue_556(v133); goto LABEL_86; } } } v35 = 0; v414 = 0; v39 = 0; v38 = 0; if ( v65 || !v418 ) goto LABEL_248; v70 = copy_keychain_item(v419, v417, *v23, &v522, 0); v533[3] = v70; if ( v522 != -25300 && v522 ) { v134 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1234, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to query existing reference key (%@/%@): %d"), v71, v72, v73, (char)v419); v33 = objc_claimAutoreleasedReturnValue_556(v134); goto LABEL_86; } v74 = copy_keychain_data(v419, v413, &v522, 0); v414 = (CFDataRef)objc_claimAutoreleasedReturnValue_556(v74); if ( v522 != -25300 && v522 ) { v135 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1240, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to query existing leaf/intermediate certificates (%@/%@): %d"), v75, v76, v77, (char)v419); v33 = objc_claimAutoreleasedReturnValue_556(v135); goto LABEL_88; } if ( !v414 ) { load_certificate(v528 + 3, v419, v412, &v522, 0); if ( v522 != -25300 && v522 ) { v161 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1272, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to query existing leaf certificate (%@/%@): %d"), v137, v138, v139, (char)v419); v33 = objc_claimAutoreleasedReturnValue_556(v161); } else { load_certificate(v524 + 3, v419, v409, &v522, 0); if ( v522 != -25300 && v522 ) { v196 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1278, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to query existing intermediate certificate (%@/%@): %d"), v140, v141, v142, (char)v419); v33 = objc_claimAutoreleasedReturnValue_556(v196); } else { if ( !v528[3] || !v524[3] ) { v414 = 0; goto LABEL_104; } v143 = objc_alloc_init((Class)off_41CEDE9A8); v144 = (void *)v517[5]; v517[5] = (__int64)v143; objc_release(v144); if ( v517[5] ) { v151 = SecCertificateCopyData_23((SecCertificateRef)v528[3]); if ( !v151 ) { v377 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1291, -1, 0, CFSTR("Failed to copy certificate data."), v148, v149, v150, v384); v33 = objc_claimAutoreleasedReturnValue_556(v377); goto LABEL_86; } objc_msgSend((id)v517[5], "appendData:", v151); v414 = SecCertificateCopyData_23((SecCertificateRef)v524[3]); objc_release(v151); if ( !v414 ) { v379 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1299, -1, 0, CFSTR("Failed to copy certificate data."), v152, v153, v154, v384); v33 = objc_claimAutoreleasedReturnValue_556(v379); goto LABEL_86; } objc_msgSend((id)v517[5], "appendData:", v414); v155 = v517[5]; v156 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v467 = *(id *)(v156 + 40); v157 = store_keychain_data(v155, v419, v413, &v467); j__objc_storeStrong_550((id *)(v156 + 40), v467); if ( (v157 & 1) != 0 ) { delete_certificate(v419, v412, 0); delete_certificate(v419, v409, 0);LABEL_104: v39 = 0; goto LABEL_105; } v380 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1306, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to store leaf/intermediate certificates."), v158, v159, v160, v384); v33 = objc_claimAutoreleasedReturnValue_556(v380);LABEL_88: v35 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; goto LABEL_23; } v199 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1285, -1, 0, CFSTR("Failed to allocate data."), v145, v146, v147, v384); v33 = objc_claimAutoreleasedReturnValue_556(v199); } }LABEL_86: v35 = 0; v36 = 0; v37 = 0; v38 = 0; v39 = 0; v414 = 0; goto LABEL_23; } v78 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); obj = *(id *)(v78 + 40); v79 = parseDERCertificatesFromChain_0(v414, &obj); v39 = (void *)objc_claimAutoreleasedReturnValue_556(v79); j__objc_storeStrong_550((id *)(v78 + 40), obj); if ( !v39 || objc_msgSend(v39, "count") != (void *)2 ) { v136 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1251, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to parse DER certificate chain."), v80, v81, v82, v384); v33 = objc_claimAutoreleasedReturnValue_556(v136); goto LABEL_90; } v83 = (const __CFData *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(v39, "objectAtIndexedSubscript:", 0)); v84 = SecCertificateCreateWithData_33(0, v83); v528[3] = (__int64)v84; objc_release(v83); if ( !v528[3] ) { v197 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1257, -1, 0, CFSTR("Failed to create certificate from DER data."), v85, v86, v87, v384); v33 = objc_claimAutoreleasedReturnValue_556(v197); goto LABEL_90; } v88 = (const __CFData *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(v39, "objectAtIndexedSubscript:", 1)); v89 = SecCertificateCreateWithData_33(0, v88); v524[3] = (__int64)v89; objc_release(v88); if ( !v524[3] ) { v93 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1263, -1, 0, CFSTR("Failed to create certificate from DER data."), v90, v91, v92, v384); v33 = objc_claimAutoreleasedReturnValue_556(v93);LABEL_90: v35 = 0; v36 = 0; v37 = 0; v38 = 0; goto LABEL_23; }LABEL_105: if ( (isRunningInRecovery() & 1) == 0 ) { v174 = copy_keychain_data(v419, v411, &v522, 0); v175 = objc_claimAutoreleasedReturnValue_556(v174); v176 = (void *)v487[5]; v487[5] = v175; objc_release(v176); if ( v522 != -25300 && v522 ) { v198 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1318, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to query existing motononic time (%@/%@): %d"), v177, v178, v179, (char)v419); v33 = objc_claimAutoreleasedReturnValue_556(v198); goto LABEL_90; } v180 = (void *)v487[5]; if ( v180 ) objc_msgSend(v180, "getBytes:length:", &v481, 8); v181 = copy_keychain_data(v419, v410, &v522, 0); v182 = objc_claimAutoreleasedReturnValue_556(v181); v183 = (void *)v511[5]; v511[5] = v182; objc_release(v183); if ( v522 != -25300 && v522 ) { v290 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1328, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to query existing RTC reset count (%@/%@): %d"), v184, v185, v186, (char)v419); v33 = objc_claimAutoreleasedReturnValue_556(v290); goto LABEL_90; } v187 = (void *)v511[5]; if ( v187 ) objc_msgSend(v187, "getBytes:length:", &v480, 4); v188 = copy_keychain_data(v419, v408, &v522, 0); v189 = objc_claimAutoreleasedReturnValue_556(v188); v190 = (void *)v505[5]; v505[5] = v189; objc_release(v190); if ( v522 != -25300 && v522 ) { v378 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1338, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to query existing server timestamp (%@/%@): %d"), v66, v67, v68, (char)v419); v33 = objc_claimAutoreleasedReturnValue_556(v378); goto LABEL_90; } v191 = (void *)v505[5]; if ( v191 ) { objc_msgSend(v191, "getBytes:length:", v473 + 3, 8); v192 = objc_alloc((Class)off_41CEDE958); v193 = objc_msgSend(v192, "initWithTimeIntervalSinceReferenceDate:", v473[3]); v194 = (void *)v493[5]; v493[5] = (__int64)v193; objc_release(v194); if ( !v493[5] ) { v195 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1347, -1, 0, CFSTR("Failed to create date from server timestamp."), v66, v67, v68, v384); v33 = objc_claimAutoreleasedReturnValue_556(v195); goto LABEL_90; } } } if ( !v533[3] || !v528[3] ) { v38 = 0;LABEL_130: v391 = 0; goto LABEL_211; } v162 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v163 = isNSArray(); v164 = (void *)objc_claimAutoreleasedReturnValue_556(v163); objc_release(v164); objc_release(v162); if ( v164 ) { v165 = v528[3]; v166 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(*v23, "objectForKeyedSubscript:", CFSTR("OIDSToInclude"))); v167 = copyCertificateOIDsThatDiffer(v165, v166); v38 = (void *)objc_claimAutoreleasedReturnValue_556(v167); objc_release(v166); } else { v38 = 0; } if ( !objc_msgSend(v38, "count") ) goto LABEL_130; v291 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1365, -1, 0, CFSTR("Mismatch in requested OIDs and existing certificate's OIDs (%@)."), v66, v67, v68, (char)v38); v292 = objc_claimAutoreleasedReturnValue_556(v291); v293 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v294 = *(void **)(v293 + 40); *(_QWORD *)(v293 + 40) = v292; objc_release(v294); v391 = 1;LABEL_211: if ( v533[3] ) { if ( (unsigned int)isFactoryMFiCertificate(v419, v528[3]) ) { v295 = v533[3]; v296 = a1 + 56; v297 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v466 = *(id *)(v297 + 40); valid = validSecureEnclaveReferenceKey(v295, 1, 0, &v466); j__objc_storeStrong_550((id *)(v297 + 40), v466); if ( !valid ) goto LABEL_221; } } v299 = v533[3]; if ( !v299 ) goto LABEL_219; v296 = a1 + 56; v300 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v465 = *(id *)(v300 + 40); v301 = validSecureEnclaveReferenceKey(v299, 0, 0, &v465); j__objc_storeStrong_550((id *)(v300 + 40), v465); if ( !v301 || v533[3] && v528[3] && (v302 = *(_QWORD *)(*(_QWORD *)v296 + 8LL), v464 = *(id *)(v302 + 40), v303 = certificatePublicKeyMatchesBIKPublicKey(), j__objc_storeStrong_550((id *)(v302 + 40), v464), (v303 & 1) == 0) ) {LABEL_221: v304 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1385, -2, *(void **)(*(_QWORD *)(*(_QWORD *)v296 + 8LL) + 40LL), CFSTR("Invalid reference key."), v66, v67, v68, v384); v305 = objc_claimAutoreleasedReturnValue_556(v304); v306 = *(_QWORD *)(*(_QWORD *)v296 + 8LL); v307 = *(void **)(v306 + 40); *(_QWORD *)(v306 + 40) = v305; objc_release(v307); } else {LABEL_219: if ( !v391 ) goto LABEL_231; } v308 = objc_retain(&_os_log_default_0); if ( os_log_type_enabled_632((os_log_t)&_os_log_default_0, OS_LOG_TYPE_DEFAULT) ) { v309 = *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL); *(_DWORD *)buf = 138412290; v557 = v309; _os_log_impl_600( &dword_40E4FC000, (os_log_t)&_os_log_default_0, OS_LOG_TYPE_DEFAULT, "Deleting invalid keys/certificates: %@", buf, 0xCu); } objc_release(&_os_log_default_0); delete_keychain_data(v419, v411, 0); delete_keychain_data(v419, v410, 0); delete_keychain_data(v419, v408, 0); delete_keychain_data(v419, v413, 0); delete_keychain_item(v419, v417, 0); delete_certificate(v419, v412, 0); delete_certificate(v419, v409, 0); v310 = v533; v311 = (const void *)v533[3]; if ( v311 ) { CFRelease_438(v311); v310 = v533; } v310[3] = 0; v312 = v528; v313 = (const void *)v528[3]; if ( v313 ) { CFRelease_438(v313); v312 = v528; } v312[3] = 0; v314 = v524; v315 = (const void *)v524[3]; if ( v315 ) { CFRelease_438(v315); v314 = v524; } v314[3] = 0; v316 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v317 = *(void **)(v316 + 40); *(_QWORD *)(v316 + 40) = 0; objc_release(v317);LABEL_231: if ( !v533[3] || !v528[3] || !v524[3] ) goto LABEL_247; if ( (isRunningInRecovery() & 1) != 0 || (v69 & 1) != 0 || (v318 = v481, v481 == 0.0) || (v319 = (void *)v493[5]) == 0 ) { v323 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE958, "date", v318)); v322 = (void *)v499[5]; v499[5] = v323; v321 = 1; } else { v320 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v319, "dateByAddingTimeInterval:", v483[3] - v481)); v321 = 0; v322 = (void *)v499[5]; v499[5] = v320; } objc_release(v322); v324 = v528[3]; objc_msgSend((id)v499[5], "timeIntervalSinceReferenceDate"); if ( !(unsigned int)SecCertificateIsValid_2(v324) || (v325 = v524[3], objc_msgSend((id)v499[5], "timeIntervalSinceReferenceDate"), !(unsigned int)SecCertificateIsValid_2(v325)) ) { v330 = 0; v329 = 0; if ( (v321 & 1) == 0 ) goto LABEL_276; goto LABEL_246; } v326 = SecCertificateNotValidAfter_8(v528[3]); v327 = SecCertificateNotValidBefore_7(v528[3]); objc_msgSend((id)v499[5], "timeIntervalSinceReferenceDate"); if ( v328 - SecCertificateNotValidBefore_7(v528[3]) >= (v326 - v327) * 0.9 ) { v330 = 1; v329 = 1; if ( (v321 & 1) == 0 ) goto LABEL_276;LABEL_246: if ( v330 ) goto LABEL_277;LABEL_247: v35 = 0; goto LABEL_248; } v329 = 0; v330 = 1; if ( (v321 & 1) != 0 ) goto LABEL_246;LABEL_276: if ( ((unsigned __int8)v330 & (*((_DWORD *)v477 + 6) == v480)) == 0 ) goto LABEL_247;LABEL_277: if ( v395 ) { v381 = v524[3]; v571[1] = v528[3]; v571[2] = v381; v382 = &v572; v383 = v499 + 5; } else { v570 = v528[3]; v382 = v571; v383 = v524 + 3; } *v382 = *v383; v35 = (id)objc_claimAutoreleasedReturnValue_556(objc_msgSend(off_41CEDE918, "arrayWithObjects:count:")); if ( v329 ) {LABEL_248: if ( queuea ) { v331 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1470, -1, 0, CFSTR("Missing or expired certificates, and network request explictly not attempted."), v66, v67, v68, v384); v332 = objc_claimAutoreleasedReturnValue_556(v331); } else { if ( v399 && (v333 = (const void *)v533[3]) != 0 ) { v334 = (__SecKey *)CFRetain_262(v333); v541[3] = (__int64)v334; } else { v335 = *(_QWORD *)(a1 + 40); v336 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v463 = *(id *)(v336 + 40); v334 = (__SecKey *)createReferenceKeyBlob(cf, v397, v335, &v463); j__objc_storeStrong_550((id *)(v336 + 40), v463); v541[3] = (__int64)v334; if ( !v334 ) { v360 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1481, -1, *(void **)(*(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL) + 40LL), CFSTR("Failed to create reference key."), v337, v338, v339, v384); v332 = objc_claimAutoreleasedReturnValue_556(v360); goto LABEL_262; } } v340 = SecKeyCopyPublicKey_11(v334); v537[3] = (__int64)v340; if ( v340 ) { v37 = SecKeyCopyExternalRepresentation_13(v340, &error); if ( v37 ) { v347 = SecKeyCopyAttributes_8((SecKeyRef)v541[3]); v36 = v347; if ( v347 ) { v354 = (void *)objc_claimAutoreleasedReturnValue_556(-[__CFDictionary objectForKeyedSubscript:](v347, "objectForKeyedSubscript:", CFSTR("toid"))); if ( v354 ) { v355 = j__dispatch_get_global_queue_364(0, 0); queuec = (NSObject *)objc_claimAutoreleasedReturnValue_556(v355); v428[0] = &_NSConcreteStackBlock_0; v428[1] = 3221225472LL; v428[2] = __DeviceIdentityIssueClientCertificateWithCompletion_block_invoke_2; v428[3] = &unk_41974FD50; v54 = &v429; v429 = objc_retain(*(id *)(a1 + 40)); v356 = objc_retain(v422); v357 = *(_QWORD *)(a1 + 56); v430 = v356; v444 = v357; v53 = objc_retain(v354); v431 = v53; v445 = v554; v446 = &v498; v358 = objc_retain(v425); v462 = v395; v425 = v358; v432 = v358; v447 = &v516; v448 = &v540; v406 = objc_retain(v406); v433 = v406; v418 = objc_retain(v418); v434 = v418; v419 = objc_retain(v419); v435 = v419; v413 = objc_retain(v413); v436 = v413; v417 = objc_retain(v417); v437 = v417; v411 = objc_retain(v411); v438 = v411; v410 = objc_retain(v410); v439 = v410; v408 = objc_retain(v408); v440 = v408; v449 = &v486; v450 = &v482; v451 = &v510; v452 = &v476; v453 = &v472; v454 = &v504; v455 = &v544; v456 = &v548; v457 = &v532; v458 = &v527; v459 = &v523; v35 = objc_retain(v35); v441 = v35; v460 = &v492; v442 = objc_retain(v5); v443 = objc_retain(*(id *)(a1 + 48)); v461 = &v536; j__dispatch_async_488(queuec, v428); objc_release(queuec); objc_release(v443); objc_release(v442); objc_release(v441); objc_release(v440); objc_release(v439); objc_release(v438); objc_release(v437); objc_release(v436); objc_release(v435); objc_release(v434); objc_release(v433); objc_release(v432); objc_release(v431); objc_release(v430); goto LABEL_36; } v376 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1532, -1, error, CFSTR("Failed to encode RK as data."), v351, v352, v353, v384); v332 = objc_claimAutoreleasedReturnValue_556(v376); goto LABEL_264; } v375 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1526, -1, error, CFSTR("Failed to copy RK attributes."), v348, v349, v350, v384); v332 = objc_claimAutoreleasedReturnValue_556(v375);LABEL_263: v36 = 0;LABEL_264: v362 = *(_QWORD *)(*(_QWORD *)(a1 + 56) + 8LL); v363 = *(void **)(v362 + 40); *(_QWORD *)(v362 + 40) = v332; objc_release(v363); goto LABEL_265; } v361 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1494, -1, error, CFSTR("Failed to encode RK public key as data."), v344, v345, v346, v384); v332 = objc_claimAutoreleasedReturnValue_556(v361); } else { v359 = createMobileActivationError_0( (__int64)"DeviceIdentityIssueClientCertificateWithCompletion_block_invoke", 1488, -1, 0, CFSTR("Failed to copy RK public key."), v341, v342, v343, v384); v332 = objc_claimAutoreleasedReturnValue_556(v359); } }LABEL_262: v37 = 0; goto LABEL_263; } v37 = 0; v36 = 0;LABEL_265: v364 = (const void *)v533[3]; if ( !v364 || !v35 ) goto LABEL_25; v365 = CFRetain_262(v364); v545[3] = (__int64)v365; j__objc_storeStrong_550(v549 + 5, v35); v41 = &_os_log_default_0; v366 = objc_retain(&_os_log_default_0); if ( os_log_type_enabled_632((os_log_t)&_os_log_default_0, OS_LOG_TYPE_DEFAULT) ) { v394 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(v549[5], "objectAtIndexedSubscript:", 0)); v398 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(v549[5], "objectAtIndexedSubscript:", 0)); v367 = objc_msgSend(off_41CEDE958, "dateWithTimeIntervalSinceReferenceDate:", SecCertificateNotValidBefore_7(v398)); v388 = objc_retain((id)objc_claimAutoreleasedReturnValue_556(v367)); v396 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(v549[5], "objectAtIndexedSubscript:", 0)); v368 = objc_msgSend(off_41CEDE958, "dateWithTimeIntervalSinceReferenceDate:", SecCertificateNotValidAfter_8(v396)); queued = objc_retain((id)objc_claimAutoreleasedReturnValue_556(v368)); v387 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(v549[5], "objectAtIndexedSubscript:", 1)); v390 = (void *)objc_claimAutoreleasedReturnValue_556(objc_msgSend(v549[5], "objectAtIndexedSubscript:", 1)); v369 = objc_msgSend(off_41CEDE958, "dateWithTimeIntervalSinceReferenceDate:", SecCertificateNotValidBefore_7(v390)); v400 = objc_retain((id)objc_claimAutoreleasedReturnValue_556(v369)); v370 = objc_claimAutoreleasedReturnValue_556(objc_msgSend(v549[5], "objectAtIndexedSubscript:", 1)); v371 = objc_msgSend(off_41CEDE958, "dateWithTimeIntervalSinceReferenceDate:", SecCertificateNotValidAfter_8(v370)); v372 = objc_retain((id)objc_claimAutoreleasedReturnValue_556(v371)); v373 = v493[5]; *(_DWORD *)buf = 138544898; v557 = v394; v558 = 2114; v559 = v388; v560 = 2114; v561 = queued; v562 = 2114; v385 = (void *)v370; v386 = v372; v563 = v387; v564 = 2114; v565 = v400; v566 = 2114; v567 = v372; v374 = v372; v568 = 2114; v569 = v373; v41 = &_os_log_default_0; _os_log_impl_600( &dword_40E4FC000, (os_log_t)&_os_log_default_0, OS_LOG_TYPE_DEFAULT, "Returning cached certificates:\n" "* %{public}@\n" " Not Valid Before: %{public}@\n" " Not Valid After: %{public}@\n" "* %{public}@\n" " Not Valid Before: %{public}@\n" " Not Valid After: %{public}@\n" "* Server Timestamp: %{public}@\n", buf, 0x48u); objc_release(v374); objc_release(v385); objc_release(v400); objc_release(v390); objc_release(v387); objc_release(queued); objc_release(v396); objc_release(v388); objc_release(v398); objc_release(v394); objc_release(v386); objc_release(v400); objc_release(queued); objc_release(v388); }LABEL_24: objc_release(v41);LABEL_25: block[0] = &_NSConcreteStackBlock_0; block[1] = 3221225472LL; block[2] = __DeviceIdentityIssueClientCertificateWithCompletion_block_invoke_309; block[3] = &unk_41974FD00; v42 = *(void **)(a1 + 48); v427[1] = *(_QWORD *)(a1 + 56); v427[0] = objc_retain(v42); v427[2] = &v544; v427[3] = &v548; j__dispatch_async_488(v5, block); v43 = v541; v44 = (const void *)v541[3]; if ( v44 ) { CFRelease_438(v44); v43 = v541; } v43[3] = 0; v45 = v537; v46 = (const void *)v537[3]; if ( v46 ) { CFRelease_438(v46); v45 = v537; } v45[3] = 0; v47 = v533; v48 = (const void *)v533[3]; if ( v48 ) { CFRelease_438(v48); v47 = v533; } v47[3] = 0; v49 = v528; v50 = (const void *)v528[3]; if ( v50 ) { CFRelease_438(v50); v49 = v528; } v49[3] = 0; v51 = v524; v52 = (const void *)v524[3]; if ( v52 ) { CFRelease_438(v52); v51 = v524; } v53 = 0; v54 = (id *)v427; v51[3] = 0;LABEL_36: objc_release(*v54); if ( v15 ) CFRelease_438(v15); if ( error ) CFRelease_438(error); error = 0; if ( cf ) CFRelease_438(cf); _Block_object_dispose_549(&v472, 8); _Block_object_dispose_549(&v476, 8); _Block_object_dispose_549(&v482, 8); objc_release(v5); objc_release(v38); objc_release(v422); _Block_object_dispose_549(&v486, 8); objc_release(v491); _Block_object_dispose_549(&v492, 8); objc_release(v497); _Block_object_dispose_549(&v498, 8); objc_release(v503); _Block_object_dispose_549(&v504, 8); objc_release(v509); _Block_object_dispose_549(&v510, 8); objc_release(v515); _Block_object_dispose_549(&v516, 8); objc_release(v521); objc_release(v39); objc_release(v414); objc_release(v408); objc_release(v411); objc_release(v410); objc_release(v417); objc_release(v409); objc_release(v412); objc_release(v413); objc_release(v419); objc_release(v418); _Block_object_dispose_549(&v523, 8); _Block_object_dispose_549(&v527, 8); _Block_object_dispose_549(&v532, 8); _Block_object_dispose_549(&v536, 8); _Block_object_dispose_549(&v540, 8); _Block_object_dispose_549(&v544, 8); objc_release(v406); objc_release(v407); objc_release(v37); objc_release(v36); objc_release(v53); objc_release(v421); _Block_object_dispose_549(&v548, 8); objc_release(v553); objc_release(v35); objc_release(v425); _Block_object_dispose_549(v554, 8); objc_release(v555);}
identityCertificateOptions 用来构造“我想要一张什么样的 identity 证书”;
DeviceIdentityIssueClientCertificateWithCompletion 则负责根据这些参数检查调用方权限、复用或重新签发 attestation 证书链,并在 keychain 中维护一整套“证书 + SE key + 时间防回拨信息”的档案。流程如下:
读取激活证书后准备加密生成token。
组合参数
_SecCertificateCopyDataid __fastcall __66__DCCertificateGenerator__generateCertificateChainWithCompletion___block_invoke( __int64 a1, __int64 a2){ void *v2; // x27 __int64 v3; // x0 __int64 v4; // x0 __int64 v5; // x21 __int64 v6; // x0 __int64 v7; // x0 __int64 v8; // x23 unsigned __int64 v9; // x0 void *v10; // x28 char v11; // w9 __int64 v12; // x2 char v13; // w8 char v14; // w19 char v15; // w26 __int64 v16; // x20 __int64 v17; // x0 void *v18; // x21 void *v19; // x26 void *v20; // x24 char *v21; // x22 int v22; // w28 int v23; // w27 char *v24; // x25 char *v25; // x0 char *v26; // x20 char *v27; // x28 void *v28; // x25 NSError *v29; // x0 NSError *v30; // x0 NSError *v31; // x0 __int64 v32; // x0 __int64 v33; // x0 __int64 v34; // x0 void *v35; // x0 __int64 v36; // x21 int v37; // w19 __int64 v38; // x0 __int64 v39; // x0 __int64 v40; // x0 __int64 v41; // x20 __int64 v42; // x0 void *v43; // x0 __int64 v44; // x0 __int64 v45; // x0 __int64 v46; // x0 __int64 v47; // x0 __int64 v48; // x0 __int64 v49; // x0 __int64 v50; // x0 __int64 v51; // x0 id result; // x0 NSError *v53; // x0 __int64 v54; // x0 unsigned int v55; // w20 __int64 v56; // x20 __int64 v57; // x0 __int64 v58; // x0 __int64 v59; // x22 __int64 v60; // x0 __int64 v61; // x0 __int64 v62; // x20 __int64 v63; // x0 NSError *v64; // x0 __int64 v65; // x20 __int64 v66; // x0 DCCertificateGenerator *v67; // x0 SEL v68; // x1 id v69; // x2 id v70; // x3 id *v71; // x4 __int64 v72; // [xsp+0h] [xbp-180h] unsigned __int64 v73; // [xsp+10h] [xbp-170h] void *v75; // [xsp+20h] [xbp-160h] void *v77; // [xsp+30h] [xbp-150h] void *v78; // [xsp+40h] [xbp-140h] char v79; // [xsp+48h] [xbp-138h] char v80; // [xsp+4Ch] [xbp-134h] __int64 v81; // [xsp+50h] [xbp-130h] BYREF __CFString *v82; // [xsp+58h] [xbp-128h] BYREF __int64 v83; // [xsp+60h] [xbp-120h] BYREF __CFString *v84; // [xsp+68h] [xbp-118h] BYREF __int64 v85; // [xsp+70h] [xbp-110h] BYREF __CFString *v86; // [xsp+78h] [xbp-108h] BYREF char __src[16]; // [xsp+80h] [xbp-100h] BYREF __int128 v88; // [xsp+90h] [xbp-F0h] __int128 v89; // [xsp+A0h] [xbp-E0h] __int128 v90; // [xsp+B0h] [xbp-D0h] __int128 v91; // [xsp+C0h] [xbp-C0h] char __str[16]; // [xsp+D0h] [xbp-B0h] BYREF __int128 v93; // [xsp+E0h] [xbp-A0h] __int128 v94; // [xsp+F0h] [xbp-90h] __int128 v95; // [xsp+100h] [xbp-80h] __int128 v96; // [xsp+110h] [xbp-70h] unsigned __int64 v97; // [xsp+120h] [xbp-60h] v97 = 0x8FCA7F6773E200E4LL; v2 = (void *)objc_retain_x2_1310(); v3 = ((__int64 (*)(void))MEMORY[0x243ECC210])(); v4 = _DCLogSystem(v3); v5 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC0A0])(v4); v6 = ((__int64 (__fastcall *)(__int64, _QWORD))MEMORY[0x243ECC2A0])(v5, 0); if ( (_DWORD)v6 ) { *(_WORD *)__str = 0; v6 = ((__int64 (__fastcall *)(int *, __int64, _QWORD, const char *, char *, __int64))MEMORY[0x243ECBE60])( &dword_24150F000, v5, 0, "Certificate issued, processing..", __str, 2); } v7 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC130])(v6); v8 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC210])(v7); v75 = (void *)((__int64 (__fastcall *)(void *))MEMORY[0x243ECC0A0])(+[NSDate date](&OBJC_CLASS___NSDate, "date")); if ( v2 && (v9 = (unsigned __int64)objc_msgSend(v2, "count"), (v9 & 0xFFFFFFFFFFFFFFFELL) == 2) ) { v73 = v9; v79 = 0; v10 = 0; v11 = 0; v12 = 0; v13 = 1; v77 = v2; while ( 1 ) { v14 = v13; v15 = v11; v16 = ((__int64 (__fastcall *)(void *))MEMORY[0x243ECC0A0])(objc_msgSend(v2, "objectAtIndexedSubscript:", v12)); MEMORY[0x243ECC120](); v17 = ((__int64 (__fastcall *)(__int64))unk_243ECBDF0)(v16); v18 = (void *)((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC1B0])(v17); v95 = 0u; v96 = 0u; v93 = 0u; v94 = 0u; *(_OWORD *)__str = 0u; v90 = 0u; v91 = 0u; v88 = 0u; v89 = 0u; *(_OWORD *)__src = 0u; if ( v18 ) { v80 = v15; v19 = (void *)((__int64 (*)(void))MEMORY[0x243ECC080])(); v20 = (void *)((__int64 (__fastcall *)(void *))MEMORY[0x243ECC0A0])(objc_msgSend(v18, "base64EncodedDataWithOptions:", 1)); v21 = (char *)objc_msgSend(v20, "length"); if ( v21 ) { v78 = v10; v22 = snprintf(__str, 0x50u, "-----BEGIN %s-----\n", "CERTIFICATE"); v23 = snprintf(__src, 0x50u, "\n-----END %s-----", "CERTIFICATE"); v24 = &v21[v22 + v23]; v25 = (char *)malloc((size_t)(v24 + 1)); if ( v25 ) { v26 = v25; v27 = &strncpy(v25, __str, v22)[v22]; objc_msgSend(v20, "getBytes:range:", v27, 0, v21); strncpy(&v21[(_QWORD)v27], __src, v23); v28 = (void *)((__int64 (__fastcall *)(NSData *))MEMORY[0x243ECC0A0])( +[NSData(NSData) dataWithBytesNoCopy:length:]( &OBJC_CLASS___NSData, "dataWithBytesNoCopy:length:", v26, v24)); if ( !v28 ) { v85 = 0x21AEAF128LL; v86 = CFSTR("Failed to create pem data."); v31 = +[NSError errorWithDomain:code:userInfo:]( &OBJC_CLASS___NSError, "errorWithDomain:code:userInfo:", CFSTR("com.apple.devicecheck.cryptoerror"), 0, ((__int64 (__fastcall *)(NSDictionary *))MEMORY[0x243ECC0A0])( +[NSDictionary dictionaryWithObjects:forKeys:count:]( &OBJC_CLASS___NSDictionary, "dictionaryWithObjects:forKeys:count:", &v86, &v85, 1))); ((void (__fastcall *)(NSError *))MEMORY[0x243ECC0A0])(v31); ((void (*)(void))unk_243ECC180)(); free(v26); } } else { v85 = 0x21AEAF128LL; v86 = CFSTR("Failed to allocate buffer."); v30 = +[NSError errorWithDomain:code:userInfo:]( &OBJC_CLASS___NSError, "errorWithDomain:code:userInfo:", CFSTR("com.apple.devicecheck.cryptoerror"), 0, ((__int64 (__fastcall *)(NSDictionary *))MEMORY[0x243ECC0A0])( +[NSDictionary dictionaryWithObjects:forKeys:count:]( &OBJC_CLASS___NSDictionary, "dictionaryWithObjects:forKeys:count:", &v86, &v85, 1))); ((void (__fastcall *)(NSError *))MEMORY[0x243ECC0A0])(v30); ((void (*)(void))unk_243ECC170)(); v28 = 0; } v2 = v77; v10 = v78; } else { v28 = 0; } ((void (*)(void))MEMORY[0x243ECC160])(); objc_autoreleasePoolPop(v19); v15 = v80; } else { v85 = 0x21AEAF128LL; v86 = CFSTR("Invalid inputs."); v29 = +[NSError errorWithDomain:code:userInfo:]( &OBJC_CLASS___NSError, "errorWithDomain:code:userInfo:", CFSTR("com.apple.devicecheck.cryptoerror"), 0, ((__int64 (__fastcall *)(NSDictionary *))MEMORY[0x243ECC0A0])( +[NSDictionary dictionaryWithObjects:forKeys:count:]( &OBJC_CLASS___NSDictionary, "dictionaryWithObjects:forKeys:count:", &v86, &v85, 1))); ((void (__fastcall *)(NSError *))MEMORY[0x243ECC0A0])(v29); ((void (*)(void))MEMORY[0x243ECC160])(); v28 = 0; } v32 = ((__int64 (*)(void))MEMORY[0x243ECC140])(); v33 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC130])(v32); v34 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC150])(v33); ((void (__fastcall *)(__int64))MEMORY[0x243ECC130])(v34); if ( !v28 ) break; if ( v10 ) objc_msgSend(v10, "appendBytes:length:", "\n", 1); else v10 = objc_msgSend( (id)((__int64 (__fastcall *)(void *))MEMORY[0x243ECC040])(&OBJC_CLASS___NSMutableData), "initWithCapacity:", objc_msgSend(v28, "length")); v35 = objc_msgSend(v10, "appendData:", v28); v13 = 0; v11 = 1; v79 = v15; v12 = 1; if ( (v14 & 1) == 0 ) { v36 = v8; goto LABEL_36; } } v83 = 0x21AEAF128LL; v84 = CFSTR("Failed to create PEM data from cert."); v53 = +[NSError errorWithDomain:code:userInfo:]( &OBJC_CLASS___NSError, "errorWithDomain:code:userInfo:", CFSTR("com.apple.devicecheck.cryptoerror"), 0, ((__int64 (__fastcall *)(NSDictionary *))MEMORY[0x243ECC0A0])( +[NSDictionary dictionaryWithObjects:forKeys:count:]( &OBJC_CLASS___NSDictionary, "dictionaryWithObjects:forKeys:count:", &v84, &v83, 1))); v36 = ((__int64 (__fastcall *)(NSError *))MEMORY[0x243ECC0A0])(v53); v54 = ((__int64 (*)(void))MEMORY[0x243ECC150])(); v35 = (void *)((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC140])(v54); v15 = v79;LABEL_36: if ( v73 == 3 ) { v55 = (unsigned int)objc_msgSend( *(id *)(a1 + 32), "_isNSDate:", ((__int64 (__fastcall *)(void *))MEMORY[0x243ECC0A0])(objc_msgSend(v2, "objectAtIndexedSubscript:", 2))); ((void (*)(void))MEMORY[0x243ECC140])(); if ( v55 ) { v56 = ((__int64 (__fastcall *)(void *))MEMORY[0x243ECC0A0])(objc_msgSend(v2, "objectAtIndexedSubscript:", 2)); v57 = MEMORY[0x243ECC1A0](); v58 = _DCLogSystem(v57); v59 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC0A0])(v58); v60 = ((__int64 (__fastcall *)(__int64, _QWORD))MEMORY[0x243ECC2A0])(v59, 0); if ( (_DWORD)v60 ) { *(_WORD *)__str = 0; v60 = ((__int64 (__fastcall *)(int *, __int64, _QWORD, const char *, char *, __int64))MEMORY[0x243ECBE60])( &dword_24150F000, v59, 0, "Using synced timestamp...", __str, 2); } ((void (__fastcall *)(__int64))MEMORY[0x243ECC140])(v60); v37 = v15 & 1; v75 = (void *)v56; } else { v81 = 0x21AEAF128LL; v82 = CFSTR("Expected date field, failing..."); v64 = +[NSError errorWithDomain:code:userInfo:]( &OBJC_CLASS___NSError, "errorWithDomain:code:userInfo:", CFSTR("com.apple.devicecheck.cryptoerror"), 0, ((__int64 (__fastcall *)(NSDictionary *))MEMORY[0x243ECC0A0])( +[NSDictionary dictionaryWithObjects:forKeys:count:]( &OBJC_CLASS___NSDictionary, "dictionaryWithObjects:forKeys:count:", &v82, &v81, 1))); v65 = ((__int64 (__fastcall *)(NSError *))MEMORY[0x243ECC0A0])(v64); v66 = MEMORY[0x243ECC130](); ((void (__fastcall *)(__int64))MEMORY[0x243ECC140])(v66); v37 = 0; v36 = v65; } } else { v61 = _DCLogSystem(v35); v62 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC0A0])(v61); v63 = ((__int64 (__fastcall *)(__int64, _QWORD))MEMORY[0x243ECC2A0])(v62, 0); if ( (_DWORD)v63 ) { *(_WORD *)__str = 0; v63 = ((__int64 (__fastcall *)(int *, __int64, _QWORD, const char *, char *, __int64))MEMORY[0x243ECBE60])( &dword_24150F000, v62, 0, "Using device timestamp...", __str, 2); } ((void (__fastcall *)(__int64))MEMORY[0x243ECC120])(v63); v37 = v15 & 1; } } else { v10 = 0; v37 = 0; v36 = v8; } v38 = a2; if ( a2 ) v38 = ((__int64 (*)(void))unk_243ECBD30)(); v39 = _DCLogSystem(v38); v40 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC0A0])(v39); v41 = v40; if ( v37 ) { v42 = ((__int64 (__fastcall *)(__int64, _QWORD))MEMORY[0x243ECC2A0])(v40, 0); if ( (_DWORD)v42 ) { v43 = objc_msgSend(v10, "length"); *(_DWORD *)__str = 134217984; *(_QWORD *)&__str[4] = v43; v42 = ((__int64 (*)(int *, __int64, _QWORD, const char *, ...))MEMORY[0x243ECBE60])( &dword_24150F000, v41, 0, "Certificate processed... (%lu)", v72); } ((void (__fastcall *)(__int64))MEMORY[0x243ECC120])(v42); v44 = (*(__int64 (__fastcall **)(_QWORD, void *, void *))(*(_QWORD *)(a1 + 40) + 16LL))( *(_QWORD *)(a1 + 40), objc_msgSend(v10, "copy"), objc_msgSend(v75, "copy")); v45 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC160])(v44); } else { if ( (unsigned int)((__int64 (__fastcall *)(__int64, __int64))MEMORY[0x243ECC2A0])(v40, 16) ) __66__DCCertificateGenerator__generateCertificateChainWithCompletion___block_invoke_cold_1(v36, v41); MEMORY[0x243ECC120](); v45 = (*(__int64 (__fastcall **)(_QWORD, _QWORD, void *))(*(_QWORD *)(a1 + 40) + 16LL))( *(_QWORD *)(a1 + 40), 0, objc_msgSend(v75, "copy")); } v46 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC120])(v45); v47 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC110])(v46); v48 = ((__int64 (__fastcall *)(__int64))unk_243ECC190)(v47); v49 = ((__int64 (__fastcall *)(__int64))unk_243ECC170)(v48); v50 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC130])(v49); v51 = ((__int64 (__fastcall *)(__int64))MEMORY[0x243ECC150])(v50); result = (id)((__int64 (__fastcall *)(__int64))unk_243ECC180)(v51); if ( v97 != 0x8FCA7F6773E200E4LL ) { v67 = (DCCertificateGenerator *)((__int64 (__fastcall *)(id))unk_243ECBE30)(result); return -[DCCertificateGenerator _encryptData:serverSyncedDate:error:](v67, v68, v69, v70, v71); } return result;}
将组合后的两个激活证传给加密方法
id __fastcall -[DCCertificateGenerator _encryptData:serverSyncedDate:error:](id *a1, __int64 a2, void *a3, void *a4){ id v6; // x21 __int64 v7; // x0 NSObject *v8; // x19 void *v9; // x19 void *v10; // x20 unsigned int v11; // w27 const void *v12; // x28 unsigned int v13; // w25 id v14; // x21 const void *v15; // x19 __int64 v16; // x23 size_t v17; // x24 _DWORD *v18; // x0 _DWORD *v19; // x22 char *v20; // x23 void *v21; // x27 void *v22; // x0 __int64 v23; // d0 __int64 v24; // x0 NSObject *v25; // x19 __int64 v26; // x8 __int64 v27; // x0 __int64 v28; // x19 __int64 v29; // x0 NSObject *v30; // x24 __int64 v31; // x0 void *v32; // x25 _OWORD *public_key_1; // x0 __int128 v34; // q0 __int128 v35; // q1 __int128 v36; // q2 __int64 i; // x20 __int64 v38; // x0 __int64 v39; // x19 __int64 v40; // x0 __int64 v41; // x0 char *v43; // x19 __int64 v44; // x20 unsigned __int8 *v45; // x25 int v46; // t1 __int64 v47; // x0 __int64 v48; // x19 __int64 v49; // x0 __int64 v50; // x0 __int64 v51; // x25 __int64 v52; // x0 __int64 v53; // x0 __int64 v54; // [xsp+28h] [xbp-D8h] id v55; // [xsp+30h] [xbp-D0h] id v56; // [xsp+38h] [xbp-C8h] size_t __n; // [xsp+40h] [xbp-C0h] BYREF __int64 v58; // [xsp+48h] [xbp-B8h] BYREF void *v59; // [xsp+50h] [xbp-B0h] BYREF __int64 v60; // [xsp+58h] [xbp-A8h] BYREF uint8_t v61[4]; // [xsp+60h] [xbp-A0h] BYREF __int64 time; // [xsp+64h] [xbp-9Ch] uint8_t buf[16]; // [xsp+70h] [xbp-90h] BYREF _DWORD v64[8]; // [xsp+80h] [xbp-80h] BYREF __int64 vars8; // [xsp+108h] [xbp+8h] v6 = objc_retain(a3); v56 = objc_retain(a4); v7 = _DCLogSystem(v56); v8 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v7); if ( os_log_type_enabled_1518(v8, OS_LOG_TYPE_DEFAULT) ) { *(_WORD *)buf = 0; _os_log_impl_1398(&dword_446A2E000, v8, OS_LOG_TYPE_DEFAULT, "Encrypting data...", buf, 2u); } objc_release(v8); v9 = (void *)objc_claimAutoreleasedReturnValue_1330(objc_msgSend(a1[2], "clientAppID")); v10 = (void *)objc_claimAutoreleasedReturnValue_1330(objc_msgSend(v9, "dataUsingEncoding:", 4)); objc_release(v9); v11 = (unsigned int)objc_msgSend(v10, "length"); v55 = objc_retainAutorelease(v10); v12 = objc_msgSend(v55, "bytes"); v13 = (unsigned int)objc_msgSend(v6, "length"); v14 = objc_retainAutorelease(v6); v15 = objc_msgSend(v14, "bytes"); v59 = 0; v60 = 0; v58 = 0; v16 = ccaes_gcm_encrypt_mode_18(); *(_OWORD *)buf = 0u; memset(v64, 0, 28); v17 = v13 + v11 + 235LL; v18 = j__calloc_516(1u, v17); v19 = v18; if ( v18 ) { v54 = v16; *(_DWORD *)((char *)v18 + 150) = v13 + v11 + 81; *v18 = 2; j__memcpy_1002(v18 + 5, objc_msgSend(a1[1], "bytes"), (size_t)objc_msgSend(a1[1], "length")); v20 = (char *)j__calloc_516(1u, *(unsigned int *)((char *)v19 + 150)); *(_DWORD *)(v20 + 73) = v13; j__memcpy_1002(v20 + 81, v15, v13); *(_DWORD *)(v20 + 77) = v11; j__memcpy_1002(&v20[*(unsigned int *)(v20 + 73) + 81], v12, v11); v21 = v56; v22 = objc_msgSend(v56, "timeIntervalSince1970"); *(_QWORD *)(v20 + 65) = v23; v24 = _DCLogSystem(v22); v25 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v24); if ( os_log_type_enabled_1518(v25, OS_LOG_TYPE_DEFAULT) ) { v26 = *(_QWORD *)(v20 + 65); *(_DWORD *)v61 = 134217984; time = v26; _os_log_impl_1398(&dword_446A2E000, v25, OS_LOG_TYPE_DEFAULT, "Token timestamp: %f", v61, 0xCu); } objc_release(v25); v27 = aks_ref_key_create_1(objc_msgSend(a1, "keybagHandle"), 11, 4, 0, 0, &v60); if ( (_DWORD)v27 ) { v28 = v27; v29 = _DCLogSystem(v27); v30 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v29); if ( os_log_type_enabled_1518(v30, OS_LOG_TYPE_ERROR) ) -[DCCertificateGenerator _encryptData:serverSyncedDate:error:].cold.6(v28, v30);LABEL_20: v32 = 0; goto LABEL_21; } __n = 0; public_key_1 = (_OWORD *)aks_ref_key_get_public_key_1(v60, &__n); if ( __n != 65 ) { v41 = _DCLogSystem(public_key_1); v30 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v41); if ( os_log_type_enabled_1518(v30, OS_LOG_TYPE_ERROR) ) -[DCCertificateGenerator _encryptData:serverSyncedDate:error:].cold.5(&__n, v30); goto LABEL_20; } *(_OWORD *)((char *)v19 + 85) = *public_key_1; v34 = public_key_1[1]; v35 = public_key_1[2]; v36 = public_key_1[3]; *((_BYTE *)v19 + 149) = *((_BYTE *)public_key_1 + 64); *(_OWORD *)((char *)v19 + 133) = v36; *(_OWORD *)((char *)v19 + 117) = v35; *(_OWORD *)((char *)v19 + 101) = v34; j__memcpy_1002(v20, public_key_1, __n); j__printf_200("%-25.25s = ", "random_pubkey"); for ( i = 85; i != 150; ++i ) j__printf_200("%02x", *((unsigned __int8 *)v19 + i)); putchar_75(10); v38 = aks_ref_key_compute_key_0(v60, 0, 0, objc_msgSend(a1[1], "bytes"), objc_msgSend(a1[1], "length"), &v59, &v58); if ( (_DWORD)v38 ) { v39 = v38; v40 = _DCLogSystem(v38); v30 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v40); if ( os_log_type_enabled_1518(v30, OS_LOG_TYPE_ERROR) ) -[DCCertificateGenerator _encryptData:serverSyncedDate:error:].cold.4(v39, v30); goto LABEL_20; } v43 = (char *)v59; v44 = v58 - 2; j__printf_200("%-25.25s = ", "ECDH shared key"); if ( v44 ) { v45 = (unsigned __int8 *)(v43 + 2); do { v46 = *v45++; j__printf_200("%02x", v46); --v44; } while ( v44 ); } putchar_75(10); v47 = cchkdf_19(&ccsha256_ltc_di, v58 - 2, (char *)v59 + 2, 0, 0, 0, 0, 44, buf); if ( (_DWORD)v47 ) { v48 = v47; v49 = _DCLogSystem(v47); v30 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v49); if ( os_log_type_enabled_1518(v30, OS_LOG_TYPE_ERROR) ) -[DCCertificateGenerator _encryptData:serverSyncedDate:error:].cold.3(v48, v30); goto LABEL_20; } hex_2((std::ios_base *)"HKDF derived key"); hex_2((std::ios_base *)"HKDF derived iv"); v50 = ccgcm_one_shot_10( v54, 32, buf, 12, &v64[4], 0, 0, *(unsigned int *)((char *)v19 + 150), v20, (char *)v19 + 154, 16, v19 + 1); if ( (_DWORD)v50 ) { v51 = v50; v52 = _DCLogSystem(v50); v30 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v52); if ( os_log_type_enabled_1518(v30, OS_LOG_TYPE_ERROR) ) -[DCCertificateGenerator _encryptData:serverSyncedDate:error:].cold.2(v51, v30); goto LABEL_20; } hex_2((std::ios_base *)"tag"); j__fprintf_285((FILE *)__stderrp_0, "encrypted_data_len: %d\n", *(_DWORD *)((char *)v19 + 150)); v32 = (void *)objc_claimAutoreleasedReturnValue_1330(objc_msgSend(&OBJC_CLASS___NSData, "dataWithBytes:length:", v19, v17)); v53 = _DCLogSystem(v32); v30 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v53); _DCLogDebugBinary_0(v30, CFSTR("Token"), v32); } else { v31 = _DCLogSystem(0); v30 = (NSObject *)objc_claimAutoreleasedReturnValue_1330(v31); if ( os_log_type_enabled_1518(v30, OS_LOG_TYPE_ERROR) ) -[DCCertificateGenerator _encryptData:serverSyncedDate:error:].cold.1(v30); v20 = 0; v32 = 0; v21 = v56; }LABEL_21: objc_release(v30); if ( v60 ) aks_ref_key_free_1(&v60); if ( v19 ) j__free_1273(v19); if ( v20 ) j__free_1273(v20); if ( v59 ) j__free_1273(v59); objc_release(v55); objc_release(v21); objc_release(v14); if ( ((vars8 ^ (2 * vars8)) & 0x4000000000000000LL) != 0 ) __break(0xC471u); return objc_autoreleaseReturnValue(v32);}
这个方法用 Secure Enclave 生成一个临时 EC 密钥 → 和服务器公钥做 ECDH → HKDF 派生 AES-256-GCM key+IV →把「[ephemeral 公钥 + 时间戳 + 激活证书 + appID]」打包加密 → 和各种公钥 / 长度 / tag 一起封装成 Token。流程如下:
4.2 加密算法流程
整个加密流程是一个变种的 ECIES (Elliptic Curve Integrated Encryption Scheme),具体步骤如下:
Payload 构建: 系统将 App ID (如 com.example.app)、设备证书链(包含 App Attest 证书和 Device CA 证书)以及 时间戳 拼接成一段二进制数据。
硬件密钥生成 (AKS): 调用私有 API aks_ref_key_create。这一步是在 Secure Enclave (SE) 安全芯片内部生成一个临时的 P-256 椭圆曲线密钥对。
ECDH 密钥协商: 调用 aks_ref_key_compute_key。系统使用刚才生成的硬件临时私钥,与代码中硬编码的 Apple 服务器公钥 进行 ECDH (Elliptic-curve Diffie–Hellman) 运算,计算出一个 共享密钥 (Shared Secret)。
HKDF 密钥派生: 调用 cchkdf (基于 HMAC 的密钥派生函数)。使用共享密钥作为输入,派生出用于后续对称加密的 AES 密钥 和 IV (初始化向量)。
AES-GCM 加密: 调用 ccgcm_one_shot。使用派生出的 AES 密钥,采用 AES-GCM 模式对第一步构建的 Payload 进行加密。GCM 模式不仅加密数据,还生成一个 Tag (认证标签),用于防止数据被篡改。
最终封装: 最终的 Token 结构大致为:
#pragma pack(push, 1)typedef struct { uint8_t ec_pubkey[65]; // 04 + X(32) + Y(32) double timestamp; // 小端 double uint32_t cert_len; // 激活证书pme uint32_t bundle_len; // app包名长度 // 下面是可变部分: uint8_t cert_pem[cert_len]; char bundle[bundle_len]; // "xxC6HB646H.com.beeasy.xxopee.xx"} TokenPlainHeader;#pragma pack(pop)
4.3 算法还原及为什么不建议生成纯算法?
import base64import timeimport structfrom typing import Tuplefrom cryptography.hazmat.primitives.ciphers.aead import AESGCMfrom cryptography.hazmat.primitives import hashesfrom cryptography.hazmat.primitives.kdf.hkdf import HKDFclass DeviceCheckTokenBuilder: """ - server_pub: 固定“服务器公钥”(65 字节,0x04 开头) - ephemeral_pub: 固定“设备临时公钥”(65 字节,0x04 开头) - ikm: 固定的“ECDH shared secret” - AES key / IV 通过 HKDF(SHA256, L=44) 从 IKM 导出 """ def __init__(self): # ==== 1. 固定服务器公钥 // fallback_server_pubkey ==== self.server_pub = bytes.fromhex( "04 50 D9 34 FA 67 BC F6 F2 DF BF 96 62 9E 0A 72" " 38 E9 20 5D 75 F2 8C FC D8 4F 35 A6 59 2B BE 05" " 8A 9C 0F 8E DB CA 2A CB 67 EF B7 74 97 1C A4 5F" " 7D 85 6A 69 4F B1 B9 C4 0B 94 FB 2E 7A 5A 94 98" " B0" ) # ==== 2. 固定设备临时公钥 _aks_ref_key_get_public_key_1 ==== self.ephemeral_pub = bytes.fromhex( "04 79 5B C4 54 FF 9D 34 1E D8 11 CE CC" " 73 C4 AF 32 1E 81 27 6D A0 BE F0 BF F6 B5 D6 3C" " 5B AC 9F 09 2D 45 90 1B 6C A1 DA BF D9 8B 63 EF" " 7E 3B 9D 14 3D 14 4D FE 70 85 7C 0A 4E 07 88 40" " 4F 92 87 D0" ) # ==== 3. 固定 IKM(ECDH shared secret)==== self.ikm = bytes.fromhex( "fe3cb482384079c224225f476244d7c7" "4031a41bf09ea60e27f9ede0861bf42e" ) # 通过 HKDF 推导 AES key & IV(仿 cchkdf_19) self.aes_key, self.aes_iv = self._hkdf_derive_key_iv(self.ikm) # ------------------ 核心加密相关 ------------------ # @staticmethod def _hkdf_derive_key_iv(ikm: bytes) -> Tuple[bytes, bytes]: """ 从 IKM 导出 44 字节 OKM,前 32 字节做 AES key,后 12 字节做 GCM IV 相当于: cchkdf_19(sha256, ikm, outLen=44, salt=NULL, info=NULL) """ hkdf = HKDF( algorithm=hashes.SHA256(), length=44, salt=None, info=None, ) okm = hkdf.derive(ikm) key = okm[:32] iv = okm[32:44] return key, iv @staticmethod def _gcm_encrypt(plaintext: bytes, key: bytes, iv: bytes) -> Tuple[bytes, bytes]: """ AES-GCM 加密: 返回 (ciphertext_without_tag, tag_16B) """ aesgcm = AESGCM(key) ct_with_tag = aesgcm.encrypt(iv, plaintext, None) tag = ct_with_tag[-16:] ciphertext_only = ct_with_tag[:-16] return ciphertext_only, tag def build_dc_token( self, appname: str = None, appcert: str = None, devicecert: str = None, ) -> str: """ Token Layout: u32 version = 2 u8 tag[16] u8 server_pub[65] u8 ephemeral_pub[65] u32 ciphertext_len u8 ciphertext[ciphertext_len] """ # ---- 1. 默认 appname / 证书 ---- # if appname is None: appname = "T7C6HB646H.com.beeasy.shoppe.tw" if appcert is None: appcert = """-----BEGIN CERTIFICATE-----MIIDJjCCAsugAwIBAgIGAZrJqz2xMAoGCCqGSM49BAMCMFMxJzAlBgNVBAMMHkJhc2ljIEF0dGVzdGF0aW9uIFVzZXIgU3ViIENBMTETMBEGA1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTAeFw0yNTExMjcwODUzNTRaFw0yNjEwMTQxODIwNTRaMIGRMUkwRwYDVQQDDEBiNjdjMGY3ZWM4OWJiOTZlZmU3ZGY5OTIzNDVlNDIxNjdiMjU3ODQyZGQyZWM5MjdkZjE5MWVjYmQwYzM0YmI5MRowGAYDVQQLDBFCQUEgQ2VydGlmaWNhdGlvbjETMBEGA1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABKoJsFk1GR/rs/Jj+3iFqwYNnMZCB/0/s40hCTNSr5iooEkoAg8Apue/liWQrcVLYvknsfpRDZ74cKnpcRI/8+ejggFKMIIBRjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIE8DCCASQGCSqGSIb3Y2QKAQSCARUEggERMYIBDf+EmqGSUA0wCxYEQ0hJUAIDAIEQ/4SqjZJEETAPFgRFQ0lEAgcYaaI8ICAe/4SSvaRECzAJFgRCT1JEAgEY/4aTtcJjGzAZFgRibWFjBBFhYzoxNjoxNTo2ZDphNToxZf+Gy7XKaRkwFxYEaW1laQQPMzU2MTI0NzE1MDY4NTU1/4erkdJkIzAhFgR1ZGlkBBkwMDAwODExMC0wMDE4NjlBMjNDMjAyMDFF/4e7tcJjGzAZFgR3bWFjBBFhYzoxNjoxNTo3OTo4ZTpmZf+Hm5XSZDowOBYEc2VpZAQwMDQyRDI3QzU4QTE2OTAwMjIzMzIwMTMxNzI0MDUyMjRGRDE3MkZCRUQxM0VFQzdCMAoGCCqGSM49BAMCA0kAMEYCIQCytP7jpU3xbaRHvXyvqCcum2F/kkDBSv1x/RFAUXLJQwIhALeFnzR9R9BFlTjLS+nql3Cb6FqxywwJfCvf9v+JJTJl-----END CERTIFICATE-----""" if devicecert is None: devicecert = """-----BEGIN CERTIFICATE-----MIICIzCCAaigAwIBAgIIeNjhG9tnDGgwCgYIKoZIzj0EAwIwUzEnMCUGA1UEAwweQmFzaWMgQXR0ZXN0YXRpb24gVXNlciBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTE3MDQyMDAwNDIwMFoXDTMyMDMyMjAwMDAwMFowUzEnMCUGA1UEAwweQmFzaWMgQXR0ZXN0YXRpb24gVXNlciBTdWIgQ0ExMRMwEQYDVQQKDApBcHBsZSBJbmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEoSZ/1t9eBAEVp5a8PrXacmbGb8zNC1X3StLI9YO6Y0CL7blHmSGmjGWTwD4Q+i0J2BY3+bPHTGRyA9jGB3MSbaNmMGQwEgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBSD5aMhnrB0w/lhkP2XTiMQdqSj8jAdBgNVHQ4EFgQU5mWf1DYLTXUdQ9xmOH/uqeNSD80wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMCA2kAMGYCMQC3M360LLtJS60Z9q3vVjJxMgMcFQ1roGTUcKqvW+4hJ4CeJjySXTgq6IEHn/yWab4CMQCm5NnK6SOSK+AqWum9lL87W3E6AA1f2TvJ/hgok/34jr93nhS87tOQNdxDS8zyiqw=-----END CERTIFICATE-----""" # ---- 2. 拼接证书 + appname ---- # cert_bytes = bytearray() cert_bytes.extend(appcert.encode("utf-8")) cert_bytes.append(0x0A) # 额外换行 cert_bytes.extend(devicecert.encode("utf-8")) app_bytes = appname.encode("utf-8") cert_len = len(cert_bytes) app_len = len(app_bytes) # ---- 3. 构造明文 ---- # 很简单,如有需要自己实现 # ---- 4. AES-GCM 加密(key/iv 来自 HKDF) ---- # 很简单,如有需要自己实现 # ---- 5. 组装最终 Token ---- # result = bytearray() result.extend(struct.pack("<I", 2)) # version = 2 (小端 u32) result.extend(tag) # 16B tag result.extend(self.server_pub) # 服务器公钥 result.extend(self.ephemeral_pub) # 设备临时公钥 result.extend(struct.pack("<I", len(ciphertext))) result.extend(ciphertext) # Base64 输出 return base64.b64encode(bytes(result)).decode("ascii")if __name__ == "__main__": builder = DeviceCheckTokenBuilder() token = builder.build_dc_token() print("Demo DC Token (base64):") print(token)
不建议生成纯算法原因在于:私钥不可导出。 我们在外部代码中只能看到 Apple 的公钥,但无法获取在那一瞬间硬件生成的临时私钥。没有私钥,就无法在外部环境中计算出与硬件一致的 ECDH 共享密钥,也就无法生成能被 Apple 服务器解密的 Token,写死一份是有风险的,不确定Apple服务器端是否有检测。RPC调用可能真实性会更高一些。
4.4 证书替换的可行性分析
除了伪造 ID,我们还可以通过 Hook _encryptData 的入参来伪造设备信息生成我们想要的token。
(function () { if (!ObjC.available) { console.error("[-] ObjC runtime not available"); return; } const NULL = ptr(0); // ========= 通用符号解析工具 ========= function resolveSymbol(moduleHint, name) { var addr = null; try { addr = Module.findExportByName(moduleHint, name); } catch (e) {} if (!addr) { try { addr = Module.findExportByName(null, name); } catch (e) {} } if (addr) { console.log("[*] Resolved " + name + " @ " + addr); } else { console.error("[-] Failed to resolve symbol: " + name); } return addr; } // ====== 导出 C 函数(允许部分缺失) ====== const func_create = resolveSymbol("Security", "SecCertificateCreateWithData"); const func_summary = resolveSymbol("Security", "SecCertificateCopySubjectSummary"); const func_copyData = resolveSymbol("Security", "SecCertificateCopyData"); const func_copyVals = resolveSymbol("Security", "SecCertificateCopyValues"); const func_release = resolveSymbol("CoreFoundation", "CFRelease"); // 这三个必须要有,否则没法干活 if (!func_create || !func_copyData || !func_release) { console.error("[-] Critical symbols missing, abort."); return; } const SecCertificateCreateWithData = new NativeFunction(func_create, 'pointer', ['pointer', 'pointer']); const SecCertificateCopyData = new NativeFunction(func_copyData, 'pointer', ['pointer']); const CFRelease = new NativeFunction(func_release, 'void', ['pointer']); var SecCertificateCopySubjectSummary = null; if (func_summary) { SecCertificateCopySubjectSummary = new NativeFunction(func_summary, 'pointer', ['pointer']); } var SecCertificateCopyValues = null; if (func_copyVals) { SecCertificateCopyValues = new NativeFunction(func_copyVals, 'pointer', ['pointer', 'pointer', 'pointer']); } // ====== 小工具函数 ====== function cfToObj(ref) { if (!ref || ref.isNull()) return null; try { return new ObjC.Object(ref); } catch (e) { return null; } } // 按标准 PEM 格式打印证书(每行 64 字符) function printPemFromDerNSData(derNSData) { if (!derNSData) return; var b64 = derNSData.base64EncodedStringWithOptions_(0).toString(); console.log("-----BEGIN CERTIFICATE-----"); for (var i = 0; i < b64.length; i += 64) { console.log(b64.substr(i, 64)); } console.log("-----END CERTIFICATE-----"); } // 打印 NSData (返回 token 用) function dumpNSData(nsdata, label, maxHexBytes) { if (!nsdata) { console.log("[" + label + "] <NSData is null>"); return; } var len = nsdata.length(); console.log("[" + label + "] length: " + len + " bytes"); // 1) Base64(全部) var b64 = nsdata.base64EncodedStringWithOptions_(0).toString(); console.log("[" + label + "] base64:"); for (var i = 0; i < b64.length; i += 64) { console.log(" " + b64.substr(i, 64)); } // 2) Hex(前 maxHexBytes) var limit = Math.min(len, maxHexBytes || 256); var bytesPtr = nsdata.bytes(); var hex = ""; for (var j = 0; j < limit; j++) { var b = Memory.readU8(bytesPtr.add(j)); var h = ("0" + b.toString(16)).slice(-2); hex += h + ((j + 1) % 16 === 0 ? "\n " : " "); } console.log("[" + label + "] hex (first " + limit + " bytes):\n " + hex); } function printCertDetail(certRef, label) { if (!certRef || certRef.isNull()) { console.log("[" + label + "] ❌ CertRef is NULL"); return; } console.log("\n========== [" + label + "] =========="); // 1. Subject Summary(如果符号存在) if (SecCertificateCopySubjectSummary) { var summaryRef = SecCertificateCopySubjectSummary(certRef); var summaryObj = cfToObj(summaryRef); if (summaryObj) { console.log("SubjectSummary : " + summaryObj.toString()); } else { console.log("SubjectSummary : <null>"); } if (summaryRef && !summaryRef.isNull()) CFRelease(summaryRef); } else { console.log("SubjectSummary : <unavailable>"); } // 2. DER -> PEM var derRef = SecCertificateCopyData(certRef); var derObj = cfToObj(derRef); if (derObj) { printPemFromDerNSData(derObj); } else { console.log("[!] SecCertificateCopyData failed"); } if (derRef && !derRef.isNull()) CFRelease(derRef); // 3. 详细 values(如果符号存在) if (SecCertificateCopyValues) { var valuesRef = SecCertificateCopyValues(certRef, NULL, NULL); var valuesObj = cfToObj(valuesRef); if (valuesObj) { console.log("Values (raw NSDictionary):"); console.log(" " + valuesObj.toString()); } else { console.log("[!] SecCertificateCopyValues returned NULL"); } if (valuesRef && !valuesRef.isNull()) CFRelease(valuesRef); } else { console.log("Values : <SecCertificateCopyValues unavailable>"); } console.log("========== [END] ==========\n"); } // ====== Hook DCCertificateGenerator ====== console.log("\n[*] Script Loaded. Waiting..."); try { var className = "DCCertificateGenerator"; var methodName = "- _encryptData:serverSyncedDate:error:"; if (!ObjC.classes[className]) { console.error("[-] Class " + className + " not found"); return; } if (!ObjC.classes[className][methodName]) { console.error("[-] Method " + methodName + " not found on " + className); return; } var hook = ObjC.classes[className][methodName]; Interceptor.attach(hook.implementation, { onEnter: function (args) { console.warn("\n[+] 🟢 Intercepted Encryption Request"); // args[2] = _encryptData: (NSData*) var dataObj = cfToObj(args[2]); if (!dataObj) { console.log(" [Payload Info] dataObj is NULL or invalid"); return; } var len = dataObj.length(); console.log(" [Payload Info] Raw Length: " + len + " bytes"); // 先直接当 DER 证书试 var certRef = SecCertificateCreateWithData(NULL, dataObj.handle); if (!certRef.isNull()) { printCertDetail(certRef, "Original (DER)"); CFRelease(certRef); } else { console.log(" [Info] SecCertificateCreateWithData failed, trying PEM path..."); var pemStrObj = ObjC.classes.NSString .alloc() .initWithData_encoding_(dataObj, 4); // UTF8 if (pemStrObj) { var strContent = pemStrObj.toString(); if (strContent.indexOf("BEGIN CERTIFICATE") !== -1) { console.log(" [Original Cert] Format: PEM (Base64 Text)"); var matches = strContent.match(/-----BEGIN CERTIFICATE-----([\s\S]+?)-----END CERTIFICATE-----/g); if (matches) { for (var i = 0; i < matches.length; i++) { var block = matches[i]; var cleanBase64 = block .replace(/-----BEGIN CERTIFICATE-----/g, "") .replace(/-----END CERTIFICATE-----/g, "") .replace(/[\r\n]/g, ""); var derData = ObjC.classes.NSData .alloc() .initWithBase64EncodedString_options_(cleanBase64, 0); if (derData) { var certRef2 = SecCertificateCreateWithData(NULL, derData.handle); if (!certRef2.isNull()) { printCertDetail(certRef2, "Parsed PEM Cert #" + (i + 1)); CFRelease(certRef2); } else { console.log(" [Parsed PEM Cert #" + (i + 1) + "] ❌ SecCertificateCreateWithData failed"); } } else { console.log(" [Parsed PEM Cert #" + (i + 1) + "] ❌ initWithBase64EncodedString failed"); } } } else { console.log(" [Original Cert] PEM markers found but no blocks matched"); } } else { console.log(" [Original Cert] Format: Unknown Binary / Non-PEM text"); } } else { console.log(" [Original Cert] Cannot decode as UTF-8 string"); } } }, onLeave: function (retval) { if (retval.isNull()) { console.log("[+] Return value is NULL"); return; } try { var retObj = new ObjC.Object(retval); var clsName = retObj.$className || "<unknown>"; console.log("[+] Return ObjC class: " + clsName); if (retObj.isKindOfClass_(ObjC.classes.NSData)) { // 返回 NSData(大概率是加密后的 token) dumpNSData(retObj, "Return NSData", 256); } else if (retObj.isKindOfClass_(ObjC.classes.NSString)) { console.log("[+] Return NSString:"); console.log(" " + retObj.toString()); } else { console.log("[+] Return object description:"); console.log(" " + retObj.toString()); } } catch (e) { console.log("[!] onLeave: cannot wrap retval as ObjC.Object -> " + e.message); } } }); console.log("[*] Hook Success"); } catch (e) { console.error("[!] Hook Error: " + e.message); }})();// frida -U -n devicecheckd -l devicecheckd1.js
五、在爬虫 / 群控场景中的实战应用
在理解了底层加密原理和 基本流程后,我们需要将视角拉回到业务对抗的一线。在黑灰产(爬虫方)与风控(防守方)的博弈中,DeviceCheck 不仅仅是一个 API,而是判定设备“生死”的判官。
5.1、爬虫方怎么用真机 + DeviceCheck 规避风控”
由于 DeviceCheck 的核心密钥(ECDH 协商用的临时私钥)被锁在 Secure Enclave 硬件中,纯算法还原(脱机算法)的路径已被彻底堵死。目前的黑灰产已全面转向**“真机群控”与“底层 Hook”**相结合的模式。
“借尸还魂”:证书与身份的批量伪造
攻击者建立一个庞大的“白名单设备库”,这些设备是真实存在的、干净的 iPhone。
5.2、防守方怎么用 DeviceCheck 收拾真机爬虫”
面对上述攻击,防守方并非束手无策。正确使用 DeviceCheck 的服务端能力,可以对真机群控造成降维打击。
强制开启“双重验证”
绝不能仅仅依赖“Token 能否被解码”来判断请求合法性。必须调用 Apple 的 Query/Update API 并检查返回值。
善用 2-bit 状态标记(持久化封禁)
DeviceCheck 最强大的地方在于状态的硬件绑定性。
时间戳与频率风控
六、总结
iOS DeviceCheck(及 App Attest)代表了移动安全领域的一个重要转折点:从“软件对抗”走向“硬件对抗”。
通过本次逆向分析,我们得出以下核心结论:
硬件是信任的基石:DeviceCheck 的不可伪造性完全依赖于 Secure Enclave。私钥不出安全区,使得纯软件层面的算法还原(如 Python 脚本生成 Token)在理论上和工程上都成为不可能。
攻防的不对称性:
攻击者不得不通过昂贵的真机群控、复杂的系统级 Hook(注入 devicecheckd)以及硬改(更换基带/闪存芯片/激活证书)来绕过防护,成本呈指数级上升。
防守方只需在服务端接入 Apple 的验证 API,并制定合理的 2-bit 状态标记策略,即可获得一个难以被清洗的设备指纹。
未来的趋势:随着 Apple 在 iOS 14+ 引入 DCAppAttestService,将密钥的绑定粒度从“设备”细化到了“设备 + App 实例”,并且支持对关键业务数据(Assertion)进行签名。这意味着未来的风控将更加精准,留给黑灰产“撞库”和“伪造”的空间将进一步被压缩。
对于安全从业者而言,理解 DeviceCheck 的底层逻辑,不仅有助于在红蓝对抗中制定更有效的策略,也提醒我们:在零信任架构下,基于硬件的可信证明(Hardware-backed Attestation)将是移动端身份认证的终极解决方案。
欢迎加我微信与我交朋友(公众号输入框回复“wx”即可)
参考资料:
https://bbs.kanxue.com/thread-281819.htm
https://iosre.com/t/%E8%BD%AC%E8%BD%BD%E6%9F%90dd%E6%9F%90%E9%9F%B3-ios-devicecheck-token-%E6%AD%A3%E5%90%91%E7%A0%94%E5%8F%91%E4%B8%8E%E9%80%86%E5%90%91%E5%88%86%E6%9E%90%E4%B9%8B%E8%B7%AF%E6%80%9D%E8%80%83/24569/1
致谢: yuzhouheike addhaloka 感谢两位大佬提供的指导与帮助