由于时间和水平有限,本文会存在诸多不足,希望得到您的及时反馈与指正,多谢!
工具环境:
iPhone 6、
系统版本 10.1.1
IDA Pro 7.0
0x00:防作弊产品介绍
1.由于IOS系统的不开放性,能获取的信息太少,所在IOS上的防作弊产品可做的功能就相比较于安卓要少很多了。硬件方面主要获取IDFA、IDFV这两个值,软件方面主要获取一些风险APP的名称。
0x01:SDK整体框架
1.该防作弊产品提供SDK形式给开发者调用,当开发者成功集成到APP后,APP启动时就会生成一个唯一的ID值。
2.SDK客户端整体流程如图1所示:
图1
3.服务器返回的ID会存放在系统中,这个ID值用通俗的话说,就是为每台设备注册一个身份证号,它代表了设备。这样一来,如果刷量者通过hook机制来修改IDFA、mac等设备模拟新用户就不起作用了。
0x02:技术细节分析
1.APP启动时会解密会判断本地是否缓存了deviceID值与风险app名单,如果没有就生成一个随机的deviceid然后解密写死在app中的风险文件名单。
2.从服务器获取deviceid值
如果没有缓存ID就生成一个ID,生成随机的deviceID代码如下:
1 // 第一次生成deviceid (uuid+当前时间) 2 id __cdecl -[SmidManager genFpId](SmidManager *self, SEL a2) 3 { 4 __int64 v2; // x0 5 __int64 v3; // x0 6 __int64 v4; // x0 7 __int64 v5; // x0 8 void *v6; // x0 9 void *v7; // x0 10 void *v8; // x0 11 void *v9; // x0 12 void *second; // x0 13 void *v11; // x0 14 __int64 v12; // x0 15 __int64 currtime; // ST68_8 16 id v14; // x0 17 __int64 uuid_md5; // x0 18 __int64 v16; // ST58_8 19 void *v17; // x0 20 void *v18; // x0 21 void *v19; // x0 22 void *v20; // x0 23 void *v21; // x9 24 void *v22; // x0 25 void *v23; // x0 26 void *v24; // x9 27 void *v25; // x0 28 void *v26; // x0 29 void *v27; // x9 30 void *v28; // x0 31 void *v29; // x0 32 void *v30; // x9 33 void *v31; // x0 34 void *v32; // x0 35 void *v33; // x9 36 void *v34; // x0 37 void *v35; // x0 38 void *v36; // x9 39 void *v37; // x0 40 void *v38; // x0 41 void *v39; // x9 42 void *v40; // x0 43 void *v41; // x0 44 void *v42; // x9 45 void *v43; // x0 46 struct objc_object *v44; // x0 47 struct objc_object *v45; // ST38_8 48 id v46; // x0 49 void *v47; // x0 50 __int64 v48; // x0 51 void *v49; // x0 52 __int64 v50; // ST30_8 53 __int64 v52; // [xsp+98h] [xbp-B8h] 54 void *v53; // [xsp+A0h] [xbp-B0h] 55 void *v54; // [xsp+A8h] [xbp-A8h] 56 void *v55; // [xsp+B0h] [xbp-A0h] 57 __int64 v56; // [xsp+B8h] [xbp-98h] 58 void *v57; // [xsp+C0h] [xbp-90h] 59 void *minute; // [xsp+C8h] [xbp-88h] 60 void *hour; // [xsp+D0h] [xbp-80h] 61 void *day; // [xsp+D8h] [xbp-78h] 62 void *month; // [xsp+E0h] [xbp-70h] 63 void *year; // [xsp+E8h] [xbp-68h] 64 void *v63; // [xsp+F0h] [xbp-60h] 65 __int64 v64; // [xsp+F8h] [xbp-58h] 66 void *v65; // [xsp+100h] [xbp-50h] 67 __int64 v66; // [xsp+108h] [xbp-48h] 68 struct objc_object *uuid; // [xsp+110h] [xbp-40h] 69 __int64 v68; // [xsp+118h] [xbp-38h] 70 __int64 v69; // [xsp+120h] [xbp-30h] 71 SEL v70; // [xsp+128h] [xbp-28h] 72 SmidManager *v71; // [xsp+130h] [xbp-20h] 73 __int64 v72; // [xsp+138h] [xbp-18h] 74 75 v71 = self; 76 v70 = a2; 77 v2 = CFUUIDCreate(); 78 v69 = v2; 79 v3 = CFUUIDCreateString(0LL, v2); 80 v68 = v3; 81 v4 = CFStringCreateCopy(0LL, v3); 82 v72 = v4; 83 v5 = objc_autoreleaseReturnValue(v4); 84 uuid = (struct objc_object *)objc_retainAutoreleasedReturnValue(v5); 85 CFRelease(v69); 86 CFRelease(v68); 87 v6 = objc_msgSend(&OBJC_CLASS___NSDate, (const char *)&unk_195EEC6AF); 88 v66 = objc_retainAutoreleasedReturnValue(v6); 89 v7 = objc_msgSend(&OBJC_CLASS___NSCalendar, (const char *)&unk_195F34590); 90 v8 = (void *)objc_retainAutoreleasedReturnValue(v7); 91 v65 = v8; 92 v64 = 252LL; 93 v9 = objc_msgSend(v8, (const char *)&unk_195F345E4, 252LL, v66); 94 v63 = (void *)objc_retainAutoreleasedReturnValue(v9); 95 year = objc_msgSend(v63, (const char *)&unk_195F9F96E); 96 month = objc_msgSend(v63, (const char *)&unk_195F9F973); 97 day = objc_msgSend(v63, (const char *)&unk_195F9F979); 98 hour = objc_msgSend(v63, (const char *)&unk_195F34810); 99 minute = objc_msgSend(v63, (const char *)&unk_195F5F105); 100 second = objc_msgSend(v63, (const char *)&unk_195F5F10C); 101 v57 = second; 102 v11 = objc_msgSend( 103 &OBJC_CLASS___NSString, 104 (const char *)&unk_195EDDC2A, 105 CFSTR("%04d%02d%02d%02d%02d%02d"), 106 year, 107 month, 108 day, 109 hour, 110 minute, 111 second); 112 v12 = objc_retainAutoreleasedReturnValue(v11); 113 v56 = v12; 114 currtime = v12; 115 v14 = ((id (__cdecl *)(SmUtils_meta *, SEL, id))objc_msgSend)( 116 (SmUtils_meta *)&OBJC_CLASS___SmUtils, 117 "md5EncodeStr:", 118 uuid); 119 uuid_md5 = objc_retainAutoreleasedReturnValue(v14); 120 v16 = uuid_md5; 121 v17 = objc_msgSend( 122 &OBJC_CLASS___NSString, 123 (const char *)&unk_195EDDC2A, 124 CFSTR("%@%@%@"), 125 currtime, 126 uuid_md5, 127 CFSTR("00")); 128 v55 = (void *)objc_retainAutoreleasedReturnValue(v17); 129 objc_release(v16); 130 v18 = (void *)objc_retain(&stru_1027FA700); 131 v54 = v18; 132 v19 = objc_msgSend(v18, (const char *)&unk_195EF0B91, CFSTR("shumei")); 133 v20 = (void *)objc_retainAutoreleasedReturnValue(v19); 134 v21 = v54; 135 v54 = v20; 136 objc_release(v21); 137 v22 = objc_msgSend(v54, (const char *)&unk_195EF0B91, CFSTR("_")); 138 v23 = (void *)objc_retainAutoreleasedReturnValue(v22); 139 v24 = v54; 140 v54 = v23; 141 objc_release(v24); 142 v25 = objc_msgSend(v54, (const char *)&unk_195EF0B91, CFSTR("ios")); 143 v26 = (void *)objc_retainAutoreleasedReturnValue(v25); 144 v27 = v54; 145 v54 = v26; 146 objc_release(v27); 147 v28 = objc_msgSend(v54, (const char *)&unk_195EF0B91, CFSTR("_")); 148 v29 = (void *)objc_retainAutoreleasedReturnValue(v28); 149 v30 = v54; 150 v54 = v29; 151 objc_release(v30); 152 v31 = objc_msgSend(v54, (const char *)&unk_195EF0B91, CFSTR("sec")); 153 v32 = (void *)objc_retainAutoreleasedReturnValue(v31); 154 v33 = v54; 155 v54 = v32; 156 objc_release(v33); 157 v34 = objc_msgSend(v54, (const char *)&unk_195EF0B91, CFSTR("_")); 158 v35 = (void *)objc_retainAutoreleasedReturnValue(v34); 159 v36 = v54; 160 v54 = v35; 161 objc_release(v36); 162 v37 = objc_msgSend(v54, (const char *)&unk_195EF0B91, CFSTR("key")); 163 v38 = (void *)objc_retainAutoreleasedReturnValue(v37); 164 v39 = v54; 165 v54 = v38; 166 objc_release(v39); 167 v40 = objc_msgSend(v54, (const char *)&unk_195EF0B91, CFSTR("_")); 168 v41 = (void *)objc_retainAutoreleasedReturnValue(v40); 169 v42 = v54; 170 v54 = v41; 171 objc_release(v42); 172 v43 = objc_msgSend(&OBJC_CLASS___NSString, (const char *)&unk_195EDDC2A, CFSTR("%@%@"), v54, v55); 173 v44 = (struct objc_object *)objc_retainAutoreleasedReturnValue(v43); 174 v45 = v44; 175 v46 = ((id (__cdecl *)(SmUtils_meta *, SEL, id))objc_msgSend)( 176 (SmUtils_meta *)&OBJC_CLASS___SmUtils, 177 "md5EncodeStr:", 178 v44); 179 v53 = (void *)objc_retainAutoreleasedReturnValue(v46); 180 objc_release(v45); 181 v47 = objc_msgSend(v53, (const char *)&unk_195F19145, 14LL); 182 v48 = objc_retainAutoreleasedReturnValue(v47); 183 v52 = v48; 184 v49 = objc_msgSend(v55, (const char *)&unk_195EF0B91, v48); 185 v50 = objc_retainAutoreleasedReturnValue(v49); 186 objc_storeStrong(&v52, 0LL); 187 objc_storeStrong(&v53, 0LL); 188 objc_storeStrong(&v54, 0LL); 189 objc_storeStrong(&v55, 0LL); 190 objc_storeStrong(&v56, 0LL); 191 objc_storeStrong(&v63, 0LL); 192 objc_storeStrong(&v65, 0LL); 193 objc_storeStrong(&v66, 0LL); 194 objc_storeStrong(&uuid, 0LL); 195 return (id)objc_autoreleaseReturnValue(v50); 196 }
判断deviceID类型 本地随机生成为0 服务下发的为1
1 signed __int64 __cdecl +[SmidManager typeId:](SmidManager_meta *self, SEL a2, id a3) 2 { 3 void *v3; // x0 4 void *v4; // x0 5 void *v5; // x0 6 void *v6; // x8 7 void *v7; // x0 8 void *v8; // x0 9 void *v9; // x8 10 void *v10; // x0 11 void *v11; // x0 12 void *v12; // x8 13 void *v13; // x0 14 void *v14; // x0 15 void *v15; // x8 16 void *v16; // x0 17 void *v17; // x0 18 void *v18; // x8 19 void *v19; // x0 20 void *v20; // x0 21 void *v21; // x8 22 void *v22; // x0 23 void *v23; // x0 24 void *v24; // x8 25 void *v25; // x0 26 void *v26; // x0 27 void *v27; // x8 28 void *v28; // x0 29 __int64 v29; // x0 30 __int64 v30; // ST18_8 31 void *v31; // x0 32 id v32; // x0 33 void *v33; // x0 34 void *v34; // x0 35 __int64 v35; // x0 36 __int64 v36; // x8 37 void *v37; // x0 38 __int64 v39; // [xsp+68h] [xbp-48h] 39 void *v40; // [xsp+70h] [xbp-40h] 40 struct objc_object *v41; // [xsp+78h] [xbp-38h] 41 void *v42; // [xsp+80h] [xbp-30h] 42 int v43; // [xsp+8Ch] [xbp-24h] 43 void *v44; // [xsp+90h] [xbp-20h] 44 SEL v45; // [xsp+98h] [xbp-18h] 45 SmidManager_meta *v46; // [xsp+A0h] [xbp-10h] 46 __int64 v47; // [xsp+A8h] [xbp-8h] 47 48 v46 = self; 49 v45 = a2; 50 v44 = 0LL; 51 objc_storeStrong(&v44, a3); 52 if ( (unsigned __int64)+[SmStrUtils empty:](&OBJC_CLASS___SmStrUtils, "empty:", v44) & 1 53 || objc_msgSend(v44, (const char *)&unk_195EE38EE) != &unk_3E ) 54 { 55 v47 = -1LL; 56 v43 = 1; 57 } 58 else 59 { 60 v3 = (void *)objc_retain(&stru_1027FA700); 61 v42 = v3; 62 v4 = objc_msgSend(v3, (const char *)&unk_195EF0B91, CFSTR("shumei")); 63 v5 = (void *)objc_retainAutoreleasedReturnValue(v4); 64 v6 = v42; 65 v42 = v5; 66 objc_release(v6); 67 v7 = objc_msgSend(v42, (const char *)&unk_195EF0B91, CFSTR("_")); 68 v8 = (void *)objc_retainAutoreleasedReturnValue(v7); 69 v9 = v42; 70 v42 = v8; 71 objc_release(v9); 72 v10 = objc_msgSend(v42, (const char *)&unk_195EF0B91, CFSTR("ios")); 73 v11 = (void *)objc_retainAutoreleasedReturnValue(v10); 74 v12 = v42; 75 v42 = v11; 76 objc_release(v12); 77 v13 = objc_msgSend(v42, (const char *)&unk_195EF0B91, CFSTR("_")); 78 v14 = (void *)objc_retainAutoreleasedReturnValue(v13); 79 v15 = v42; 80 v42 = v14; 81 objc_release(v15); 82 v16 = objc_msgSend(v42, (const char *)&unk_195EF0B91, CFSTR("sec")); 83 v17 = (void *)objc_retainAutoreleasedReturnValue(v16); 84 v18 = v42; 85 v42 = v17; 86 objc_release(v18); 87 v19 = objc_msgSend(v42, (const char *)&unk_195EF0B91, CFSTR("_")); 88 v20 = (void *)objc_retainAutoreleasedReturnValue(v19); 89 v21 = v42; 90 v42 = v20; 91 objc_release(v21); 92 v22 = objc_msgSend(v42, (const char *)&unk_195EF0B91, CFSTR("key")); 93 v23 = (void *)objc_retainAutoreleasedReturnValue(v22); 94 v24 = v42; 95 v42 = v23; 96 objc_release(v24); 97 v25 = objc_msgSend(v42, (const char *)&unk_195EF0B91, CFSTR("_")); 98 v26 = (void *)objc_retainAutoreleasedReturnValue(v25); 99 v27 = v42; 100 v42 = v26; 101 objc_release(v27); 102 v28 = objc_msgSend(v44, (const char *)&unk_195F19145, 48LL); 103 v29 = objc_retainAutoreleasedReturnValue(v28); 104 v30 = v29; 105 v31 = objc_msgSend(&OBJC_CLASS___NSString, (const char *)&unk_195EDDC2A, CFSTR("%@%@"), v42, v29); 106 v41 = (struct objc_object *)objc_retainAutoreleasedReturnValue(v31); 107 objc_release(v30); 108 v32 = ((id (__cdecl *)(SmUtils_meta *, SEL, id))objc_msgSend)( 109 (SmUtils_meta *)&OBJC_CLASS___SmUtils, 110 "md5EncodeStr:", 111 v41); 112 v33 = (void *)objc_retainAutoreleasedReturnValue(v32); 113 v40 = v33; 114 v34 = objc_msgSend(v33, (const char *)&unk_195F19145, 14LL); 115 v35 = objc_retainAutoreleasedReturnValue(v34); 116 v36 = (__int64)v40; 117 v40 = (void *)v35; 118 objc_release(v36); 119 v37 = objc_msgSend(v44, (const char *)&unk_195EDFD20, 48LL); 120 v39 = objc_retainAutoreleasedReturnValue(v37); 121 if ( (unsigned __int64)+[SmStrUtils equal:right:](&OBJC_CLASS___SmStrUtils, "equal:right:", v40, v39) & 1 ) 122 { 123 if ( (unsigned __int16)objc_msgSend(v44, (const char *)&unk_195F17186, 47LL) == 48 ) 124 { 125 v47 = 0LL; 126 v43 = 1; 127 } 128 else 129 { 130 if ( (unsigned __int16)objc_msgSend(v44, (const char *)&unk_195F17186, 47LL) == 49 ) 131 v47 = 1LL; 132 else 133 v47 = -1LL; 134 v43 = 1; 135 } 136 } 137 else 138 { 139 v47 = 2LL; 140 v43 = 1; 141 } 142 objc_storeStrong(&v39, 0LL); 143 objc_storeStrong(&v40, 0LL); 144 objc_storeStrong(&v41, 0LL); 145 objc_storeStrong(&v42, 0LL); 146 } 147 objc_storeStrong(&v44, 0LL); 148 return v47; 149 }
将获取到的硬件信息与刚生成的deviceid组合加密传给服务器,如果成功服务器就返回一个deviceID值。
1 //组合请求体 2 { 3 "lstat":[ 4 1, 5 0 6 ], 7 "idfa":"56076342-6AA8-4EF3-A3B3-FF0E2C6Exxxx", 8 "os":"ios", 9 "rtype":"core", 10 "t":1559112353610, 11 "sdkver":"2.5.0", 12 "idfv":"DFF15047-2F42-4612-8BE2-8D0B2482xxxx", 13 "boot":1559009952219, 14 "appId":"", 15 "lfrom":"gen", 16 "smid":"2019052914070272ea50eee30ea85b0bcc2141c04e5bcd00ebfc34bfe82ae9" //本地随机生成 17 }
加密传给服务器 获取deviceid key为smsdkWd4Z1WnKWa9R3ud4Jxxx(md5值)
1 id __cdecl -[SmAntiFraud wrap:](SmAntiFraud *self, SEL a2, id a3) 2 { 3 void *v3; // x0 4 __int64 v4; // x0 5 __int64 v5; // STD0_8 6 void *v6; // x0 7 void *v7; // STC8_8 8 void *v8; // x0 9 __int64 v9; // x0 10 __int64 v10; // STC0_8 11 void *v11; // x0 12 id v12; // x0 13 void *v13; // x0 14 void *v14; // STB8_8 15 void *v15; // x0 16 id v16; // x0 17 __int64 v17; // x0 18 __int64 v18; // x8 19 NSMutableDictionary *v19; // x0 20 void *v20; // x0 21 void *v21; // STA8_8 22 char v22; // STA4_1 23 void *v23; // x0 24 __int64 v24; // ST90_8 25 void *v25; // x0 26 __int64 v26; // ST78_8 27 id v27; // x0 28 __int64 v28; // x0 29 __int64 v29; // ST58_8 30 void *v30; // x0 31 void *v31; // x0 32 __int64 v32; // x0 33 const __CFString *v33; // x9 34 __int64 v34; // ST48_8 35 void *v35; // x0 36 id v36; // x0 37 struct objc_object *v37; // x0 38 id v38; // x0 39 __int64 v39; // x0 40 __int64 v40; // x8 41 __int64 v41; // ST30_8 42 __int64 v43; // [xsp+D8h] [xbp-68h] 43 struct objc_object *v44; // [xsp+E0h] [xbp-60h] 44 __int64 v45; // [xsp+E8h] [xbp-58h] 45 void *v46; // [xsp+F0h] [xbp-50h] 46 struct objc_object *v47; // [xsp+F8h] [xbp-48h] 47 struct objc_object *v48; // [xsp+100h] [xbp-40h] 48 __int64 v49; // [xsp+108h] [xbp-38h] 49 char v50; // [xsp+117h] [xbp-29h] 50 struct objc_object *v51; // [xsp+118h] [xbp-28h] 51 SEL v52; // [xsp+120h] [xbp-20h] 52 SmAntiFraud *v53; // [xsp+128h] [xbp-18h] 53 54 v53 = self; 55 v52 = a2; 56 v51 = 0LL; 57 objc_storeStrong(&v51, a3); 58 if ( (unsigned __int64)+[SmStrUtils empty:](&OBJC_CLASS___SmStrUtils, "empty:", v51) & 1 ) 59 objc_storeStrong(&v51, &stru_1027FA700); 60 v50 = 0; 61 v49 = 0LL; 62 if ( (unsigned __int64)objc_msgSend(v53->_option, (const char *)&unk_1A7804C37) & 1 ) 63 { 64 v3 = objc_msgSend(v53->_option, (const char *)&unk_192B2C190); 65 v4 = objc_retainAutoreleasedReturnValue(v3); 66 v5 = v4; 67 v6 = objc_msgSend(CFSTR("smsdk"), (const char *)&unk_195EF0B91, v4); 68 v7 = (void *)objc_retainAutoreleasedReturnValue(v6); 69 v8 = -[SmOption privKey](v53->_option, "privKey"); 70 v9 = objc_retainAutoreleasedReturnValue(v8); 71 v10 = v9; 72 v11 = objc_msgSend(v7, (const char *)&unk_195EF0B91, v9); 73 v48 = (struct objc_object *)objc_retainAutoreleasedReturnValue(v11); 74 objc_release(v10); 75 objc_release(v7); 76 objc_release(v5); 77 v12 = ((id (__cdecl *)(SmUtils_meta *, SEL, id))objc_msgSend)( 78 (SmUtils_meta *)&OBJC_CLASS___SmUtils, 79 "md5EncodeStr:", 80 v48); 81 v13 = (void *)objc_retainAutoreleasedReturnValue(v12); 82 v14 = v13; 83 v15 = objc_msgSend(v13, (const char *)&unk_195F390C0); 84 v47 = (struct objc_object *)objc_retainAutoreleasedReturnValue(v15); 85 objc_release(v14); 86 v16 = ((id (__cdecl *)(SmUtils_meta *, SEL, id, id))objc_msgSend)( 87 (SmUtils_meta *)&OBJC_CLASS___SmUtils, 88 "aes256EncryptStr:key:", 89 v51, 90 v47); 91 v17 = objc_retainAutoreleasedReturnValue(v16); 92 v18 = v49; 93 v49 = v17; 94 objc_release(v18); 95 v50 = 1; 96 objc_storeStrong(&v47, 0LL); 97 objc_storeStrong(&v48, 0LL); 98 } 99 else 100 { 101 objc_storeStrong(&v49, v51); 102 } 103 if ( (unsigned __int64)+[SmStrUtils empty:](&OBJC_CLASS___SmStrUtils, "empty:", v49) & 1 ) 104 objc_storeStrong(&v49, &stru_1027FA700)