数盟IOS端可信ID

一、基本情况介绍

数盟IOS端可信ID介绍页: 数字联盟

数盟号称是还原出原生的IDFA, 但是苹果官网这么介绍:

用户开启跟踪允许跟踪后,APP才可以请求获取IDFA,且用户交互界面允许后,APP才能获取到IDFA.

官网给出的基本架构:

APP集成SDK后,SDK上报一些信息到后台,后台进行一些数据分析并与数据库比对,返回可信设备ID和IDFA到客户端。

二、SDK及上报数据分析

官网给出了这么多合作客户:

以知乎IOS客户端分析数盟SDK,提取知乎APP后发现数盟SDK以动态库的形式集成:

du.framework即为SDK库

反编译主程序du文件,SDK使用了代码平坦化混淆、类名方法名混淆、字符串混淆。

直接定位到请求后台的关键代码处:

输出请求后台后返回的JSON数据并解密后格式如下:

{

"err" :0 ,

"rid" :"2TU2CA:0KM1:R7E6:3R0E8" , // 数盟APP层面设备ID

"cdd" :"D2mvLaZZIwmd8SJa6RXIHkOA1sdwcmsG5gw6YPSo3o6a=X0d" , // 后台生成的APP层面可信设备ID

"cck" :"36" ,

"rdm" :"176" ,

"qid" :"FC44AE3D-B6F1-A01E-9C03-24EA241CE1B4" //全局的IDFA

}

cdd是可信设备ID, qid 是IDFA

同时接口 http://idfa2.shuzilm.cn/q?did=&pkg= 可以返回IDFA,参数为设备ID和包名,这里的did即返回的cdd。

SDK请求后台有两个部分:携带的数据类似:

1)只上报数据,后台无返回数据,每次启动上报:http://idaa.shuzilm.cn/report?v=1.0&t=iaa

2)上报数据后,后台返回设备ID,首次运行(APP缓存内无相关字段时)获取:++https://ipi.shuzilm.cn/report?v=1.0++

拦截请求前和加密前的上报字符串,如下:

javascript 复制代码
{
    AAA = "v1.0";
    AI3 =     (
        "zh-Hans-CN"
    );
    BBB = "v1.0";
    BP1 = 1;
    Be8 = "12603.479420792";
    En9 =     {
        bO4 = "";
        sb4O = "";
        sl2 = "";
    };
    FU2 = "u9v3o@Wlp";
    Fx4 =     {
        AI7 = "7@jlA7h8:A?;k7AlAm7A?mlmm";
    };
    GI7 =     {
        AI7 = "hkj@A7k<hA?hmlA?Ak7A?@l9m";
    };
    Gd9 = 1;
    Gl1 = iOS;
    HJ2 = 0;
    Hg2 =     {
        kCFProxyTypeKey = kCFProxyTypeNone;
    };
    Hq2 = "0.119999997317791";
    Ih2 = "2.3.4";
    Ke6 = "sg.bigo.alpha";
    LW5 = "";
    LZ3 =     {
        fW2 = 77777777477777777747777477777777747;
        gy8 = "";
        js2 = ":<;:M<;@4:LM?;=9KJ4K9<J47<H7<;@?94M";
        qH4 = "M89??I>;?4L=9HK;9H<4:KIL48I<M889<:4K";
        se1 = "48B8B8:D2119D:F25820:fc00";
        sf2W = 66be31e;
        sg8y = "";
        sj2s = 06964dc;
        zT2 = "l?k@78<lm<7li:k<him7?h8i7:i;>>88;8ll=87l";
    };
    NA8 = 1;
    NP1 = osee2unifiedRelease;
    OW5 = "7.3.1";
    PJ2 = 3;
    Pm4 = "48B8B8:D2119D:F25820:fc00";
    Pq2 =     {
        alt = 0;
        lat = 0;
        lng = 0;
    };
    RP5 = 858;
    RQ5 = "8;;";
    TV5 = 1615277876;
    VR1 = 1615290767;
    Wm7 = 4;
    Wt9 = 1;
    XE3 =     (
        "77??5577?958"
    );
    ZY9 = 4G;
    at9 =     {
        IW2 = 67895296;
        bB8 = 3146072064;
        vB9 = 234242048;
    };
    aw2 =     {
        AI7 = "7A@k?j<iA:?Ak;m<9jAA>=l<@;m?AAh?97k;j9";
        Oa6 = "5>=;:8855:7>8";
        Ox7 = "5<<<<9955<<<<99";
        tK5 = "5>=;:8855:7>8";
    };
    bj9 = 3866;
    bk6 =     {
        qA4 = 47185707008;
        uu2 = 127968497664;
    };
    eK5 = "wIwKh65ujvhpt{nhpj\"p6sKw9wLHI67lHs?kHuH|KI86Lz4yLl7uJpHh4{IuMvHj;64y<h:};6>l4{9h=}<p>y9wH6";
    fC8 = 6332d8dbf4b37a95e1ea4b773c35c109;
    go4 = 2;
    hL4 = ":=>";
    Identifier prefix = 1;
    jN2 =     {
    };
    jj5 =     {
  
        fW2 = 77777777477777777747777477777777747;
        js2 = ":<;:M<;@4:LM?;=9KJ4K9<J47<H7<;@?94M";
        qH4 = "M89??I>;?4L=9HK;9H<4:KIL48I<M889<:4K";
        se1 = "48B8B8:D2119D:F25820:fc00";
        sf2W = 66be31e;
        sj2s = 06964dc;
        zT2 = "l?k@78<lm<7li:k<him7?h8i7:i;>>88;8ll=87l";
    };
    kU4 = "zhihu_shuzilm_cn";
    kn7 = "dj/jzHEK";
    kp6 = 1615291006;
    lH8 =     {
        AI7 = "ijA@m8l8lAAm:m<>jjAA=7<<<;?lAA?;7@;89";
    };
    lo7 = "2020-10-03 04:14:37 +0000,2020-10-03 04:14:37 +0000";
    mM3 = 1;
    mT5 = 1;
    mi1 =     {
        Uc4 = "+9cmRoTSYyKLhgs5";
        mE1 = uj;
        nO8 = 87;
        xX9 = "=7;";
    };
    ms1 =     {
        RH9 = 2;
        bt3 = ARM64;
    };
    nC9 = "Jv@p8{;h8jMpIs=w8w@H=6:h4{JhLK@6Iz4y>l7u7p;h4{:uMv8JK64l>s;p;iJvIt96Ly;h6}u6";
    oF8 = "0.7466846704483032";
    ou5 = 1615290786;
    tJ3 = 1615277876983893;
    tP9 = "14.1";
    tf8 =     {
        fW2 = 77777777477777777747777477777777747;
        js2 = ":<;:M<;@4:LM?;=9KJ4K9<J47<H7<;@?94M";
        qH4 = "M89??I>;?4L=9HK;9H<4:KIL48I<M889<:4K";
        se1 = "48B8B8:D2119D:F25820:fc00";
        sf2W = 66be31e;
        sj2s = 06964dc;
        zT2 = "l?k@78<lm<7li:k<him7?h8i7:i;>>88;8ll=87l";
    };
    th1 = 1615291006;
    xs6 = 0;
    zk4 =     (
        "A??A?A????A???7A;79",
        "A?@A@A?@?@A???7A;79"
    );
    zv7 = 1;
}

JSON字符串的Key和Value都有加密处理,上报内容丰富

利用iPhone 7P 越狱手机, 测试 贝壳找房APP和 知乎APP 测试得到不同的可信设备ID,但是请求接口 http://idfa2.shuzilm.cn/q?did=&pkg= 时,返回了相同的IDFA!

三、解密关键数据

上报数据的接口都做了加密处理,定位到关键解密的类,HOOK输出参数和加密结果(加密方式有多种):

还原出字符串的原始值:

