jiangwei212 发表于 2018-5-3 08:29

Android中静态方式分析破解视频编辑应用「Vue」水印问题

本帖最后由 mengzhenhai 于 2018-5-3 11:46 编辑

一、故事背景

现在很多人都喜欢玩文艺,特别是我身边的UI们,拍照一分钟修图半小时。就是为了能够在朋友圈显得逼格高,不过的确是挺好看的,修图的软件太多了就不多说了,而且一般都没有水印啥的。相比较短视频有一个比较有逼格的编辑工具「Vue」个人已经用了很长时间了,拍出来的视频借助强大滤镜真的很好看,显得逼格也高,更重要的是他有我最喜欢的功能就是可以添加视频背景音乐,选择自己喜欢的音乐,然后还可以编辑这段背景音乐,反正我个人觉的这个是我最喜欢用的产品了。但是好用的东西必定有它不好的地方,因为他真的很强大所以应用就把视频加上了水印,为了更好的宣传作用。其实有很多视频都是有水印的,比如抖音视频,不过这里顺便说一下抖音视频其实传到服务器上是没有水印的,而在我们保存到本地的时候有水印的。因为开发过视频的人都知道,一般就是借助ffmpeg库添加水印,水印一般都是一张图片。如果抖音后台把视频加上水印一方面是设计版权问题,因为现在很多原创作者一个作品视频会在很多平台发放,那么同样的视频有抖音水印,西瓜水印,快手水印等。再者就是添加水印是有点消耗性能的,抖音现在每天上传视频数量巨大,每个都添加水印服务器压力会很大的。介于这两点抖音没有选择给服务器后台的视频添加水印,只有用户保存到本地的时候把水印在本地添加,所以网上很多人都想去除抖音水印,其实很简单直接抓包然后获取视频原始地址就可以了。不了解抖音的数据协议,可以看这篇文章:Android中分析某音视频协议数据。
二、逆向分析应用

说的有点远了,接着回来看看我们这款应用给的水印问题,其实这个应用没有视频上传功能,就是把本地视频编辑加上滤镜和背景音乐然后在保存到本地,而保存的过程中就把水印给添加上了,所以我们的目的去除水印,那么就在这个过程做手脚就可以了。关于视频添加水印的功能其实网上很多资料,大部分都是借助ffmpeg的库进行操作。先来看看这个应用添加的水印效果吧:
http://img.blog.csdn.net/20180226171810402?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
然后我们看看应用的使用过程:
http://img.blog.csdn.net/20180226171839817?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

他是通过分段拍摄处理然后合并的操作,直接跳到后面看看保存的地方:
http://img.blog.csdn.net/20180226171911584?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

看到这里就在保存视频了,那么添加水印的地方就很有可能在这个地方了,我们借助UI工具直接提取这个进度条的id作为突破口信息:
http://img.blog.csdn.net/20180226171954604?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

看到了控件的resid值,然后去jadx中直接搜索R.id.video_view,以后大家都这么搜,如果搜不到在去public.xml中转化成十进制搜索,这里的应用就两个dex不是很大,但是资源很多,大家可以用压缩工具打开apk把res文件夹删了,因为Jadx卡需要解析res下的资源。这里我们不查看res下的东东就直接删除,然后直接打开apk即可,这样也不用多开jadx打开多个dex了:
http://img.blog.csdn.net/20180226175948192?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

找到之后点击进入查看详情:
http://img.blog.csdn.net/20180226180158965?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

果然看到用到了最常用的TextureVideoView这个是用来处理视频滤镜效果结合ffmpeg的常用手法,不过我们关心的是进度,因为保存肯定有进度的。网上看到自定义了一个矩形动画进度控件,点进去看看:
http://img.blog.csdn.net/20180226180407563?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

的确查看到了他有一个更新进度的方法,然后右键查看这个方法的调用地方:
http://img.blog.csdn.net/20180226180433533?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

点进去查看详情即可:
http://img.blog.csdn.net/20180226180446081?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

看到这里是a.n.a方法通过回调更新进度的,不过这里有个问题就是这个a方法点击跳转失败的,这个之前说过了,因为Jadx可能解析类失败,所以我们需要手动去找这个方法,查看n类型:
http://img.blog.csdn.net/20180226180544507?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

