|
本帖最后由 jiangmingzi 于 2024-3-24 17:30 编辑
hjsz Z2O安全攻防 2024-02-27 20:38 北京
文章正文快过年了,提前祝大家过年好,开车的小伙伴回家带孩子过年肯定需要个哄娃的车机app。我就在车机应用市场下了个给小孩哥讲故事的app。准备源代码分析启动广告
* 保存、打包、签名、安装、测试。从下面的gif可以看出,直接跳过了广告和开始的同意协议步骤,直接进入了主界面。![](http://82.157.65.239:53401/eakfj ... es//mds/private/APK逆向分析-以某车机哄娃app为例-hjsz/images/6L4sIpETiMdlqNAW.gif)应用内弹窗• 当进入主界面,会有个开通会员的弹窗提示,这里去掉吧,车机app尽可能少多余的操作,毕竟有时候要开车时操作。 • 进入MainActivity查看具体的代码逻辑。大致看了看一下并没有非常明显的Dialog提示,那就从显示的元素下手。 • 使用开发助手app中的布局查看功能查看弹窗的具体id。得到如下图的结果。从布局结果来看,这并不是一个自定义的Dialog,而是一张Img,并且其id为: R.id.mAdCoverImg ,我说刚才代码中为什么没有Dialog的逻辑代码。
* 分析PullADFragment,发现了另外一个关键的元素:即关闭广告的Img,在上一步布局查看中,由于此Img太小,期初并没有注意。在分析PullADFragment才发现这一Img控件。
* 继续分析关闭广告的Img的Click逻辑。((ImageView) view.findViewById(R$id.mAdCloseImg)).setOnClickListener(new a(1, this));在代码中,new a(1, this)表示创建了一个名为a的匿名内部类的实例,并将其作为点击事件的监听器传递给setOnClickListener方法。函数a的具体代码如下:
public static final class a implements View.OnClickListener {
public final /* synthetic */ int a;
public final /* synthetic */ Object b;
public a(int i, Object obj) {
this.a = i;
this.b = obj;
}
@Override // android.view.View.OnClickListener
public final void onClick(View view) {
int i = this.a;
if (i != 0) {
if (i == 1) {
((PullADFragment) this.b).dismiss();
return;
}
throw null;
}
PullADFragment.a((PullADFragment) this.b);
IAppService a = PullADRepo.b.a();
if (a != null) {
FragmentActivity requireActivity = ((PullADFragment) this.b).requireActivity();
h.a((Object) requireActivity, "requireActivity()");
c.a.b.g.a.b.a aVar = ((PullADFragment) this.b).f1308c;
if (aVar != null) {
String d = aVar.d();
if (d == null) {
d = "";
}
a.a(requireActivity, d, null);
} else {
h.b("vo");
throw null;
}
}
((PullADFragment) this.b).dismiss();
}
}
* 之前分析了这么多,到试图修改的时候才发现逻辑有问题,上面的分析到了Click的地方,而我们的需求是让这个fragment直接不显示,何来Click之说。
* 然后想其他办法,这里是不是可以在fragment的Create函数中直接return-void,不进行下面的Image或者fragment初始化操作。在下面函数中的smali代码中直接加入return-void。
* 进行上面的修改,找到该fragment的smali代码。
* 保存、打包、签名、安装、测试。发现fragment直接不显示,也就达成了我们的目的。
会员资源解锁• 首先需要登录,那就抓包看一下登录的请求。抓到下面一系列的包,简单分析一下。
• 其中比较重要的是下面这个请求 /inner/user/member 与响应。从响应来看这是针对用户登录后的信息,而且没有加密。
• 方法一是针对/inner/user/member这一请求进行静态注入,将关于vip的返回信息都改为true。
• 静态注入后重新登录,发现小黄鸟提示注入成功,点开app个人中心看到,显示是vip,但是到期时间由于格式不请求就没修改,所以是null。
• 方法二:修改原始代码逻辑。抓包的环境不可能都有,车上更难配置相关环境了,所以改原始的代码逻辑才是一步到位的。
* 简单分析一下上面三个Result,其中比较重要的应该是MemberInfoResult,这是关于用户登录后信息的Result。里面有关于用户状态的set和boolean函数。
* 其中只有一个关于是否是会员的函数,即上面截图中的is_vip()函数,且返回值是boolean。一个修改的方法是将返回值固定改为0x1。
* 保存、打包、签名、安装、测试。发现和之前抓包静态注入一样,都显示会员,而且可以收听需要vip的故事。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
|