Dy设备注册激活算法分析

流氓凡 技术分享 2021-06-18 1.47 W 2

本篇所讲调用libEncryptor.so进行注册激活设备,附上分析及部分核心JAVA代码片段提供参考。 抖音设备版本15.0.0

看下设备注册的包:

POST https://log-lq.snssdk.com/service/2/device_register/?device_id=56581003169&
is_activated=1&aid=1128&tt_data=a&version_code=12.4.0&app_name=aweme&app_version=12.4.0&vid=84185501-88C0-4E38-BA3D-F3656A073020&device_id=56581003169&channel=App%20Store&mcc_mnc=46001&aid=1128&screen_width=1125&openudid=690af6a89ae78c69306c8a07bca241b840sd156&cdid=AD072FE4-41B7-4890-BEBC-2D57A4F3F253&os_api=18&ac=4G&os_version=12.4&build_number=123011&device_platform=android&iid=3125112636576938&device_type=Huawei%C8600&is_vcd=1 HTTP/1.1
Host: log-lq.snssdk.com
Connection: keep-alive
Content-Length: 856
Accept: application/json
Cookie: odin_tt=458f8eb0d95b7b9adb4b6fc6591918bfb996096967a7aa4305bd81b5150a8199d2e29ed21883cdd7709c5beaa2be3baa; sessionid=66e5128a179ef5f03f5187bae265bf9c; sessionid_ss=ff5128a179ef5f03f5187baecss22; sid_guard=d2da128a179ef5f03f5187bae265bf9c%7C1598662639%7C5183349%7CWed%2C+28-Oct-2020+00%3A46%3A28+GMT; sid_tt=66e5128a179ef5f03f5187bae265bf9c; uid_tt=fsffdc1fa00bb0ddddd400f58d5795df3; uid_tt_ss=232ec1fa00bb0ddddd400f58d5795321; install_id=3125112636576938; ttreq=1$432133fb80de2e267dd1a8478e5394cdd0cd23d1
Content-Type: application/octet-stream;tt-data=a
X-SS-Cookie: install_id=3125112636576938; ttreq=432133fb80de2e267dd1a8478e5394cdd0cd23d1; sessionid=ff5128a179ef5f03f5187baecss22; sessionid_ss=ff5128a179ef5f03f5187baecss22; sid_guard=ff5128a179ef5f03f5187baecss22%7C1598662639%7C5183349%7CWed%2C+28-Oct-2020+00%3A46%3A28+GMT; sid_tt=ff5128a179ef5f03f5187baecss22; uid_tt=d36ec1fa00bb0ddddd400f58d5795df3; uid_tt_ss=d36ec1fa00bb0ddddd400f58d5795df3; odin_tt=a09d8eb0d95b7b9adb4b6fc6591918bfb996096967a7aa4305bd81b5150a8199d2e29ed21883cdd7709c5beaa2be3baa
tt-request-time: 15994653422123
User-Agent: Aweme 12.3.0 rv:123015 (iPhone; iOS 12.2; zh_CN) Cronet
aid: 1128
x-Tt-Token: 00632e5128a179ef5f03f5187bae265bf9cdded28ab77be5f36e4259d59aa924b6c7f5284cdd07bf788188bb5185d61c32145
sdk-version: 2
passport-sdk-version: 5.12.1
X-SS-STUB: 34C32EDE4A3C45F55403E5EBD44A321B
X-SS-DP: 1128
x-tt-trace-id: 00-6123a32f7a09f80897b9fe6e7cc5490468-62a08f7a09f32457-01
Accept-Encoding: gzip, deflate, br
X-Khronos: 1599465342
X-Gorgon: 040802f0000e09020319e1d6be6194bfbd32024c25831c86bce


抖音判断一台设备无非就是根据手机的IMEI,IMSI,MAC,系统版本型号之类的来判断时候同一台设备

我们利用JADX来逆向,关键函数在ttEncrypt方法:

func IIDEncrypt(plainStr []byte) []byte {
	CplainStr := C.CString(string(plainStr))
	defer C.free(unsafe.Pointer(CplainStr))
	plainlength := len(plainStr)
	libPathC := C.CString(EXTENSION_DIR + OIDB_API)
	defer C.free(unsafe.Pointer(libPathC))
	encryptedLength := plainlength + 4 + (16 - plainlength%16)
	CKeyStr := C.CString("!*ss!_defaul%t54K&EY")
	defer C.free(unsafe.Pointer(CKeyStr))
	CEncryptedStr := C.encode(libPathC, CplainStr, C.int(encryptedLength), CKeyStr, C.int(20))
	defer C.free(unsafe.Pointer(CEncryptedStr))
	encryptedStr := C.GoBytes(unsafe.Pointer(CEncryptedStr), C.int(encryptedLength))
	//encryptedHexStr := hex.EncodeToString(encryptedStr)
	return encryptedStr
}
char* Encode(char* plain, int plainlength, char* key, int keylength)
{
    //string plain = hexToStr(hexplain);
    char *xkey;
    char *xplain;
    //int keylength = key.length();
    //int plainlength = plain.length();
    xkey = (char*) malloc(keylength);
    xplain = (char*) malloc(plainlength);
    memcpy(xkey, key, keylength);
    memcpy(xplain, plain, plainlength);
    unsigned char *out = (unsigned char*) malloc(plainlength + 100);
    aweme_aes((__int64)xplain, plainlength, (__int64)xkey, keylength, (__int64)out);
    free(xkey);
    free(xplain);
    xkey = NULL;
    xplain = NULL;
//    int cryptedStr_length = plainlength + 4 + (16 - plainlength%16);
//    std::string hexStr = charsToHex(out, cryptedStr_length);
//    free(out);
    //out = NULL;
    return (char*)out;
}


通过上面device_register的url我们可以知道,设备注册其实是向抖音提交当前设备的一些信息,例如MAC、SSID、UUID、IMEI、IMSI、WIFIMAC、device_brand、device_model、device_board、device_type、openudid、clientudid、build_serial等等来注册得到 device_id和install_id。

我们模拟调用so核心代码:

public JniDispatchRegister(){

        emulator = createARMEmulator();
        final Memory memory = emulator.getMemory();
        memory.setLibraryResolver(createLibraryResolver());

        vm = emulator.createDalvikVM(null);
        vm.setJni(this);
        vm.setVerbose(true);
        ClassPathResource resource = new ClassPathResource(soPath);
        File soFile = null;
        InputStream inputStream = null;
        try {
            inputStream = resource.getInputStream();
            File tempFile = File.createTempFile(soName, ".so");
            FileUtils.copyInputStreamToFile(inputStream,tempFile);
            soFile = tempFile;
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            IOUtils.closeQuietly(inputStream);
        }

        DalvikModule dm = vm.loadLibrary(soFile, false);
        dm.callJNI_OnLoad(emulator);
        this.module = dm.getModule();

        Native = vm.resolveClass(className);

        Symbol __system_property_get = module.findSymbolByName("__system_property_get", true);
        MemoryBlock block = memory.malloc(0x10);
        Number ret = __system_property_get.call(emulator, "ro.build.version.sdk", block.getPointer())[0];
        logger.info("sdk=" + new String(block.getPointer().getByteArray(0, ret.intValue())));
    }

然后进行设备的注册:

public String callRegisterUrl(Map<String, Object> deviceParam, byte[] requestBody) {

        String url = "https://log.snssdk.com/service/2/device_register/?ac=wifi&mac_address=C0%3AEE%3AFB%3AD5%3A4B%3A16&channel=oppo&aid=2329&app_name=douyin_lite&version_code=110500&version_name=11.5.0&device_platform=android&ssmix=a&device_type=ONEPLUS+A3000&device_brand=OnePlus&language=zh&os_api=23&os_version=6.0.1&uuid=860046033047160&openudid=d4080df15130f0d9&manifest_version_code=110500&resolution=1080*1920&dpi=480&update_version_code=11509900&_rticket=1600423440596&mcc_mnc=46011&ts=1600423440&app_type=normal&cdid=4dda0a2b-6572-418c-bdfa-89cfd78a3aaf&tt_data=a&os_api=23&device_type=ONEPLUS%20A3000&ssmix=a&manifest_version_code=110500&dpi=480&uuid=860046033047160&app_name=douyin_lite&version_name=11.5.0&ts=1600423440&app_type=normal&ac=wifi&update_version_code=11509900&channel=oppo&_rticket=1600423440787&device_platform=android&version_code=110500&mac_address=C0%3AEE%3AFB%3AD5%3A4B%3A16&cdid=4dda0a2b-6572-418c-bdfa-89cfd78a3aaf&openudid=d4080df15130f0d9&device_id=40178045261&resolution=1080*1920&os_version=6.0.1&language=zh&device_brand=OnePlus&aid=2329&mcc_mnc=46011";
        url = URLUtil.replaceParam(url, deviceParam);
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        MediaType mediaType = MediaType.parse("application/octet-stream;tt-data=a");
        RequestBody body = RequestBody.create(mediaType, requestBody);
        Request request = new Request.Builder()
                .url(url)
                .method("POST", body)
                .addHeader("Host", "log.snssdk.com")
                .addHeader("Connection", "keep-alive")
                .addHeader("sdk-version", "1")
                .addHeader("Content-Type", "application/octet-stream;tt-data=a")
                .addHeader("User-Agent", "com.ss.android.ugc.aweme/899 (Linux; U; Android 8.2.3; zh_CN; SM-G9650; Build/N2G47H; Cronet/58.0.2991.0)")
                .build();
        try {
            Response response = client.newCall(request).execute();
            String resp = response.body().string();
            return resp;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

激活设备:

public void appAlert(Map<String,Object> device_params){
        String url = "https://ichannel.snssdk.com/service/2/app_alert_check/?build_serial=37c96a14&timezone=8.0&carrier=CHN-CT&mcc_mnc=46011&sim_region=cn&sim_serial_number=89860320750105912020&device_id=40178045261&ac=wifi&mac_address=C0%3AEE%3AFB%3AD5%3A4B%3A16&channel=oppo&aid=2329&app_name=douyin_lite&version_code=110500&version_name=11.5.0&device_platform=android&ssmix=a&device_type=ONEPLUS+A3000&device_brand=OnePlus&language=zh&os_api=23&os_version=6.0.1&uuid=860046033047160&openudid=d4080df15130f0d9&manifest_version_code=110500&resolution=1080*1920&dpi=480&update_version_code=11509900&_rticket=1600423440642&ts=1600423440&app_type=normal&cdid=4dda0a2b-6572-418c-bdfa-89cfd78a3aaf&req_id=7522ead3-00cb-435c-9376-5dd2e012bc71&os_api=23&device_type=ONEPLUS%20A3000&ssmix=a&manifest_version_code=110500&dpi=480&uuid=860046033047160&app_name=douyin_lite&version_name=11.5.0&ts=1600423440&app_type=normal&ac=wifi&update_version_code=11509900&channel=oppo&_rticket=1600423440803&device_platform=android&version_code=110500&mac_address=C0%3AEE%3AFB%3AD5%3A4B%3A16&cdid=4dda0a2b-6572-418c-bdfa-89cfd78a3aaf&openudid=d4080df15130f0d9&device_id=40178045261&resolution=1080*1920&os_version=6.0.1&language=zh&device_brand=OnePlus&aid=2329&mcc_mnc=46011";
        url = URLUtil.replaceParam(url, device_params);
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        Request request = new Request.Builder()
                .url(url)
                .method("GET", null)
                .addHeader("Host", "ichannel.snssdk.com")
                .addHeader("Connection", "keep-alive")
                .addHeader("X-SS-REQ-TICKET", device_params.get("_rticket").toString())
                .addHeader("sdk-version", "12")
                .addHeader("User-Agent", "com.ss.android.ugc.aweme.lite/110500 (Linux; U; Android 6.0.1; zh_CN; ONEPLUS A3000; Build/MMB29M; Cronet/TTNetVersion:4df3ca9d 2019-11-25)")
                .build();
        try {
            Response response = client.newCall(request).execute();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


好了,一些核心的算法就这些,除了调用抖音驱动来做之外,还可以纯算法实现,这里就简单说下实现的几个重点:

获取device_id有几个重点:

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

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

(3) Openudid:随机生成的

device_register接口中post包体是加密的,算法实际上是AES,加密的参数是一些基础信息

实现大致过程:首先使用标准Gzip压缩参数然后调AES进行加密。Android和iOS加密方法相同。


最后关于device_id、xlog、xg04、xg08等算法解析后续将会提供api免费调用(次数限制),关注QdApi吧!

2022年04月12日16:37:06更新

Java开源项目地址:https://gitee.com/ripperTs/tiktok-device-registration 代码仅供学习参考使用

评论

精彩评论
  • 2021-06-19 18:35:34

    大佬你好,我想请教一下,我目前能够获取到device_id和install_id 但是使用您文章上面接口来激活并没有用,激活后,使用device_id和install_id仍然是返回空数据,想请教一下又没有解决办法还是我操作不当?