有了包名类名就好办了,直接去查看这个类信息:
http://img.blog.csdn.net/20180226180606469?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

找到了a方法,看到这里感觉游戏了,保存本地视频的文件有了,继续往下跟进:
http://img.blog.csdn.net/20180226180639935?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

这里有断片了,方法点击失败,而且发现多层调用按照包名变量查找太费劲了,直接查看smali代码比较直接,这里记住这个小技巧,当在Jadx中查看一个方法失败可以去查看smali代码:
http://img.blog.csdn.net/20180226180733945?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

最后调用的是h类的a方法,再去Jadx中找这个h类:
http://img.blog.csdn.net/20180226180757025?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

到这里,就开始豁然开朗了因为我们已经找到最关键的地方了,就是这个执行ffmpeg命令的方法,因为我之前做过视频应用,用ffmpeg做过滤镜效果。所以看到这种代码瞬间就眼前一亮。不过你没做过也没关系,这里可以直接hook操作了:
http://img.blog.csdn.net/20180226180918687?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

直接拦截方法,打印参数看结果即可,这里顺便就把我去除水印的几个方法介绍一下吧:
http://img.blog.csdn.net/20180226180950044?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

首先我想到的第一个方案是:过滤添加水印的命令参数,因为添加水印的命令网上很多:
http://img.blog.csdn.net/20180226181128382?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

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

看到命令被打印出来了,而且看到了默认的水印图片,这个图片地址一定要记住,后面会给出一个更加巧妙的破解方案就是要用到这个地址。看到水印的xy坐标值,我们直接修改:
http://img.blog.csdn.net/20180226181431831?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

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

那么到这里我们大致就搞清楚了这个应用添加水印的流程和技术,主要就是借助ffmpeg库利用命令进行添加水印,我们去除水印的方式比较粗暴就是直接修改水印图片位置。但是到这里就结束了吗?肯定不是因为我们想让每个人都能用到无水印效果的Vue,所以得弄出一个成品apk文件。那么这里有很多思路:
第一个思路:修改smali代码,修改xy值,然后回编译。这个的确是个思路但是我觉得修改smali代码有点费劲。
第二个思路:弄一个空白的水印图片,放在手机的sd卡,然后修改smali代码,替换默认的水印图片地址,这个思路靠谱但是还是需要修改smali代码不方便。
第三个思路:从上面的命令看到那个默认的水印图片存在sd卡的目录,可以直接用空白图片替换这个有水印的图片,这个思路可以,不过可惜的是不可信,因为我们去查看这个目录:
http://img.blog.csdn.net/20180226182932162?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

我操作了三次,就产生三张图片,也就说这里每次编辑视频都会从一个地方弄个水印图片后面的数字是变化的,所以这种方案我们没法提前预知图片名字无法完成提前替换。
第四个思路:这个是在第三个思路基础上想到的,也是最终方案。我们从第三个思路中可以看到这个水印图片肯定不是本地用代码生成的,从网上下载下来的可能性也很低,因为是同样的图片,而且没必要从网上获取,所以想了一下发现这图片肯定在本地apk中,那么不多猜想直接解压apk去res下查找:
http://img.blog.csdn.net/20180226183531974?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

皇天不负有心人总算被我找到了,也验证了我的猜想,我们对比这个和sd卡中的默认水印图片:
http://img.blog.csdn.net/20180226185203077?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

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

下面就怎么生成一个空白图片呢?这个不难,谁叫我们会PS呢?打开PS软件,通过上面查看那个res图片的大小尺寸是132*40的:
http://img.blog.csdn.net/20180226190126264?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

记得一定要选择透明的,尺寸也是注意是像素单位,然后确定就好了:
http://img.blog.csdn.net/20180226190150719?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

然后保存为png格式即可。直接替换原来的水印图片:
http://img.blog.csdn.net/20180226190348615?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

