字节某条设备注册算法分析

基于“9.5.4”版本分析还原设备注册代码,测试通过

1. 抓包

设备注册接口请求及返回内容如下:

2. 定位数据包原文

在 Jadx 中搜索 device_register 找到类 X.1pd,trace 发现堆栈都带 Applog类:

继续跟踪Applog的函数(数据量有点大,重定向到文件中分析),看到堆栈中有一个网络接口的实现类: 

继续 trace 该类,发现某次调用返回和抓包得到的数据匹配

类似的逻辑层层关联分析(绕了不少弯路),最终找到直接打印请求及加密结果的类 X.1rb ,请求体原文如下:

 {
    "header":{
        "os":"Android",
        "os_version":"9",
        "os_api":28,
        "device_model":"Pixel",
        "device_brand":"google",
        "device_manufacturer":"Google",
        "cpu_abi":"arm64-v8a",
        "channel":"article_download_page",
        "not_request_sender":1,
        "aid":13,
        "release_build":"1111111111111111",
        "custom":{
            "cold_start":true
        },
        "density_dpi":420,
        "display_density":"mdpi",
        "resolution":"1794x1080",
        "display_density_v2":"xxhdpi",
        "resolution_v2":"1920x1080",
        "language":"zh",
        "timezone":8,
        "region":"CN",
        "tz_name":"Asia\/Shanghai",
        "tz_offset":28800,
        "access":"wifi",
        "package":"com.ss.android.article.news",
        "app_version":"9.5.4",
        "app_version_minor":"",
        "version_code":954,
        "update_version_code":95407,
        "manifest_version_code":9540,
        "app_name":"news_article",
        "tweaked_channel":"article_download_page",
        "display_name":"今日头条",
        "rom":"5670241",
        "rom_version":"PQ3A.190801.002",
        "sig_hash":"11111111111111111",
        "clientudid":"1111111111111111",
        "openudid":"1111111111111111",
        "cdid":"1111111111111111111",
        "appkey":"4fd805175270154a3c000005",
        "mc":"111111111111111",
        "sim_serial_number":[

        ],
        "oaid_may_support":false,
        "device_platform":"android",
        "git_hash":"8a70419",
        "sdk_version_code":4000184,
        "sdk_target_version":30,
        "req_id":"11111111111111111111",
        "sdk_version":"4.0.1-rc.34-toutiao",
        "guest_mode":0,
        "sdk_flavor":"cnInner",
        "pre_installed_channel":"",
        "apk_first_install_time":1111111111,
        "is_system_app":0
    },
    "magic_tag":"ss_app_log",
    "_gen_time":11111111
}

3. 数据包加密流程

直接查看 X.1rb 类中加密过程:

加密函数实现:

 

 

4. 还原设备注册流程

创建一个 Android 工程,直接把相关代码抠出来:

编写设备注册类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

package com.example.deviceregister;

import android.net.Uri;

import android.util.Log;

import com.bytedance.frameworks.encryptor.EncryptorUtil;

import org.json.JSONObject;

import java.io.BufferedReader;

import java.io.ByteArrayOutputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.UUID;

import java.util.zip.GZIPOutputStream;

public class DeviceRegister {

    static String TAG = "DeviceReg";

    private static String bodyTemplate = "{\"header\":{\"os\":\"Android\",\"os_version\":\"9\",\"os_api\":28,\"device_model\":\"Pixel\",\"device_brand\":\"google\",\"device_manufacturer\":\"Google\",\"cpu_abi\":\"arm64-v8a\",\"channel\":\"article_download_page\",\"not_request_sender\":1,\"aid\":13,\"release_build\":\"11111111\",\"custom\":{\"cold_start\":true},\"density_dpi\":420,\"display_density\":\"mdpi\",\"resolution\":\"1794x1080\",\"display_density_v2\":\"xxhdpi\",\"resolution_v2\":\"1920x1080\",\"language\":\"zh\",\"timezone\":8,\"region\":\"CN\",\"tz_name\":\"Asia\\/Shanghai\",\"tz_offset\":28800,\"access\":\"wifi\",\"package\":\"com.ss.android.article.news\",\"app_version\":\"9.5.4\",\"app_version_minor\":\"\",\"version_code\":954,\"update_version_code\":95407,\"manifest_version_code\":9540,\"app_name\":\"news_article\",\"tweaked_channel\":\"article_download_page\",\"display_name\":\"今日头条\",\"rom\":\"5670241\",\"rom_version\":\"PQ3A.190801.002\",\"sig_hash\":\"aea615ab910015038f73c47e45d21466\",\"clientudid\":\"11111111\",\"openudid\":\"11111111\",\"cdid\":\"11111111\",\"appkey\":\"4fd805175270154a3c000005\",\"mc\":\"11111111\",\"sim_serial_number\":[],\"oaid_may_support\":false,\"device_platform\":\"android\",\"git_hash\":\"8a70419\",\"sdk_version_code\":4000184,\"sdk_target_version\":30,\"req_id\":\"11111111\",\"sdk_version\":\"4.0.1-rc.34-toutiao\",\"guest_mode\":0,\"sdk_flavor\":\"cnInner\",\"pre_installed_channel\":\"\",\"apk_first_install_time\":11111111,\"is_system_app\":0},\"magic_tag\":\"ss_app_log\",\"_gen_time\":11111111}";

