吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 10166|回复: 34
收起左侧

[Android 原创] [xposed]掌中英语_6.4.0 VIP破解By_kwaiching

[复制链接]
穿透骨頭撫摸妳 发表于 2019-7-29 12:37
0x0. 非會員只可以打開試聽章節

002.png


003.png


0x1. ApkKiller反編譯, 發現軟件經過360加固

        000.png

0x2. 脫殼, 根據界面信息, 搜尋VIP

        001.jpg

0x3. isVip 應該是關鍵

[Asm] 纯文本查看 复制代码
	isVipUser		// 是否為VIP用戶

	isVipVideo		// 是否為VIP視頻



0x4. 以下三個類有isVipUser 相關

[Java] 纯文本查看 复制代码
com.zzenglish.client.vo.VoCollectionBean{

    public int getIsVipUser() {
        return this.isVipUser;
    }


    public int getIsvip() {
        return this.isvip;
    }

}


[Java] 纯文本查看 复制代码
/* renamed from: com.zzenglish.client.vo.VoOpeningTalk */
public class VoOpeningTalk {
    private ArrayList<VoCollectionBean> datas;
    private int isVipUser;

    public int getIsVipUser() {
        return this.isVipUser;
    }

    public void setIsVipUser(int i) {
        this.isVipUser = i;
    }

    public ArrayList<VoCollectionBean> getDatas() {
        return this.datas;
    }

    public void setDatas(ArrayList<VoCollectionBean> arrayList) {
        this.datas = arrayList;
    }
}


[Java] 纯文本查看 复制代码
com.zzenglish.client.vo.VoVideoPractise{

    public int getIsVipVideo() {
        return this.isVipVideo;
    }

    public int getIsVipUser() {
        return this.isVipUser;
    }


}


0x5. Xposed hook 相關函數

[Python] 纯文本查看 复制代码
        val mVoCollectionBeanClass: Class<*>?
        val mVoOpeningTalkClass: Class<*>?
        val mVoVideoPractiseClass: Class<*>?
        val mDBZZUserClass: Class<*>?
        try {
            mVoCollectionBeanClass = dexClassLoader.loadClass("com.zzenglish.client.vo.VoCollectionBean")
            mVoOpeningTalkClass = dexClassLoader.loadClass("com.zzenglish.client.vo.VoOpeningTalk")
            mVoVideoPractiseClass = dexClassLoader.loadClass("com.zzenglish.client.vo.VoVideoPractise")
            mDBZZUserClass = dexClassLoader.loadClass("com.zzenglish.client.db.DBZZUser")
        } catch (e: Exception) {
            XposedBridge.log("錯誤$e")
            return
        }

        XposedHelpers.findAndHookMethod(mVoCollectionBeanClass, "getIsVipUser",object : XC_MethodHook() {
            @Throws(Throwable::class)
            override fun afterHookedMethod(param: MethodHookParam) {
                param.result = 1
            }
        })

        XposedHelpers.findAndHookMethod(mVoOpeningTalkClass, "getIsVipUser",object : XC_MethodHook() {
            @Throws(Throwable::class)
            override fun afterHookedMethod(param: MethodHookParam) {
                param.result = 1
            }
        })

        XposedHelpers.findAndHookMethod(mVoVideoPractiseClass, "getIsVipUser",object : XC_MethodHook() {
            @Throws(Throwable::class)
            override fun afterHookedMethod(param: MethodHookParam) {
                param.result = 1
            }
        })


發現沒什麼反應


0x6. 胡亂再觀察一波, 搜尋"未開通"

[Java] 纯文本查看 复制代码
    public static String getOpenProgramText(int i) {
        return i == -1 ? "审核不通过" : i == 1 ? "已开通" : i == 2 ? "审核中" : "未开通";
    }


此類中有用戶信息:

Lcom/zzenglish/client/activity/EditUserActivity

