午后,社区上很快就涌出了大量相关资讯,有来自小道的消息,有事件的经过,有案件的总结,也有网友们的各种猜测。就像在帮助吃瓜群众能更好的了解整个事件的来龙去脉。
然而这些资讯并非凭空而来,都是通过一些人进行了数据的整理和分析,然后再以能让群众理解的方式去发表。
在逆向里,我们时常会提到"分析"这一个单词。可是对于新手来说"分析"是一个又熟悉且陌生的词汇。熟悉的是他们理解分析的意思,陌生的则是他们不懂如何去分析。
所谓分析,就是将代码转化为自己能理解的方式去解读。
现在来进行一个简单的分析,这是一个smali代码,我们目的是要把它转成能理解的语句。
const-string v0, "Apple"
iput-object v0, v1, Lcom/sample/code;->action:Ljava/lang/String;
const-string 是定义一个字符串变量,变量存放着一个apple单词,然后再通过iput把变量里的apple放到了名为action的容器里。
接着我们换一个更好理解的方式去解读。
我手上有一个颗苹果,然后我把苹果放到了一个名为action的箱子里,所以现在我们知道action箱子里被我们放进了一颗苹果。
通过分析解读,可以发现它已经变成显而易懂的内容了。所以玩逆向破解,真正要学习的是如何分析,而不是如何破解,唯有理清原由,我们才会知道下一步该如何去做,对人对事亦如此,而不是不分青红皂白的胡来一顿。
再来看一段smali代码,这是一段判断是否为付费用户的代码
invoke-static {}, Lcom/lightcone/analogcam/dao/AppSharedPrefManager;->getInstance()Lcom/lightcone/analogcam/dao/AppSharedPrefManager;
move-result-object v0
invoke-virtual {v0}, Lcom/lightcone/analogcam/dao/AppSharedPrefManager;->getEvalPro()Z
move-result v0
if-eqz v0, :cond_37
const-string v0, "subscribe user"
return-void
:cond_37
const-string v0, "non subscribe user"
return-void
通过分析,可以知道这段代码主要是通过获取AppSharedPrefManager里的getEvalPro来判断自身是否已付费,Z在代码里则表示boolean,boolean数据只有2种结果,"true" or "false",在代码表示上则是"1"或"0"。所以可以知道从getEvalPro返回的结果要么是1,要么是0。然后再把得到的结果存放到v0里,接着通过if-eqz来判断是否等于0,如果等于0则执行未付费代码,等于1则执行已付费代码。
这时候可以再进一步分析,进入到getEvalPro代码段,看看具体情况。
.method private getEvalPro()Z
.registers 4
.line 572
iget-object v0, p0, Lcom/lightcone/analogcam/dao/AppSharedPrefManager;->sharedPreferences:Landroid/content/SharedPreferences;
const-string v1, "eval_pro"
const/4 v2, 0x0
invoke-static {v0, v1, v2}, Lcom/lightcone/analogcam/dao/AppSharedPrefManager;->getBoolean(Landroid/content/SharedPreferences;Ljava/lang/String;Z)Z
move-result v0
return v0
.end method
SharedPreferences是android的轻量级存储类,可以存储各种配置信息。这段代码主要是获取配置文件里名为evel_pro的boolean数据,最后再把获取到的数据赋予v0并返回到getEvalPro结果。所以从上面的分析,我们就可以知道,在未付费之前,eval_pro的数据一定是0。同时也可以发现,从分析过程中,自然就有了该怎么去破解的思路,只要把0改成1,就能完成破解。所以很多新手都存在一个问题,每次跟着教程都会破解,可是到自己独自破解的时候却就不会了,这就是因为没学会分析,不懂原由,也就不知道如何去破解。
可是现在软件的保护手段越来越强,很多时候并不是只改个判断就能完事,这时候拼的就是技术与知识。所以要记住从分析,破解,到实现,是三种概念。从分析里我们可以了解到如何去破解,可是从破解里我们要做的是如何去实现出来。
理论到这里也讲得差不多了,那现在就来个实践吧。
准备工具:
[ol]
[/ol]
操刀软件:
Nomo相机
这软件我不会进行完整的讲解,主要前半段的破解只需要修改boolean值就能完成本地vip破解,都是一些初级的东西,所以这里就略过咯。
软件付费限制为相机滤镜,未付费只能使用几款滤镜。
Screenshot_20220819-185648_NOMO CAM.jpg (274.6 KB, 下载次数: 0)
下载附件
2022-8-19 23:08 上传
可是当完成本地破解后,发现依然无法使用滤镜。这时候怀疑数据可能是通过网络验证,所以对其进行抓包处理。
Screenshot_20220819-190603_NOMO CAM.jpg (308 KB, 下载次数: 0)
下载附件
2022-8-19 23:08 上传
Screenshot_20220819-190618_NOMO CAM.jpg (162.06 KB, 下载次数: 0)
下载附件
2022-8-19 23:09 上传
通过抓包,其中有一条数据android_product_list引起我注意。
Screenshot_20220819-190907_HttpCanary.jpg (145.87 KB, 下载次数: 0)
下载附件
2022-8-19 23:09 上传
检查响应包发现已通过base64加密。
Screenshot_20220819-190922_HttpCanary.jpg (611.56 KB, 下载次数: 0)
下载附件
2022-8-19 23:09 上传
这里直接使用在线base64解密对其转换成解密数据。解密后发现,会员滤镜在未付费之前是不提供下载地址的。图中可以看到download_url是空白的,所以仅修改本地vip是无法完成破解的。
Screenshot_20220819-200947_MT Manager.jpg (583.34 KB, 下载次数: 0)
下载附件
2022-8-19 23:10 上传
已知下载地址需要通过服务器验证会员才可以获取,是否就无法破解?咳咳,现在放弃还太早,我们从试用软件过程可以知道,未付费情况下有提供几款免费的滤镜,从数据包里可以看见免费的下载地址并未经过任何加密,所以可以利用这点进行分析。
Screenshot_20220819-201338_Gallery.jpg (257.79 KB, 下载次数: 0)
下载附件
2022-8-19 23:10 上传
从2组下载地址里可以看出,不一样的仅仅只是skin后面的内容。如果说skin后面的是滤镜名称,那么名称后面的那组数字又代表什么呢?
https://nomo-cdn-na.dafork.com/Skin-Tropical-30.zip
https://nomo-cdn-na.dafork.com/Skin-FR2-15.zip
经过观察内容,可以得出前面是滤镜名称,后面数字表示skin的版本号。这样我们也就可以推断出会员的下载地址了。
PicsArt_08-19-08.32.43.jpg (172.19 KB, 下载次数: 0)
下载附件
2022-8-19 23:11 上传
首先我们先来整理一下下载地址。
download_url = "https://nomo-cdn-na.dafork.com/Skin" + "-" + skin name + "-" + skin version + ".zip"
然后随便找一个会员滤镜在浏览器测试一下,嘿嘿,成功了,可以正常下载。
https://nomo-cdn-na.dafork.com/Skin-135P-18.zip
PicsArt_08-19-10.11.18.png (86.16 KB, 下载次数: 0)
下载附件
2022-8-19 23:07 上传
至此我们已经找出了会员的x地址,那么我们也就有了如何破解的思路,只需要把下载地址都补全即可。
接下来我们就要把这想法给实现,mt里搜索download_url定位到关键出。
Screenshot_20220819-204803_MT Manager.jpg (204.01 KB, 下载次数: 0)
下载附件
2022-8-19 23:11 上传
然后我们需要写一段代码进行补全,代码如下
.method public getDownload_url()Ljava/lang/String;
.registers 15
.line 1
//获取原本的下载地址
iget-object v0, p0, Lcom/blink/academy/nomo/bean/store/CameraGoodBean;->download_url:Ljava/lang/String;
//判断下载地址是否为空
invoke-static {v0}, Landroid/text/TextUtils;->isEmpty(Ljava/lang/CharSequence;)Z
move-result v2
if-eqz v2, :cond_ac
//下载地址如果不存在则折行此处
//获取ios_id的滤镜名称
iget-object v3, p0, Lcom/blink/academy/nomo/bean/store/CameraGoodBean;->ios_id:Ljava/lang/String;
const-string v4, "blink.academy.nomo."
const-string v5, ""
//过滤掉前面多余的字符
invoke-virtual {v3, v4, v5}, Ljava/lang/String;->replace(Ljava/lang/CharSequence;Ljava/lang/CharSequence;)Ljava/lang/String;
move-result-object v3
//然后转换成大写字母
invoke-virtual {v3}, Ljava/lang/String;->toUpperCase()Ljava/lang/String;
move-result-object v3
//接着再获取skin版本
iget v4, p0, Lcom/blink/academy/nomo/bean/store/CameraGoodBean;->skin_version:I
//最后将下载地址进行合并
new-instance v5, Ljava/lang/StringBuilder;
invoke-direct {v5}, Ljava/lang/StringBuilder;->()V
const-string v6, "https://nomo-cdn-na.dafork.com/Skin-"
invoke-virtual {v5, v6}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v5, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
const-string v3, "-"
invoke-virtual {v5, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v5, v4}, Ljava/lang/StringBuilder;->append(I)Ljava/lang/StringBuilder;
const-string v3, ".zip"
invoke-virtual {v5, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
invoke-virtual {v5}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;
move-result-object v0
:cond_ac
return-object v0
.end method
完成后,我们还需要对几个参数的数据进行修改,如图中标记的地方,这里就不一一列出了。
PicsArt_08-19-08.03.31.jpg (493.91 KB, 下载次数: 0)
下载附件
2022-8-19 23:10 上传
现在可以进行打包和安装了,可以看见已经可以正常下载和使用了,表示我们已经破解完成。
1a4814a4d507cd4c- 1.png (1.6 MB, 下载次数: 0)
下载附件
2022-8-19 23:11 上传
3152ea1e03107d94- 1.png (1.6 MB, 下载次数: 0)
下载附件
2022-8-19 23:12 上传
-426689a12567b42e- 1.png (1.75 MB, 下载次数: 0)
下载附件
2022-8-19 23:13 上传
后记: 只要顺着破解三步骤 分析->破解->实现,基本就不会有什么大问题了,如果说破解不到,就是分析不到位,如果说实现不了,就是技术上还需要增强。这样的去进行进行简化,自然就会找到自身的不足。凡事只要理清了,问题也就明了了。