发表于 2017-9-14 20:12

申 请 I D:欲断魂【申请通过】

1、申 请 I D:欲断魂
2、个人邮箱:1183618058@qq.com
3、原创技术文章:知米背单词V4.8.6破解方法以及思路

最近在背单词发现知米很不错就是主要功能都需要收费于是就动起手来。

首先发现有支付宝支付方式应该可以内购破解,但考虑到篇幅以及入门的问题所以就用了其他方式破解

破解:
首先要了解这款软件,才能对破解有一个准确的思路。
软件特点:
1.新注册的用户有3天试用。
2.登录后退出软件,断网,进入软件不会提示“没网”,而且能够准确显示用户信息,收费功能可用。
3.注销后退出软件,断网,进入软件提示“没网”
4.这款软件没有vip,收费功能单独购买

通过这4点就可以对这款软件得出点结论。
1.首次登录后本地会存储用户的信息(是完整的信息包括每个功能是否购买)
2.软件是通过读取本地的信息运行的(可离线运行)

首先由这2点我就想到了2种的破解方法,
1.既然软件是通过读取本地的信息运行,本地信息又包含了功能是否购买,应该可以通过修改信息文件的方法,让软件读取到错误的信息误以为已经购买,但这个方法不太理想,不可能永久离线,一旦联网信息就会被服务端的覆盖失去效果。而且信息文件的编码方式未知。
2.修改关键跳这也是最常用的。软件读取信息后改变跳转(我用的这种方法)要明确这不是vip像修改isvip()返回值的方式肯定行不通而且每个功能的信息都是单独的。


开始:

                                    
       
软件需要破解的有3个主要功能 图片,词根,一堆词库

首先反编译软件,软件用了混淆但对修改关键跳而言影响不大。先从词库(右图)开始。


词库:


点击下词组弹出付费框如下



一般方法找关键字“知米豆才”千万别全输入,数量是代码确定的



搜索后找到了窗口的布局文件,在public.xml中搜索文件名”view_pay_dialog“获取id”0x7f03014b”




再在smail中搜索id,看看是什么方法调用了这个布局。


很明显下面, 上面的是个定义。进入f.smali分析代码

这里比较简单方法b()的作用就是对这个对话框进行进行处理,都在进行处理了证明已经判断了功能未购买,关键跳已经过了往上看谁调用了b()方法。

这是个构造方法可见该软件用了一个类来处理框(毕竟还有充值功能在里面)。这里就可以看做这个类就代表着充值框,全局搜索”Lcn/edu/zjicm/wordsnet_d/ui/a/f“看看谁用了这个类,发现这个类被很多方法使用。好像思路断掉了其实没有,我们是在词库列表下产生的充值框。词库列表下肯定有个onclick调用了这个类。接下来定位词库列表,关键字 “中考词库” ??? 如果这样你就输了。你会发现中文Unicode 搜不到。其实原因很简单词库会随着官方更新很大可能不存储在软件里毕竟软件才30m。这里我一般是搜索标题 “选择词汇书||\u9009\u62e9\u8bcd\u6c47\u4e66”定位到SelectBookActivity.smali接着搜索”Lcn/edu/zjicm/wordsnet_d/ui/a/f“来到最关键的a(Ljava/lang/Integer;)V方法代码如下

.method private a(Ljava/lang/Integer;)V
    .locals 2

    .prologue
    .line 333
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/SelectBookActivity;->f:Lcn/edu/zjicm/wordsnet_d/db/h;

    invoke-virtual {p1}, Ljava/lang/Integer;->intValue()I

    move-result v1

    invoke-virtual {v0, v1}, Lcn/edu/zjicm/wordsnet_d/db/h;->E(I)I

move-result v0

if-lez v0, :cond_1 

    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/SelectBookActivity;->f:Lcn/edu/zjicm/wordsnet_d/db/h;

    invoke-virtual {p1}, Ljava/lang/Integer;->intValue()I

    move-result v1

    invoke-virtual {v0, v1}, Lcn/edu/zjicm/wordsnet_d/db/h;->F(I)Z //判断购买的方法返回0未购买

    move-result v0

