最近tz不太好用,之前用的破解版的某洞已经彻底挂了。于是在网上找了一个某豹加速器。但是下载后发现只有两小时的会员时间,用完后还要花重金续费。作为社会主义爱国青年,面对这种违法app还在肆无忌惮的收费的现象,当然是不能忍了,于是决心破解之,以达到维护中华人民共和国宪法与法律尊严的目的!
违法app截图:
将app装在手机上打开,结果有提示:
应该是检测到root了,因为我在用一台root过的手机进行实验。
使用jadx加载apk,全局搜索关键字:检测到当前设备
确实有这个字符串,他的id名叫 toast_app_fail,再次搜索这个id名看看哪里引用了这个:
发现了很多处调用,主要在MainActivity与StartActivity里。出现在这两个文件里也正常,因为这通常是android程序最早启动的两个类,很多检测都会放在启动阶段做。注意到每次调用有不同的后缀,逗号,叹号等等。我们的是逗号,所以选择后缀为逗号的进入。
看到调用了DeviceUtils.a()函数,如果返回true就会弹出 检测设备...字符串,然后退出。看看.a()函数是什么
好家伙,果然是在检查root。检查设备是否root的常规方式就是尝试打开这些/system目录下的su文件,如果能打开,则说明设备有root权限。
使用MT管理器打开包,找到a函数,通过修改smali代码,让a函数不检测而直接返回false即可:
直接让他返回v0即可。
重新打包,安装。又弹出了那串文字,不过后缀变成了感叹号:
查看这个感叹号出现的位置:
好家伙,看到那个DeviceUtils.AntiRoot()了。如此欲盖弥彰的安全保护,真令破解者狂喜。本着学习的态度,我们还是看一下这个函数怎么antiroot的:
点进去发现是一个native函数,而加载的so叫myapplication:
使用ida加载libmyapplication.so这个文件,全局搜索AntiRoot:
发现还是在检查 su 文件,如果发现有就返回“yes”,没有就返回“no”,这和java代码中检测对上了
而check_su_files()还是在本地尝试打开各种su文件:
既然如此,可以直接用MT管理器修改java代码,将比对的“yes”改成“f*ck”,这样就算检测到root,java层的比对也会失败。
至此,root检测就全部绕过了。可以打开app了。但是打开后一片空白:
这种情况通常是因为没有拿到正确的返回数据导致的。app打开后肯定会向后端请求各种数据,如果数据异常,则无法正常显示。这时候就要抓包看看了。
打开手机代理,
启动fiddler,结果app又无法正常启动,这次弹出了这个:
app生怕你不知道他在检测代理,给出了非常温馨的提示。那我们就按图索骥。
看到字符串id是 toast_api_proxy_fail,查找引用:
和root检测的流程基本相同。不过是调用了一个b函数来检测是否有代理的,看看b函数:
可以看到,代理检测的逻辑是要确保 http.proxyHost(代理地址) 为空字符串,或者http.proxyPort(代理端口)为-1。
我们直接修改java代码让他始终返回false就好。
这样之后,就可以成功打开app,并且抓到了数据包:
但是,app内部依然是一片白,查看返回的数据,发现是加密的:
看到后面的== 以为是base64,但是base64解码失败,于是猜测是aes或者des加密。
去哪里找解密的地方呢?这需要研究andorid系统网络请求的数据流了。
通常,客户端会使用okhttp作为http客户端进行收发请求。(目前还有使用cronet做客户端的,但仅限于字节这样的大厂,而且大多是在okhttp上嫁接的。)
okhttp工作方式是责任链,或者说pipline,每一环节处理一些事情,比如在发送阶段,第一个pipline是添加基本信息,如设备id,时间戳,等等。第二个pipline是计算签名值,第三个pipline是把发送数据加密,然后发出去。
收包时候也有pipline,解密操作一般就放在某个pipline中。所以我们的目的是找到okhttp客户端创建的地方,然后找到他添加pipline的地方。
查看okhttp,好家伙,被混淆了:
通常,okhttp的创建是在okhttpclient这个类里做的。混淆通常只能混淆函数名,类名,但是无法混淆函数的实现,包括一些特殊的字符串,我们可以从字符串入手,找到okhttpclient。
下载一份okhttp的源码,查看okhttpclient这个类有何特征:
发现在内部的builder里,有三个连续的字符串“timeout”,而这是无法被混淆的。我们在jadx里全局搜索“timeout”:
果然有。
点进去看看,发现结构和okhttpclient的结构如出一辙,我们断定这就是okhttpclient类。
查看引用,我们也因此找到了app创建okhttpclient的位置:
okhttp客户端另一个特征是对读写超时的设置,从TIMEUnit也可以看出这是在设置http请求的读写超时。
同时,看到后面一连串的.a函数,这是在添加一个一个pipline。(okhttp中叫拦截器,不过我个人感觉本质就是pipline)
分别查看这些pipline。
一个是添加请求头的:
还有一个是和数据处理有关的:
看到里面的response,bodystring字符串,好有d_key_three,不由的让人浮想联翩,这是在做什么,为什么出现了秘钥和返回体?
点进去看f5865a.a这个函数:
实锤!!看到了password,iv,SecretKeySpec,Cipher,doFinal这些特征。显然是在做aes解密。
为了更准确,看看SecretKetSpec 中的f5866b与Cipher.getInstance(f)中的f分别是什么?
f5766b与f都反编译崩了,转到smali看看:
确信了,在用AES解密,模式是 CBC,填充方式是PKCS5padding
我们hook这个a函数,看看解密后的值是什么?
写一个简单的frida脚本:
hook后发现,打印出了奇怪的东西:
传入的参数确实是加密的返回数据,但是解密后没有东西。而且秘钥很怪,以error结尾??
查看系统日志:
发现解密失败,报错Unsupported key。
仔细看了一下,所使用的的秘钥和iv 确实是14字节。而aes通常有128,192,256三种秘钥,所以秘钥只能是16,24,32字节,那么显然秘钥错了。
找找秘钥生成的地方,发现秘钥是由三部分相加得来:
第一部分是从资源文件中获取的:
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2023-11-21 13:14
被乐子人编辑
,原因: