当前位置: 首页 > news >正文

Android逆向之旅---静态方式分析破解视频编辑应用「Vue」水印问题

一、故事背景

现在很多人都喜欢玩文艺,特别是我身边的UI们,拍照一分钟修图半小时。就是为了能够在朋友圈显得逼格高,不过的确是挺好看的,修图的软件太多了就不多说了,而且一般都没有水印啥的。相比较短视频有一个比较有逼格的编辑工具「Vue」个人已经用了很长时间了,拍出来的视频借助强大滤镜真的很好看,显得逼格也高,更重要的是他有我最喜欢的功能就是可以添加视频背景音乐,选择自己喜欢的音乐,然后还可以编辑这段背景音乐,反正我个人觉的这个是我最喜欢用的产品了。但是好用的东西必定有它不好的地方,因为他真的很强大所以应用就把视频加上了水印,为了更好的宣传作用。

其实有很多视频都是有水印的,比如抖音视频,不过这里顺便说一下抖音视频其实传到服务器上是没有水印的,而在我们保存到本地的时候有水印的。因为开发过视频的人都知道,一般就是借助ffmpeg库添加水印,水印一般都是一张图片。如果抖音后台把视频加上水印一方面是设计版权问题,因为现在很多原创作者一个作品视频会在很多平台发放,那么同样的视频有抖音水印,西瓜水印,快手水印等。再者就是添加水印是有点消耗性能的,抖音现在每天上传视频数量巨大,每个都添加水印服务器压力会很大的。介于这两点抖音没有选择给服务器后台的视频添加水印,只有用户保存到本地的时候把水印在本地添加,所以网上很多人都想去除抖音水印,其实很简单直接抓包然后获取视频原始地址就可以了。不了解抖音的数据协议,可以看这篇文章:Android中分析某音视频协议数据。

 

二、逆向分析应用

说的有点远了,接着回来看看我们这款应用给的水印问题,其实这个应用没有视频上传功能,就是把本地视频编辑加上滤镜和背景音乐然后在保存到本地,而保存的过程中就把水印给添加上了,所以我们的目的去除水印,那么就在这个过程做手脚就可以了。关于视频添加水印的功能其实网上很多资料,大部分都是借助ffmpeg的库进行操作。先来看看这个应用添加的水印效果吧:

然后我们看看应用的使用过程:

他是通过分段拍摄处理然后合并的操作,直接跳到后面看看保存的地方:

看到这里就在保存视频了,那么添加水印的地方就很有可能在这个地方了,我们借助UI工具直接提取这个进度条的id作为突破口信息:

看到了控件的resid值,然后去jadx中直接搜索R.id.video_view,以后大家都这么搜,如果搜不到在去public.xml中转化成十进制搜索,这里的应用就两个dex不是很大,但是资源很多,大家可以用压缩工具打开apk把res文件夹删了,因为Jadx卡需要解析res下的资源。这里我们不查看res下的东东就直接删除,然后直接打开apk即可,这样也不用多开jadx打开多个dex了:

找到之后点击进入查看详情:

果然看到用到了最常用的TextureVideoView这个是用来处理视频滤镜效果结合ffmpeg的常用手法,不过我们关心的是进度,因为保存肯定有进度的。网上看到自定义了一个矩形动画进度控件,点进去看看:

的确查看到了他有一个更新进度的方法,然后右键查看这个方法的调用地方:

点进去查看详情即可:

看到这里是a.n.a方法通过回调更新进度的,不过这里有个问题就是这个a方法点击跳转失败的,这个之前说过了,因为Jadx可能解析类失败,所以我们需要手动去找这个方法,查看n类型:

有了包名类名就好办了,直接去查看这个类信息:

找到了a方法,看到这里感觉游戏了,保存本地视频的文件有了,继续往下跟进:

这里有断片了,方法点击失败,而且发现多层调用按照包名变量查找太费劲了,直接查看smali代码比较直接,这里记住这个小技巧,当在Jadx中查看一个方法失败可以去查看smali代码:

最后调用的是h类的a方法,再去Jadx中找这个h类:

到这里,就开始豁然开朗了因为我们已经找到最关键的地方了,就是这个执行ffmpeg命令的方法,因为我之前做过视频应用,用ffmpeg做过滤镜效果。所以看到这种代码瞬间就眼前一亮。不过你没做过也没关系,这里可以直接hook操作了:

直接拦截方法,打印参数看结果即可,这里顺便就把我去除水印的几个方法介绍一下吧:

首先我想到的第一个方案是:过滤添加水印的命令参数,因为添加水印的命令网上很多:

那么我就把相关的四个命令给删除了。所以看到我上面的处理命令代码比较简单自己看就好了。不过可惜的是这个方案我执行失败了,我猜想可能是哪个-filter_complex还有其他用途不能直接删除,但是这个命令的参数值太复杂了看得我头疼,所以放弃用了第二个方案:就是在-filter_complex命令参数中修改水印图片的位置,让其超过手机屏幕,这样就看不到水印了,这个方案肯定靠谱的,我们运行这个Xposed模块,然后看看日志:

看到命令被打印出来了,而且看到了默认的水印图片,这个图片地址一定要记住,后面会给出一个更加巧妙的破解方案就是要用到这个地址。看到水印的xy坐标值,我们直接修改:

然后在操作Vue录制视频,发现视频的确没有水印效果了,这里不方便上次视频,大家可以自己操作看效果就好了。

 

三、解决方案

那么到这里我们大致就搞清楚了这个应用添加水印的流程和技术,主要就是借助ffmpeg库利用命令进行添加水印,我们去除水印的方式比较粗暴就是直接修改水印图片位置。但是到这里就结束了吗?肯定不是因为我们想让每个人都能用到无水印效果的Vue,所以得弄出一个成品apk文件。那么这里有很多思路:

第一个思路:修改smali代码,修改xy值,然后回编译。这个的确是个思路但是我觉得修改smali代码有点费劲。

第二个思路:弄一个空白的水印图片,放在手机的sd卡,然后修改smali代码,替换默认的水印图片地址,这个思路靠谱但是还是需要修改smali代码不方便。

第三个思路:从上面的命令看到那个默认的水印图片存在sd卡的目录,可以直接用空白图片替换这个有水印的图片,这个思路可以,不过可惜的是不可信,因为我们去查看这个目录:

我操作了三次,就产生三张图片,也就说这里每次编辑视频都会从一个地方弄个水印图片后面的数字是变化的,所以这种方案我们没法提前预知图片名字无法完成提前替换。

第四个思路:这个是在第三个思路基础上想到的,也是最终方案。我们从第三个思路中可以看到这个水印图片肯定不是本地用代码生成的,从网上下载下来的可能性也很低,因为是同样的图片,而且没必要从网上获取,所以想了一下发现这图片肯定在本地apk中,那么不多猜想直接解压apk去res下查找:

皇天不负有心人总算被我找到了,也验证了我的猜想,我们对比这个和sd卡中的默认水印图片:

完全一样,肉眼没法辨别了。好了到这里我们就开始大胆尝试吧,弄个空白图片,直接替换res下的水印图片,这样应用内部在使用多个地方使用水印图片都是我们替换之后的空白图片,这个思路还是很巧妙的。

 

四、二次打包

下面就怎么生成一个空白图片呢?这个不难,谁叫我们会PS呢?打开PS软件,通过上面查看那个res图片的大小尺寸是132*40的:

记得一定要选择透明的,尺寸也是注意是像素单位,然后确定就好了:

然后保存为png格式即可。直接替换原来的水印图片:

这里就替换成功了,开始回编译吧,可惜的是回编译失败。一般现在很多都会回编译失败问题,这类问题我一般都是避免,因为解决的话没个头了。那么我们怎么不反编译就能替换这个文件呢?有的同学会想到直接用解压工具解压apk,然后替换会压缩修改后缀名apk即可。这个你们可以去尝试一下会发现压缩成apk是有问题的,因为路径问题没法这么做的,那么我们该怎么办呢?这个就要借助我的逆向大黄书「Android应用安全防护和逆向分析」的第三章中介绍的aapt命令用法了,还没有购买的同学赶紧入手吧。aapt命令可以用来操作apk文件的,比如查看apk的xml文件,添加删除一个文件到apk中。用aapt命令添加无需解压apk文件的,比如这里我们替换这个文件,可以先删除这个文件,命令如下:aapt remove -v vue.apk res\drawable- www.120xh.cn   xxhdpi-v4\ www.taohuayuan178.com stamp_logo.png;这样就把原始的水印图片删除了,然后在用命令添加我们的空白水印图片:aapt add -v vue.apk res/drawable-xxhdpi-v4/stamp_logo. www.jypt178.cn png 这里有个小小的坑,就是这个命令执行的路径一定要包含res/drawable-xxhdpi-v4/stamp_logo.png文件,而命令中的这个路径是不能变化的,不然添加是失败的。

 

