刘龙锦 张志杰 梁世民
关键词:Android;Jadx;逆向
1引言
Jadx工具是一款反编译利器,支持命令行和图形化界面,能够以最简单的方式完成APK的反编译工作,反编译后的代码可阅读程度极高,同时拥有强大的搜索定位功能,可以极大地提高反编译后阅读代码及寻找关键代码的效率。本文以句读APP为例,对Android APP逆向进行了研究。
2环境介绍及逆向思路
本文使用的句读APP版本号为V4.5.0,在豌豆荚上发布时间为2022年01月13日。抓包工具为Progress Telerik Fiddler Classic V5.0。模拟器为夜神Android模拟器V7.0.3.0(安装Xposed框架,JustTruseMe模块)。
逆向的思路一般为:(1)对应用进行抓包分析;(2)使用JADX反编译APK程序;(3)使用JADX寻找分析关键函数;(4)使用编程语言还原通信协议算法。
3抓包分析
句读APP在防抓包层面未做有效的防护,使用常规抓包环境即可抓取,对sentences/random接口进行抓取,得到以下数据。
GET:
https:
∥judouapp. com/api/v2/sentences/random?
newbie= true&system_version=7.1.2&platform=android&device_ type=MI9&app—key=fd13a4la-a194-4650-aOb2-56ld4b3187lc&device—id=458d834d-ee47-7f34-c5d4-8cle6bf825f3&signature= 7a602ae13dbfda013f23f5311948134l&version= 4.5.O×tamp= 1657659250&version_code= 1057&channel= ch_huawei
经多次抓取发现,句读APP的API接口公共参数为system—version, platform, device—type,app _key,device_ id,
signature,
version,
timestamp,
version一code,channel。signature的值为动态计算,timestamp的值为当前时间戳,其他参数为固定值。抓包过程中并未发现上传日记等操作,可以暂时推断句读APP的风控系统主要是对signature参数值计算,计算正确值即可获取服务端正常的数据返回。
4反编译APK
使用Jadx工具打开句读APP,通过Jadx返回的源文件列表判定句讀APP使用了Tencent的安全加固服务,需要进行脱壳后才能得到Dex文件,使用FDex2的Xposed进行脱壳得到对应的Dex文件后导出到桌面,拖人Jadx进行分析即可。由于反编译后的Dex文件较多,在分析时会稍微麻烦,因此得到启示:使用加固平台及对APP进行多Dex文件处理可以提高APP的安全性,延缓攻击者破解的速度。
5分析关键函数
多数APP使用okhttp库进行网络请求,okhttp库处理公共参数的方法一般为实现Interceptor接口,所以可以直接搜索Interceptor关键字,从而快速定位添加公共参数代码位置[1]。通过分析定位到句读APP添加公共参数的代码的dex文件,使用Jadx工具打开该文件,搜索关键字“Interceptor”,得到图1所示数据。
排除okhttp开始的节点,最终只剩下tech开头的两个节点,再根据关键字network推断最后一个节点可能性最大,进入tech.caicheng. judourili. network.g类中,阅读代码,在intercept方法中发现了相关代码,如图2所示。
signature参数由aVar.c方法计算得出,此方法传人了两个参数,一个是固定字符串,另外一个为HashMap类型的容器。首先,确认HashMap的数据内容,阅读tech.caicheng.judourili. network-g类的代码,通过Jadx分析出HashMap的内容为两种形式,一种是CET方式请求数据,另一种是POST方式提交数据。如果是CET方式提交数据,则把URL中的键值对参数拆分并依次加入HashMap;如果是POST方式提交数据,则把RequestBody中的键值对参数依次加入HashMap。其次,判断是否已经登录,如果已经登录则把token加入HashMap。最后,把公共参数加入HashMap即可。
确认aVar.c方法的代码,阅读反编译后的代码得知aVar为s.a类型,从导包代码中确认s.a类型来自tech.caicheng.judourili. util.s类中,但是在此Dex文件中并未发现有对应的util包,由此推断util包存放在别的Dex文件中。经过一个个文件的打开寻找,确认tech.caicheng.judourili. util包存放的Dex文件后使用Jadx打开。
阅读该Dex文件代码,分析出c方法的大致逻辑为判定参数str,hashMap不为空之后,取出hashMap的键名做数组排序,再将键值以“键名=值”的形式加入arrayList,最后加上secret_key= strc此处的str为参数str也就是一个固定字符串),全部加入数组之后,再调用m(1())方法,所以我们需要继续向下阅读I(1())方法。
l方法的代码比较简单容易理解,遍历list,在每一个元素后面加上字符串“&”,最后返回一个字符串。
m方法代码也比较容易理解,大致的流程为:判断str参数不为空,长度不为0之后,进行md5加密,返回加密后的字符串,该字符串就是signature参数的值。在代码中看到有一行代码为byte[]bytes=str.getBytes( d.a),此处需要确定d.a参数,在m方法中并未发现有定义d.a,可以推断d.a为类成员变量或者为其他类的静态常量,在导包代码处发现了导包语句import
kotlin. text.d,可以确定d.a为系统常量,再根据getBytes方法所需要的参数可以断定d.a为字符串类型,即应该是文字的编码格式,大概率为utf-8,最终的值在还原算法是再确认即可。至此,加密的流程已经走完,接下来还原该参数的计算方法。
6还原加密算法
上述分析步骤得出计算signature参数主要需要还原m,l,c三个方法,得益于Jadx强大的反编译功能,反编译后的代码还原程度非常高[2],接近于源代码,所以还原加密算法大致的流程为:复制Jadx中的代码,导人需要的包,处理程序中的错误即可。
(1)还原m方法,在Jadx中复制m方法代码,手动修改d.a为UTF-8,去除i.d方法的代码、@NotNull代碼之后,最终还原的代码为:
(4)对还原的代码进行测试,测试需要构建数据请求,参照文中抓包数据的例子构建即可,只需要判定加密后的字符串与抓包的加密字符串是否一致,发送请求后句读APP的服务器正常返回数据即可。句读APP请求的Header参数中并未有其他值,爬取句读APP的数据,拼接好URL发送到句读APP的服务器即可,测试代码如下:
7结束语
得益于Jadx工具强大的反编译功能,面对加密算法在Java层的应用,Jadx可以方便地还原加密算法。如果攻击者有一定的编程经验,还原APP的加密算法所需要的时间不会太长。从本次逆向分析得到了很多宝贵的经验,为设计APP的风险控制系统提供了必要的理论实践基础,在设计移动风险控制系统时,APP端应该着重注意以下事项:(1)对于生成的device_id应该做合法性校验,限制每一个device_id单位时间内请求次数;(2)应在合理、合法范围内收集用户的行为数据并上传到服务器分析,从而判定用户发送的请求是否合法;(3)尽可能不要使用常规的MD5加密算法进行加密,可以使用AES,RSA等高级加密算法;(4)签名加密算法尽量放到SO层计算,在SO层也要做好代码混淆以及采用OLLVM等防护手段。