点击上方“何俊林”,马上关注,每天早上8:50准时推送

真爱,请置顶或星标

本文作者:蓝师傅_Android,转载自https://www.jianshu.com/p/51dcc24900ba

前言

在一个夜黑风高的晚上,我的基友突然给我发了一个叫“xx社区”的app,这是什么玩意?找了一张可以上墙的图

我凑,是个美女直播软件,迫不及待的我,一阵点点点,发现最亮点的功能是第二个tab页,是类似抖音的短视频,找了一张正经的图,抖音都没这么正经吧。。。

我去,做的效果跟抖音一毛一样,上下滑动切换视频,聊这个,那我可不困了,在滑动了差不多20个视频之后,出现了这个

卧槽,这能忍,作为一个Android开发攻城狮,充值是不可能充值的。太晚了,打算明天再破解它的收费功能。于是,第二天很早就起床打开电脑,这篇文章就开始了…

反编译

将apk发送到电脑,然后打开jadx-gui传送门,直接选择这个apk,打开
发现源码是这个样子的

熟悉逆向的朋友们肯定猜到了,这个apk使用了腾讯加固,所以反编译出来只有腾讯加固的几个类,看不到目标源码。那怎么办?
既然加固了,第一步就是要给它脱壳

脱壳(需要xposed支持)

FDex2

通过Hook ClassLoader的loadClass方法,反射调用getDex方法取得Dex(com.android.dex.Dex类对象),在将里面的dex写出。

下载安装,在xposedinstaller中勾选模块并重启,然后打开FDex2选择xx社区,然后重启xx社区,即可在对应目录找到dex文件的踪影

分析代码

上一步通过FDex2,成功脱壳

拿到三个dex,依次用jadx-gui打开,根据包名,可以找到对应Activity的位置

如何得到Activity名称,这个可以用无障碍,也可以直接过滤日志,比如,打开界面,然后日志过滤“start|activity” start u0

D: pid=30739, uid=10274, component=ComponentInfo{com.one.tomato/com.one.tomato.ui.StartUpActivity}
I: AppChangeImpl:pid: 30739 uid: 10274 pkg: com.one.tomato class: com.one.tomato.ui.StartUpActivity
D: activityResumed:pid=30739, uid=10274, component=ComponentInfo{com.one.tomato/com.one.tomato.ui.StartUpActivity}
D: checkIsMonitorVideoScence input :com.one.tomato,com.one.tomato.ui.StartUpActivity
D: handleActivityChange,  curPackage:com.one.tomato, curClass:com.one.tomato.ui.StartUpActivity
D: checkIsMonitorAPKScence input :com.one.tomato,com.one.tomato.ui.StartUpActivity
D: handleActivityChange, it is not a care app or scence
D: handleActivityChange,  curr mAppType:-1, lastType:-1

com.one.tomato.ui.StartUpActivity 就是主页了
主页一共有5个tab,每个tab应该对应一个fragment,我们要先找到第二个tab对应的fragment

看到点击事件,通过命名方式可以猜到这个是底部tab的点击事件,点一下应该会切换显示fragment

果然不出我所料,第二个tab是PapaTabFragment,搜索一下

打开看看

虽然代码被混淆了,但是可以猜到这里是初始化的方法,有头像和收藏图标的点击事件,当然,这个不是重点,哈哈,我们还是要先分析一下什么时候触发这个弹窗,弹窗的条件是播放次数到达到一个值,根据这个条件,快速浏览一下PapaTabFragment这个类,代码不多,只有1千行多一点

发现疑点,LookTimes是观看时间,VideoPlayCountUtils是播放次数。

VideoPlayCountUtils 是一个单例,所以看b和c方法

“video_play_count” 这么明显的字眼,播放次数,这个次数是从PreferencesUtil中获取的,也就是存在sp中,

PreferencesUtil 中的e方法,如果登录信息不为空,就返回信息中的id,空就返回0,所以第一次打开才会是0,可以观看,之后这个LoginInfo不为空了,开始统计观看次数了。
so,让它总是返回0?

上代码

Xposed模块开发基础就不说了,默认你已经会了,不会自己去查一下,Xposed基础不是本文的重点。
//播放数总返回0,无限制观看

    private static void hookVideoCount(XC_LoadPackage.LoadPackageParam param, ClassLoader loader){LogUtil.d(TAG,"hookVideoCount start");hook_method("com.one.tomato.utils.PreferencesUtil", loader, "e", new XC_MethodHook() {@Overrideprotected void beforeHookedMethod(MethodHookParam param) throws Throwable {LogUtil.d(TAG,"beforeHookedMethod hookVideoCount");}@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {LogUtil.d(TAG,"afterHookedMethod 视频次数返回 0 ");param.setResult(0);}});}protected static void hook_method(String className, ClassLoader classLoader, String methodName,Object... parameterTypesAndCallback) {try {XposedHelpers.findAndHookMethod(className, classLoader, methodName, parameterTypesAndCallback);} catch (Exception e) {XposedBridge.log(e);xLog(e.getMessage());}}

然后其实会发现一个问题,class not found,找了很久,最后才反应过来,因为apk经过加固,必须要用壳的ClassLoader来加载类,因为真正的代码是腾讯加固程序启动后它去加载真正的dex文件的。

这里我们可以hook TxAppEntry 的 attachBaseContext 方法

