吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 17129|回复: 55
收起左侧

[Android 脱壳] 利用xposed逆向某4k视频软件付费服务(二)

  [复制链接]
nbwzlyd 发表于 2019-9-26 18:11
本帖最后由 nbwzlyd 于 2019-9-26 19:00 编辑

上一篇利用xposed逆向某4k视频付费服务"")主要讲了一些破解的准备工作,这一篇将会进入重点,分为两个部分,一个是xposed的开发准备,一个是结合代码进行hook

<!--more---->

Xposed的开发

我们可以再这里下载到最新的xposed.jar 文件,网上有教程是下载jar包放到工程的lib文件夹下,我们不这么做,用gradle方式进行引用

开发环境

Mac

Android Studio 3.4.2

夜神模拟器Mac版 安卓版本4.4

xposed框架2.7版本(只有这个版本支持安卓4.4)

引入jar包

在app目录下的build.gradle 的dependencies中添加如下代码

compileOnly 'de.robv.android.xposed:api:82'

需要注意的是,由于2.7版本的xposed框架自带了xposed.jar,所以我们这里只需要compileOnly即可,否则会报错,官方文档是

compile 'de.robv.android.xposed:api:82'

这个要根据自己实际情况来酌情处理,关于 compileOnly 和compile 区别,可以查看

gradle 新的依赖方式 implementation、api、compileOnly

成为xposed模块

在mainfest文件的application标签下添加如下代码

<application
        android:name=".base.BaseApplication"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name">
        <meta-data
            android:name="xposedmodule"
            android:value="true"/>
        <meta-data
            android:name="xposeddescription"
            android:value="模块描述文字"/>//会在模块里显示你的xposed具体描述
        <meta-data
            android:name="xposedminversion"
            android:value="53"/>//由于2.7版本的xposed不支持82版本所以这里写53,支持的最低版本是53
</application>

这样,再gradle sync一下,我们的准备工作就完毕了。

进入其他应用的进程

在这里,将会进入我们的实际开发工作。上篇我们了解到,我们第一步需要hook掉用户的登录操作。

创建一个类FourK_Xposed,继承IXposedHookLoadPackage类,覆写handleLoadPackage方法,xposed的该方法在任何应用启动时都会被调用,故可以进入任何应用程序的进程,但是一般只针对某个特定的应用,例如,当前应用

public class FourK_Xposed implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        XposedBridge.log("FourK_Xposed 模块生效");//进入这段代码说明我们的xposed模块生效了
        //先判断是不是我们想要hook的应用,以包名判断,不是的话直接return
        if (!TextUtils.equals(lpparam.packageName,"com.evo.watchbar.tv")){
            return;
        }
        //hook 登录
 XposedHelpers.findAndHookMethod(lpparam.classLoader.loadClass("com.evo.watchbar.tv.ui.activity.VRMovieDetailActivity"), "checkLogin", new XC_MethodHook() {
            @Override
            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                param.setResult(true);
            }
        });

在handleLoadPackage方法中,调用findAndHookMethod方法,并重写afterHookedMethod方法,由于检查登录的逻辑很简单,就在VRMovieDetailActivity中,所以我们只需要传入要hook的类以及方法名即可。

看一眼源码,

private boolean checkLogin()
  {
    boolean bool = true;
    if (MyStorage.user == null)
    {
      errorAlert("请先登录", true);
      new Handler().postDelayed(new Runnable()
      {
        public void run()
        {
          Intent localIntent = new Intent(VRMovieDetailActivity.this, PersonCenterActivity.class);
          localIntent.putExtra("forResult", true);
          localIntent.putExtra("type", 1);
          VRMovieDetailActivity.this.startActivityForResult(localIntent, 100);
        }
      }, 500L);
    }
    for (;;)
    {
      return bool;
      bool = false;
    }
  }

源码的逻辑看起来会很奇怪,不如直接smali看起来容易理解 因为有一段这样的代码

for (;;)
    {
      return bool;
      bool = false;
    }

这个不用管,通过smali代码可以猜到,如果是vip,那么这个返回值一定是false,(很奇怪是吧,逻辑就是这样的)

所以复写

 protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                super.afterHookedMethod(param);
                param.setResult(false);
                }

param.setResult(false);即可

