确保它没有加固,如果有加固的话还是360加固,那也没有关系,之后我会用hook方式来破解,但这仅限root,这篇文章只做最基本的软件会员破解,我会全程详细讲解,每一个步骤所有的含义包括这串代码,在软件中起什么作用图中软件仅用作演示,不提供破解后的安装包
先点开软件
随便点一个dex文件, dex编辑器++
进到这个界面后,我们直接点击常量,因为用搜索搜isvip或者是getvip,vip这类字眼往往一般会搜不到或者被软件厂商换种叫法,或者是有其他问题,常量搜索会员
这里也是轻松找到了永久会员,这个文字直接点击搜索
这里也是搜到了三种结果,有些小白就会慌了,不知道选哪个,那么我们一个一个开始排查
先点开第1个
右上角三个点转成Java代码,找不到会员就直接搜索会员,可以发现刚才搜索到的永久会员,他跟实际没有任何关系,他是充值页面上的文字,也就是价格这些跟有没有vip没关系,所以第1个可以直接排除
那么来看第3个
同样转成Java代码
看到这可能会懵了,那么我们直接来一串高亮代码解释一下
public final String x2(String str) {
switch (str.hashCode()) { // 根据字符串的哈希值进行分支判断
case -968291847: // 哈希值为 -968291847 的情况
return !str.equals("vipMonthlyPrice") ? "" : "月度会员"; // 如果字符串是 "vipMonthlyPrice",返回 "月度会员",否则返回空字符串
case -673972369: // 哈希值为 -673972369 的情况
if (str.equals("vipYearPrice")) { // 如果字符串是 "vipYearPrice"
return "年度会员"; // 返回 "年度会员"
}
break; // 如果不匹配,跳出分支
case 852904651: // 哈希值为 852904651 的情况
if (str.equals("lifeDays1Price")) { // 如果字符串是 "lifeDays1Price"
return "永久会员-生命周期1"; // 返回 "永久会员-生命周期1"
}
break; // 如果不匹配,跳出分支
case 881533802: // 哈希值为 881533802 的情况
if (str.equals("lifeDays2Price")) { // 如果字符串是 "lifeDays2Price"
return "永久会员-生命周期2"; // 返回 "永久会员-生命周期2"
}
break; // 如果不匹配,跳出分支
case 1261029048: // 哈希值为 1261029048 的情况
if (str.equals("vipPermanentPrice")) { // 如果字符串是 "vipPermanentPrice"
return "永久会员"; // 返回 "永久会员"
}
break; // 如果不匹配,跳出分支
}
return ""; // 默认返回空字符串
}
很显然,这三个还不是,那只剩第2个了
看到这儿看不懂没关系,我也看不懂,转成Java再看一遍
到这儿就通俗易懂了
因为屏幕局限的原因写不了太多文字,我就直接用高亮代码写出来了
// 如果用户信息对象 userInfoBean3 不为空
if (userInfoBean3 != null) {
// 获取用户的 VIP 等级状态(i3)
i3 = userInfoBean3.getVIP();
}
// 如果 VIP 等级大于 0(表示有会员状态)
if (i3 > 0) {
UserInfoBean userInfoBean4 = this.s; // 从类成员变量获取用户信息
Long membersEndDateMs = null; // 初始化会员结束时间
// 如果 userInfoBean4 存在且能获取到会员结束时间
if (userInfoBean4 != null && (membersEndDateMs = userInfoBean4.getMembersEndDateMs()) != null) {
// 通过 xf9.a1 方法处理时间(可能是时间格式转换)
l2 = xf9.a1(membersEndDateMs);
}
// 判断会员是否有效:
if (
(l2 != null && l2.longValue() >= System.currentTimeMillis()) || // 结束时间未过期
l2 == null // 或没有结束时间(永久会员)
) {
if (l2 == null) {
pbVar2.E("vipstatus", "永久会员"); // 标记为永久会员
return;
} else {
pbVar2.E("vipstatus", "订阅会员"); // 标记为订阅会员
return;
}
}
// 如果会员已过期
pbVar2.E("vipstatus", "过期会员");
return;
}
// 非会员状态
pbVar2.E("vipstatus", "非会员");
return;
根据上述我们可知i3 = userInfoBean3.getVIP();才是是否为vip的关键
一般情况下我们只看小数点后面的,getVIP()
这是 userInfoBean3对象的一个方法,用于获取用户的 VIP 等级或状态。
所以我们只需要给getvip赋值就行了
想必知道的人应该怎么做了,我详细讲解一下每层含义吧
.method public final getVIP()I
声明一个公开的 (public) 不可重写的 (final) 方法,方法名为 getVIP,返回类型为 int (对应 I)。
寄存器数量
.registers 2
表示该方法共使用 2 个寄存器(p0 和 v0)。
p0 是隐式的 this 指针(非静态方法的第一个参数)。
v0 用于临时存储字段值。
字段读取
iget v0, p0, Lcom/app/modelintegral/data/bean/UserInfoBean;->VIP:I
iget 指令从实例中读取字段值。
v0: 目标寄存器,存储读取到的值。
p0: 当前对象 (this),即 UserInfoBean 实例。
VIP:I: 字段标识符,表示 UserInfoBean 类中的 int 类型字段 VIP
所以我们目标是给V0赋一个值
const/4 v0, 0x1
解释:const/4 v0, 0x1 将立即数值 1 存入寄存器 v0
保存完后一路返回
自动签名并更新
有问题的话评论底下留言
没有回复内容