就这样我们用aapt命令巧妙的替换了水印图片,当然要二次签名了,因为我们替换文件了。二次签名简单不多解释了,这样我们就安装弄好之后的应用,运行都是成功的,这个有点出乎我的意料,应用没做签名校验防止二次打包吗?正当我怀疑的时候,发现问题了,视频滤镜失效了,所以这个应用还是做了检测了。不过没关系,这时候第一眼就要想到我写的爆破工具kstools,不了解这个工具的同学可以查看这里:Android中爆破签名校验问题工具kstools原理解析,这里要注意得先用工具获取正确的原始签名,不然还是失败的,好了这里在继续操作安装吧,这下就可以愉快的操作无水印的高逼格视频编辑工作了。到这里我们就把所有的流程都说完了,内容还是很多的,下面来总结一下本文获取的知识点:

  • 第一、了解了视频添加水印一般都采用ffmpeg库的命令方式添加一张水印图片
  • 第二、使用ps造一个空白png图片
  • 第三、使用aapt命令实现apk包文件的原始操作

相关文章:

  • 2017-12-24 手机编程环境初尝试-用AIDE开发Android应用
  • 2018 年第一季度报告:JavaScript 仍是最热门语言
  • Windows 7 用户已开始收到停止支持的提醒
  • 将用Axis2编写的Web Service项目打包成aar包
  • 微信端web页面传值
  • 知识阅读的好处你都了解吗?芒果xo来告诉你答案
  • git 常用命令
  • 开源一个自用的Android事件分发中心库,实现类似系统广播功能。
  • 九九乘法表
  • CentOS 7 LNMP部署—php
  • 利用原生javascript完成倒计时
  • pycharm 设置py文件的默认模版头部信息
  • 关于stackoverflow网页加载很慢的解决办法
  • 由比特币说起 - 区块链的前世今生及未来趋势
  • 典型用户和场景描述(团队项目)
  • [译] 怎样写一个基础的编译器
  • 230. Kth Smallest Element in a BST
  • Angular 响应式表单之下拉框
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • Javascript基础之Array数组API
  • Sass Day-01
  • vue总结
  • 读懂package.json -- 依赖管理
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 前端路由实现-history
  • 前端面试总结(at, md)
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • !!java web学习笔记(一到五)
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (1)(1.13) SiK无线电高级配置(六)
  • (2)MFC+openGL单文档框架glFrame
  • (6)添加vue-cookie
  • (ros//EnvironmentVariables)ros环境变量
  • (ZT)薛涌:谈贫说富
  • ****** 二十三 ******、软设笔记【数据库】-数据操作-常用关系操作、关系运算
  • .helper勒索病毒的最新威胁:如何恢复您的数据?
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .NET Core 成都线下面基会拉开序幕
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .NET8.0 AOT 经验分享 FreeSql/FreeRedis/FreeScheduler 均已通过测试
  • .Net中ListT 泛型转成DataTable、DataSet
  • .net最好用的JSON类Newtonsoft.Json获取多级数据SelectToken
  • @AutoConfigurationPackage的使用
  • @column注解_MyBatis注解开发 -MyBatis(15)
  • @开发者,一文搞懂什么是 C# 计时器!
  • [ vulhub漏洞复现篇 ] JBOSS AS 5.x/6.x反序列化远程代码执行漏洞CVE-2017-12149
  • [ 攻防演练演示篇 ] 利用通达OA 文件上传漏洞上传webshell获取主机权限
  • [ 云计算 | AWS ] AI 编程助手新势力 Amazon CodeWhisperer:优势功能及实用技巧
  • [2]十道算法题【Java实现】
  • [2021ICPC济南 L] Strange Series (Bell 数 多项式exp)
  • [AX]AX2012 R2 出差申请和支出报告
  • [C#]winform部署PaddleOCRV3推理模型
  • [C++]类和对象【下】
  • [CQOI 2010]扑克牌
  • [Docker]十二.Docker consul集群搭建、微服务部署,Consul集群+Swarm集群部署微服务实战