因为这次破解本身也很简单,并且我一直认为,逆向最重要的就是寻找关键点的过程,所以我会着重说自己的思路,忽略掉自己写的代码以及一些具体操作部分。
10.14次日更新
因为昨天发帖子是后面又重新走了一遍,所以写的时候无意间看见了 imageedit
并且也有 vip 等字眼,所以又看了一下,最后发现它的 VIP 功能大抵是:解锁拍照时所有相机模板、设置里所有时间戳模板、编辑图片以及视频时所有功能、还有去广告。
然后今天重新看的时候我就发现了,之前的思路虽然不算错,但还是有问题。先说结论,isVip
还是关键,isPro
只是对那些功能做了限制。通俗的讲,改 isPro
就是把所有会员功能变成了普通功能,而如果改 isVip
就相当于把当前用户变成了会员,那些会员功能还是会员功能,但是我们可以用。
到这里我也理解了昨天说的,为什么关键 isVip
没什么用,实际上是有用只不过是我没理解。
接着说详细思路了,可能大佬看起来这个帖子很小白,但是我就是想分享一下自己的思路,想把自己的探索过程说出来,讲自己的解题过程,而不是拿着答案讲题,希望能帮到一些像我一样 0 基础的朋友们。
首先就是我在测试图片编辑的时候发现,一共有三个地方需要会员,一个刚进去可以更换相机模板,那个和之前的一样,因为之前改了 isPro
(这里忘记说了,是 CcdCamera
这个类),所以直接就能用,然后就是曝光补偿里面有几个选项需要会员,还有就是可以选照片相框模板,也是有会员模板。
我当时第一个想法就是,还存在一些类里面有 isPro
,改了它就好了,这个简单。然后就屁颠屁颠的去改了,发现除了昨天的还剩下两个类,就全改了(着重讲我的思路历程,所以具体类不说了,毕竟一搜就知道了)。改完以后发现,相框倒是能用了,但是曝光补偿还是不行。
怎么办呢,就想还从 activity 入手,然后就找到了,编辑页面是 com.lightcone.ccdcamera.activity.ImageEditActivity
,而进入曝光补偿就变成了 com.lightcone.ccdcamera.activity.DetailRenderActivity
,思路:肯定有一个从 ImageEditActivity
到 DetailRenderActivity
的方法,就和昨天那个一样,结果没找到。
那就只能再想办法了,从跳转(DetailRenderActivity
)到付款(PurchaseActivity
)购买入手,我找到那个跳转方法(在安卓里应该叫新建 Activity 吧,不太懂,反正肯定是个方法)然后看看能不能阻止它跳不就行了。然后就发现了,还是没找到,就想接着反向找调用,就看有很多,但是大多数都是自己调用,所以就忽略了只关注其他类。
在第一个里面就有新收获,通过我三脚猫功夫推测,这玩意就是跳转的其中一环,找调它的上层
可以看到第一个和第6个(index=5)刚好是前面提到的 DetailRenderActivity
(曝光补偿),直觉告诉我肯定在其中一个里面,而进入第一个可以看见
public class DetailRenderActivity.g implements a {
public final DetailRenderActivity a;
public DetailRenderActivity.g(DetailRenderActivity arg1) {
this.a = arg1;
super();
}
@Override // e.f.e.t.w3$a
public void a() {
Intent v0 = e.a(this.a);
v0.putExtra("isFrom", "PresetUpgradeProDialog");
this.a.startActivity(v0);
c.b("import", "preset_vip_popup_upgrade", "2.1.0");
}
}
这就是全部代码,很少,并且通过仅有的词汇量推测可能是升级VIP的,和我要找的不一样,就进入第二个里面
public final boolean f0() {
if(!e.h().l()) {
this.startActivity(e.f.e.e.a(this));
e.f.l.c.c.b("pay", "menu_purchase_enter", "1.8.0");
return 0;
}
return 1;
}
感觉就是它了,都有判断,然后验证了一下,正常情况确实进了判断,接着进入 e.h().l()
public boolean l() {
return (d.b().k()) || (e.e);
}
因为前面判断条件成立了,所以这个方法返回的应该是false,而又是或关系,所以这两个都是false才行,先说 e.e
我当时确实先看它,因为看见它是个字段,不是方法,一看它果不其然默认值是个false,那就代表 d.b().k()
肯定也返回了false,然后再看它是个什么方法
public boolean k() {
return this.c != null && (this.c.isVipEffective());
}
这里的 this.c
刚好是一个 vipState
类,然后看与后面的,其中昨天截图里面也有
看到这里,我顿悟了,昨天我找 isVip
的思路是没错的,只不过这里没有把它做一个会员状态结果,而是 isVipEffective
,也怪我英语不好,我以为这个是判断vip有没有失效的,用于查询会员状态判断是否要续费,结果今天一查才发现这玩意意思是有效的,和我想的刚好相反,这玩意就是要找的判断是不是会员的关键方法。
然后就清晰明了了,这里我也没改这个方法的返回值,而是改了上一层那个 k 方法的返回值。并且把之前改的 isPro
又改回了。最后测试,所有会员功能都可使用,也就是说,只改了这一个方法,让我们成为了会员状态,而不是把会员功能改成免费功能。
有兄弟说怎么用mt,其实我也不太清楚,我基本上不在手机上操作,如果单纯更改的话很简单,直接去签名,然后 dex++ 编辑,k 方法所在包:e.f.s.g.d 然后找到 k 方法,改返回值一路保存返回就行
刚才又测了一下直接改 isVipEffective
的返回值是不行的,那证明在k方法里面那个 this.c
就是 null
,所以简单起见就直接改 k 方法就好了
成品展示:蓝奏云: https://wwi.lanzoup.com/iyi5q0dv1nnc
阿里云不能直接分享,压成exe了,双击解压就能得到 https://www.aliyundrive.com/s/hXiQkaaggC8
--------------------------------------分割线-----------------------------------
1. 起因
今天刷视频看到有人推荐这个相机,然后有人评论说好是好就是要钱。刚好这两天在了解 xposed 插件开发,就下载下来准备搞一波。
2.目的
下载下来试用发现,相机是有模板的,类似滤镜,然后有的免费有的需要购买或者开通VIP,免费的直接可以用,需要VIP的点击会跳转到另一个页面让你购买或者开通VIP。于是清楚自己此行目标:实现模板自由,解锁所有模板
3.工具
jeb
逍遥模拟器
4.思路
注意:因为我是用的jeb,所以可能出现 java 居多。
按照惯例,我最开始搜索了 isVip
,并且确实有这个方法
引入眼帘的 VipState
这个类让人提神,顾名思义,VIP状态,那么肯定就和我们有关系了。
点进去
发现这个类只有两个字段,分别是 isVip
和 expiredTime
,这一看不就是是否是 vip 并且还有过期时间吗?到这里我都以为快要结束了,因为我以为只需要在有调用 isVip
的时候给它 true
就行了
但是接下来我陷入了困境,我发现这个 isVip
没有 get
或者 set
方法,当时是第一想法,在初始化的时候,通过构造器给它一个 true
,但是等我写完发现并没有作用。
于是便想,看看到底是那里用到它了,所幸并不多
可以看到,有五个地方调用了,并且有三个是本类,还是 get
,大眼一看都是基于它的值做判断的,所以只需要关注第一个和最后一个就行了。
来到第一个方法
这里可以看见,它 new
了一个 VipState
,并且还给 isVip
赋 true
,我当时就想,那基本上就和这个没什么关系了,可以看下一个了。
来到最后一个方法
在这里,和 isVip 的值息息相关的三行代码 boolean v4 = false;
,v4 = (v4) || ("vip".equals(v5_1.item));
,v13_1.isVip = v4;
那么说到底最关键的还是 v4 = (v4) || ("vip".equals(v5_1.item));
但是它在两个条件判断下,所以我当时第一想法就是看看能不能走到这,结果发现,传进来的那个 arg13 直接就是个空,if 都进不来。
然后就一路追上去,看看传进来的参数是什么,最后看见了 response,感觉像是请求服务器拿来的,就去抓包,但是也没抓到。(因为这是个错误思路,就不贴截图了)
5.破局
到这里,基操是不行了,就想着转变思路。
在主页面(图1)点左下角可以切换模板(图2),可以看见有些模板是不能直接免费使用的,点了就会跳到另一个页面(图3)
然后我的思路就是,找到这个跳转的,这是个关键点。刚好模拟器上有装开发者助手,通过它发现,在主界面是 com.lightcone.ccdcamera.activity.CameraActivity
这个 activity
,但是到了图3那个就成了 com.lightcone.ccdcamera.activity.CameraSampleActivity
于是,找到 CameraActivity
,并在里面搜索 CameraSampleActivity,结果没搜到,因为我不懂安卓开发,不清楚这个 activity
到底是怎么个运行原理,所以只好逆向思维,通过 CameraSampleActivity
找调用它的方法。
虽然很多地方都调用了,但是很幸运不需要搜索直接就能看见,有一个 CameraActivity
,第一感觉就是它了。
进去一看,果不其然
在这里能看见,它先判断传进来的 arg3
是不是空的,不是就跳了,然后我验证发现,arg3
确实不是空,尝试性让 arg3
直接为 null
不进入下面的方法,果不其然行不通。
那就只能看上层调用了
能看到有两个方法调了这个 g
方法,一个 d
,一个 e
。
先看 e,能看到只有两个判断,并且在第二个判断成立的时候才会调用 g 方法,而看它的条件,很明显是在判断是不是原相机的,点进去可以看到具体判断,这里就不展示了。不过在这里我注意到了 CameraId,发现它是通过 CameraId 来标识每一个模板的。
再进入 d 方法查看
能看到这里在 else 里面调用了 g
方法,也就是说,if
里面的判断是 false
,那就看看这个 false
怎么来的
进入到 m.e().h()
发现,有五个判断
public boolean h(CcdCamera arg2) {
return arg2 != null && (e.h().l()) || !arg2.isPro() || (this.g(arg2)) || (CameraId.isOriginalCamera(arg2));
}
然后通过打 log 发现,这个 isPro
就是标识是否是会员专用的,也就是说,它是 true
就代表不免费,是 false
就代表免费,那就好办了,直接让它返回 false
就行了。
6.结尾
通过上面,已经成功解锁了所有的模板,但是是有可能有问题的,因为我在看 isPro
的调用的时候,发现有好几个,有两个是图片编辑和视频编辑,可能是在保存完编辑的时候的某些功能,但是我懒得测了。
还有就是会员,我现在总不能会员就一个这个吧,它上面写着还可以解锁更高级功能,但是找了半天,就发现一个加时间戳水印的功能,也是可以选模板然后模板有的需要 VIP,就顺便看了看,发现和相机一样,都是 ispro。
然后就是又用 mt 做了破解版,因为已经知道了 ispro 这个关键点,并且也定位到了位置,所以改起来很快,唯一有点麻烦的可能就是我下载的包是有签名验证的,需要去一下。
不知道为什么用md编辑出来有的代码生效了,有的没有,因为图也不少,懒的改了,凑合看吧。
总结:这篇帖子,主要是讲思路的,从一开始的 isvip 到抓包再到后面的 activity,然后找到了需要的 ispro,总的来说非常简单,但是因为自己太菜,弄了半天。
最后上个成果图吧