if-nez v0, :cond_1                //这里可以跳过cond_0到cond_1成功破解
            //不推荐直接跳转,F(I)Z是判断购买的方法可能有其他地方也调用,应该进入函数修改返回值。
    .line 334
    invoke-static {}, Lcn/edu/zjicm/wordsnet_d/l/k;->a()Lcn/edu/zjicm/wordsnet_d/l/k;

    move-result-object v0

    invoke-virtual {v0}, Lcn/edu/zjicm/wordsnet_d/l/k;->b()Z

    move-result v0

    if-nez v0, :cond_0 //这里跳转cond_0,注释掉后发现点击提示用户未登录不是这里,往上再找跳

    .line 335
    invoke-direct {p0}, Lcn/edu/zjicm/wordsnet_d/ui/activity/SelectBookActivity;->D()V

    .line 342
    :goto_0
    return-void

    .line 337
    :cond_0
    new-instance v0, Lcn/edu/zjicm/wordsnet_d/ui/a/f; //这里创建了充值类,由于cond_0上是个return-void所以只能通过跳转的方式到达。

    invoke-virtual {p1}, Ljava/lang/Integer;->intValue()I

    move-result v1

    invoke-direct {v0, p0, v1, p0}, Lcn/edu/zjicm/wordsnet_d/ui/a/f;-><init>(Lcn/edu/zjicm/wordsnet_d/ui/view/b;ILcn/edu/zjicm/wordsnet_d/b/b;)V

    iput-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/SelectBookActivity;->g:Lcn/edu/zjicm/wordsnet_d/ui/a/f;

    goto :goto_0 //跳向返回

    .line 340
    :cond_1
    invoke-direct {p0, p1}, Lcn/edu/zjicm/wordsnet_d/ui/activity/SelectBookActivity;->b(Ljava/lang/Integer;)V  
    goto :goto_0
.end method
修改F(I)Z
回编译成功破解








图片/词根
关键词”已到期/\u5df2\u5230\u671f”

”StudyExtandActivity.smali”就是我们需要的文件,2个已到期分别是词根和图片的进入第一个来到方法C()V smail代码如下略长。

.method private C()V
   




    :cond_2
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/StudyExtandActivity;->f:Lcn/edu/zjicm/wordsnet_d/c/b;

invoke-virtual {v0}, Lcn/edu/zjicm/wordsnet_d/c/b;->f()Lcn/edu/zjicm/wordsnet_d/c/a/a$b;     //这个方法提供本地信息,然后和下方信息对比,如果是到期信息
                                         //就和下方v1相等不跳转提示已到期所以进入该方法让他返回一个
                                         //虚假的vip信息

    move-result-object v0

    sget-object v1, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;->d:Lcn/edu/zjicm/wordsnet_d/c/a/a$b;    //提供v1(d:Lcn/edu/zjicm/wordsnet_d/c/a/a$b是到期依据,后面贴出代码)

if-ne v0, v1, :cond_3      //关键跳判断是否到期(改为跳转就能破解但不推荐)
             //应该修改提供v0,v1值的方法,很有可能其他地方也是调用这方法比如词根
              //所以接着往上找方法

    .line 335
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/StudyExtandActivity;->a:Lcn/edu/zjicm/wordsnet_d/e/a;

    iget-object v0, v0, Lcn/edu/zjicm/wordsnet_d/e/a;->y:Landroid/widget/TextView;

    const-string v1, "\u5df2\u5230\u671f" //已到期(这里就是搜索的地方)

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    goto :goto_0

    .line 337
    :cond_3
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/StudyExtandActivity;->f:Lcn/edu/zjicm/wordsnet_d/c/b;

    invoke-virtual {v0}, Lcn/edu/zjicm/wordsnet_d/c/b;->f()Lcn/edu/zjicm/wordsnet_d/c/a/a$b; //同上 提供本地信息

    move-result-object v0

    sget-object v1, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;->b:Lcn/edu/zjicm/wordsnet_d/c/a/a$b; //提供v1(b:Lcn/edu/zjicm/wordsnet_d/c/a/a$b是vip依据,后面贴出代码)


    if-ne v0, v1, :cond_6

    .line 338
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/StudyExtandActivity;->a:Lcn/edu/zjicm/wordsnet_d/e/a;

    iget-object v0, v0, Lcn/edu/zjicm/wordsnet_d/e/a;->y:Landroid/widget/TextView;

    const-string v1, "\u5df2\u5f00\u901a"   //已开通

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

    .line 339
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/StudyExtandActivity;->f:Lcn/edu/zjicm/wordsnet_d/c/b;

    invoke-virtual {v0}, Lcn/edu/zjicm/wordsnet_d/c/b;->i()I

    move-result v0

    sget v1, Lcn/edu/zjicm/wordsnet_d/c/a/a;->c:I //

    if-lt v0, v1, :cond_4   //这里跳转到续费 修改上方c:I原因同上防止多处调用

    .line 340
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/StudyExtandActivity;->a:Lcn/edu/zjicm/wordsnet_d/e/a;

    iget-object v0, v0, Lcn/edu/zjicm/wordsnet_d/e/a;->l:Landroid/widget/LinearLayout;

    invoke-virtual {v0, v4}, Landroid/widget/LinearLayout;->setVisibility(I)V

    .line 341
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/StudyExtandActivity;->a:Lcn/edu/zjicm/wordsnet_d/e/a;

    iget-object v0, v0, Lcn/edu/zjicm/wordsnet_d/e/a;->h:Landroid/widget/TextView;

    invoke-virtual {v0, v2}, Landroid/widget/TextView;->setVisibility(I)V

    .line 342
    iget-object v0, p0, Lcn/edu/zjicm/wordsnet_d/ui/activity/StudyExtandActivity;->a:Lcn/edu/zjicm/wordsnet_d/e/a;

    iget-object v0, v0, Lcn/edu/zjicm/wordsnet_d/e/a;->h:Landroid/widget/TextView;

    const-string v1, "\u5df2\u6c38\u4e45\u5f00\u901a"  //已永久开通

    invoke-virtual {v0, v1}, Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;)V