通常情况下这样就可以了,打包模块,将模块推送到手机安装,这时候xposed模块会提示你重启,选择软重启即可。

然后进入日志选项,看看我们的应用生效没

可以看到xposed模块已经生效,但是hook生效了吗?进入应用验证,发现还是要登录,截图就不发了,

打开xposed日志我们发现这样的报错
image-20190906155210116.png

没有找到com.evo.watchbar.tv.ui.activity.VRMovieDetailActivity这个类,事实上这个类是真实存在的,不是找不到,而是被腾讯加固给“隐藏”了

解决腾讯加固导致的classNotFound问题

通常情况下,如果代码没有进行加固,我们只需要按照上面的步骤解决即可,但是这个应用腾讯加固了,直接这么走就行不通了,原因在于apk经过加固,必须要用壳的ClassLoader来加载类,因为真正的代码是腾讯加固程序启动后它去加载真正的dex文件的。

所以第一步我们要hook TxAppEntry 的 attachBaseContext 方法

public static void hookClassLoader(final XC_LoadPackage.LoadPackageParam loadPackageParam){
        if (classLoader == null){

            try {
                //腾讯加固,需要获取对应classloader
                XposedHelpers.findAndHookMethod("com.tencent.StubShell.TxAppEntry", loadPackageParam.classLoader,
                        "attachBaseContext", Context.class, new XC_MethodHook() {
                            @Override
                            protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                                super.afterHookedMethod(param);
                                //获取到Context对象,通过这个对象来获取classloader
                                Context context = (Context) param.args[0];
                                //获取classloader,之后hook加固后的就使用这个classloader
                                 context.getClassLoader();//这个classLoader才是真正需要的classLoader
                            }

                        });
            }catch (Exception e){
            }
        }

    }

并修改代码如下

public class FourK_Xposed implements IXposedHookLoadPackage {
    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable {

        XposedBridge.log("FourK_Xposed 模块生效");
        //先判断是不是我们想要hook的应用,以包名判断
        if (!TextUtils.equals(lpparam.packageName,"com.evo.watchbar.tv")){
            return;
        }
        //腾讯加固,需要获取对应classloader
        XposedHelpers.findAndHookMethod("com.tencent.StubShell.TxAppEntry", lpparam.classLoader,
                "attachBaseContext", Context.class, new XC_MethodHook() {
                    @Override
                    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                        super.afterHookedMethod(param);
                        //获取到Context对象,通过这个对象来获取classloader
                        Context context = (Context) param.args[0];
                        //获取classloader,之后hook加固后的就使用这个classloader
                        context.getClassLoader();
                        hookLogin(context.getClassLoader());
                    }
                });
    }

    private static void hookLogin(ClassLoader classLoader){
        //hook 登录
        try {
            XposedHelpers.findAndHookMethod(classLoader.loadClass("com.evo.watchbar.tv.ui.activity.VRMovieDetailActivity"), "checkLogin", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    param.setResult(true);
                    XposedBridge.log("hook成功");
                }
            });
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }
}

打包验证

图就不上传了,太大了,超过1M限制

可以看到会员免费看一闪而过,至于为什么后面又出现让你登录的界面,是因为在播放界面他又验证有没有登录了,破解方法一致,这里就不再演示了,如果你想一劳永逸,可以从

MyStorage.user == null

这段代码入手,

hook方式就是常用的反射,代码如下:

 cls = classLoader.loadClass("com.evo.watchbar.tv.storage.MyStorage");
            Field field = cls.getField("user");
            Class User = classLoader.loadClass("com.evo.m_base.bean.User");
            field.set(cls.newInstance(),User.newInstance());

只要保证user!=null 即可

这样,就不会再提示登录了。

破解VIP

有了上文的铺垫,Vip的破解也就很容易了,在源码中我们多次看到这个方法

 UserUtils.checkVIP()

所以从这段代码入手就行了,代码如下

    private void hookVip(ClassLoader classLoader)  {
        try {
            XposedHelpers.findAndHookMethod(classLoader.loadClass("com.evo.watchbar.tv.utils.UserUtils"), "checkVIP", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    param.setResult(true);
                }
            });
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

编写完毕后你就会神奇的发现,付费按钮消失了,只有一个播放按钮,点击播放按钮看一下效果

WX20190926-185401@2x.png