public static void hookClassLoader(final XC_LoadPackage.LoadPackageParam loadPackageParam){if (classLoader == null){try {//腾讯加固,需要获取对应classloaderXposedHelpers.findAndHookMethod("com.tencent.StubShell.TxAppEntry", loadPackageParam.classLoader,"attachBaseContext", Context.class, new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {super.afterHookedMethod(param);//获取到Context对象,通过这个对象来获取classloaderContext context = (Context) param.args[0];//获取classloader,之后hook加固后的就使用这个classloaderTomatoModule.classLoader = context.getClassLoader();LogUtil.d("成功hook classloader");hookAD(loadPackageParam, classLoader);openLog(loadPackageParam, classLoader);hookVideoCount(loadPackageParam, classLoader);}});}catch (Exception e){LogUtil.e(e.getMessage());}}}

然后安装试了一下,卧槽,真的无限制观看了,我是V8了?

确实成功了,效果图就不发了,大家可以动手试试。

另外,跳过首页广告和打开日志的hook点我也很快找到了

//自动跳过广告private static void hookAD(XC_LoadPackage.LoadPackageParam param, ClassLoader loader) {LogUtil.d(TAG,"hook StartUpActivity start");hook_method("com.one.tomato.ui.StartUpActivity", loader, "onCreate", Bundle.class, new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {LogUtil.d(TAG,"beforeHookedMethod onCreate");Object object = param.thisObject;LogUtil.d(object.toString());Class<?> aClass = object.getClass();Method[] methods = aClass.getDeclaredMethods();for (Method method : methods) {LogUtil.d(method.getName());if (method.getName().equals("z")){LogUtil.d("自动跳过广告页");method.setAccessible(true);method.invoke(object);}}Toast.makeText((Context) param.thisObject, "xposed并跳过广告,功能正常", Toast.LENGTH_SHORT).show();}});}//打开日志开关private static void openLog(XC_LoadPackage.LoadPackageParam param, ClassLoader loader){LogUtil.d(TAG,"hook LogUtil start");hook_method("com.one.tomato.utils.LogUtil", loader, "a", int.class,String.class,Object.class, new XC_MethodHook() {@Overrideprotected void beforeHookedMethod(MethodHookParam param) throws Throwable {Object object = param.thisObject;LogUtil.d(object.toString());Class<?> aClass = object.getClass();Method[] methods = aClass.getDeclaredMethods();for (Method method : methods) {LogUtil.d(method.getName());if (method.getName().equals("a")){LogUtil.d("openLog");method.setAccessible(true);method.invoke(object,true);return;}}}});}

不是很难找,这里就留给大家自己去实践学习了。

注意:不管xx社区后期是否停止服务(你懂的),本文只是技术分享,拒绝黄赌毒。

虽然破解了短视频模块播放次数限制之后,发现播放经常弹出“参数错误 ”的toast,这TM能忍,继续干。然后看到”我的“界面的次数没有被hook

说明没有hook彻底,如果应用中其它地方用了这里的 0/30 做判断,那么有可能还会被限制,请继续看:

首先,打开 MineTabFragment 这个类,这个上一章已经分析过了,”我的“ 那个tab对应 MineTabFragment,然后寻寻觅觅,起初没找到免费观看次数是哪个textview,然后翻到最上面,发现导包的地方有个 import com.one.tomato.utils.VideoPlayCountUtils;,顾名思义,就是获取播放次数的类,然后就发现了上图这个调用的地方

            if (VideoPlayCountUtils.a().b() != -2) {z = false;}a(z, VideoPlayCountUtils.a().b(), VideoPlayCountUtils.a().c());

看下 VideoPlayCountUtils.a()

VideoPlayCountUtils 是一个单例,所以我们直接看 b 方法

和c 方法

看到 video_play_count 没,都是跟播放次数有关,盘它就对了

    private static void hookVideoCountUtil(XC_LoadPackage.LoadPackageParam param, ClassLoader loader){hook_method("com.one.tomato.utils.VideoPlayCountUtils", loader, "b", new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {LogUtil.d(TAG,"afterHookedMethod VideoPlayCountUtils.b --- " + param.getResult());}});hook_method("com.one.tomato.utils.VideoPlayCountUtils", loader, "c", new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {LogUtil.d(TAG,"afterHookedMethod VideoPlayCountUtils.c --- " + param.getResult());}});}

先打印两个值看看,
build and install 重启xx社区,看log

28/30,对应就是剩余播放次数和总的可以播放次数
上面的原图是29,因为中间手抖播放了一次,所以剩下28,没毛病。。
改返回值啦,很简单了,最终代码如下

    private static void hookVideoCountUtil(XC_LoadPackage.LoadPackageParam param, ClassLoader loader){//剩余播放次数hook_method("com.one.tomato.utils.VideoPlayCountUtils", loader, "b", new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {LogUtil.d(TAG,"afterHookedMethod VideoPlayCountUtils.b --- " + param.getResult());param.setResult(1000);}});//总的可以播放次数hook_method("com.one.tomato.utils.VideoPlayCountUtils", loader, "c", new XC_MethodHook() {@Overrideprotected void afterHookedMethod(MethodHookParam param) throws Throwable {LogUtil.d(TAG,"afterHookedMethod VideoPlayCountUtils.c --- " + param.getResult());param.setResult(1000);}});}

重新打开xx社区

可播放了总次数都是1000,怎么播都不变了

*文章为作者独立观点,仅供技术交流,不代表本公号立场

End

说句题外话,有不少人想加鱼哥微信,鱼哥姑且放出来,但是坑位有限哦

 推荐阅读

作为程序员,要保持工作和家庭平衡,就那么难么?

刷抖音上瘾后,决定探究如果做一款类似抖音短视频app

屌丝的眼泪,因为错过的初恋,才搞清楚PNG图片压缩原理

我用Python爬了点你们需要的电影,这些电影真的很不错~

喜欢就点个在看吧

深夜,基友给我发了个某短视频app,我没忍住把它给...相关推荐

  1. 抖音视频如何发到快手?短视频如何一键发布?

    抖音视频如何发到快手?抖音和快手是目前流行的短视频共享交互软件,许多朋友在玩.最近,一位用户问抖音视频是否可以发布到快手?如何将抖音短片完整发送到快手?很多人一定会说直接下载视频,一个一个上传到快手就 ...

  2. 腾讯视频下载安装免费2020_腾讯视频app的哪里发贴

    本文播放器家园网给大家整理了腾讯视频下载安装免费2020_腾讯视频app的哪里发贴子的方面的内容.腾讯视频是一款可以电影资源非常丰富的播放器软件,用户可以在这里观看各种有趣的电影,每天都有精彩的影视资 ...

  3. 短视频内容创作:内容发给谁?为什么发?发什么?以什么形式发?

    一句话介绍短视频内容定位,我赢助手每周一课短视频运营关键节点介绍. 内容定位无非就是视频发给谁?为什么发?以什么形式发? 短视频发给谁?就是做好你的目标受众的细分. 商业定位我们之前聊过了,如果你看过 ...

  4. python发朋友圈突破朋友圈限制_突破限制!原来朋友圈可以发长达5分钟的视频,后悔没早点知道...

    原标题:突破限制!原来朋友圈可以发长达5分钟的视频,后悔没早点知道 现在使用微信的人越来越多,很多人喜欢在微信朋友圈分享自己的生活,可能是发图片,也可能是发日常的视频,但是视频有限制怎么办? 一.朋友 ...

  5. 微信发红包、QQ登录、搜索框、水杯、聊天窗口、两台电梯、微信/淘宝支付、笔、 抖音发布短视频等功能测试用例

    文章目录 一.微信发红包测试用例 三.搜索框测试用例 四.水杯测试用例 五.聊天窗口测试用例 六.两台电梯测试用例 七.(微信/淘宝)支付功能的测试用例 八.笔测试用例 九.抖音发布短视频功能测试用例 ...

  6. 微信朋友圈如何发已存的小视频

    我们知道,微信发朋友圈的时候,只能即录即发,不能够发已经存好的视频,或者转发别人的视频.下面以转发别人的小视频为例,说说如何发送已经存好的小视频.有时候,看到别人发的直升机,钞票啊等等小视频,感觉很拉 ...

  7. 服务器发微信朋友圈长视频,微信朋友圈过长的视频怎么发 发布长视频技巧

    相信大家在玩微信的时候经常会碰到一个问题,就是一些比较大的视频无法分享到朋友圈,那应该怎么办呢?下面通过这篇文章给大家介绍一下如何设置. 首先打开微信最新版,然后我们在通讯录里随便找一个好友,然后在消 ...

  8. 拍的视频大了发不出去怎么办?视频太大怎么处理变小?

    拍的视频大了发不出去怎么办?视频太大怎么处理变小?经常有朋友问我视频太大了怎么压缩,我也找了很多软件,但是都不怎么样好用,小编今天给小伙伴们介绍一个简单的方法视频压缩软件,我在这里介绍一个简单的方法来 ...

  9. 抖音视频发布时间技巧,短视频什么时间发比较好

    由于大家每做的一步实际操作都关联着大家账户的分享量.关注点赞量及其访问量,更关联到大家是不是能上热门. 因而不能小看抖音发布这一简易的实际操作,抖音短视频视频制做进行以后,怎样发布?有哪些抖音发布方法 ...

  10. 发短视频是怎么赚钱的?视频搬运工怎么挣钱?

    发短视频是怎么赚钱的?视频搬运工怎么挣钱? 一.确定领域 首先你要明白你准备创作哪个类型的内容,以后输出哪个方向的内容,以便在平时不断的搜集所需的素材,这样才能保证你的内容输出不会间断. 二.通过平台 ...

最新文章

  1. 在家想远程公司电脑?Python +微信一键连接
  2. 基因对智力的预测能力不到7%,别迷信它
  3. 利用Oracle分析函数实现多行数据合并为一行
  4. docker 容器中yum网速慢报错 Operation too slow. Less than 1000 bytes/sec transferred the last 30 seconds 解决方法
  5. tpcc-mysql的使用
  6. UA MATH571B 试验设计V 2K析因设计简介
  7. MySQL数据库修改用户登录密码的三种方式
  8. Kubernetes基础组件概述
  9. python从文件初始化失败_iOS 6:libpython2.7.a初始化导入错误
  10. 修改ECSHOP后台的商品列表里显示该商品品牌
  11. zookeeper入门综合概要介绍
  12. 学python多大年龄可以学车_2020想学车的注意,关于学车的年龄问题,你都了解吗?...
  13. 小马儿随笔十一:朋友一生一起走
  14. DirectX编译环境配置
  15. linux c 宏 文件名,C语言标准宏获取文件名、行号、函数名的方法以及#和##的用法...
  16. 重复类发展手法_正确护肤手法图解!
  17. Android 多线程断点下载
  18. 在平面国生活,会是怎样的体验?
  19. 【李守聪原创】攻坚克难,梦在远方
  20. CC2530 IIC 4线驱动中景0.96寸OLED屏显示程序,从c51移植过来的

热门文章

  1. jq移除一条html语句,jquery html()删除脚本标签
  2. IDA Pro7使用总结
  3. FFmpeg学习(1)——视频文件格式转换
  4. 随手记_英语_50大英文经典句/美句
  5. leetcode之逆波兰表达式
  6. Beta阶段 - 博客链接合集
  7. JavaScript基础1
  8. 说一说javascript跨域和jsonp
  9. Response.End() 与Response.Close()的区别
  10. 车间调度建模系列2|复杂车间调度问题描述