某小说APP-会员分析过程

科技   2024-10-23 21:12   江苏  

某小说-会员分析过程

前置工具:

雷电模拟器9.0.77.0(64) + Redmi Note 8真机 frida15.22 jadx

脱壳网站https://nop.gs/

分析流程
脱壳

首先MT提取安装包发现该APP是使用了腾讯御进行加固的

脱壳的话使用上面那个网站就好了,上传APP后等待一会就会提示成功,随便选着一个下载方式下载下来。

下载下来的是一个压缩包,解压密码是:dump

解压完成之后进入文件夹会看到类似这样的文件结构,其中7z的文件名就是该APP脱壳后的md5值,最好记下来。如果不小心丢失了该压缩包,可以通过这个md5值去上面那个网站进行查询。

application.txt文件里面存储了该App脱壳后的Activity主入口,需要我们手动修改一下。

把这个7z压缩包push到模拟器

  1. adb push d:\Android\APP\1419bf6dec8.zip\1419bf6dec8.7z /data/local/tmp

来到模拟器该路径下发现push过来的7z包没有后缀,手动添加一下解压该包就好。

这就是脱壳后的dex文件了,我们进入原包查看一下区别

显然,脱壳包里也包含了原包中的dex文件,我们需要把脱壳包里的这两个文件删除掉。

只需要这三个就好了,全选这三个包后选着DEX修复

这样选着就好。接着我们把修复好的dex文件复制到原包中。记得先把原包中所有的dex删除掉

修改一下dex的名称,把classes4改为classes.dex就好了。

接着我们进入AndroidManifest.xml中修改一下app的入口点

在application标签中修改android:name的属性为脱壳包中txt文件提供的字符串。修改完成之后保存就好了

可以看到已经是伪加固了,签名的话使用MT给一个签名就好了。

我们安装App测试一下

程序无闪退,代表脱壳已经成功了。

会员分析

使用jadx反编译app后通过关键字快速定位到代码

例如:isVIP

显然这个是比较好的入口点,根据类名不难得到这个是用户信息类

尝试使用frida去hook这个函数使得这个函数直接返回true观察app的变化

  1. let UserVip = Java.use("com....model.entity.User");

  2. UserVip["isVip"].implementation = function () {

  3. // console.log(`User.isVip is called`);

  4. let result = this["isVip"]();

  5. result = true;

  6. console.log(`User.isVip result=${result}`);

  7. return result;

  8. };

发现显示了会员到期的时间,但是这个时间不对啊,这是取1970的时间VIP。测试会员功能也发现无法使用。

我们继续分析isVIP方法,在方法名点击按X查看交叉引用。

定位到这个方法,跟踪进入分析

代码调用了getVipEndTime函数,根据函数名不难看出是会员到期时间,不得不夸夸这app开发,真滴好。

跟进这个函数分析

直接返回了一个long类型的vipEndTime属性,查看这个属性的交叉引用

这太完美了,直接使用frida去hook这个函数,传递一个long类的参数。

  1. let UserVipTime = Java.use("com.....entity.User");

  2. UserVipTime["getVipEndTime"].implementation = function () {

  3. // console.log(`User.getVipEndTime is called`);

  4. let result = this["getVipEndTime"]();

  5. result = 4735689600000;

  6. console.log(`User.getVipEndTime result=${result}`);

  7. return result;

  8. };

观察app的变化

发现已经显示我们自定义的时间到期了,如何自定义时间呢?

4735689600000减去自1970年的时间戳就好了。

可以发现VIP功能可以正常使用了。

用户名称自定义

在用户类User中发现了一个setNick的方法,显然这个是设置用户名的,这样的话我们就能够自定义用户名了。

使用frida去hook这个函数,传入自定义的名称后观察app的变化。

  1. let UserNick = Java.use("com.....entity.User");

  2. UserNick["getNick"].implementation = function () {

  3. // console.log(`User.getNick is called`);

  4. let result = this["getNick"]();

  5. result = "GaGa";

  6. console.log(`User.getNick result= ${result}`);

  7. return result;

  8. };

发现app并没有显示我们的用户名,但是getNick也确实是获取到了我们设置的用户名,那么为啥没有显示呢?

此时换个思路分析,既然app这里显示了点击登陆那么肯定要先去判断我们有没有用户信息,如果用户信息为空的话就显示点击登陆,否则就显示用户的名称。我们在jadx中直接搜索点击登陆这四个字

竟然没有搜到,问题是:在jadx中,中文字符串是以Unicode的形式存放的,所以我们需要搜索

\u70b9\u51fb\u767b\u5f55

如果B为false,那么就直接走else分析,显示点击登陆。显然不能让B返回false。

我们找到这个B函数分析

如果user为空或者getMobile函数返回空,那么这个函数就直接返回false,问题就在这里了,我们让getMobile函数返回一个值,这样B函数就会返回true了。至于g为什么不为空?当我们调用setNick函数的时候这里的user就已经不为空了。

分析getMobile函数

![[imgae-番薯 27.png]]

直接返回mobile的值,既然这个函数要反会一个String类的数据,那么我们直接让他返回我们的名称不就好了

使用frida去hook他

  1. let User = Java.use("com....model.entity.User");

  2. User["getMobile"].implementation = function () {

  3. // console.log(`User.getMobile is called`);

  4. let result = this["getMobile"]();

  5. console.log(`User.getMobile result=${result}`);

  6. return "GaGa";

  7. };

再次观察app变化。

实习/校招/社招



长期持续内推长亭、360、绿盟等安全大厂,已累计内推2000+人
长亭科技25校招投递链接:https://join.chaitin.cn/campus 
或直接点击文末原文链接
内推码:NTAWkpg
或微信扫码投递

25校招持续内推中~~~明年毕业的同学欢迎加我,1对1简历辅导,全程跟踪内推情况

安全服务工程师、安全攻防工程师、安全研发工程师、前后端开发工程师、测试工程师等等,所有岗位均可内推




内推|长亭科技25届校招启动,附内推码~


你能拿她学校的shell,但永远拿不了她的shell


渗透实战|记一次简单的Docker逃逸+反编译jar接管云主机


渗透实战|NPS反制之绕过登陆验证


渗透实战|记一次曲折的EDU通杀漏洞挖掘


渗透实战|记一次RCE+heapdump信息泄露引发的血案


免责声明
由于传播、利用本公众号藏剑安全所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,公众号藏剑安全及作者不为承担任何责任,一旦造成后果请自行承担!如有侵权烦请告知,我们会立即删除并致歉。谢谢!
好文分享收藏赞一下最美点在看

藏剑安全
知识面决定攻击面
 最新文章