当前位置: 首页 > 后端技术 > Python

抖音设备注册生成device_id和install_idhook分析记录

时间:2023-03-26 15:55:21 Python

前言前段时间得知火山小视频升级到抖音火山版,相应的安全措施肯定也升级了。目的是研究抖音火山版的设备注册方式,即生成device_id和iid(install_id)的过程。因此,我们找到了如何模拟和生成这两个id。生成的两个id在访问抖音火山版网络接口时被证明是有效的,但不知道是否可以在其他今日头条应用中使用。参考。ReverseStaticAnalysis静态分析就是反编译。反编译软件很多,从最基本的Apktool工具到功能强大的jadx,再到功能比较强大的JEB。有时候Androidstudio也可以帮忙分析一下。我之前也尝试过GDA,笔者比较常用的还是jadx和JEB。工欲善其事,必先利其器。这句话太适合逆向分析的研究了。话不多说,让我们开始吧。jadx打开抖音火山版apk文件,可以先找到AndroidManifest.xml文件,记录下它的包名package=”com.ss.android.ugc.live”,然后呢?我一头雾水,如果没有看过前人的工作不知道看什么,才知道有个api很重要:https://log.snssdk.com/servic...,那么先搜索这个字符串,你可以尝试搜索_device_register_或_service/2/device_register/_等可能的字符串,看看能找到什么代码。使用jadx进行具体操作时,需要选择_navigation->searchtext_,然后稍等片刻,因为正在反编译,如下图:反编译后,可以尝试找到text:_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的一个错误。那么该怎么办?这时候JEB就可以玩了。笔者之前用过JEB2。我在做的时候搜索了一下这个工具,发现JEB3也出来了。上面提到的JEB超链接给出了一个JEB3地址。虽然好像是内测版,但不影响使用。.之前在使用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的重命名功能还是很有用的。作者手动重命名后的函数如下图所示:这样看起来舒服多了,但有些跳转还是很奇怪。经过作者手动改写,提取代码如下:privatebooleanis_successful_get_app_config_from_net(Stringargs_json_string){Stringresponse=null;对象args_bytes_clone;字符串网址;inturl_index;字符串default_response=null;布尔值is_in_10min_from_last_request_;{args_bytes=args_json_string.getBytes("UTF-8");now_time=System.currentTimeMillis();如果(现在时间-this.b.mLastGetAppConfigTime<600000){is_in_10min_from_last_request=true;}else{is_in_10min_from_last}al_sequest(Throwablev0){returnfalse;}尝试{this.b.mLastGetAppConfigTime=now_time;String[]url_list=com.ss.android.deviceregister.b.a.URL_DEVICE_RE吉斯特();if(url_list==null){thrownewIllegalArgumentException("urlisnull");}inturls_length=url_list.length;url_index=0;while(true){if(url_index>=urls_length){中断;}url=url_list[url_index];args_bytes_clone=args_bytes.clone();if(StringUtils.isEmpty(url)){++url_index;继续;}url=NetUtil.addCommonParams(SemUtils.updateUrl(this.b.mContext,url),true);记录器.调试();尝试{如果(!this.is_encrypt()){如果(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);休息;}尝试{response=NetUtil.sendEncryptLog(url,((byte[])args_bytes_clone),this.b.mContext,is_in_10min_from_last_request);休息;}catch(RuntimeExceptionv0_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);休息;}catch(Throwablev0){try{if(!this.b.shouldRetryWhenError(v0)){throwv0;}++url_index;继续;}赶上(通过wablev0){返回false;}}}response=NetworkClient.getDefault().post(url,args_bytes,true,"application/json;charset=utf-8",false);休息;}}catch(Throwablev0){try{if(!this.b.shouldRetryWhenError(v0)){throwv0;}++url_index;继续;}catch(Throwablev0){返回假;}}}}catch(Throwablev0){返回假;}if(response!=null){try{if(response.length()!=0){this.parse_net_config(newJSONObject(response));返回真;}}赶上(Throwablev0){返回假;}}returnfalse;}这样就可以基本明白它在干什么了。简单的说就是先获取设备注册的url地址列表,然后遍历访问。如果访问成功,则结束。访问时,先添加Public参数,再判断是否需要加密请求。如果需要加密请求,则调用加密请求函数,否则调用普通请求函数。另外,如果加密的请求函数抛出异常,正常的请求函数也会被调用,还有一些重试参数等等。这时想到抓包发现的设备注册请求都是加密的,所以可以判断is_encrypt()函数返回true,那么如果这个函数返回false,是不是未加密请求呢??好了,静态分析部分先到这里,我们来做一个动态分析,也就是试试这个函数返回false时的效果。动态分析动态分析是在app运行时对其进行分析。比较常见的是分析app的网络请求行为,调用系统API的行为,访问文件的行为等等。由于本文讲的是设备id的生成,其实就是设备注册时的网络接口,所以只需要分析网络请求行为即可。笔者比较常用的网络抓包工具是Charles。需要在手机上配置代理,安装Charles证书。这部分将不作详细描述。如前所述,本文主要研究这个接口:https://log.snssdk.com/servic...,一般情况下,设备在注册的时候会加密访问这个接口,比如当一个app被注册时新安装或应用被屏蔽清理数据后,再次打开应用时会进入该界面。访问的时候是POST请求,参数是明文,但是数据是加密的,如下图:通过上面的静态分析,我们可以知道函数is_encrypt()可以控制是否加密transmission,所以可以想到使用Xposed来执行Hook函数,让函数的返回值固定为false。Xposed非常强大。它可以在其他应用程序运行时注入代码。具体原理和使用教程这里不再详述。下面贴出hook部分的代码。它实际上很短:)param.getResult();Log.i(TAG,"com.ss.android.deviceregister.b.a.isEncrypt(),oldResult="+oldResult+",newResult="+false);param.setResult(false);}});可以看到这里的数据部分变成了明文。至此,找到了设备注册的明文接口,但是根据前辈的工作,密文请求注册方式生成的device_id和iid是不能用的,所以笔者就使用这种明文注册方式来模拟生成设备ID。方法和前辈的代码差不多,然后用模拟生成的deviceid来测试其他接口的访问,貌似可以用。综上所述,抖音Volcano版本的安全强度高于之前的火山小视频,可能与抖音有关。毕竟是今日头条产品,技术上复用难度不大,而且感觉代码的关键逻辑部分应该进行了一些反编译,就像上面作者手动还原的功能一样。本文仅对一个小功能进行更详细的逆向分析,不涉及native层。估计那部分的阻力比较大,先动手吧。声明请勿将本技术用于商业用途或大规模爬取!如因使用该技术而与抖音火山官网造成不必要的纠纷,本人概不负责。我纯属技术爱好。如有侵犯抖音火山相关企业权益,请及时告知!转载请注明出处,谢谢!