逆向某视频app(一)

本文为纯技术分享,文章内容不涉黄,适合对xposed有兴趣的读者

前言

有一段时间没写博客了,6月份的时候入职了一家做逆向的公司,很长一段时间都处在高度紧张的工作状态,连着两个月经常加班到10点,虽然有点辛苦,但是学到的东西更多,现在有一段时间要闲下来,趁着这个机会把学到的东西实践一下,破解一个视频app犒劳一下广大的程序员们。这次破解我会选择两种方式:使用xposed和修改smali,使用xposed方便快捷,但是需要root手机和安装xposed框架,而修改smali比较麻烦,但是可以随意安装在任何手机上,并且不收手机环境限制。这篇文章先介绍使用xposed。
需要apk文件的可以给我留言。

xposed破解

xposed是一个hook框架,可以在不改变app的情况下加入我们自己的逻辑(在方法前和方法后加入自己的逻辑,类似于代理模式),具体使用方法我就不一一介绍了,网上一大堆,下面正式开始。

1.反编译apk

使用jadx打开apk文件,发现源码如下:在这里插入图片描述
熟悉逆向的朋友们肯定猜到了,这个apk使用了360加固,所以反编译出来只有360加固的几个类,看不到目标源码。

那怎么办?

既然加固了,第一步就是要给它脱壳
关于脱壳可以参考这篇文章:Android APK脱壳–腾讯乐固、360加固一键脱壳

脱壳后拿到的dex文件如下:
在这里插入图片描述
总共有4个dex文件,我们可以在jadx中打开这些文件,dex会自动被转换成java代码,我们打开其中一个,如下:
在这里插入图片描述
可以看到代码已经混淆了,不仅加固还混淆了代码,有必要吗?

2.分析代码

想要破解一个app,首先要掌握工具的使用,但是这并不是最重要的,最重要的是要有逆向的思想,下面我们来分析如何破解这个app。

这个app在播放视频的时候会检查你是否是会员,如果不是会员在播放一分钟之后会弹出下面的提示并停止播放:
在这里插入图片描述
我们想要继续播放就要找到他的判断逻辑并跳过他,代码已经有了,但是我们不知道这个页面是哪个Activity,这时我们可以借助一个工具查看当前页面是哪个Activity,android-TopActivity,在手机上运行并打开这个app右上角就会显示当前页面所在的路径:
在这里插入图片描述
找到了位置,我们去看一下这个Activity,注意我们有5个dex文件,这个文件可能在其中的任何一个里面,耐心找一下并不难。在这里插入图片描述
打开这个文件之后发现里面只有七十多行代码,都围绕着开头声明的**“qa”**对象,我们到这个对象中看一下:
在这里插入图片描述
刚打开这个文件就发现了两个,不知道有没有人用过GSYVideoPlayer这个播放框架,在github上star还挺高的,这里就确定这里就是播放的实现类。
简单看了一下这个类的成员变量,发现有几个有用的变量

    private VideoDetail K;
    private UserInfoBean L;
    AdVideoPlayer Y;
    VideoPlayer f566g;

从字面意思理解VideoDetail是存放视频信息的类,UserInfoBean是存放用户信息的类,AdVideoPlayer是广告播放类,VideoPlayer是真正的视频播放类,到他们各自的代码中看发现确实如猜想一样,对我们最重要的类是VideoPlayer,我们就看看哪里调用了VideoPlayer,在qa中搜索关键在**“f566g”**,在这里插入图片描述
注意这里有一个log:

Log.i(“jinmu”, “ad播放完结的监听”);

广告播放完之后是不是就要开始播放视频了呢?继续看代码发现有一个setVideoVipFlagState方法值得注意,暂且放着继续往下看,第380行设置了视频的cover(封面),第390行筛选一个清晰度并设置该清晰度下的播放url,第395行设置准备完成后就开始播放,最后第401行还设置了水印。
这其中最可疑的就是setVideoVipFlagState方法,这个方法的参数是视频信息的VipFlag,他是不是标识该视频是否是vip视频(因为app里有免费视频) 我们到VideoPlayer中看一下这个方法:

 public void setVideoVipFlagState(int i2) {
        xb = i2;
    }

