某虚拟定位APP从破解到原理分析
工具环境
ida7.0
iphone 6
ios 10.2
0x00:基本情况
1. 该app可以修改模拟手机地理位置(gps、基站、WIFI),拥有全局定位、指定应用定位、模拟扫街等功能,只能在已越狱的IOS系统上使用,安装须要用到Cydia,安装后主要分为插件与主程序两个部分,主程序负责与用户交互,插件主要实现了修改地理位置的功能。在Cydia插件安装目录可以找到它释放的xxtweak.dylib文件,拷贝出来后面做详细分析。
2. 程序运行后如果不是vip用户是不能使用修改定位的功能,如下:
0x01:保护机制分析
1. 将手机设置好代理,启动app登录,用抓包工具获取数据包做分析,发送到服务器的数据与服务器返回的数据都是加密的,如下图:
2. 通过动态调试主app来寻找突破口,主app通过sysctl来做反调试,先编写一个tweak来过掉反调试。这个代码网上很多,如下:
static int (*orig_sysctl)(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize); static int my_sysctl(int * name, u_int namelen, void * info, size_t * infosize, void * newinfo, size_t newinfosize){ int ret = orig_sysctl(name,namelen,info,infosize,newinfo,newinfosize); if(namelen == 4 && name[0] == 1 && name[1] == 14 && name[2] == 1){ struct kinfo_proc *info_ptr = (struct kinfo_proc *)info; if(info_ptr && (info_ptr->kp_proc.p_flag & P_TRACED) != 0){ NSLog(@"[AntiAntiDebug] - sysctl query trace status."); info_ptr->kp_proc.p_flag ^= P_TRACED; if((info_ptr->kp_proc.p_flag & P_TRACED) == 0){ NSLog(@"[AntiAntiDebug] trace status reomve success!"); } } } return ret; }
3. 将app放入ida中反编,用登录抓包获取到的信息中关键字来查找字符串定位到组合参数的地方,组合后格式如下:
{ "data":"{ "clientid":"4092f7a187943eff48d1c4b827b5f53c", "username":"xxxxx",//用户名 "password":"xxxxxx"//密码 }", "header":{ "uptime":"1540607913", "sysapi":"10.2", "model":"iPhone 6", "systype":"1", "vercode":"15.13", "uuid":"DA148217C2491937" } }
然后将组合后的代码用AES加密发送到服务器代码如下:
void __cdecl -[TXYUserInfoRequset loginUserwith:andPassword:andClientid:](TXYUserInfoRequset *self, SEL a2, id a3, id a4, id a5) { id v5; // x21 id v6; // x20 TXYUserInfoRequset *v7; // x22 __int64 username; // x19 __int64 v9; // x1 __int64 passwrod; // x20 __int64 v11; // x1 __int64 v12; // x21 void *url; // x0 void *v14; // x0 void *v15; // x0 void *v16; // x24 void *v17; // x0 __int64 clientId; // x23 void *v19; // x0 const __CFString *v20; // x2 struct objc_object *v21; // x0 struct objc_object *v22; // ST28_8 id v23; // x0 __int64 v24; // ST20_8 id v25; // x0 void *v26; // x0 void *v27; // x28 void *v28; // x0 __int64 v29; // x25 void *v30; // x0 struct objc_object *v31; // ST18_8 id v32; // x0 struct objc_object *info_json; // x0 struct objc_object *v34; // x28 id ret; // x0 __int64 v36; // x21 void *v37; // x0 void *v38; // x26 double v39; // d0 void *v40; // x0 __int64 v41; // x25 void *v42; // x0 struct objc_object *bodydata; // x24 __int64 v44; // x1 NSURLSessionTask *v45; // x0 __int64 v46; // x0 struct objc_object *httpurl; // [xsp+38h] [xbp-138h] void *v48; // [xsp+40h] [xbp-130h] int v49; // [xsp+48h] [xbp-128h] int v50; // [xsp+4Ch] [xbp-124h] __int64 (__fastcall *v51)(__int64, __int64); // [xsp+50h] [xbp-120h] void *v52; // [xsp+58h] [xbp-118h] __int64 v53; // [xsp+60h] [xbp-110h] const __CFString *body; // [xsp+68h] [xbp-108h] const __CFString *v55; // [xsp+70h] [xbp-100h] const __CFString *v56; // [xsp+78h] [xbp-F8h] const __CFString *v57; // [xsp+80h] [xbp-F0h] __int64 encdata; // [xsp+88h] [xbp-E8h] const __CFString *v59; // [xsp+90h] [xbp-E0h] const __CFString *v60; // [xsp+98h] [xbp-D8h] __int64 v61; // [xsp+A0h] [xbp-D0h] const __CFString *v62; // [xsp+A8h] [xbp-C8h] const __CFString *v63; // [xsp+B0h] [xbp-C0h] __int64 v64; // [xsp+B8h] [xbp-B8h] __int64 v65; // [xsp+C0h] [xbp-B0h] const __CFString *v66; // [xsp+C8h] [xbp-A8h] const __CFString *v67; // [xsp+D0h] [xbp-A0h] const __CFString *v68; // [xsp+D8h] [xbp-98h] __int64 username_1; // [xsp+E0h] [xbp-90h] __int64 passwrod_1; // [xsp+E8h] [xbp-88h] __int64 clientId_1; // [xsp+F0h] [xbp-80h] const __CFString *v72; // [xsp+F8h] [xbp-78h] const __CFString *v73; // [xsp+100h] [xbp-70h] __int64 v74; // [xsp+108h] [xbp-68h] __int64 v75; // [xsp+110h] [xbp-60h] __int64 v76; // [xsp+118h] [xbp-58h] v5 = a5; v6 = a4; v7 = self; v76 = -7228227847426539268LL; username = objc_retain(a3, a2); passwrod = objc_retain(v6, v9); v12 = objc_retain(v5, v11); if ( !username ) { v20 = CFSTR("缺少用户名"); LABEL_7: objc_msgSend(v7, (const char *)&MEMORY[0x19AEA7047], v20); clientId = v12; goto LABEL_10; } if ( !passwrod ) { v20 = CFSTR("缺少密码"); goto LABEL_7; } url = objc_msgSend( &MEMORY[0x1B559E398], (const char *)&MEMORY[0x1966A229A], CFSTR("%@%@"), CFSTR("http://ipay.txyapp.com:7658/api/entrance"), CFSTR("/111")); httpurl = (struct objc_object *)objc_retainAutoreleasedReturnValue(url); v14 = objc_msgSend(&MEMORY[0x1B5593F88], (const char *)&MEMORY[0x1966A95FA]); v15 = (void *)objc_retainAutoreleasedReturnValue(v14); v16 = v15; v17 = objc_msgSend(v15, (const char *)&MEMORY[0x1966A8093], CFSTR("clientId")); clientId = objc_retainAutoreleasedReturnValue(v17); objc_release(v12); objc_release(v16); if ( clientId ) { username_1 = username; v66 = CFSTR("username"); v67 = CFSTR("password"); passwrod_1 = passwrod; v68 = CFSTR("clientid"); clientId_1 = clientId; v19 = objc_msgSend(&MEMORY[0x1B5593128], (const char *)&MEMORY[0x1966A2036], &username_1, &v66, 3LL); } else { v72 = CFSTR("username"); v73 = CFSTR("password"); v74 = username; v75 = passwrod; v19 = objc_msgSend(&MEMORY[0x1B5593128], (const char *)&MEMORY[0x1966A2036], &v74, &v72, 2LL); } v21 = (struct objc_object *)objc_retainAutoreleasedReturnValue(v19); v22 = v21; v23 = ((id (__cdecl *)(TXYUserInfoRequset *, SEL, id))objc_msgSend)(v7, "convertToJSONData:", v21); v24 = objc_retainAutoreleasedReturnValue(v23); v62 = CFSTR("data"); v63 = CFSTR("header"); v64 = v24; v25 = ((id (__cdecl *)(DeviceAbout_meta *, SEL))objc_msgSend)( (DeviceAbout_meta *)&OBJC_CLASS___DeviceAbout, "sharedDevice"); v26 = (void *)objc_retainAutoreleasedReturnValue(v25); v27 = v26; v28 = objc_msgSend(v26, "getPublicPhone"); v29 = objc_retainAutoreleasedReturnValue(v28); v65 = v29; v30 = objc_msgSend(&MEMORY[0x1B5593128], (const char *)&MEMORY[0x1966A2036], &v64, &v62, 2LL); v31 = (struct objc_object *)objc_retainAutoreleasedReturnValue(v30); objc_release(v29); objc_release(v27); v32 = ((id (__cdecl *)(TXYUserInfoRequset *, SEL, id))objc_msgSend)(v7, "convertToJSONData:", v31); info_json = (struct objc_object *)objc_retainAutoreleasedReturnValue(v32); v34 = info_json; ret = ((id (__cdecl *)(AES128_meta *, SEL, id, id))objc_msgSend)(// 加密参数 (AES128_meta *)&OBJC_CLASS___AES128, "AES128Encrypt:withKey:", info_json, (id)CFSTR("Hz2Ywe8UBe@YfZ0*")); v36 = objc_retainAutoreleasedReturnValue(ret); encdata = v36; body = CFSTR("body"); v55 = CFSTR("type"); v59 = CFSTR("111"); v56 = CFSTR("flag"); v60 = CFSTR("4"); v57 = CFSTR("t1"); v37 = objc_msgSend(&MEMORY[0x1B5592FC0], (const char *)&MEMORY[0x1966B0E63]); v38 = (void *)objc_retainAutoreleasedReturnValue(v37); objc_msgSend(v38, (const char *)&MEMORY[0x19678A07E]); v40 = objc_msgSend(&MEMORY[0x1B559E398], (const char *)&MEMORY[0x1966A229A], CFSTR("%lld"), (signed __int64)v39); v41 = objc_retainAutoreleasedReturnValue(v40); v61 = v41; v42 = objc_msgSend(&MEMORY[0x1B5593128], (const char *)&MEMORY[0x1966A2036], &encdata, &body, 4LL); bodydata = (struct objc_object *)objc_retainAutoreleasedReturnValue(v42); objc_release(v41); objc_release(v38); v48 = &MEMORY[0x1B558B298]; v49 = -1040187392; v50 = 0; v51 = __60__TXYUserInfoRequset_loginUserwith_andPassword_andClientid___block_invoke_2;// 解密返回数并存放配置文件中 v52 = &__block_descriptor_tmp259; v53 = objc_retain(v7, v44); v45 = ((NSURLSessionTask *(__cdecl *)(TXYNetManager_meta *, SEL, unsigned __int64, id, id, id, id, id))objc_msgSend)(// 发送网络 (TXYNetManager_meta *)&OBJC_CLASS___TXYNetManager, "txy_requestWithType:urlString:parameters:progress:successBlock:failureBlock:", 1uLL, httpurl, bodydata, (id)&__block_literal_global240, (id)&v48, (id)&__block_literal_global262); v46 = objc_retainAutoreleasedReturnValue(v45); objc_release(v46); objc_release(v53); objc_release(bodydata); objc_release(v36); objc_release(v34); objc_release(v31); objc_release(v24); objc_release(v22); objc_release(httpurl); LABEL_10: objc_release(clientId); objc_release(passwrod); objc_release(username); }
4. 解密与解析服务器返回的数据,解密后数据格式如下:
{ "status":0, "token":"de9dc56d7d7cc085f4bb1897075e4801", "username":"xxxx",//用户名 "vip":0, //是否为vip用户 "expiretime":0 //会员过期时间 }
解密代码如下:
/ 登录后存放authValue到文件 __int64 __fastcall __60__TXYUserInfoRequset_loginUserwith_andPassword_andClientid___block_invoke_2(__int64 a1, __int64 a2) { __int64 v2; // x28 __int64 v3; // x19 void *v4; // x0 void *v5; // x21 __int64 v6; // x1 void *v7; // x19 void *v8; // x0 __int64 v9; // x22 void *v10; // x0 __int64 v11; // x23 void *v12; // x0 __int64 v13; // ST10_8 void *v14; // x0 void *v15; // x23 void *v16; // x24 void *v17; // x0 struct objc_object *data; // x0 struct objc_object *v19; // x24 id v20; // x0 void *v21; // x0 void *v22; // x28 void *v23; // x0 __int64 v24; // x0 void *v25; // x0 void *v26; // x0 void *v27; // x26 void *v28; // x0 __int64 v29; // ST08_8 void *v30; // x0 void *v31; // x23 void *v32; // x22 void *v33; // x0 __int64 v34; // x22 __int64 v35; // x23 void *v36; // x20 void *v37; // x0 __int64 v38; // x21 __int64 v39; // x0 void *v40; // x0 __int64 v41; // x22 void *v42; // x0 __int64 v43; // ST00_8 void *v44; // x0 void *v45; // x23 void *v46; // x0 __int64 v47; // x28 void *v48; // x0 __int64 v49; // x22 void *v50; // x0 __int64 v51; // ST00_8 void *v52; // x0 void *v53; // x23 void *v54; // x0 __int64 v55; // x22 void *v56; // x0 __int64 v57; // x22 __int64 v58; // x24 void *v59; // x0 void *v60; // x23 void *v61; // x22 void *v62; // x0 void *v63; // x0 void *v64; // x23 void *v65; // x0 __int64 v66; // x24 void *v67; // x0 __int64 v68; // x0 __int64 v69; // x22 __int64 v70; // x0 void *v71; // x0 void *v72; // x22 int vip; // w24 id v74; // x0 void *v75; // x0 void *v76; // x23 void *v77; // x0 void *v78; // x28 void *v79; // x0 __int64 v80; // x24 void *v81; // x0 __int64 v82; // x23 void *v83; // x0 void *v84; // x23 id v85; // x0 void *v86; // x0 __int64 v87; // x24 void *v88; // x0 __int64 v89; // x23 void *v90; // x0 void *v91; // x22 void *v92; // x0 __int64 v93; // x21 void *v94; // x0 __int64 v95; // x20 __int64 v97; // [xsp+0h] [xbp-90h] void *v98; // [xsp+20h] [xbp-70h] struct objc_object *v99; // [xsp+28h] [xbp-68h] __int64 v100; // [xsp+30h] [xbp-60h] __int64 v101; // [xsp+38h] [xbp-58h] __int64 v102; // [xsp+38h] [xbp-58h] v2 = a1; v3 = objc_retain(a2, a2); v4 = objc_msgSend(&MEMORY[0x1B5593F88], (const char *)&MEMORY[0x1966A95FA]); v5 = (void *)objc_retainAutoreleasedReturnValue(v4); objc_msgSend(v5, (const char *)&MEMORY[0x1966A8EE2], CFSTR("no"), CFSTR("geostates")); objc_release(v5); v7 = (void *)objc_retain(v3, v6); NSLog(CFSTR("response====%@")); v8 = objc_msgSend(v7, (const char *)&MEMORY[0x1966A4322], CFSTR("error"), v7); v9 = objc_retainAutoreleasedReturnValue(v8); v10 = objc_msgSend(v7, (const char *)&MEMORY[0x1966A4322], CFSTR("info")); v11 = objc_retainAutoreleasedReturnValue(v10); v12 = objc_msgSend(v7, (const char *)&MEMORY[0x1966A4322], CFSTR("status")); v13 = objc_retainAutoreleasedReturnValue(v12); NSLog(CFSTR("error = %@ info = %@ status = %@")); objc_release(v13); objc_release(v11); objc_release(v9); v14 = objc_msgSend(v7, (const char *)&MEMORY[0x1966A4322], CFSTR("status"), v9, v11, v13); v15 = (void *)objc_retainAutoreleasedReturnValue(v14); v16 = objc_msgSend(v15, (const char *)&MEMORY[0x1966A5F6B]); objc_release(v15); if ( !v16 ) // 判断网络是否返回成功 { v101 = v2; v17 = objc_msgSend(v7, (const char *)&MEMORY[0x1966A4322], CFSTR("data"));// 获取返回值中的data数据 data = (struct objc_object *)objc_retainAutoreleasedReturnValue(v17); v19 = data; v20 = ((id (__cdecl *)(AES128_meta *, SEL, id, id))objc_msgSend)(// 解密data数据 (AES128_meta *)&OBJC_CLASS___AES128, "AES128Decrypt:withKey:", data, (id)CFSTR("Hz2Ywe8UBe@YfZ0*")); v21 = (void *)objc_retainAutoreleasedReturnValue(v20); v22 = v21; v23 = objc_msgSend(v21, (const char *)&MEMORY[0x196754444], 4LL); v24 = objc_retainAutoreleasedReturnValue(v23); v100 = v24; v25 = objc_msgSend(&MEMORY[0x1B55A0FF8], (const char *)&MEMORY[0x197C763B3], v24, 1LL, 0LL); v26 = (void *)objc_retainAutoreleasedReturnValue(v25); v27 = v26; v28 = objc_msgSend(v26, (const char *)&MEMORY[0x1966A4322], CFSTR("msg")); v29 = objc_retainAutoreleasedReturnValue(v28); NSLog(CFSTR("----%@ -------%@")); objc_release(v29); v30 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("status"), v27, v29); v31 = (void *)objc_retainAutoreleasedReturnValue(v30); v32 = objc_msgSend(v31, (const char *)&MEMORY[0x1966A5F6B]); objc_release(v31); if ( v32 ) { v33 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("msg")); v34 = objc_retainAutoreleasedReturnValue(v33); objc_release(v34); v35 = v100; if ( !v34 ) { LABEL_21: objc_release(v27); objc_release(v35); objc_release(v22); objc_release(v19); goto LABEL_22; } v36 = *(void **)(v101 + 32); v37 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("msg")); v38 = objc_retainAutoreleasedReturnValue(v37); objc_msgSend(v36, (const char *)&MEMORY[0x19AEA7047], v38); v39 = v38; } else { v98 = v22; v40 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("token")); v41 = objc_retainAutoreleasedReturnValue(v40); objc_release(v41); if ( v41 ) { v42 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("token")); v43 = objc_retainAutoreleasedReturnValue(v42); NSLog(CFSTR("%@")); objc_release(v43); v44 = objc_msgSend(&MEMORY[0x1B5593F88], (const char *)&MEMORY[0x1966A95FA], v43); v45 = (void *)objc_retainAutoreleasedReturnValue(v44); v46 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("token")); v47 = objc_retainAutoreleasedReturnValue(v46); objc_msgSend(v45, (const char *)&MEMORY[0x1966A8EE2], v47, CFSTR("token")); objc_release(v47); objc_release(v45); } v99 = v19; v48 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("username")); v49 = objc_retainAutoreleasedReturnValue(v48); objc_release(v49); if ( v49 ) { v50 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("username")); v51 = objc_retainAutoreleasedReturnValue(v50); NSLog(CFSTR("%@")); objc_release(v51); v52 = objc_msgSend(&MEMORY[0x1B5593F88], (const char *)&MEMORY[0x1966A95FA], v51); v53 = (void *)objc_retainAutoreleasedReturnValue(v52); v54 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("username")); v55 = objc_retainAutoreleasedReturnValue(v54); objc_msgSend(v53, (const char *)&MEMORY[0x1966A8EE2], v55, CFSTR("userName")); objc_release(v55); objc_release(v53); } v56 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("expiretime")); v57 = objc_retainAutoreleasedReturnValue(v56); objc_release(v57); v58 = v101; if ( v57 ) { v59 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("expiretime")); v60 = (void *)objc_retainAutoreleasedReturnValue(v59); v61 = objc_msgSend(v60, (const char *)&MEMORY[0x1966ABDF3]); objc_release(v60); v62 = objc_msgSend(&MEMORY[0x1B5593F88], (const char *)&MEMORY[0x1966A95FA]); v63 = (void *)objc_retainAutoreleasedReturnValue(v62); v64 = v63; if ( (_DWORD)v61 ) { v65 = objc_msgSend(*(void **)(v101 + 32), "timeFormatted:", v61); v66 = objc_retainAutoreleasedReturnValue(v65); objc_msgSend(v64, (const char *)&MEMORY[0x1966A8EE2], v66, CFSTR("expiretime")); objc_release(v66); objc_release(v64); v58 = v101; v67 = objc_msgSend(*(void **)(v101 + 32), "timeFormatted:", v61); v68 = objc_retainAutoreleasedReturnValue(v67); v69 = v68; v97 = v68; NSLog(CFSTR("expiretime = %@ ")); v70 = v69; } else { objc_msgSend(v63, (const char *)&MEMORY[0x1966A8EE2], CFSTR("0"), CFSTR("expiretime")); v70 = (__int64)v64; } objc_release(v70); } v102 = v58; v71 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("vip"), v97); v72 = (void *)objc_retainAutoreleasedReturnValue(v71); vip = (unsigned __int64)objc_msgSend(v72, (const char *)&MEMORY[0x1966ABDF3]); objc_release(v72); v74 = ((id (__cdecl *)(TXYTools_meta *, SEL))objc_msgSend)((TXYTools_meta *)&OBJC_CLASS___TXYTools, "sharedTools"); v75 = (void *)objc_retainAutoreleasedReturnValue(v74); v76 = v75; v77 = objc_msgSend(v75, "loadSetDictForPath:", CFSTR("/var/mobile/Library/Preferences/com.txy.TxyNew.plist")); v78 = (void *)objc_retainAutoreleasedReturnValue(v77); objc_release(v76); if ( vip ) // 如果vip不为0 { v79 = objc_msgSend(&MEMORY[0x1B559E4B0], (const char *)&MEMORY[0x1966A7D6A], 1LL); v80 = objc_retainAutoreleasedReturnValue(v79); objc_msgSend(v78, (const char *)&MEMORY[0x1966A8EE2], v80, CFSTR("authValue")); objc_release(v80); v81 = objc_msgSend(&MEMORY[0x1B559E4B0], (const char *)&MEMORY[0x1966A7D6A], 1LL); v82 = objc_retainAutoreleasedReturnValue(v81); objc_msgSend(v78, (const char *)&MEMORY[0x1966A8EE2], v82, CFSTR("Toggle")); objc_release(v82); v83 = objc_msgSend(&MEMORY[0x1B5593F88], (const char *)&MEMORY[0x1966A95FA]); v84 = (void *)objc_retainAutoreleasedReturnValue(v83); objc_msgSend(v84, (const char *)&MEMORY[0x1966A8EE2], CFSTR("1"), CFSTR("isVIP")); } else // 如果vip为0 { v86 = objc_msgSend(&MEMORY[0x1B559E4B0], (const char *)&MEMORY[0x1966A7D6A], 0LL); v87 = objc_retainAutoreleasedReturnValue(v86); objc_msgSend(v78, (const char *)&MEMORY[0x1966A8EE2], v87, CFSTR("authValue")); objc_release(v87); v88 = objc_msgSend(&MEMORY[0x1B559E4B0], (const char *)&MEMORY[0x1966A7D6A], 0LL); v89 = objc_retainAutoreleasedReturnValue(v88); objc_msgSend(v78, (const char *)&MEMORY[0x1966A8EE2], v89, CFSTR("Toggle")); objc_release(v89); v90 = objc_msgSend(&MEMORY[0x1B5593F88], (const char *)&MEMORY[0x1966A95FA]); v84 = (void *)objc_retainAutoreleasedReturnValue(v90); objc_msgSend(v84, (const char *)&MEMORY[0x1966A8EE2], CFSTR("0"), CFSTR("isVIP")); } objc_release(v84); v85 = ((id (__cdecl *)(TXYTools_meta *, SEL))objc_msgSend)((TXYTools_meta *)&OBJC_CLASS___TXYTools, "sharedTools"); v91 = (void *)objc_retainAutoreleasedReturnValue(v85); objc_msgSend(v91, "writeDict:toPath:", v78, CFSTR("/var/mobile/Library/Preferences/com.txy.TxyNew.plist"));// 写入配置文件 objc_release(v91); objc_release(v78); v35 = v100; v22 = v98; v19 = v99; v92 = objc_msgSend(v27, (const char *)&MEMORY[0x1966A4322], CFSTR("msg")); v93 = objc_retainAutoreleasedReturnValue(v92); objc_release(v93); if ( v93 ) objc_msgSend(*(void **)(v102 + 32), (const char *)&MEMORY[0x19AEA7047], CFSTR("登录成功")); v94 = objc_msgSend(*(void **)(v102 + 32), "requestResult"); v95 = objc_retainAutoreleasedReturnValue(v94); (*(void (**)(void))(v95 + 16))(); v39 = v95; } objc_release(v39); goto LABEL_21; } LABEL_22: objc_release(v7); return objc_release(v7); }
1. 整个登录过程就分析完成了,主要用到了AES加密算法。
0x02:破解思路
1. 通过上面登录过程的分析,根据上面数据格式可以直接改vip与expiretime的值就能成功破解成会员用户,如下图 :
2. 将服务器返回的值存入.plist文件后,程序会调用-[TXYTools isCanOpen]方法读取文件判断是否为vip,代码如下:
bool __cdecl -[TXYTools isCanOpen](TXYTools *self, SEL a2) { void *v2; // x0 void *v3; // x0 void *v4; // x20 void *v5; // x0 void *v6; // x23 void *isVIP; // x19 id v8; // x0 void *v9; // x0 void *v10; // x23 void *v11; // x0 void *v12; // x20 void *v13; // x0 void *v14; // x23 void *authValue; // x21 v2 = objc_msgSend(&OBJC_CLASS___NSUserDefaults, (const char *)&unk_188A615FA); v3 = (void *)objc_retainAutoreleasedReturnValue(v2); v4 = v3; v5 = objc_msgSend(v3, (const char *)&unk_188A60093, CFSTR("isVIP")); v6 = (void *)objc_retainAutoreleasedReturnValue(v5); isVIP = objc_msgSend(v6, (const char *)&unk_188A5DF6B); objc_release(v6); objc_release(v4); v8 = ((id (__cdecl *)(TXYTools_meta *, SEL))objc_msgSend)((TXYTools_meta *)&OBJC_CLASS___TXYTools, "sharedTools"); v9 = (void *)objc_retainAutoreleasedReturnValue(v8); v10 = v9; v11 = objc_msgSend(v9, "loadSetDictForPath:", CFSTR("/var/mobile/Library/Preferences/com.txy.TxyNew.plist")); v12 = (void *)objc_retainAutoreleasedReturnValue(v11); objc_release(v10); v13 = objc_msgSend(v12, (const char *)&unk_188A60093, CFSTR("authValue")); v14 = (void *)objc_retainAutoreleasedReturnValue(v13); authValue = objc_msgSend(v14, (const char *)&unk_188A5DF6B); objc_release(v14); NSLog(CFSTR("user = %ld")); NSLog(CFSTR("isVIP = %ld")); objc_release(v12); return (signed __int64)isVIP > 0 && (signed __int64)authValue > 0; }
3. 第一是可以通过修改服务器返回值做破解,第二是通过hook方法isCanOpen来做破解。代码如下 :
%hook TXYTools - (BOOL)isCanOpen { return YES; } %end
破解成功后可以正常使用功能,如下图所示 :
0x03:实现原理
1. 主app获取到要修改的经纬度与地名后DES加密存放在.plist配置文件中,将选择的地图上的经纬度与地址名加密后写入.plist配置文件,代码如下:
//将选择的app的Build地图上的经纬度与地址名加密后写入.plist配置文件 __int64 __fastcall -[TXYConfig setLocationWithBundleId:andType:andGPS:withAddress:withIsOn:](void *a1, __int64 a2, __int64 a3, __int64 a4, __int64 a5, __int64 a6, double a7, double a8) { __int64 v8; // x26 __int64 v9; // x19 double v10; // d8 double v11; // d9 __int64 v12; // x25 void *v13; // x20 __int64 v14; // x1 const __CFString *v15; // x19 void *v16; // x0 void *v17; // x0 void *v18; // x21 void *v19; // x0 __int64 v20; // x1 void *v21; // x22 void *v22; // x0 void *v23; // x0 __int64 v24; // x0 __int64 v25; // x28 void *v26; // x0 __int64 v27; // x0 __int64 v28; // x24 void *v29; // x0 __int64 v30; // x0 __int64 v31; // x20 void *v32; // x0 void *v33; // x26 void *v34; // x0 __int64 v35; // x20 void *v36; // x0 __int64 v37; // x20 __int64 v39; // [xsp+10h] [xbp-C0h] __int64 v40; // [xsp+18h] [xbp-B8h] void *v41; // [xsp+20h] [xbp-B0h] const __CFString *v42; // [xsp+28h] [xbp-A8h] const __CFString *v43; // [xsp+30h] [xbp-A0h] const __CFString *v44; // [xsp+38h] [xbp-98h] const __CFString *v45; // [xsp+40h] [xbp-90h] __int64 v46; // [xsp+48h] [xbp-88h] __int64 v47; // [xsp+50h] [xbp-80h] const __CFString *v48; // [xsp+58h] [xbp-78h] __int64 v49; // [xsp+60h] [xbp-70h] __int64 v50; // [xsp+68h] [xbp-68h] v8 = a6; v9 = a5; v10 = a8; v11 = a7; v12 = a4; v13 = a1; v40 = a3; v41 = a1; v50 = -7228227847426539268LL; v39 = objc_retain(a3, a2); v15 = (const __CFString *)objc_retain(v9, v14); v16 = objc_msgSend(v13, "loadSetDict"); v17 = (void *)objc_retainAutoreleasedReturnValue(v16); v18 = v17; v19 = objc_msgSend(v17, (const char *)&unk_1966A8093, CFSTR("AppLocation")); v21 = (void *)objc_retainAutoreleasedReturnValue(v19); if ( !v21 ) { v22 = objc_msgSend(&OBJC_CLASS___NSMutableDictionary, (const char *)&unk_1966A833B); v21 = (void *)objc_retainAutoreleasedReturnValue(v22); } if ( !(_DWORD)v12 ) { objc_retain(CFSTR("跟随系统真实位置"), v20); objc_release(v15); v15 = CFSTR("跟随系统真实位置"); } v42 = CFSTR("Latitude"); v23 = objc_msgSend(&OBJC_CLASS___NSNumber, (const char *)&unk_1966A25C1, v11); v24 = objc_retainAutoreleasedReturnValue(v23); v25 = v24; v46 = v24; v43 = CFSTR("Longitude"); v26 = objc_msgSend(&OBJC_CLASS___NSNumber, (const char *)&unk_1966A25C1, v10); v27 = objc_retainAutoreleasedReturnValue(v26); v28 = v27; v47 = v27; v44 = CFSTR("address"); v48 = v15; v45 = CFSTR("isOn"); v29 = objc_msgSend(&OBJC_CLASS___NSNumber, &aNumberwithbool, v8); v30 = objc_retainAutoreleasedReturnValue(v29); v31 = v30; v49 = v30; v32 = objc_msgSend(&OBJC_CLASS___NSDictionary, &aDictionarywith, &v46, &v42, 4LL); v33 = objc_msgSend(v32, "mutableCopy"); objc_release(v31); objc_release(v28); objc_release(v25); v34 = objc_msgSend(&OBJC_CLASS___NSNumber, &aNumberwithunsi, v12); v35 = objc_retainAutoreleasedReturnValue(v34); objc_msgSend(v33, &aSetobjectForke, v35, CFSTR("FakeType")); objc_release(v35); objc_msgSend(v21, &aSetobjectForke, v33, v40); objc_release(v39); v36 = objc_msgSend(&OBJC_CLASS___NSNumber, &aNumberwithbool, 1LL); v37 = objc_retainAutoreleasedReturnValue(v36); objc_msgSend(v18, &aSetobjectForke, v37, CFSTR("Toggle")); objc_release(v37); objc_msgSend(v18, &aSetobjectForke, v21, CFSTR("AppLocation")); NSLog(CFSTR("%@")); objc_msgSend(v41, "writeSetConfigWithDict:", v18, v18);// 加密并写入配置文件 objc_release(v33); objc_release(v21); objc_release(v18); return objc_release(v15); } //加密并写入配置文件 bool __cdecl -[TXYConfig writeSetConfigWithDict:](TXYConfig *self, SEL a2, id a3) { void *v3; // x0 __int64 v4; // x19 void *v5; // x0 void *v6; // x0 void *v7; // x20 struct objc_object *v8; // x0 void *v9; // x21 char v10; // w22 __int64 v12; // [xsp+8h] [xbp-28h] v3 = objc_msgSend(&OBJC_CLASS___NSJSONSerialization, &aDatawithjsonob, a3, 1LL, 0LL); v4 = objc_retainAutoreleasedReturnValue(v3); v5 = objc_msgSend(&OBJC_CLASS___NSString, &aAlloc_0); v6 = objc_msgSend(v5, &aInitwithdataEn, v4, 4LL); v7 = v6; v8 = +[DES encryptString:](&OBJC_CLASS___DES, "encryptString:", v6);// des加密 v9 = (void *)objc_retainAutoreleasedReturnValue(v8); v12 = 0LL; v10 = (unsigned __int64)objc_msgSend( v9, &aWritetofileAto, CFSTR("/var/mobile/Library/Preferences/com.txy.TxyNew.plist"), 0LL, 4LL, &v12); objc_release(v9); objc_release(v7); objc_release(v4); return v10; } id __cdecl +[DES encryptString:](DES_meta *self, SEL a2, id a3) { return (id)objc_msgSend(self, "TripleDES:encryptOrDecrypt:key:", a3, 0LL, CFSTR("3b38e11ffd65698aedeb5ffc")); }
2. Tweak插件主要是hook了几个函数,当目标程序调用获取地理位置信息函数时就解密主app加密存放好的值做为获取值,代码如下:
Hook获取位置函数
char *__fastcall _logosLocalCtor_3415ee8c(int a1, char **a2, char **a3) { void *v3; // ST30_8 __int64 v4; // x0 __int64 v5; // x8 const char *v7; // [xsp+0h] [xbp-4C0h] const char *v8; // [xsp+8h] [xbp-4B8h] signed __int64 v9; // [xsp+10h] [xbp-4B0h] const char *v10; // [xsp+18h] [xbp-4A8h] void *v11; // [xsp+20h] [xbp-4A0h] char v12; // [xsp+58h] [xbp-468h] __int64 v13; // [xsp+70h] [xbp-450h] int v14; // [xsp+7Ch] [xbp-444h] __int64 CLLocationManager; // [xsp+80h] [xbp-440h] __int64 v16; // [xsp+88h] [xbp-438h] char **v17; // [xsp+90h] [xbp-430h] char **v18; // [xsp+98h] [xbp-428h] int v19; // [xsp+A4h] [xbp-41Ch] char v20; // [xsp+A8h] [xbp-418h] char v21; // [xsp+A9h] [xbp-417h] char v22; // [xsp+AAh] [xbp-416h] char v23; // [xsp+ABh] [xbp-415h] char v24; // [xsp+ACh] [xbp-414h] char v25; // [xsp+ADh] [xbp-413h] char v26; // [xsp+AEh] [xbp-412h] char v27; // [xsp+AFh] [xbp-411h] v19 = a1; v18 = a2; v17 = a3; v16 = objc_getClass("AMapLocationManager"); if ( v16 ) { MSHookMessageEx( v16, "detectRiskOfFakeLocation", _logos_method$_ungrouped$AMapLocationManager$detectRiskOfFakeLocation,// 检测虚拟定位 &_logos_orig$_ungrouped$AMapLocationManager$detectRiskOfFakeLocation); } else { v11 = objc_msgSend(&OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("logos: nil class %s"), "AMapLocationManager"); v10 = "ERROR"; v9 = 276LL; v8 = "Tweak.xm"; v7 = "txytweak"; CFLog(3LL, CFSTR("\x1B[1;31m[%s] \x1B[m\x1B[0;31m%s:%d\x1B[m \x1B[0;30;41m%s:\x1B[m %@")); } CLLocationManager = objc_getClass("CLLocationManager"); if ( CLLocationManager ) { MSHookMessageEx( CLLocationManager, "location", _logos_method$_ungrouped$CLLocationManager$location, &_logos_orig$_ungrouped$CLLocationManager$location); } else { v11 = objc_msgSend( &OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("logos: nil class %s"), "CLLocationManager", v8, v9, v10, v11); v10 = "ERROR"; v9 = 276LL; v8 = "Tweak.xm"; v7 = "txytweak"; CFLog(3LL, CFSTR("\x1B[1;31m[%s] \x1B[m\x1B[0;31m%s:%d\x1B[m \x1B[0;30;41m%s:\x1B[m %@")); } if ( CLLocationManager ) { MSHookMessageEx( CLLocationManager, "startUpdatingLocation", _logos_method$_ungrouped$CLLocationManager$startUpdatingLocation, &_logos_orig$_ungrouped$CLLocationManager$startUpdatingLocation); } else { v11 = objc_msgSend( &OBJC_CLASS___NSString, "stringWithFormat:", CFSTR("logos: nil class %s"), "CLLocationManager", v8, v9, v10, v11); v10 = "ERROR"; v9 = 276LL; v8 = "Tweak.xm"; v7 = "txytweak"; CFLog(3LL, CFSTR("\x1B[1;31m[%s] \x1B[m\x1B[0;31m%s:%d\x1B[m \x1B[0;30;41m%s:\x1B[m %@")); } v20 = 118; v21 = 64; v22 = 58; v23 = 35; v24 = 58; v25 = 35; v26 = 58; v14 = 7; v27 = 0; class_addMethod(); v13 = CFNotificationCenterGetDarwinNotifyCenter(); CFNotificationCenterAddObserver(); objc_msgSend(&OBJC_CLASS___NSBundle, "mainBundle", v7, v8, v9, v10, v11); v3 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v3, "bundleIdentifier"); v4 = objc_retainAutoreleasedReturnValue(); v5 = curBundle; curBundle = v4; objc_release(v5); objc_release(v3); NSLog(CFSTR("txy hook success1111111")); return &v12; }
读取 .plist配置文中的数据并解密。
void __cdecl -[TXYLocation replacedLocationManager:didUpdateToLocation:fromLocation:](TXYLocation *self, SEL a2, id a3, id a4, id a5) { void *v5; // ST2F8_8 __int64 v6; // x0 void *v7; // ST1F0_8 void *v8; // x0 void *v9; // ST1E0_8 void *v10; // ST1D0_8 char v11; // ST1CC_1 void *v12; // ST2A8_8 void *v13; // ST1B8_8 double v14; // d0 double v15; // ST2C0_8 void *v16; // ST1A8_8 double v17; // d0 double v18; // ST2C8_8 __int64 v19; // ST2A0_8 void *v20; // ST1A0_8 double v21; // d0 double v22; // ST198_8 double v23; // d0 double v24; // ST190_8 double v25; // d0 double v26; // ST188_8 double v27; // ST180_8 double v28; // d0 double v29; // d0 double v30; // d1 void *v31; // ST150_8 void *v32; // ST148_8 int v33; // ST144_4 void *v34; // ST258_8 void *v35; // ST138_8 double v36; // d0 void *v37; // ST130_8 double v38; // d0 void *v39; // ST128_8 int v40; // ST124_4 void *v41; // ST238_8 void *v42; // ST118_8 double v43; // d0 void *v44; // ST110_8 double v45; // d0 void *v46; // STF8_8 double v47; // d0 double v48; // STE8_8 double v49; // d0 double v50; // STD8_8 double v51; // d0 double v52; // STC8_8 double v53; // d0 double v54; // STB8_8 double v55; // d0 double v56; // STA8_8 __int64 v57; // x0 __int64 v58; // ST98_8 void *v59; // x0 __int64 v60; // x9 void *v61; // ST88_8 double v62; // d0 double v63; // ST80_8 double v64; // d0 double v65; // ST78_8 double v66; // d0 double v67; // ST70_8 double v68; // d0 double v69; // ST68_8 double v70; // d0 double v71; // ST60_8 __int64 v72; // ST58_8 void *v73; // ST50_8 double v74; // d0 double v75; // ST48_8 double v76; // d0 double v77; // ST40_8 double v78; // d0 double v79; // ST38_8 double v80; // d0 double v81; // ST30_8 double v82; // d0 double v83; // ST28_8 __int64 v84; // ST20_8 double v85; // d0 double v86; // d1 double v87; // d2 double v88; // d3 char v89; // [xsp+15Ch] [xbp-1E4h] char v90; // [xsp+1DCh] [xbp-164h] char v91; // [xsp+1ECh] [xbp-154h] void *v92; // [xsp+228h] [xbp-118h] char v93; // [xsp+267h] [xbp-D9h] void *v94; // [xsp+268h] [xbp-D8h] unsigned int v95; // [xsp+274h] [xbp-CCh] double v96; // [xsp+290h] [xbp-B0h] void *v97; // [xsp+298h] [xbp-A8h] void *v98; // [xsp+2B0h] [xbp-90h] void *v99; // [xsp+2B8h] [xbp-88h] double v100; // [xsp+2C0h] [xbp-80h] double v101; // [xsp+2C8h] [xbp-78h] void *v102; // [xsp+2D0h] [xbp-70h] void *jsondata; // [xsp+2E8h] [xbp-58h] struct objc_object *v104; // [xsp+300h] [xbp-40h] TXYLocation *v105; // [xsp+328h] [xbp-18h] v105 = self; objc_storeStrong(); objc_storeStrong(); objc_storeStrong(); NSLog(CFSTR("第一个方法相应")); objc_msgSend( &OBJC_CLASS___NSString, "stringWithContentsOfFile:encoding:error:", CFSTR("/var/mobile/Library/Preferences/com.txy.TxyNew.plist"), 4LL, 0LL); v104 = (struct objc_object *)objc_retainAutoreleasedReturnValue(); if ( v104 ) { ((void (__cdecl *)(DES_meta *, SEL, id))objc_msgSend)((DES_meta *)&OBJC_CLASS___DES, "decryptString:", v104);// 解密 v5 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v5, "dataUsingEncoding:", 4LL); v6 = objc_retainAutoreleasedReturnValue(); objc_msgSend(&OBJC_CLASS___NSJSONSerialization, "JSONObjectWithData:options:error:", v6, 1LL, 0LL); jsondata = (void *)objc_retainAutoreleasedReturnValue(); if ( !jsondata ) { objc_msgSend(&OBJC_CLASS___NSMutableDictionary, "dictionary"); jsondata = (void *)objc_retainAutoreleasedReturnValue(); objc_release(0LL); } objc_msgSend(jsondata, "valueForKey:", CFSTR("Toggle")); v7 = (void *)objc_retainAutoreleasedReturnValue(); v91 = (unsigned __int64)objc_msgSend(v7, "boolValue"); objc_release(v7); if ( objc_retain(CFSTR("/var/mobile/Library/Preferences/com.txy.FakeStatus.plist")) ) { v8 = objc_msgSend(&OBJC_CLASS___NSMutableDictionary, "alloc"); v102 = objc_msgSend( v8, "initWithContentsOfFile:", CFSTR("/var/mobile/Library/Preferences/com.txy.FakeStatus.plist")); objc_release(0LL); if ( !v102 ) { objc_msgSend(&OBJC_CLASS___NSMutableDictionary, "dictionary"); v102 = (void *)objc_retainAutoreleasedReturnValue(); objc_release(0LL); } } else { objc_msgSend(&OBJC_CLASS___NSMutableDictionary, "dictionary"); v102 = (void *)objc_retainAutoreleasedReturnValue(); objc_release(0LL); } objc_msgSend(v102, "objectForKey:", CFSTR("fakeStatus")); v9 = (void *)objc_retainAutoreleasedReturnValue(); v90 = (unsigned __int64)objc_msgSend(v9, "isEqualToString:", CFSTR("no")); objc_release(v9); if ( !(v91 & 1) ) { _objc_msgSend(v105, "replacedLocationManager:didUpdateToLocation:fromLocation:", 0LL, 0LL, 0LL); LABEL_36: v95 = 0; LABEL_37: objc_storeStrong(); objc_storeStrong(); objc_storeStrong(); objc_storeStrong(); objc_storeStrong(); if ( v95 ) goto LABEL_41; goto LABEL_40; } objc_msgSend(jsondata, "objectForKey:", CFSTR("AppLocation")); v99 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(jsondata, "objectForKey:", CFSTR("AppScan")); v98 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v98, "allKeys"); v10 = (void *)objc_retainAutoreleasedReturnValue(); v11 = (unsigned __int64)objc_msgSend(v10, "containsObject:", curBundle); objc_release(v10); if ( v11 & 1 ) { objc_msgSend(v98, "objectForKey:", curBundle); v12 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v12, "objectForKey:", CFSTR("Latitude")); v13 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v13, "doubleValue"); v15 = v14; objc_release(v13); objc_msgSend(v12, "objectForKey:", CFSTR("Longitude")); v16 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v16, "doubleValue"); v18 = v17; objc_release(v16); objc_msgSend(&OBJC_CLASS___NSDate, "date"); v19 = objc_retainAutoreleasedReturnValue(); v20 = objc_msgSend(&OBJC_CLASS___CLLocation, "alloc"); objc_msgSend(0LL, "altitude"); v22 = v21; objc_msgSend(0LL, "horizontalAccuracy"); v24 = v23; objc_msgSend(0LL, "verticalAccuracy"); v26 = v25; v27 = *(double *)&lastCourse; objc_msgSend(0LL, "speed"); v97 = objc_msgSend( v20, "initWithCoordinate:altitude:horizontalAccuracy:verticalAccuracy:course:speed:timestamp:", v19, v15, v18, v22, v24, v26, v27, v28); objc_msgSend((void *)lastFakeFromLocation, "coordinate"); v96 = headingToLocation(v15, v18, v29, v30); objc_storeStrong(); if ( v96 != 0.0 ) lastCourse = *(_QWORD *)&v96; _objc_msgSend(v105, "replacedLocationManager:didUpdateToLocation:fromLocation:", 0LL, v97, v97); v95 = 1; objc_storeStrong(); objc_storeStrong(); objc_storeStrong(); goto LABEL_33; } v93 = 0; v89 = 0; if ( v99 ) { objc_msgSend(v99, "allKeys"); v94 = (void *)objc_retainAutoreleasedReturnValue(); v93 = 1; v89 = (unsigned __int64)objc_msgSend(v94, "containsObject:", curBundle); } if ( v93 & 1 ) objc_release(v94); if ( v89 & 1 ) { objc_msgSend(v99, "objectForKeyedSubscript:", curBundle); v31 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v31, "objectForKeyedSubscript:", CFSTR("isOn")); v32 = (void *)objc_retainAutoreleasedReturnValue(); v33 = (unsigned __int64)objc_msgSend(v32, "intValue"); objc_release(v32); objc_release(v31); if ( v33 != 1 ) { _objc_msgSend(v105, "replacedLocationManager:didUpdateToLocation:fromLocation:", 0LL, 0LL, 0LL); v95 = 1; goto LABEL_33; } objc_msgSend(v99, "objectForKey:", curBundle); v34 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v34, "objectForKey:", CFSTR("Latitude")); v35 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v35, "doubleValue"); v100 = v36; objc_release(v35); objc_msgSend(v34, "objectForKey:", CFSTR("Longitude")); v37 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v37, "doubleValue"); v101 = v38; objc_release(v37); objc_msgSend(v34, "objectForKey:", CFSTR("FakeType")); v39 = (void *)objc_retainAutoreleasedReturnValue(); v40 = (unsigned __int64)objc_msgSend(v39, "intValue"); objc_release(v39); if ( v40 ) { v95 = 0; } else { _objc_msgSend(v105, "replacedLocationManager:didUpdateToLocation:fromLocation:", 0LL, 0LL, 0LL); v95 = 1; } objc_storeStrong(); if ( v95 ) { LABEL_33: objc_storeStrong(); objc_storeStrong(); if ( v95 ) goto LABEL_37; goto LABEL_36; } } else { if ( (v90 & 1) != 0 ) { _objc_msgSend(v105, "replacedLocationManager:didUpdateToLocation:fromLocation:", 0LL, 0LL, 0LL); v95 = 1; goto LABEL_33; } objc_msgSend(jsondata, "objectForKey:", CFSTR("FakeLocation")); v41 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v41, "objectForKey:", CFSTR("FakeLatitude")); v42 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v42, "doubleValue"); v100 = v43; objc_release(v42); objc_msgSend(v41, "objectForKey:", CFSTR("FakeLongitude")); v44 = (void *)objc_retainAutoreleasedReturnValue(); objc_msgSend(v44, "doubleValue"); v101 = v45; objc_release(v44); objc_storeStrong(); } if ( lastFakeFromLocation ) { v73 = objc_msgSend(&OBJC_CLASS___CLLocation, "alloc"); objc_msgSend(0LL, "altitude"); v75 = v74; objc_msgSend(0LL, "horizontalAccuracy"); v77 = v76; objc_msgSend(0LL, "verticalAccuracy"); v79 = v78; objc_msgSend(0LL, "course"); v81 = v80; objc_msgSend(0LL, "speed"); v83 = v82; objc_msgSend(0LL, "timestamp"); v84 = objc_retainAutoreleasedReturnValue(); v92 = objc_msgSend( v73, "initWithCoordinate:altitude:horizontalAccuracy:verticalAccuracy:course:speed:timestamp:", v84, v100, v101, v75, v77, v79, v81, v83); objc_release(0LL); objc_release(v84); } else { v46 = objc_msgSend(&OBJC_CLASS___CLLocation, "alloc"); objc_msgSend(0LL, "altitude"); v48 = v47; objc_msgSend(0LL, "horizontalAccuracy"); v50 = v49; objc_msgSend(0LL, "verticalAccuracy"); v52 = v51; objc_msgSend(0LL, "course"); v54 = v53; objc_msgSend(0LL, "speed"); v56 = v55; objc_msgSend(0LL, "timestamp"); v57 = objc_retainAutoreleasedReturnValue(); v58 = v57; v59 = objc_msgSend( v46, "initWithCoordinate:altitude:horizontalAccuracy:verticalAccuracy:course:speed:timestamp:", v57, v100, v101, v48, v50, v52, v54, v56); v60 = lastFakeFromLocation; lastFakeFromLocation = (__int64)v59; objc_release(v60); objc_release(v58); v61 = objc_msgSend(&OBJC_CLASS___CLLocation, "alloc"); objc_msgSend(0LL, "altitude"); v63 = v62; objc_msgSend(0LL, "horizontalAccuracy"); v65 = v64; objc_msgSend(0LL, "verticalAccuracy"); v67 = v66; objc_msgSend(0LL, "course"); v69 = v68; objc_msgSend(0LL, "speed"); v71 = v70; objc_msgSend(0LL, "timestamp"); v72 = objc_retainAutoreleasedReturnValue(); v92 = objc_msgSend( v61, "initWithCoordinate:altitude:horizontalAccuracy:verticalAccuracy:course:speed:timestamp:", v72, v100, v101, v63, v65, v67, v69, v71); objc_release(0LL); objc_release(v72); } _objc_msgSend(v105, "replacedLocationManager:didUpdateToLocation:fromLocation:", 0LL, v92, v92); objc_storeStrong(); objc_storeStrong(); v95 = 0; goto LABEL_33; } _objc_msgSend(v105, "replacedLocationManager:didUpdateToLocation:fromLocation:", 0LL, 0LL, 0LL); LABEL_40: v95 = 0; LABEL_41: objc_storeStrong(); objc_storeStrong(); objc_storeStrong(); objc_storeStrong(); if ( v95 > 1 ) headingToLocation(v85, v86, v87, v88); }
0x04:总结
1. 虽然与服务器交互的数据是加密的,但软件保护逻辑比较简单,实现修改地理位置的功能主要是通过hook获取位置的函数。
欢迎关注公众号