WTF,竟然显示会员才能享受服务,难道有服务端验证??

如果真的有服务端验证,那我们真的将前功尽弃。所以,我们现在必须得抓包看看

抓包破解vip

抓包的方法这里就不多说了,fiddler或者Charles都可以,我这里用的Charles

在抓包界面中我们看到
image-20190906173404106.png

有一个sourceUrl字段,这个字段以.mp4结尾,很大概率是视频链接,把这个链接放到浏览器访问一下,发现居然播放了,所以,只要有了播放链接,那我们本地破解100%没问题,但是为什么还是提示   会员才能享受服务呢?

搜一下这段文案

在VRPlayerActivity和TwoDPlayerActivity中搜到了这段文案
image-20190906173849407.png

binggo!!!,查看一下它的判断逻辑是 localData.getRetCode!=0 所以呢?我们的破解逻辑就有了

就是将getRectCode返回0不就行了

这段代码就不写啦,相信聪明的你已经领悟了,我就不放出来了,以防和谐,我还要偷偷摸摸用呢

最后,放一下实际效果吧
WX20190926-185443@2x.png

低调。。。。

免费评分

参与人数 22吾爱币 +34 热心值 +22 收起 理由
huairuirui + 1 + 1 谢谢@Thanks!
不坑人的中学生 + 1 + 1 谢谢@Thanks!
study_hot + 1 + 1 谢谢@Thanks!
夏雨微凉 + 2 + 1 热心回复!
孤独患者” + 1 + 1 谢谢@Thanks!
yushen + 1 我很赞同!低调~
zxc逆天 + 1 + 1 热心回复!
多幸运遇见baby + 1 + 1 用心讨论,共获提升!
404_undefined + 1 + 1 我很赞同!
小鬼cece + 1 + 1 我很赞同!
cyj158 + 1 热心回复!
SomnusXZY + 1 + 1 热心回复!
默生a + 1 热心回复!
木羊羽 + 3 + 1 我很赞同!
陈世界 + 1 + 1 我很赞同!
失焦镜像 + 1 + 1 我很赞同!
kakudesu + 1 + 1 我很赞同!
独行风云 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
CrazyNut + 3 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
nrmyh732 + 1 + 1 热心回复!
qtfreet00 + 12 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
言川心 + 1 谢谢@Thanks!

查看全部评分

本帖被以下淘专辑推荐:

  • · 好帖|主题: 549, 订阅: 87

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

aihacker 发表于 2019-10-11 10:07
本帖最后由 aihacker 于 2019-10-11 10:18 编辑

[Java] 纯文本查看 复制代码
//如果有用希望看官给点积分
public class Hook_WatchBarTV implements IXposedHookLoadPackage {
    private static String CLASS_TAG = "Hook_WatchBarTV";
    private String AppPkgName = "com.evo.watchbar.tv";

    private static String ApplicationClz = "com.tencent.StubShell.TxAppEntry";
    private String VRMovieDetailActivityclz = "com.evo.watchbar.tv.ui.activity.VRMovieDetailActivity";

    @Override
    public void handleLoadPackage(final LoadPackageParam loadPackageParam) throws Throwable {
        final String METHOD_TAG = CLASS_TAG + "--> handleLoadPackage()";
        //先判断是不是我们想要hook的应用,以包名判断
        if (loadPackageParam.processName.equals(AppPkgName)) {
            Log.e(METHOD_TAG, "start hook");
            XposedBridge.log("FourK_Xposed 模块生效");//进入这段代码说明我们的xposed模块生效了
            XposedHelpers.findAndHookMethod(loadPackageParam.classLoader.loadClass(ApplicationClz), "attachBaseContext", Context.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    //获取到Context对象,通过这个对象来获取classloader,这个classLoader才是真正需要的classLoader
                    Context context = (Context) param.args[0];
                    ClassLoader classLoader = context.getClassLoader();
                    hookLogin(classLoader);
                    hookVip(classLoader);
                    printMp4Url(classLoader);
                    hookGetRetCode(classLoader);
                    hookgetUrl(classLoader);
                }
            });