javascript 复制代码
{
    "model":"iPhone9,2",
    "fC8":"11dc97a54f95d15dcb3ea403223a5f69",
    "RQ5":"414",
    "PJ2":"3",
    "mi1":{     // SIM卡信息
        "locale":"CN",
        "xX9":"460",    //中国 移动网络标志
        "Uc4":"+9cmRoTSYyKLhgs5", // 应该是 中国联通
        "nO8":"01"      // 01 是联通
    },
    "tJ3":1615133047280091,
    "proxy_info":{     // 代理
        "port":8080,
        "type":"http",
        "ip":"172.24.67.27"
    },
    "net_type":"WIFI",
    "lo7":"2020-10-03 04:14:37 +0000,2020-10-03 04:14:37 +0000",   // 系统文件的改写时间,可以认为是系统更新的时间
    "ips":[
        "172.24.8.15",
        "172.24.8.16"
    ],
    "ou5":1615185614,
    "En9":{
        "sl2":"",
        "bO4":"",
        "sb4O":""
    },
    "ms1":{
        "bt3":"ARM64",
        "RH9":2
    },
    "nC9":"/var/mobile/Containers/Data/Application/57E3F5DB-B9C6-448B-AA7A-B24010B266C4",   // 文件保存路径
    "Hq2":0.43000000715255737,
    "mM3":0,
    "kn7":"9uwmRarGbDmbBtvLcAHu",
    "Be8":"15086.353942000",
    "NA8":false,
    "Wm7":4,
    "time":1615185614,
    "BP1":"0.",
    "at9":{
        "bB8":3146072064,
        "vB9":218480640,
        "IW2":46333952
    },
    "AI3":[
        "zh-Hans-CN"
    ],
    "Pq2":{
        "lat":22.934495944497922,
        "lng":113.38160809348251,
        "alt":5.5634598731994629
    },
    "Gd9":true,   //应该是越狱状态
    "TV5":1615133047,
    "tf8":{
        "IDFV":"0ECDDDCC-2CCA-4720-A173-90F92AAB971F",
        "OpenUDID":"b61de9b10bdd52286dc9b198b2d249ea2ae5c7e2",
        "IDFA":"00000000-0000-0000-0000-000000000000",
        "simulateIDFA":"D32151ED-A4A6-4B81-6617-5438DACAA604",
        "deviceid":"9C487F:ACC4DC:CB91C9:5200"
    },
    "oF8":0.73140573501586914,
    "app_versionn":"7.3.1",
    "utun0 ":"fe80::dcd3:f490:692c:4fd0", // 应该是ipv6地址
    "aw2":{    // 移动网络IP信息
        "cip":"10.91.113.211",
        "mask":"255.255.255.255",
        "pdp_ip0 ":"2408:8456:c03:46ed:4d54:6579:af3b:7103" //应该是ipv6地址
    },
    "os_type":"iOS",
    "LW5":"",
    "jN2":{
 
    },
    "VR1":1614826186,
    "zv7":true,
    "BBB":"v1.0",
    "xs6":true,
    "lip":"172.24.106.152",  // 内网ip地址
    "deviceid":"9C487F:ACC4DC:CB91C9:5200",
    "AAA":"v1.0",
    "jj5":{
        "did":"9C487F:ACC4DC:CB91C9:5200",
        "idfa":"00000000-0000-0000-0000-000000000000",
        "idfv":"0ECDDDCC-2CCA-4720-A173-90F92AAB971F",
        "IDFA1":"",
        "simulateIDFA":"D32151ED-A4A6-4B81-6617-5438DACAA604",
        "OpenUDID":"b61de9b10bdd52286dc9b198b2d249ea2ae5c7e2"
    },
    "go4":1,
    "kU4":"zhihu_shuzilm_cn", //应该是集成的key
    "tP9":"14.1",
    "RP5":1170,
    "bj9":"3866",  // APP版本信息
    "bk6":{
        "qA4":48616042496,
        "uu2":127968497664
    },
    "identifierPrefix":4,
    "eK5":"/var/mobile/Containers/Data/Application/57E3F5DB-B9C6-448B-AA7A-B24010B266C4",
    "mT5":4,
    "identifier":"com.zhihu.ios",
    "ip0":"2408:8556:c07:bda6:241c:150c:f9ae:8f91", // ipv6
    "hL4":"736",
    "Wt9":true,
    "HJ2":false,
    "sdk_ver":"2.3.4",
    "LZ3":{
        "IDFV":"0ECDDDCC-2CCA-4720-A173-90F92AAB971F ",
        "openUDID":"b61de9b10bdd52286dc9b198b2d249ea2ae5c7e2",
        "IDFA":"00000000-0000-0000-00000000",
        "simulateIDFA ":"D32151ED-A4A6-4B81-6617-5438DACAA604",
        "IDFA1":"", //这个字段如果不为空,权重较大。
        "did":"9C487F:ACC4DC:CB91C9:5200"
    },
    "filename":"osee2unifiedRelease",
    "zk4":[
 
    ]
}

几个确定设备的重要参数:

1、did

形式如:9C487F:ACC4DC:CB91C9:5200 , 如果设备是越狱状态,APP有文件系统的读权限时,从下面四个路径获取:

  1. /Library/Managed Preferences/mobile/com.apple.mobileserver.plist

2)/private/var/MobileDevice/ProvisioningProfiles/b87aa91c-bdb2-1b91-baaf-d73ec4bfb86c

  1. /private/var/logs/mediaserverd/com.apple.mediaserverd.plist

4)/var/mobile/Library/Preferences/com.mobicom.net2.plist

也就是说对于越狱设备,直接读取到的就是与APP无关的全局设备ID,当系统不存在这些文件以及设备未越狱时,由SDK生成并保存,未越狱设备测试发现每次清空数据后启动did值改变。

2)IDFA

系统提供的获取IDFA的接口,但是IOS14以后默认关闭,因为正常情况下基本是全0

2)openUDID

一个开源的ID方案,测试更改包名变化较大。

3)simulateIDFA

一个开源的ID方案,有变化,有一定稳定性。

组合方案包括:系统版本、硬件型号、SIM卡信息、系统容量等,

以及开机时间、国家码、语言、设备名称两部分组成

碰撞率小,但是明显存在不稳定性。

4)IDFA1

暂且叫做IDFA1,应为它是后台返回的IDFA缓存在本地,每次都会带上,可能APP中缓存和剪切板中缓存(跨APP,新版本系统限定在同一开发者)

5)IDFV

跟APP的开发者有关,一个开发者的所有APP都卸载后,再次运行会改变。

6)lo7

某个系统文件上次的改写时间,目前APP沙盒外的文件,具备读权限的只发现一个:

/System/Library/CoreServices/SystemVersion.plist

可以认为是上次系统更新的时间。该文件记录了系统版本,系统类型(IOS、MacOS)以及系统版本的ID和系统镜像的ID(对应机型和系统版本)

7)文件路径

文件路径中存在随机字符串,可能也会成为归因的一个因素

8)设备其它信息:机型、系统版本、设备名、IP、经纬度等

测试几组数据:

1、改变包名,但是是同一个开发者账号,IDFA1不为空,上报返回同一个qid和cdd。

2、改变包名,不是同一个开发者,IDFA1此时为空,simulateIDFA相同,其余ID不同,但是返回了不同的qid和cdd

基本结论: 所谓的可信设备ID,并不是还原原生的IDFA,同样只是上报一些数据,后台归因然后返回后台保存的IDFA.后台归因时,不是简单的根据某个ID一样判断出是一个设备。而是结合了多个ID,可能每个ID有一定的权重。

用户安装一个全新的APP时下列情况IDFA肯定会变:

1、全新安装,并且没有安装该开发者其它的APP,且设备有重启或系统更新等。这种情况下各个ID都出现不同的值。

2、SDK内部的did出现碰撞等。SDK以did作为高权重。did一样,基本认为是同一个设备,即did出现碰撞,则IDFA会对应错误。

3、系统更新后再安装一个未安装过的应用。

只考虑正常用户,设备ID保存在缓存中或者keychain中能够提高稳定性,基本不会发散。

相关推荐
若水无华2 天前
fiddler 配置ios手机代理调试
ios·智能手机·fiddler
Aress"2 天前
【ios越狱包安装失败?uniapp导出ipa文件如何安装到苹果手机】苹果IOS直接安装IPA文件
ios·uni-app·ipa安装
Jouzzy2 天前
【iOS安全】Dopamine越狱 iPhone X iOS 16.6 (20G75) | 解决Jailbreak failed with error
安全·ios·iphone
瓜子三百克2 天前
采用sherpa-onnx 实现 ios语音唤起的调研
macos·ios·cocoa
左钦杨2 天前
IOS CSS3 right transformX 动画卡顿 回弹
前端·ios·css3
努力成为包租婆2 天前
SDK does not contain ‘libarclite‘ at the path
ios
安和昂3 天前
【iOS】Tagged Pointer
macos·ios·cocoa
I烟雨云渊T3 天前
iOS 阅后即焚功能的实现
macos·ios·cocoa
struggle20253 天前
适用于 iOS 的 开源Ultralytics YOLO:应用程序和 Swift 软件包,用于在您自己的 iOS 应用程序中运行 YOLO
yolo·ios·开源·app·swift
Unlimitedz3 天前
iOS视频编码详细步骤(视频编码器,基于 VideoToolbox,支持硬件编码 H264/H265)
ios·音视频