    public static byte[] gzipAndEnc(String str) {

        if (str == null || str.length() == 0) {

            return null;

        }

        ByteArrayOutputStream out = new ByteArrayOutputStream();

        GZIPOutputStream gzip;

        try {

            gzip = new GZIPOutputStream(out);

            gzip.write(str.getBytes("UTF-8"));

            gzip.close();

        catch (IOException e) {

            Log.e(TAG, "gzip error:" + e.getMessage());

        }

        byte[] gzipout = out.toByteArray();

        Log.e(TAG, "gzip out-len:" + Integer.toHexString(gzipout.length));

        byte[] ret = EncryptorUtil.ttEncrypt(gzipout, gzipout.length);

        Log.e(TAG, "encrypt out-len:" + Integer.toHexString(ret.length));

        return ret;

    }

    public static byte[] genBody(String req_id) {

        try {

            JSONObject json = new JSONObject(bodyTemplate);

            JSONObject header = json.getJSONObject("header");

            header.put("release_build""11111");

            header.put("clientudid", UUID.randomUUID().toString());

            header.put("openudid""111111");

            header.put("cdid", UUID.randomUUID().toString());

            header.put("mc""02:00:00:00:00:00");

            header.put("req_id", req_id);

            header.put("apk_first_install_time", System.currentTimeMillis());

            json.put("header", header);

            json.put("_gen_time", System.currentTimeMillis());

            Log.d(TAG, json.toString());

            return gzipAndEnc(json.toString());

        }

        catch (Exception e) {

            throw new RuntimeException(e);

        }

    }

    public static String request() {

        String req_id = UUID.randomUUID().toString();

        String reqUri = "https://log.snssdk.com/service/2/device_register/";

        Uri uri = Uri.parse(reqUri);

        Uri.Builder uriBuilder = uri.buildUpon();

        uriBuilder.appendQueryParameter("req_id", req_id);

        uriBuilder.appendQueryParameter("tt_data""a");

        uriBuilder.appendQueryParameter("cronet_version""ff3f7153_2023-10-11");

        uriBuilder.appendQueryParameter("ttnet_version""4.2.137.21-toutiao");

        uriBuilder.appendQueryParameter("use_store_region_cookie""1");

        String result = "";

        try {

            URL url = new URL(uriBuilder.build().toString());

            HttpURLConnection connection = (HttpURLConnection)url.openConnection();

            connection.setRequestMethod("POST");

            connection.setRequestProperty("Content-Type""application/octet-stream;tt-data=a");

            connection.setRequestProperty("Accept-Encoding""gzip, deflate");

            connection.setRequestProperty("User-Agent""com.ss.android.article.news/9540 (Linux; U; Android 9; zh_CN_#Hans; Pixel; Build/PQ3A.190801.002; Cronet/TTNetVersion:ff3f7153 2023-10-11 QuicVersion:ec35dc6e 2023-10-11)");

            connection.setRequestProperty("x-ss-req-ticket", String.valueOf(System.currentTimeMillis()));

            connection.setDoInput(true);

            connection.setDoOutput(true);

            DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());

            outputStream.write(genBody(req_id));

            outputStream.flush();

            outputStream.close();

            InputStream inputStream = connection.getInputStream();

            int status = connection.getResponseCode();

            Log.d(TAG, "reponse-status: " + String.valueOf(status));

            if(inputStream != null){

                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));

                String line="";

                while ((line = bufferedReader.readLine()) != null) {

                    Log.d(TAG, "reponse-line: " + line);

                    result += (line+"\n");

                }

            else{

                result = "post ret null!";

            }

        catch (Exception e) {

            Log.d(TAG, "post err: " + e.toString());

        }

        Log.d(TAG, "post ret: " + result);

        return result;

    }

}

5. 测试结果

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值