[Java] 纯文本查看 复制代码
    private void setUser() {
        this.vOUser2 = DBZZUser.getInstance().getUser(MDataBase.UUID);
        if (this.vOUser2 != null) {		// 用戶信息不為空
            if (StrUtil.isNotBlank(this.vOUser2.getMoblile())) {		// 手機綁定
                this.info_phone_text.setText(this.vOUser2.getMoblile());
            } else {
                this.info_phone_text.setText("请绑定");
            }
            initHead();
            TextView textView = (TextView) findViewById(C0422R.C0420id.info_vip_state_text);
            String str = "会员状态:";
            StringBuilder stringBuilder;
            if (DBZZUser.getInstance().isForeverMember(MDataBase.UUID)) {		// 1 永久會員
                stringBuilder = new StringBuilder();
                stringBuilder.append(str);
                stringBuilder.append("终身会员");
                str = stringBuilder.toString();
                ((ImageView) findViewById(C0422R.C0420id.info_head_img_vip)).setImageResource(C0422R.drawable.zz_personal_v);
                ((TextView) findViewById(C0422R.C0420id.info_vip_state_operator)).setText("续费");
            } else if (DBZZUser.getInstance().isMember(MDataBase.UUID)) {		// 會員
                try {
                    long memberEndTimeMillis = DBZZUser.getInstance().getMemberEndTimeMillis(MDataBase.UUID);
                    if (memberEndTimeMillis > 0) {
                        stringBuilder = new StringBuilder();
                        stringBuilder.append(str);
                        stringBuilder.append("  <font color=\"#f58927\">");
                        stringBuilder.append(new SimpleDateFormat(DateUtil.DEFAULT_FORMAT).format(Long.valueOf(memberEndTimeMillis)));
                        stringBuilder.append("到期</font>");
                        str = stringBuilder.toString();
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                this.zz_personal_vip.setImageResource(C0422R.drawable.zz_personal_v);
                ((TextView) findViewById(C0422R.C0420id.info_vip_state_operator)).setText("续费");
            } else {
                stringBuilder = new StringBuilder();
                stringBuilder.append(str);
                stringBuilder.append("未开通");
                str = stringBuilder.toString();
                ((ImageView) findViewById(C0422R.C0420id.info_head_img_vip)).setImageResource(C0422R.drawable.zz_personal_v_off);
                ((TextView) findViewById(C0422R.C0420id.info_vip_state_operator)).setText("开通");
            }
            textView.setText(Html.fromHtml(str));
            ((TextView) findViewById(C0422R.C0420id.info_nickname_text)).setText(URLDecoder.decode(this.vOUser2.getNick()));
            this.birth = (TextView) findViewById(C0422R.C0420id.info_birthday_text);
            this.birth.setText(this.vOUser2.getBirth());
            String sex = this.vOUser2.getSex();
            this.sexbt = (TextView) findViewById(C0422R.C0420id.info_gender_text);
            if (StrUtil.equals(sex, "F")) {
                this.sexbt.setText("女");
            } else if (StrUtil.equals(sex, "M")) {
                this.sexbt.setText("男");
            } else {
                this.sexbt.setText("未知");
            }
        }
        this.student.setVisibility(SpSet.get().isTeacher() ? 8 : 0);		// 是否為殭屍
        ZZImageLoader.getInstance(this).displayImage(this.background_image, getIntent().getStringExtra(VStatic.BACKGROUND), (int) C0422R.drawable.person_default);
    }


0x7. 追蹤方法DBZZUser

[Java] 纯文本查看 复制代码
com.zzenglish.client.db.DBZZUser{


    public boolean isForeverMember(int i) {
        boolean z = false;
        if (i <= 0) {
            return false;
        }
        long memberEndTimeMillis = getMemberEndTimeMillis(i);
        long memberDurationTimeMillis = getMemberDurationTimeMillis(i);
        boolean isLogin = isLogin(i);
        if (i > 0 && isLogin // 登陸
					&& (DBMyGood.get().isPurchaseByPid(String.valueOf(i), MDataBase.GID_MEMBER) 
					|| DBMyGood.get().isPurchaseByPid(String.valueOf(i), MDataBase.GID_SETMEAL) 
					|| (memberDurationTimeMillis > 0 && 0 == memberEndTimeMillis))) {
            z = true;
        }
        return z;
    }

    public boolean isMember(int i) {
        boolean z = false;
        if (i <= 0) {
            return false;
        }
        if (isForeverMember(i) || isCommonMember(i)) {
            z = true;
        }
        return z;
    }


    public boolean isCommonMember(int i) {
        return i > 0 && isLogin(i) && checkMemberTimeMillis(i);
    }
	
    public boolean hasBuyHelper(int i) {
        boolean z = false;
        if (i <= 0) {
            return false;
        }
        if (isMember(i) || DBMyGood.get().isPurchaseByPid(String.valueOf(i), MDataBase.GID_HELPER)) {
            z = true;
        }
        return z;
    }


}


0x8. 永久會員isForeverMember調用DBMyGood

[Java] 纯文本查看 复制代码
/* renamed from: com.zzenglish.client.db.DBMyGood */
public class DBMyGood {
	
    public boolean isPurchaseByPid(String str, String str2) {
        Exception e;
        Throwable th;
        boolean z = false;
        if (StrUtil.isBlank(str2)) {
            return false;
        }
        Cursor cursor = null;
        try {
            MySQLiteHelper instance = MySQLiteHelper.getInstance();
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append("select col_purchase from ");
            stringBuilder.append(TB_NAME);
            stringBuilder.append(" where ");
            stringBuilder.append(COL_UID);
            stringBuilder.append("=? and ");
            stringBuilder.append(COL_PID);
            stringBuilder.append("=?");
            Cursor select = instance.select(stringBuilder.toString(), new String[]{str, str2});
            if (select != null) {
                try {
                    if (select.moveToFirst()) {
                        StringBuilder stringBuilder2 = new StringBuilder();
                        stringBuilder2.append(str);
                        stringBuilder2.append(1);
                        stringBuilder2.append(str2);
                        z = Util.MD5(stringBuilder2.toString()).equals(select.getString(0));
                    }
                } catch (Exception e2) {
                    e = e2;
                    cursor = select;
                    try {
                        e.printStackTrace();
                        if (cursor != null) {
                        }
                        return z;
                    } catch (Throwable th2) {
                        th = th2;
                        if (cursor != null) {
                        }
                        throw th;
                    }
                } catch (Throwable th3) {
                    th = th3;
                    cursor = select;
                    if (cursor != null) {
                        try {
                            cursor.close();
                        } catch (Exception unused) {
                        }
                    }
                    throw th;
                }
            }
            if (select != null) {
                try {
                    select.close();
                } catch (Exception unused2) {
                }
            }
        } catch (Exception e3) {
            e = e3;
            e.printStackTrace();
            if (cursor != null) {
                cursor.close();
            }
            return z;
        }
        return z;
    }

}



0x9. Xposed HOOK

[Python] 纯文本查看 复制代码
    val mVoCollectionBeanClass: Class<*>?
        val mVoOpeningTalkClass: Class<*>?
        val mVoVideoPractiseClass: Class<*>?
        val mDBZZUserClass: Class<*>?
        val mDBMyGoodClass: Class<*>?
        try {
            mVoCollectionBeanClass = dexClassLoader.loadClass("com.zzenglish.client.vo.VoCollectionBean")
            mVoOpeningTalkClass = dexClassLoader.loadClass("com.zzenglish.client.vo.VoOpeningTalk")
            mVoVideoPractiseClass = dexClassLoader.loadClass("com.zzenglish.client.vo.VoVideoPractise")
            mDBZZUserClass = dexClassLoader.loadClass("com.zzenglish.client.db.DBZZUser")
            mDBMyGoodClass = dexClassLoader.loadClass("com.zzenglish.client.db.DBMyGood")
        } catch (e: Exception) {
            XposedBridge.log("掌上英語錯誤$e")
            return
        }

        XposedHelpers.findAndHookMethod(mDBMyGoodClass, "isPurchaseByPid", String::class.java, String::class.java, object : XC_MethodHook() {
            @Throws(Throwable::class)
            override fun afterHookedMethod(param: MethodHookParam) {
                param.result = true
            }
        })

        // hasBuyHelper

        XposedHelpers.findAndHookMethod(mDBZZUserClass, "isForeverMember", Int::class.java, object : XC_MethodHook() {
            @Throws(Throwable::class)
            override fun afterHookedMethod(param: MethodHookParam) {
                param.result = true
            }
        })

        XposedHelpers.findAndHookMethod(mDBZZUserClass, "hasBuyHelper", Int::class.java, object : XC_MethodHook() {
            @Throws(Throwable::class)
            override fun afterHookedMethod(param: MethodHookParam) {
                param.result = true
            }
        })


0xA. 破解效果

Screenshot_20190729-123256.jpg

Screenshot_2019-07-29-11-35-34-93.png

0xB. 成品

掌中英語_1.0_20190729.7z (788.63 KB, 下载次数: 255)



免费评分

参与人数 9吾爱币 +7 热心值 +8 收起 理由
赫氏家族 + 1 + 1 要下载模块破解吗
flexb15 + 1 谢谢@Thanks!
ohmydog + 1 谢谢@Thanks!
Mr_54 + 1 + 1 谢谢@Thanks!
uebian + 1 + 1 用xposed爆破,思路很新
年年雪里 + 1 我很赞同!
wangzhenuen + 1 + 1 谢谢@Thanks!
shaunkelly + 1 + 1 谢谢@Thanks!
jiang196771 + 1 + 1 我想要别的模块,够直接吧

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

毒瘤 发表于 2019-7-29 15:59
打开一看“360”字样特别显眼 我很明显不会脱360,所以我还是先学习最新360,不过楼主这篇帖子非常不错,用XPOSED下刀,值得学习
棉花绒人 发表于 2019-7-29 13:12
这个压缩包解压后等到的文件名是
掌中英語_1.0_20190729.apk,暂时不打算安装到手机,先收藏了!感谢楼主分享!
SUwenjian1995 发表于 2019-7-29 12:57
idyllic639 发表于 2019-7-29 12:58
下载试试,感谢楼主分享
historyboy 发表于 2019-7-29 13:07
感谢楼主分享方法,学习了
qazxcvbnm 发表于 2019-7-29 13:30
下载试试看。
soleilyang 发表于 2019-7-29 13:36
这个需要root在xposed里面安装才是和谐版吗
 楼主| 穿透骨頭撫摸妳 发表于 2019-7-29 13:38
soleilyang 发表于 2019-7-29 13:36
这个需要root在xposed里面安装才是和谐版吗

對, 安裝原版再安裝這個
jiang196771 发表于 2019-7-29 13:38
可以分享一下别的模块吗&#128541;&#128541;&#128541;
SunerC 发表于 2019-7-29 14:00
想要红橙黄绿青蓝紫那个模块
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 21:40

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表