.line 343


~
~
~



.end method

需要修改的有2个地方1.”f()Lcn/edu/zjicm/wordsnet_d/c/a/a$b”让它返回vip信息 2.“Lcn/edu/zjicm/wordsnet_d/c/a/a;->c:I”修改c:l为0比较后总不跳转 看f()代码前先看看 “Lcn/edu/zjicm/wordsnet_d/c/a/a$b;->b:Lcn/edu/zjicm/wordsnet_d/c/a/a$b;” 是什么.打开文件Lcn/edu/zjicm/wordsnet_d/c/a/a$b搜索b:Lcn/edu/zjicm/wordsnet_d/c/a/a$b代码如下

.method static constructor <clinit>()V





    const-string v1, "VIP_NOT_OPEN"

    invoke-direct {v0, v1, v3, v3}, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;-><init>(Ljava/lang/String;II)V

    sput-object v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;->a:Lcn/edu/zjicm/wordsnet_d/c/a/a$b; //a代表未开通

    .line 50
    new-instance v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;

    const-string v1, "VIP_OPEN"

    invoke-direct {v0, v1, v4, v4}, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;-><init>(Ljava/lang/String;II)V

    sput-object v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;->b:Lcn/edu/zjicm/wordsnet_d/c/a/a$b;   //b代表开通

    .line 51
    new-instance v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;

    const-string v1, "VIP_TRIAL"

    invoke-direct {v0, v1, v5, v5}, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;-><init>(Ljava/lang/String;II)V

    sput-object v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;->c:Lcn/edu/zjicm/wordsnet_d/c/a/a$b;   //c代表试用

    .line 52
    new-instance v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;

    const-string v1, "VIP_TIMEOUT"

    invoke-direct {v0, v1, v6, v6}, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;-><init>(Ljava/lang/String;II)V

    sput-object v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;->d:Lcn/edu/zjicm/wordsnet_d/c/a/a$b;   //d代表过期

    .line 53
    new-instance v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;

    const-string v1, "VIP_UNKNOWN"

    const/4 v2, -0x1

    invoke-direct {v0, v1, v7, v2}, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;-><init>(Ljava/lang/String;II)V

    sput-object v0, Lcn/edu/zjicm/wordsnet_d/c/a/a$b;->e:Lcn/edu/zjicm/wordsnet_d/c/a/a$b;  //e代表状态未知




.end method
到这里就明白之前对比的依据是什么了”f()”返回的是本地信息,我们要做的就是修改返回为b(开通)就行了进入f()添加如下代码

进入“Lcn/edu/zjicm/wordsnet_d/c/a/a修改c:I” 为0

然后转入第二个”已到期/\u5df2\u5230\u671f” 分析方法同上发现由”invoke-virtual {v0}, Lcn/edu/zjicm/wordsnet_d/c/a;->f()Lcn/edu/zjicm/wordsnet_d/c/a/a$b;”提供信息进入”Lcn/edu/zjicm/wordsnet_d/c/a”修改f()

到此回编译签名破解完毕。     



wwxt0224 发表于 2017-9-15 11:23

@Hmily

Hmily 发表于 2017-9-15 15:58

账号:欲断魂
邮箱:1183618058@qq.com

申请通过,欢迎光临吾爱破解论坛,期待吾爱破解有你更加精彩,ID和密码自己通过邮件密码找回功能修改,请即时登陆并修改密码!
登陆后请在一周内在此帖报道,否则将删除ID信息。

ps:登录报道后把文章整理一下发到移动安全区。

欲断魂 发表于 2017-9-15 17:13

报道! 处理得真快!

温柔的笑 发表于 2017-9-15 18:02

这好详细

我口袋有糖 发表于 2017-9-15 23:50

欢迎欢迎。
页: [1]
查看完整版本: 申 请 I D:欲断魂【申请通过】