            Log.e(METHOD_TAG, "end hook ");
            XposedBridge.log("XposedLog将写信息到标准的logcat中(/data/data/de.robv.android.xposed.installer/log/debug.log)");
        }

    }

    private void hookLogin(ClassLoader classLoader){
        try {
            XposedHelpers.findAndHookMethod(classLoader.loadClass(VRMovieDetailActivityclz), "checkLogin", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    param.setResult(false);
                    XposedBridge.log("HookLogin 成功!!!");
                    Log.e(CLASS_TAG, "HookLogin 成功!!!");
                }
            });
            Class MyStorageClz = classLoader.loadClass("com.evo.watchbar.tv.storage.MyStorage");
            Field userField = MyStorageClz.getField("user");
            Class User = classLoader.loadClass("com.evo.m_base.bean.User");
            userField.set(MyStorageClz.newInstance(),User.newInstance());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

    private void hookVip(ClassLoader classLoader){
        try {
            XposedHelpers.findAndHookMethod(classLoader.loadClass("com.evo.watchbar.tv.utils.UserUtils"), "checkVIP", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    param.setResult(true);
                    XposedBridge.log("HookVip 成功!!!");
                    Log.e(CLASS_TAG, "HookVip 成功!!!");
                }
            });
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    private void printMp4Url(ClassLoader classLoader){
        try {
            XposedHelpers.findAndHookMethod(classLoader.loadClass("com.evo.tvplayer.bean.Definition"), "setUrl", String.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    String vidioUrl = (String) param.args[0];
                    XposedBridge.log("请求的视频路径为:" + vidioUrl);
                    Log.e(CLASS_TAG, "请求的视频路径为:" + vidioUrl);
                }
            });
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    private void hookgetUrl(ClassLoader classLoader){
        try {
            XposedHelpers.findAndHookMethod(classLoader.loadClass("com.evo.tvplayer.bean.Definition"), "getUrl", String.class, new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    String vidioUrl = "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4";
                    param.setResult(vidioUrl);
                    XposedBridge.log("视频路径设置为:" + vidioUrl);
                    Log.e(CLASS_TAG, "视频路径设置为:" + vidioUrl);
                }
            });
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    private void hookGetRetCode(ClassLoader classLoader){
        try {
            XposedHelpers.findAndHookMethod(classLoader.loadClass("com.evo.watchbar.tv.bean.RealUrlBean"), "getRetCode", new XC_MethodHook() {
                @Override
                protected void afterHookedMethod(MethodHookParam param) throws Throwable {
                    super.afterHookedMethod(param);
                    param.setResult(0);
                    XposedBridge.log("hookGetRetCode=0 成功!!!");
                    Log.e(CLASS_TAG, "hookGetRetCode=0 成功!!!");
                }
            });
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

}
febsky 发表于 2019-9-30 14:47
夏雨微凉 发表于 2019-9-28 08:34
老哥是安卓开发对吗?我能不能请教一个问题?  

某掌上营业厅为什么用DDMS和开发者工具都不能分析它的UI ...

至于为什么,没有详细研究,应该是属于360 加固的方案,做了adb 检测,检测到 dmup  或者  uiautomator 的时候返回来假数据,也有可能是hook了某个系统函数返回了假数据,不过可以通过其他的界面分析统计来分析,比如网易的airtest,可以做到分析出view 树的结构

免费评分

参与人数 1吾爱币 +2 热心值 +1 收起 理由
夏雨微凉 + 2 + 1 用心讨论,共获提升!感谢老哥 我去学一下

查看全部评分

wu8511128 发表于 2019-9-26 18:20
一叶知夏 发表于 2019-9-26 18:42
可以尝试一下
woawapj 发表于 2019-9-26 18:56
这个操作厉害了
wakichie 发表于 2019-9-26 19:50
大佬牛逼啊
nrmyh732 发表于 2019-9-26 20:10
这都可以,行哈,膜拜大佬
hzxsdwg 发表于 2019-9-26 21:03
虽然我不会操作,但是还是要为你点个赞
 楼主| nbwzlyd 发表于 2019-9-26 21:22
hzxsdwg 发表于 2019-9-26 21:03
虽然我不会操作,但是还是要为你点个赞

为你点赞
隐与匿 发表于 2019-9-26 21:34
谢谢大神分享.
风绕柳絮轻敲雪 发表于 2019-9-26 21:41
思路不错 搞得我也想发教程了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

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

GMT+8, 2024-11-24 15:35

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

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