精华内容
下载资源
问答
  • 抖音通信协议的加密算法是目前最完善的了,一些关键函数都被VM混淆过 ,比如设备注册、视频信息等常用接口,只能通过动态调试跟踪去理解其过程。...https://log.snssdk.com/service/2/device_register/? method...

    抖音通信协议的加密算法是目前最完善的了,一些关键函数都被VM混淆过 ,比如设备注册、视频信息等常用接口,只能通过动态调试跟踪去理解其过程。

    我们先来分析一下常用的设备注册是如何生成的,这是请求抖音接口的第一步,如果没有它,请求抖音的任何接口都不会返回数据的。

    1.抖音的设备注册接口

    https://log.snssdk.com/service/2/device_register/?
    

    method:POST

    body:设备信息加密数据

    url参数:设备信息参数

    2.设备信息参数生成

    device_id的生成是根据我们提交给抖音里的参数进行计算的,所以我们要随机生成一些参数。

    重点参数:

    carrier
    display_name字段:这个字段不是utf-8编码,是GBK编码,要做编码转换

    Idfa、VendorID字段:标准UUID算法生成即可

    Openudid:随机生成的

    跟踪调试过程省略……

    通过动态调试最后定位到sub_101E7830设备加密函数

    sub函数的参数是传入一个字典

    {
        fingerprint = "";
        header =     {
            access = WIFI;
            aid = 1128;
            "app_language" = zh;
            "app_name" = aweme;
            "app_region" = CN;
            "app_version" = "8.7.1";
            carrier = "\U4e2d\U56fd\U79fb\U52a8";
            channel = AppStore;
            custom =         {
                "app_language" = zh;
                "app_region" = CN;
                "build_number" = 87100;
                "earphone_status" = on;
            };
            "device_id" = ;
            "device_model" = "iPhone X";
            "display_name" = "\U6296\U97f3\U77ed\U89c6\U9891";
            idfa = "E3D93D3-U747-R394-E2033-HF383J3984JE";
            "install_id" = ;
            "is_jailbroken" = 0;
            "is_upgrade_user" = 1;
            language = zh;
            mc = "00:00:00:00:00:00";
            "mcc_mnc" = "";
            openudid = 9234923948d9392934dkk3939935d93939r3a3s3;
            os = iOS;
            "os_version" = "12.1";
            package = "com.ss.iphone.ugc.Aweme";
            region = CN;
            resolution = "1024*768";
            "sdk_version" = 0011;
            timezone = 1;
            "tz_name" = "Asia/Shanghai";
            "tz_offset" = 99000;
            "user_agent" = "Aweme 8.7.1 rv:87100 (iPhone; iPhone OS 12.1; zh_CN) Cronet";
            "vendor_id" = "6J3DJD34-3DE4-R3KD-DS33-739394839384";
        };
        "magic_tag" = "ss_app_log";
    }
    
    

    我们所要替换的就是json里的vendor_id,openudid,idfa然后进行加密

    加密过程的算法实际上是AES,首先使用标准Gzip压缩参数然后调AES进行加密。Android和iOS加密方法相同。

    流程图如下:
    在这里插入图片描述
    完成上述步骤就可以提交设备注册请求了,成功请求结果如下:

    {
    	"server_time": 1557474647,
    	"device_id": 61853858364,
    	"install_id": 99375638378,
    	"device_id_str": "61853858364",
    	"install_id_str": "99375638378",
    	"new_user": 1
    }
    

    iOS抖音8系列版本针对设备注册的最新风控多了一个log算法。

    3.问答交流

    如果有什么不懂的可以联系我交流

    邮箱:shenydowa@outlook.com

    测试地址:https://www.showdoc.cc/527312186916410?page_id=3113306537235933

    4.免责声明

    请勿使用本服务于商用或大量抓取
    若因使用本服务与抖音官方造成不必要的纠纷,本人盖不负责,存粹技术爱好,若侵犯抖音贵公司的权益,请告知!

    5.其他

    除了device_register算法还有mas,as,cp,X-gorgon算法,我会在下一篇讲解。

    iOS抖音风控加密算法的来龙去脉之X-gorgon算法mas、as、cp算法(二)

    展开全文
  • 抖音设备注册device_register签名加密流程device_id,iid,install_id 接口:/service/2/device_register/ 抖音生成设备id算法 获取device_id有几个重点: (1) carrier、display_name字段:这个字段不是utf-8编码,是...

    接口:/service/2/device_register/

    抖音生成设备id算法
    获取device_id有几个重点:
    (1) carrier、display_name字段:这个字段不是utf-8编码,是GBK编码,要做编码转换
    (2) Idfa、VendorID字段:标准UUID算法生成即可
    (3) Openudid:随机生成的
    device_register接口中post包体是加密的,算法实际上是AES,加密的参数是一些基础信息
    过程:
    首先使用标准Gzip压缩参数然后调AES进行加密。Android和iOS加密方法相同。
    8系列版本针对设备注册的最新风控多了一个log算法。

    测试地址
    https://www.showdoc.cc/527312186916410?page_id=3113306537235933

    更多了解
    邮箱:
    giulenkas@outlook.com

    展开全文
  • 了解到前一段时间,火山小视频升级为了抖音火山版,想必其相应的安全措施也升级了吧,笔者本着学术交流的目的研究了一下抖音火山版的设备注册方法,也就是生成device_id与iid(install_id)的过程。从而找到了如何...

    前言

    了解到前一段时间,火山小视频升级为了抖音火山版,想必其相应的安全措施也升级了吧,笔者本着学术交流的目的研究了一下抖音火山版的设备注册方法,也就是生成device_id与iid(install_id)的过程。从而找到了如何能够模拟生成这两个id,生成出来的这两个id在访问抖音火山版网络接口的时候证明有效,但是能否用于其他头条系应用就不得而知了,可供参考。

    逆向

    静态分析

    静态分析也就是反编译,反编译软件很多,从基本的Apktool工具,到强大的jadx,还有也比较强大的JEB,有时候Android studio也能帮忙分析,之前也试过GDA也不错,笔者比较常用的还是jadx和JEB。工欲善其事,必先利其器,这句话在逆向分析的研究中太适配了。废话不多说,下面就开始吧。

    jadx打开抖音火山版的apk文件,可以先找到AndroidManifest.xml文件,记录一下它的包名package=”com.ss.android.ugc.live”,然后呢?一脸懵,要不是看了前辈的工作才不知道要看什么,可以得知有个api很关键:https://log.snssdk.com/service/2/device_register/ ,那么就先搜索这个字符串吧,可以尝试搜索device_register或者service/2/device_register/等等可能的字符串都行,看看能找到什么代码。使用jadx具体操作的时候需要选择导航-》搜索文本,然后要等一会儿,因为它正在反编译,如下图所示:

    Alt pic
    反编译完之后可以试试查找文本:service/2/device_register/,发现有个类很可疑:…deviceregister.b.a.URL_DEVICE_REGISTER(),如下图所示:

     

     

     

     

    点进去仔细瞧瞧。发现这是个构造url列表的函数,肯定有什么地方调用它了。然后按着control键寻找该函数的用例,发现除了它自己就只有一个地方调用它了,进入调用它的函数发现是未能正常反编译的函数,如下图所示:


    可以看到有个DeviceRegisterThread字符串映入眼帘,然后就能大概知道这个类比较重要了,上面能看到它继承的Thread类,那么这就应该是设备注册请求网络部分的子线程了。唉,其实一开始笔者找到别的地方去了,一开始专注于分析这个device_id所在的本地缓存了,因为本地有缓存的时候会优先加载本地缓存而不是发起这个网络请求,后来发现分析完了本地缓存之后并没有什么用,不过倒是把附近的几个类整明白了一点。扯远了,下面还是继续分析这个继承自Thread类的com.ss.android.deviceregister.b.c.a类吧,这个类其实可以从头分析,这里不再详细说了,先把jadx正常反编译的部分仔细过一遍,然后就能发现上图那个反编译失败的函数很重要,应该就是发起网络请求相关的部分。但是jadx反编译失败了,而且这个伪码看起来也不适合分析,那么就想着看smail代码呗,但是发现竟然找不到这个类对应的smail代码,只能说是jadx的bug了吧。那怎么办?这时候JEB就可以出场了。

    笔者之前用的是JEB2,这次搞这个的时候搜了一下这个工具发现JEB3也出来了,上面提到的JEB超链接给的就是一个JEB3的地址,虽然好像是个beta版本,但是也不影响使用。之前用JEB2的时候就遇到过一个问题,那就是直接打开一个apk安装包的时候,特别是体积比较大的安装包的时候会提示内存溢出而无法打开的情况,解决方法是找到想要具体分析的dex文件,然后只打开该dex文件分析即可。所以这次笔者也是先找到了上面要分析的代码所在的dex文件,然后单独分析该dex文件即可。那么问题来了,怎么找到代码所在的dex文件呢?这时候想到jadx反编译的时候好像在shell上面输出了一些日志信息,可以看看这些信息能不能有所帮助。重新使用jadx打开apk文件,然后从源代码目录中找到com.ss.android.deviceregister.b.c.a类,进行反编译,如下图所示:


    从上图中能够看到,日志中输出了该类所在的dex文件为classes4.dex。那么就用JEB打开classes4.dex吧,然后找到这个类,分析一下上面那个重要的函数,如下图所示:

     


    这个看起来就不错了,jeb对匿名内部类的反编译效果的确比jadx好一些,那就仔细分析一下这个函数吧,jeb的改名功能还是很好用的,经过笔者手动改名之后的函数,如下图所示:


    这样看起来就舒服一些了,但是有些跳转还是很奇怪,经过笔者的手动重写,代码提取如下:

    private boolean is_successful_get_app_config_from_net(String args_json_string) {
        String response = null;
        Object args_bytes_clone;
        String url;
        int url_index;
        String default_response = null;
        boolean is_in_10min_from_last_request;
        long now_time;
        byte[] args_bytes;
        try {
            args_bytes = args_json_string.getBytes("UTF-8");
            now_time = System.currentTimeMillis();
            if(now_time - this.b.mLastGetAppConfigTime < 600000) {
                is_in_10min_from_last_request = true;
            }
            else {
                is_in_10min_from_last_request = false;
            }
        }
        catch(Throwable v0) {
            return false;
        }
     
        try {
            this.b.mLastGetAppConfigTime = now_time;
            String[] url_list = com.ss.android.deviceregister.b.a.URL_DEVICE_REGISTER();
            if(url_list == null) {
                throw new IllegalArgumentException("url is null");
            }
     
            int urls_length = url_list.length;
            url_index = 0;
            while(true) {
                if(url_index >= urls_length) {
                    break;
                }
     
                url = url_list[url_index];
                args_bytes_clone = args_bytes.clone();
                if(StringUtils.isEmpty(url)) {
                    ++url_index;
                    continue;
                }
     
                url = NetUtil.addCommonParams(SemUtils.updateUrl(this.b.mContext, url), true);
                Logger.debug();
     
                try {
                    if(!this.is_encrypt()) {
                        if(is_in_10min_from_last_request) {
                            url = url + "&config_retry=b";
                        }
     
                        response = NetworkClient.getDefault().post(url, args_bytes, true, "application/json; charset=utf-8", false);
                        break;
                    }
     
                    try {
                        response = NetUtil.sendEncryptLog(url, ((byte[])args_bytes_clone), this.b.mContext, is_in_10min_from_last_request);
                        break;
                    }
                    catch(RuntimeException v0_3) {
                        if(is_in_10min_from_last_request) {
                            try {
                                url = url + "&config_retry=b";
                                response = NetworkClient.getDefault().post(url, args_bytes, true, "application/json; charset=utf-8", false);
                                break;
                            }
                            catch(Throwable v0) {
                                try {
                                    if(!this.b.shouldRetryWhenError(v0)) {
                                        throw v0;
                                    }
                                    ++url_index;
                                    continue;
                                }
                                catch(Throwable v0) {
                                    return false;
                                }
                            }
                        }
     
                        response = NetworkClient.getDefault().post(url, args_bytes, true, "application/json; charset=utf-8", false);
                        break;
                    }
                }
                catch(Throwable v0) {
                    try {
                        if(!this.b.shouldRetryWhenError(v0)) {
                            throw v0;
                        }
                        ++url_index;
                        continue;
                    }
                    catch(Throwable v0) {
                        return false;
                    }
                }
            }
        }
        catch(Throwable v0) {
            return false;
        }
     
        if(response != null) {
            try {
                if(response.length() != 0) {
                    this.parse_net_config(new JSONObject(response));
                    return true;
                }
            }
            catch(Throwable v0) {
                return false;
            }
        }
     
        return false;
    }

     

    这样就基本上能明白它在干什么了。

    简单来说就是先拿到一个设备注册的url地址列表,然后遍历访问,如果访问成功了就结束,访问的时候先添加公共参数,然后判断是否需要加密请求,如果需要加密请求则调用加密请求函数,否则调用普通请求函数,另外如果调用加密请求函数抛异常时也会去调用普通请求函数,还有一些重试参数等等。这时候想到之前抓包的时候找到的设备注册请求都是加密的,那么可以判断is_encrypt()这个函数的都是返回的true,那么如果这个函数返回false的时候是不是就是不加密的请求了呢?好了,静态分析部分就先到这里,下面来动态分析一下,也就是尝试一下这个函数返回false的时候的效果。

    动态分析

    动态分析也就是在app运行时,对其进行分析,比较常见的是分析app的网络请求行为,调用系统API的行为,访问文件的行为等等。由于本文是研究设备id的生成,其实也就是研究设备注册时的一个网络接口,那么就只分析网络请求行为即可。笔者比较常用的网络抓包工具是Charles,需要在手机端配置代理和安装Charles的证书,这部分也不详细说了。

    上文也提到了,本文主要是研究这个接口:https://log.snssdk.com/service/2/device_register/ ,正常情况下设备在注册的时候会加密访问这个接口,比如新安装了app或者app被清理数据之后,再打开app时就会去访问这个接口,访问时是个POST请求,参数是明文,但是带的data是加密的,如下图所示:


    通过上文静态分析可知is_encrypt()这个函数能够控制是否加密传输,所以可以想到利用Xposed进行Hook函数,使得该函数的返回值固定为false。

    Xposed很强大,它能够在其他app运行时注入代码,具体原理和使用教程这里也不再详述,下面笔者贴一下hook部分的代码吧,其实很短:

    findAndHookMethod("com.ss.android.deviceregister.b.a", param.classLoader, "isEncrypt", new XC_MethodHook() {
        @Override
        protected void afterHookedMethod(MethodHookParam param) throws Throwable {
            boolean oldResult = (boolean) param.getResult();
            Log.i(TAG, "com.ss.android.deviceregister.b.a.isEncrypt(), oldResult=" + oldResult + ", newResult=" + false);
            param.setResult(false);
        }
    });
     
    
    可以看到这里的data部分已经变成明文了。
    
    

    至此,找到了设备注册的明文接口,但是看前辈的工作,他用密文请求注册的方式模拟生成的device_id和iid不能用,所以笔者用这种明文注册方式进行了模拟生成设备id,模拟方式同前辈的代码类似,然后用模拟生成的设备id进行了其他接口的访问测试,貌似可以用。

    总结

    整体来看,抖音火山版比之前的火山小视频的安全强度要高一些,或许是和抖音有一些关系吧,毕竟都是头条系产品,技术上复用一下也不太困难,而且感觉在关键的代码逻辑部分应该存在一定的反反编译,就像上面笔者手动还原的那个函数。本文只是针对一个小功能进行了较为详细的逆向分析,还并没有涉及到native层,那一块的对抗估计更加强烈,所以,先这样吧。

    声明

    请勿使用本技术于商用或大量抓取!

    若因使用本技术与抖音火山版官方造成不必要的纠纷,本人盖不负责,存粹技术爱好,若侵犯抖音火山版相关公司的权益,请告知!

    转载请注明出处,谢谢!

    展开全文
  • ac=wifi&channel=wandoujia_aweme2&aid=1128&app_name=aweme&version_code=750&version_name=7.5.0&device_platform=android&ssmix=a&device_type=HWI-AL00&device_brand=HUAWEI&language=zh&os_api=28&os_vers
  • 今天有空分享一下抖音的加密算法,作为拥有庞大用户量的App,其通信协议加密的强度肯定是不弱的,关键算法被VM,只能动态分析去理解。我们通过抓包分析,请求的url上带有as、cp两个加密字段,这两个字段是早期版本...
    今天有空分享一下抖音的加密算法,作为拥有庞大用户量的App,其通信协议加密的强度肯定是不弱的,关键算法被VM,只能动态分析去理解。我们通过抓包分析,请求的url上带有as、cp两个加密字段,这两个字段是早期版本算法,后又陆续添加了mas、X-gorgon算法。我们今天先对as、cp两个字段进行分析,这个只能通过动态调试去跟踪加密过程。
    首先我们通过工具调试定位到函数
    - [IESAntiSpam testForAlert:msg:]
    
    定位的详细过程忽略……,进入继续调试后发现调用sub_102E3345函数进行加密排序

    1.整理分析流程

    
    1.时间戳转十六进制
    
    2.将时间戳排序俩次,
      a1 v3 是排序key
      sprintf(byte_102323F30, "%08x", a1);
      sprintf(byte_102323F3A, "%08x", v3);
    
    3.将url参数用MD5加密一次或俩次根据时间戳&运算
    
    4.将第一次排序结果写入前16位地址加一写入(从1插入),隔一位插入,前边拼a1
    
    5.将第二次排序结果写入后16位(从0插入)后边拼e1
    
    
    

    2.结果排序

    a1d5b43se234dccea7
    
    456dcd5s2320cf3e1
    
    &cp=456fcd5s2320cfs3e1&as=a1d5b43se234dccea7
    
    拼接完成后就可以请求了
    

    后期版本添加了mas算法和最新的X-gorgon算法,目前最新系列版本算法如果需要了解的话可以交流。

    3.流程详述

    抖音x-gorgon算法,as、mas、cp

    4.免责声明

    请勿使用本服务于商用或大量抓取
    若因使用本服务与抖音官方造成不必要的纠纷,本人盖不负责,存粹技术爱好,若侵犯抖音贵公司的权益,请告知!

    5.问答交流

    如果有什么不懂的可以联系我交流

    邮箱:giulenkas@outlook.com
    测试地址:https://www.showdoc.cc/527312186916410?page_id=3113306537235933

    6.其他

    有快手、小红书、tiktok等其他技术问题,也可随时交流。

    展开全文
  • 了解到前一段时间,火山小视频升级为了抖音火山版,想必其相应的安全措施也升级了吧,笔者本着学术交流的目的研究了一下抖音火山版的设备注册方法,也就是生成device_id与iid(install_id)的过程。从而找到了如何...
  • 抖音APP真机设备信息

    千次阅读 2018-09-16 14:45:31
    联系QQ198934 大量需求各种APP 如:抖音或者微信的 idfa,openudid,vid. osver 真机设备信息
  • 抖音设备号注册

    千次阅读 2021-06-13 17:08:45
    模拟设备信息无限量生成device_id和install_id
  • 杨过听她说这几句话时眼神凄楚,一颗心怦的一跳,胸口一痛,失声叫道:“姑姑!” 就在此时,完颜萍已横刀自刎。耶律齐抢上两步,右手长出,又伸两指将她柳叶刀夺了过来,随手点了她臂上穴道,说道:“好端端的,...
  • 今天有空分享一下抖音的加密算法,作为拥有庞大用户量的App,其通信协议加密的强度肯定是不弱的,关键算法被VM,只能动态分析去理解。我们通过抓包分析,请求的url上带有as、cp两个加密字段,这两个字段是早期版本...
  • 抖音设备注册、抖音逆向、device_register、x-gorgon
  • 抖音设备注册算法实现(二)

    千次阅读 热门讨论 2020-06-21 02:27:24
    抖音APP升级比较快,最近利用空闲时间又研究了一番设备注册算法,过程比较痛苦,反编译、逆向、对拍...等过程绞尽脑汁,不过最终还是搞定了(手动高兴一波)! “从所周知”: 抖音设备注册算法是在native层,...
  • 是利用mitmproxy代理https协议,从而判定抖音个人信息接口,在个人信息接口的返回体接收时将用户信息数据,以及Header头(主要是Cookie),Query体(包含设备ID)进行远程存储,用于请求后续其他接口,从而实现抖音设备...
  • * 抖音上线通知 * @author wechat:happybabby110 * @blog http://www.wlkankan.cn */ public void handleMsg(ChannelHandlerContext ctx, TransportMessage vo) { try { ImOnlineNoticeMessage req = vo....
  • 抖音增加视频播放量

    2021-07-02 14:45:18
    经抓包分析,播放量的增加只与一个...device_type=OPPO%20R11%20Plus&device_platform=android&ssmix=a&iid=1090312220960680&manifest_version_code=850&dpi=240&uuid=866174861732390&
  • 经测试每个抖音设备ID,每天只能请求300次左右,超过这个次数,就会提示访问请求太频繁了,解决办法就是模拟注册生成设备ID。 效果如图: 有兴趣的可以交流学习下扣扣:519545433
  • 通过Xgorgon可正常爬取到数据,通过设备信息的加密可注册到新的设备号(device_id)。 一、反编译APK(Xgorgon) 1、jadx打开apk并搜索xgorgon,可定位到init_gorgon 2、读init_gorgon()里面的伪代码,你会发现...
  • 抖音sdk,抖音开发api接口

    千次阅读 2020-12-14 16:54:23
    抖音sdk,抖音开发api接口 1、抖音上线下线 /** * 抖音上线通知 * @author wechat:happybabby110 * @blog http://www.wlkankan.cn */ public void handleMsg(ChannelHandlerContext ctx, TransportMessage ...
  • 抖音协议中的加解密算法实现

    千次阅读 2020-04-17 16:45:49
    iOS版抖音协议中的加解密算法实现 前两年的工作中涉及到抖音协议的分析部分,分析了两个跟加密有关的接口,项目结束了,现拿出来与大家分享 因为项目结束,最新版本是否有改动不清楚了,当时测试可用的抖音版本:IOS...
  • 抖音数据爬取

    2020-11-24 20:01:57
    前言在抖音APP中根据关键词爬取响应视频的具体信息,主要包括视频标题、作者ID、视频url地址以及点赞数等。1 需要用到的工具安卓模拟器fiddlermituproxy(mitmdump)python3.7Auto.js2 环境准备在PC端安装安卓模拟器,...
  • 抖音api接口,抖音sdk

    2020-12-14 12:35:28
    抖音api接口,抖音sdk 1、抖音上线下线 /** * 抖音上线通知 * @author wechat:happybabby110 * @blog http://www.wlkankan.cn */ public void handleMsg(ChannelHandlerContext ctx, TransportMessage vo) { ...
  • 抖音开发sdk,抖音api接口

    千次阅读 2020-12-14 16:12:29
    抖音开发sdk,抖音api接口 1、抖音上线下线 /** * 抖音上线通知 * @author wechat:happybabby110 * @blog http://www.wlkankan.cn */ public void handleMsg(ChannelHandlerContext ctx, TransportMessage ...
  • url = replaceUrlParam(url, "device_id", deviceData.getString("device_id")); url = replaceUrlParam(url, "iid", deviceData.getString("install_id")); // Log.i("orderCreate", "替换device_id成功!"); } // ...
  • 如何采集抖音的数据

    2020-11-23 16:30:39
    抖音App和服务端交互使用的是HTTPS协议,使用Fiddler很容易可以捕获到数据,如下图所示。不过想要自己模拟一个有效的请求可不是那么容易了,因为它使用了签名机制,在所有请求中都有as和cp两个签名参数,除非得知...
  • 如果看到特别感兴趣的抖音vlogger的视频,想全部dump下来,如何操作呢?下面介绍介绍如何使用python导出特定用户所有视频信息抓包分析Chrome Deveploer Tools Chrome 浏览器开发者工具在抖音APP端,复制vlogger主页...
  • 抖音sdk,抖音api接口java调用源代码

    千次阅读 2021-03-13 04:33:03
    抖音sdk,抖音api接口1、抖音上线下线/*** 抖音上线通知* @author wechat:happybabby110* @blog http://www.wlkankan.cn*/public void handleMsg(ChannelHandlerContext ctx, TransportMessage vo) {try {...
  • 抖音api接口,抖音sdk调用java代码

    千次阅读 2020-12-15 10:09:27
    抖音sdk,抖音api接口 1、抖音上线下线 /** * 抖音上线通知 * @author wechat:happybabby110 * @blog http://www.wlkankan.cn */ public void handleMsg(ChannelHandlerContext ctx, TransportMessage vo) {...
  • 抖音sdk,抖音api接口

    千次阅读 2020-12-14 12:32:26
    抖音sdk,抖音api接口 1、抖音上线下线 /** * 抖音上线通知 * @author wechat:happybabby110 * @blog http://www.wlkankan.cn */ public void handleMsg(ChannelHandlerContext ctx, TransportMessage vo) {...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 738
精华内容 295
关键字:

抖音Deviceid