这是一个set方法,这里将字段的值给了xb,我们在VideoPlayer中搜一下xb
在这里插入图片描述
只有5个地方使用到了它,其中四个地方是赋值,一个地方是使用,上图510行就是使用的地方,这里如果xb等于1并且其他几个地方都为true就会去执行 getCurrentPlayer().b()这段代码,我们看一下这段代码做了什么:

 public void b() {
        if (this.f1172j == 1) {
            this.A = true;
        }
        try {
            if (getGSYVideoManager() != null && getGSYVideoManager().isPlaying()) {
                setStateAndUi(5);
                this.q = getGSYVideoManager().getCurrentPosition();
                if (getGSYVideoManager() != null) {
                    getGSYVideoManager().pause();
                }
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }

这里只是暂停播放视频的操作,现在我们猜想Sa()是检查是否是会员的方法,如果不是就会暂停播放,我们来验证一下我们的猜想。既然getCurrentPlayer().b()是暂停播放的语句,那么我们不执行它不就行了,也就是不进Sa()的if语句里面,我们通过xposed hook setVideoVipFlagState方法,让xb的值始终为0,这样就永远也不会走到if语句里面:

    @Override
    public void handleLoadPackage(XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
        String packageName = loadPackageParam.packageName;
        String processName = loadPackageParam.processName;
        Log.e("processName", "process:" + processName);
        Log.e("packageName", "package:" + packageName);
        if (packageName.equals(HUANGGUA_PACKAGE_NAME)) {
            XposedHelpers.findAndHookMethod("com.one.venus.video.VideoPlayer", loadPackageParam.classLoader
                    , "setVideoVipFlagState",
                    int.class,
                    new XC_MethodHook() {
                        @Override
                        protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                            Log.e(TAG, "beforeHookedMethod:setVideoVipFlagState " + param.args[0]);
                            param.args[0] = 0;
                        }
                    });
        }
    }

然后其实会发现一个问题,class not found,找了很久,最后才反应过来,因为apk经过加固,必须要用壳的ClassLoader来加载类,因为真正的代码是360加固程序启动后它去加载真正的dex文件的。
在这里插入图片描述
这里我们可以hook StubApp 的 attachBaseContext 方法:

    public static void hook(XC_LoadPackage.LoadPackageParam loadPackageParam) {
        if (classLoader == null) {
            try {
                //腾讯加固,需要获取对应classloader
                XposedHelpers.findAndHookMethod(XposedHelpers.findClass("com.stub.StubApp", 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
                                classLoader = context.getClassLoader();
                                Log.e(TAG, "afterHookedMethod:classloader " + classLoader);
                                XposedHelpers.findAndHookMethod("com.one.venus.video.VideoPlayer", classLoader
                                        , "setVideoVipFlagState",
                                        int.class,
                                        new XC_MethodHook() {
                                            @Override
                                            protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
                                                Log.e(TAG, "beforeHookedMethod:setVideoVipFlagState " + param.args[0]);
                                                param.args[0] = 0;
                                            }
                                        });
                            }
                        });
            } catch (Exception e) {
                Log.e(TAG, "hookClassLoader: " + e.getMessage());
            }
        }
    }

当我们再次观看视频的时候发现,卧槽可以。

观看一段时间后发现不能切换清晰度,切换时会提醒“你不是vip会员”,这怎么行,我都是要看超清的,最后找到在UserInfoBean中有一个isExpired参数,简单来说这个参数决定了你是不是会员,在播放视频和切换清晰度的时候都能生效,改这一个就行了。

        XposedHelpers.findAndHookMethod("com.one.venus.entity.UserInfoBean", classLoader
                , "getIsExpired",
                new XC_MethodReplacement() {
                    @Override
                    protected Object replaceHookedMethod(MethodHookParam param) throws Throwable {
                        return 1;
                    }
                });

我们hook UserInfoBean中的getIsExpired方法,让他始终返回1,试了一下,卧槽可以,现在可以看1080p了。

至于怎么找到isExpired这个参数的有兴趣的可以自己找找。

到这里就已经完成使用xposed破解这个app了。

有兴趣的可以看我的下一篇文章:逆向某视频app(二)

发布了65 篇原创文章 · 获赞 24 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/shanshui911587154/article/details/102517047
今日推荐