更新
填坑|南X周易程序超出试用的解决办法
https://www.52pojie.cn/thread-1204354-1-1.html
(出处: 吾爱破解论坛)
1.缘起
前几天在咱们论坛发了一篇x奥周易系列软件逆向思路\更新了视频演示,反响还不错。然后正好找到了一款竞品,就是下面这位了。其实这篇文章从发完X奥就一直在酝酿了,但是技术不过关,一直没达到完美的欺骗效果。今天顺藤摸瓜就摸到了一个关键点,改一下就好。如果不想看思路的就直接看第6部分,如果想看思路的就往下翻翻,看完全文,不过思路挺长的,但是如果您像我一样,也是小白,看完还是有收获的。
2.软件介绍
八字、六爻、风水、奇门、姓名、择吉、合婚,多种平台上应用,不断完善!
3.软件列表(版本在支持系统里面有区分)
练手包下载地址在附件里
以下安卓手机软件都可免费试用30次。
当然,跟着我做完以后就没有使用限制了
- 批八字算命
- 玄空风水
- 综合排盘
- 六爻断卦
- 奇门适甲
- 专业起名
- 八字合婚
- 择吉程序
- 金口诀
- 八字用神
- 南方万年历
- 家居风水
- 六爻排盘
- 八字排盘
4.支持系统
V1.73,适用于安卓系统4.0版至安卓7.11版。
V1.81,适用于安卓8.0及以上版本。
5.逆向程序
MT管理器
6.害,我都不好意思写标题
方法很简单,MT进入安装包,DEX++编辑器打开classes.dex文件,打开An_xxxxxActivity,搜索add
,第一个结果如下:
add-int/lit8 v0,v0,0x1
删除这一行,一路保存后编译、签名。
好了,破解完了。
说句题外话,兄弟们,看着玩意没用,这句add-int/lit8 v0,v0,0x1是我找出来的,不是你。就像我能按照小夜大佬交代的查找ChkNum来欺骗X奥系列软件一样。换成这个系列我又啥都不会了。所以你只看这句价值不大,想学点东西还得看下面的思路。
至于成品嘛,这么简单你还好意思要成品?
7逆向过程
以“八字排盘 V1.73”为例,首先安装原版软件点完试用的30次,从第31次开始,则无法正常排盘,会引导注册。如图
我们点击注册,然后会弹出注册页面
然后有以下几种情景:
- 点击“确定”,提示“您还没有输入注册码”
- 随便输入注册码,点击“确定”,提示“您输入的注册码不对”
- 点击“退出”,则返回软件主页面
好了,直接进到MT管理器里,打开apk文件,使用DEX编辑器++打开classes.dex
随便浏览一下类列表,有一个“activity_register”类。
然后点击搜索,搜索上面几个关键词。
比如搜索“注册”可以看到以下结果
我们点击“您已经注册了本程序”这一条,看到如下代码:
if-nez v1, :cond_96
sget-boolean v1, Lcom/nfbazi/PaiBazi/a/a;->f:Z
if-eqz v1, :cond_aa
:cond_96
const v1, -0xffff01
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setTextColor(I)V
const-string v1, "您已经注册了本程序。"
invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V
const-string v0, "************"
invoke-virtual {v6, v0}, Landroid/widget/EditText;->setText(Ljava/lang/CharSequence;)V
const/4 v0, 0x0
invoke-virtual {v6, v0}, Landroid/widget/EditText;->setEnabled(Z)V
:cond_aa
return-void
.end method
这里面有两条判断:
if-nez v1, :cond_96
if-eqz v1, :cond_aa
关于Smali语法的解读,我们可以参考这篇文章:
if-eq 如果等于
if-ne 如果不等于
if-lt 如果小于
if-le 如果小于等于
if-gt 如果大于
if-ge 如果大于等于
if-eqz 如果等于零
if-nez 如果不等于0
if-ltz 如果小于零
if-lez 如果小于等于零
if-gtz 如果大于零
if-gez 如果大于等于零
————————————————
版权声明:本文为CSDN博主「Ceryool」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Ceryool/java/article/details/51314394
我们现在知道了
if-nez v1, :cond_96 #如果v1不等于0,就执行cond_96的代码
if-eqz v1, :cond_aa #如果v1等于0,就执行cond_aa的代码
我们通过第一个代码块可以发现cond_96的代码就是包含"您已经注册了本程序。"的那一堆,cond_aa返回空,就是什么都不返回。
可以推断一下,未注册的情况下,v1应该是0,注册后,v1就不是0了,此时返回cond_96,也就是"您已经注册了本程序。"
那我们就欺骗一下,让未注册情况下,也能返回"您已经注册了本程序。"有两种途径可以实现此目的
- 修改if-nez v1, :cond_96为if-eqz v1, :cond_96
- 修改if-eqz v1, :cond_aa为if-eqz v1, :cond_96
修改之后,我们可以看到效果如图
但是经过测试之后我发现,这只是个美化效果,也就是说,我们只是更改了外观,并没有欺骗软件以达到注册的目的
好,接下来接着操作。
回到MT管理器,先反编译一下AndroidManifest.xml,这里是软件权限,我感觉给它联网权限不太好,那么删除android.permission.INTERNET
就行了
......
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 读取手机状态和身份 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 修改或删除您的USB存储设备中的内容 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 检索正在运行的应用 -->
<uses-permission android:name="android.permission.GET_TASKS" />
<!-- 安装快捷方式 -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- 此应用可显示在其他应用上方 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
下面是软件的Activity
<!-- 这块注释是我加的,一般第一个Activity就是程序的入口(主界面),不过也不绝对 -->
<activity
android:theme="@style/startback"
android:label="@string/app_name"
android:name=".An_PaiBaziActivity"
android:configChanges="keyboardHidden|orientation"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<!-- 但是有下面这句 android.intent.action.MAIN 就确定了,这就是入口(主界面) -->
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- 下面的代码被我精简了,省篇幅,主要就是让大家看一下有这么几个Activity -->
<activity android:name=".activity_register" /> <!-- 注册 -->
<activity android:name=".webshow" /> <!-- 排盘结果 -->
<activity android:name=".baziList" />
<activity android:name=".BaziToShengri" />
<activity android:name=".BaziSetting" />
<activity android:name=".SelectSet" />
<activity android:name=".DushuList" />
<activity android:name=".textShareActivity"/>
<activity android:name=".ShareOrFeedback" />
<activity android:name=".BazippActivity" />
<activity android:name=".RuanjianXuyong" /> <!-- 软件续用 -->
<!-- 没写注释的Activity都是实现具体软件功能的,不是咱们的欺骗目标 -->
看完之后,接着使用DEX编辑器++打开classes.dex,刚才咱们修改了activity_register,并且发现这里面并不是验证是否激活的关键所在。
然后看一眼An_PaiBaziActivity,毕竟这是主界面,信息会多一些。Smali可读性比较差,我们转化成Java代码,可是代码有很多,看哪?咱们在一开始测试过,试用次数没了之后,再使用就会跳转到软件续用界面,那我们就搜一搜什么条件下跳转,搜索我们在AndroidManifest.xml看到的RuanjianXuyong,然后我们发现就一处可以找到:
public void b() {
Intent intent = new Intent();
intent.setClass(this, RuanjianXuyong.class);
startActivity(intent);
}
这句代码是什么意思呢。因为我没学过Java。所以我也没看明白,不过我清楚,肯定就是从这里跳转到软件续用界面去了。
我们不想见到软件续用界面,因此就不能让它intent.setClass(this, RuanjianXuyong.class);
所以,我就兴致勃勃的在Smali代码中定位RuanjianXuyong
.method public b()V
.registers 3
new-instance v0, Landroid/content/Intent;
invoke-direct {v0}, Landroid/content/Intent;-><init>()V
const-class v1, Lcom/nfbazi/PaiBazi/RuanjianXuyong;
invoke-virtual {v0, p0, v1}, Landroid/content/Intent;->setClass(Landroid/content/Context;Ljava/lang/Class;)Landroid/content/Intent;
invoke-virtual {p0, v0}, Lcom/nfbazi/PaiBazi/An_PaiBaziActivity;->startActivity(Landroid/content/Intent;)V
return-void
.end method
用我这脑子想,就是,我不想要哪一行就直接注释掉哪一行,于是我在 const-class v1, Lcom/nfbazi/PaiBazi/RuanjianXuyong;
前面加了一个#,然后心满意足的转进Java看了一眼,注释错了,然后我返回Smali代码,又把 invoke-virtual {v0, p0, v1}, Landroid/content/Intent;->setClass(Landroid/content/Context;Ljava/lang/Class;)Landroid/content/Intent;
注释掉了,结果还是不行。
我不禁陷入了深思!我为啥要注释掉它?因为我不想见到软件续用啊;那我想见到什么?肯定是排盘结果啊!那我直接把RuanjianXuyong替换成webshow不就行了吗?!我可真是个小机灵鬼,说干就干。
然后我就把这行代码改成了:
const-class v1, Lcom/nfbazi/PaiBazi/webshow;
一路保存,反编译,覆盖安装,排个八字
嘿嘿,剧本好像有点不一样,软件试用界面是没了,排盘界面也出来了,可是内容去哪了?玩呢?气得我脑瓜子嗡嗡的,算了,先不破了,看看这软件哪里还有验证的地方。。咋这么麻烦呢?
这还有一个显示命例,按钮,点进去一看就是个档案夹的功能,可以时不时的把保存的案例拿出来复盘。然后我随便点了一个,想要看看复原效果,结果又看到这个熟悉的面孔了:
事情进行到这里,我又要开始深思了
- 这软件到底搞了多少个验证的地方?
- 验证方法是啥?
- 就我这水平还能不能破完给我可爱的坛友写文章去了?
- 这软件就没啥总阀门吗?
嗯~总的,我好像嗅到成功的味道了,突破点在试用次数上!试用期间功能不受限制,说干就干。成功我来了。
痛定思痛、细心研读An_PaiBaziActivity的Java代码(我能看懂?其实我就是看看我认识哪几个单词)
147行:如果我没猜错的话,trytimes就是试用次数吧,我真是个小机灵鬼
private void e() {
this.h = getSharedPreferences("trytimesxml", 0);
a.k = Integer.parseInt(this.a.b(this.h.getString("tms", this.a.a("65AB24201"))).substring(7, 9));
if (a.k < 32) {
a.k++;
}
this.h.edit().putString("tms", this.a.a("65AB242" + String.valueOf(h.e(a.k)))).commit();
a.d("trytimesxml");
a.a("trytimesxml.xml", "system.out");
}
看完之后,啊,这段代码就是。。嗯,,那啥的、、是吧。(球都没看懂)
不过,这段代码过于眼熟
if (a.k < 32) { /*如果a.k < 32,就执行a.k++*/
a.k++; /*a.k++ 就是 a.k = a.k + 1*/
} /*a.k = a.k + 1就是说a.k每次加1*/
我混迹吾爱数载,一看这货就是在计数,没猜错的话,应该是这样的:
if(使用次数 < 32) {
使用次数++;
}
/*“使用次数”在具体程序中会对应不一样的变量名,表示的都是使用次数的意思*/
然后我又开始我的脑洞了:
- 把试用次数设置为一个特别大的数,然后就随便试用呗!
- 不行,再多的试用次数也有用完的时候?
- 那就让使用次数自减,这样永远都小于32
- 不行,减成负数报错怎么办?
- 即便不报错,减到特别小,程序会不会崩也是个问题
- 为什么不锁定使用次数?
啊哈,直接把使用次数++;
删掉不就行了,我真是个小机灵鬼。当然上面是java代码,咱不能修改,那咱就去改Smali代码,怎么定位呢?反正我看不懂这东西,翻也不见得能翻到,先去网上冲一会儿浪:
ARM常用指令
ADD 加指令
SUB 减指令
STR 把寄存器内容存到栈上
LDR 把栈上内容载入一个寄存器中
.W 是一个可选指令宽度说明符。不会影响为此指令的行为,它只是确保生成32位指令。
BL 执行函数调用,并把使lr指向调用者的下一条指令,即函数的返回地址
BLX 同上,但是在ARM和thumb指令集间切换
CMP 指令进行比较两个操作数的大小
来源: wOw的博客
文章作者: Wossoneri
文章链接: http://wossoneri.github.io/2019/09/12/[Android][Security]Decompile-smali/#toc-heading-23
本文章著作权归作者所有,任何形式的转载都请注明出处。
浪了一圈,哦不,搜索了一圈,我感觉我又行了,看样子,直接搜add就行,然后这是搜索add的第一个结果:
1.const/16 v1,0x20
2.if-ge vo,v1,:cond_38
3.sget vo,Lcom/nfbazi/LiuyaoPaipan/a/a;>l:I
4.add-int/lit8 v0,v0,0x1
5.sput vo,Lcom/nfbazi/LiuyaoPaipan/a/a;>l:I
第1行就是给v1赋值,16位的20正好对应十进制的32。十六进制20=2*16<sup>1</sup>+0*16<sup>0</sup>=32
第2行就是那个判断语句
第4行就是让使用次数+1
第3、5行兴许是传递参数的?看不懂
我们只需要删除或者注释掉add-int/lit8 v0,v0,0x1
即可,注释就是在行首输入#。删除就是直接删掉。
然后保存、编译、签名、安装、测试。畅通无阻。
软件截图
略,分析里面都有了,截图没意义。
总结
感悟
有个故事:
一天,一个农夫的农机坏了。自己怎么修也修不好。没办法,只能找人来修了。他请来一个修机器的,那人左看看又看看,最后在机器的某个部位,敲了一下,然后机器重新启动起来。农夫很高兴,于是便问:“多少钱。”那人说:“200美元”,农夫说:“这么贵”。那人说:“这一锤子并不贵,但是,这一锤子往哪敲就贵了”。
其实小夜大神的搜索ChkNum和我的搜索add都没啥价值,分析思路是我得到的教训,这是有价值的地方。所以希望想自己学逆向的同学可以看看我的思路,少走一些弯路,而不是学会搜add,从我的例子来说,学会搜ChkNum对于此次欺骗毫无价值。
其他小问题
- 如果在删除
使用次数++
以前就用完了32次试用机会,触发了跳转到软件续用界面,再覆盖安装欺骗版的,仍然会跳转到软件续用界面。解决方案:https://www.52pojie.cn/thread-1204354-1-1.html
- 如果把时间调到几年后(具体没测试),会弹窗提示软件过期、悬浮窗提示软件过期,但是没什么影响,跳过即可。去除弹窗、悬浮窗可以在论坛搜一些其他大佬的帖子,或者我晚一些时间再补一个帖子。
- 如果仅删除add那一句,注册界面仍然显示未注册,这个地方就是个强迫症问题,想改就改,不想改的话正常使用也没人点进去看。
- 这几个小问题我还没着手解决,如果你尝试解决时遇到难题,可以在评论区交流,或者在论坛求助。
这个帖子前后耗时6个多小时吧,总算写清楚自己思路了,希望对您有用,也期待大家踊跃互动,我目前着手欺骗一个新的系列,这一系列的软件颜值很高,像是iOS界面,如果这贴子反响比较好,我就抓紧把这个高颜值的欺骗手段放出来。
最后这句话没什么用,就是怕复制MD出错。