这里就替换成功了,开始回编译吧,可惜的是回编译失败。一般现在很多都会回编译失败问题,这类问题我一般都是避免,因为解决的话没个头了。那么我们怎么不反编译就能替换这个文件呢?有的同学会想到直接用解压工具解压apk,然后替换会压缩修改后缀名apk即可。这个你们可以去尝试一下会发现压缩成apk是有问题的,因为路径问题没法这么做的,那么我们该怎么办呢?这个就要借助我的逆向大黄书「Android应用安全防护和逆向分析」的第三章中介绍的aapt命令用法了,还没有购买的同学赶紧入手吧。aapt命令可以用来操作apk文件的,比如查看apk的xml文件,添加删除一个文件到apk中。用aapt命令添加无需解压apk文件的,比如这里我们替换这个文件,可以先删除这个文件,命令如下:aapt remove -v vue.apk res\drawable-xxhdpi-v4\stamp_logo.png;这样就把原始的水印图片删除了,然后在用命令添加我们的空白水印图片:aapt add -v vue.apk res/drawable-xxhdpi-v4/stamp_logo.png 这里有个小小的坑,就是这个命令执行的路径一定要包含res/drawable-xxhdpi-v4/stamp_logo.png文件,而命令中的这个路径是不能变化的,不然添加是失败的。
就这样我们用aapt命令巧妙的替换了水印图片,当然要二次签名了,因为我们替换文件了。二次签名简单不多解释了,这样我们就安装弄好之后的应用,运行都是成功的,这个有点出乎我的意料,应用没做签名校验防止二次打包吗?正当我怀疑的时候,发现问题了,视频滤镜失效了,所以这个应用还是做了检测了。不过没关系,这时候第一眼就要想到我写的爆破工具kstools,不了解这个工具的同学可以查看这里:Android中爆破签名校验问题工具kstools原理解析,这里要注意得先用工具获取正确的原始签名,不然还是失败的,好了这里在继续操作安装吧,这下就可以愉快的操作无水印的高逼格视频编辑工作了。到这里我们就把所有的流程都说完了,内容还是很多的,下面来总结一下本文获取的知识点:
[*]第一、了解了视频添加水印一般都采用ffmpeg库的命令方式添加一张水印图片
[*]

[*]第二、使用ps造一个空白png图片
[*]

[*]第三、使用aapt命令实现apk包文件的原始操作
而且这个ffmpeg库非常强大,还可以去除水印,不过去除之后很难看,但是可以让原始的水印看不清了,现在也有这样的需求的。感兴趣的同学可以去查看这个命令如何去除水印效果吧。下面来看看去除水印之后的视频截图:
http://img.blog.csdn.net/20180226193451466?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvamlhbmd3ZWkwOTEwNDEwMDAz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

五、总结

本文通过逆向分析一个视频编辑的应用学习到了很多知识点最大的收获就是视频库ffmpeg的了解和使用,不管对于后续开发还是破解都会有很大的作用,欢迎购买本人逆向大黄书





jiangwei212 发表于 2018-5-3 09:09

stefkang 发表于 2018-5-3 08:48
新版本的VUE没有水印了想知道如何自己添加水印进去!!制作个水印,如何添加呢?

举一反三呀,用ffmpeg加上命令水印不就好了吗

玩世不攻 发表于 2018-5-3 22:32

玩世不攻 发表于 2018-5-3 22:03
为什么使用删除和添加总是提示 failed opening/creating   .apk as zip file

好吧,是因为我正在打开状态

stefkang 发表于 2018-5-3 08:48

新版本的VUE没有水印了想知道如何自己添加水印进去!!制作个水印,如何添加呢?

sunx1532 发表于 2018-5-3 09:29

好贴,学习了,还没有接触逆向工程,但是先学习了

あRobin 发表于 2018-5-3 09:32

用心讨论,共获提升!已经买了大黄书支持下!

玩世不攻 发表于 2018-5-3 11:13

使用aapt删除,提示 failed opening as zip files

孤狼微博 发表于 2018-5-3 11:13

直接可以设置无水印

mengzhenhai 发表于 2018-5-3 11:45


@jiangwei212帖子后的购买链接还是不要加了,已帮忙编辑掉,如有疑问可跟帖回复   

冰楓丶殘瀷 发表于 2018-5-3 17:27

jiangwei212 发表于 2018-5-3 09:09
举一反三呀,用ffmpeg加上命令水印不就好了吗

Ageisub+小丸

玩世不攻 发表于 2018-5-3 22:03

为什么使用删除和添加总是提示 failed opening/creating   .apk as zip file
页: [1] 2 3 4 5
查看完整版本: Android中静态方式分析破解视频编辑应用「Vue」水印问题