一、简介
最近,我产生了制作一个应用程序的想法。 我暂时不说它是一个什么样的应用程序。 稍后我会详细介绍这个App的开发流程和架构。 不过,我需要先解决一些技术先决条件。 技术问题是我需要对当前的四个短视频进行分析和解密。 小龙:抖音、火山、秒拍、快手四家短视频公司的数据请求加密协议,只有在加密协议被破解的情况下才能定制检索数据。 废话不多说,本文先去第一站处理一下数据请求的两种加密协议,抖音和火山。 为什么说是这两个人呢? 因为我们后面分析会发现,这两个App其实都使用了一套加密协议。 毕竟这两款App都是今日头条内部孵化的项目。 所以就买一个吧。 我们决定摆脱抖音。 毕竟我比较看好也喜欢看抖音。
2、逆向分析
话不多说,我们快速分析一下。 不过,本文不会使用粗暴的静态方法来破解。 应广大同学的要求,我将介绍IDA动态调试so破解,也可以给大家带来IDA的使用技巧。 毕竟我是为你写技术文章的。 不用说,这种请求数据分析的突破点就是抓包。 但由于使用了,所以需要在设备中手动安装证书才能捕获正确的数据信息:
打开抖音后,看到数据刷新得很快,发现有一个feed接口从首页返回了数据。 分析它的请求参数的时候,有3个字段,其实这3个字段是后面数据分页请求用的。 稍后将详细讨论该密钥。 然而,这里没有问题。 但是,如果你再往下看更多的请求参数,你会发现两个字段:
这时候你会发现其他参数都是和本地设备相关或者直接硬编码的,但这两个参数的信息一直在变化。 所以我猜测这两个字段是用来请求协议数据加密和服务器端验证的。 所以如果我们要单独构造信息来请求,这两个字段中的信息必须是正确的,否则我们将无法请求到正确的数据。 好吧,这里很容易。 只需使用Jadx打开抖音应用程序,直接搜索全局字段“as=”中的信息即可:
看到这里构造了as和cp字段的值,直接点击进入:
这里的总体逻辑也比较简单。 使用 。 函数获取字符串,然后将其分成两半,交给 as 和 cp 字段。 右移操作的意思是除以2。这里我们不分析代码看看参数是怎么来的。 我们直接使用钩子函数打印参数并查看结果。 它既粗糙又快速。 未来,这实际上将是一种快速解决问题的方法。 钩法是最无敌的。
我们先看一下这个加密方法的参数信息,看到是,说明加密操作是在so中完成的,就是这个so,后面需要调试。 不管怎样,hook这个方法然后打印信息就可以看到参数结构了:
直接运行模块,打印log即可看到信息:
查看三个参数的打印值,发现三个参数的含义是:当前时间戳、请求url、请求参数的数组信息。 好了,现在我们可以新建一个项目,然后构造这三个参数信息,然后调用它的so函数了。 为了快速找到so名,我们可以使用万能的方法:全局查找字符串信息“.”:
这样,我们就找到了so名字。 进入libs目录,将这个so复制到我们自己构建的demo工程中。 这里我们不用担心加密函数功能的调试和分析。 我们应该使用旧的规则,直接从上层构建一个。 对于同包名的函数,只需调用它的so即可得到结果:
然后我们开始构造参数信息。 为了简单起见,我们首先记下设备的sid、aid、版本号等公共参数信息:
这里我们使用公共参数信息来构造请求字段数组信息,有几个单独的字段值无法参与操作,可以通过前面的打印日志来分析。 当然,时间戳也是服务器格式,比本地少三位。 除以1000就可以了。为了简单起见,直接写公共参数就可以了。 当然,后续的优化就是动态获取并填充这些参数值:
构造完参数后,开始调用函数并获取返回结果:
至此,我们的搭建工作就完成了,我们开始直接运行吧,但是遗憾的是,并没有那么顺利,直接运行就崩溃了:
这里加载so应该有问题,所以我们回头看看是不是我们的一些环境还没有初始化,看看类中是否还有一些初始化方法没有被调用:
这里我们看到确实有两个方法有点可疑。 全局查看这两个方法的调用地方:
看到该方法在全局世界中只调用了一个地方,并且值被硬编码为2,其他方法有点麻烦,但它仍然是一个通用的钩子方法。 只需hook这个方法并打印其参数信息即可。
运行模块并查看打印的日志信息:
可以看到,参数信息始终是这个字符串信息。 您只需复制它并将其分配给值即可:
3.IDA调试so代码
这次运行的时候发现可惜还是报错,而且奇怪的是日志没有打印出来,也就是说函数没有调用就退出了。 那你会怎么想? so中的函数中是否做了一些判断逻辑? 直接用IDA打开so文件即可:
打开后,发现了这个功能。 我用F5查看了它的C代码,发现内部判断确实很多。 然后我就直接调用exit函数退出了。 所以想要成功调用它的so方法,首先要通过他的判断。 下面我们就开始调试操作。 其实这里有一个直接静态分析的快速方法,不过为了给大家介绍动态调试所以技巧就多走点弯路吧。 稍后我会讲一些粗略和简单的技术。
现在我们开始调试so文件。 关于IDA调试so文件,我之前写过一篇很详细的文章:; 具体步骤我这里就不详细介绍了,直接开始吧:
第一步:将IDA安装目录下的文件复制到设备目录下
第 2 步:运行命令
步骤3:转发端口并以模式打开应用程序
这里有同学好奇为什么xml中的属性不需要修改呢? 因为我调试的是自己的demo项目,默认签名打包的apk的属性值为true,所以不需要修改。
第 4 步:启动 IDA 附加过程
设置本地地址和一些选项:
因为我们现在知道需要调试函数,所以我们需要设置加载函数暂停的地方,然后选择要调试的应用程序进程:
第五步:查看调试端口并连接调试器
在DDMS中,检查红蜘蛛的调试应用端口号为8647,然后连接调试器:
这里一定要注意端口的正确性,否则链接操作会失败。
第六步:点击IDA中的运行按钮,或者F9快捷键
这时我发现红蜘蛛变绿了,调试对话框也消失了。 此时,您将进入调试页面:
为了安全起见,请再次检查该选项是否有任何挂起的加载函数:
如果发现不可用,还需要手动检查:
因为我们已经暂停了该功能,而一个应用程序会加载很多系统so文件,所以我们这里总是点击运行或者F9:
系统加载后的步骤如下:
这些都是加载的系统so文件,所以只需一路运行它们并绕过调试:
可以看到这里会加载很多系统so文件。 当我们点击应用程序按钮并加载我们自己的.so文件时,我们就开始调试:
单击“确定”加载它,然后它保持暂停状态。 这时候我们在右栏寻找这个so文件:
然后点击继续寻找他的函数:
点击进入函数并设置下一个断点:
因为之前我们静态分析了这个函数内部有很多退出函数,为了定位退出在哪里,我们在每个退出函数之前设置一个断点来确定退出逻辑。 这里设置断点是有技巧的,因为是if语句,所以在arm指令中肯定是CMP指令后面的BEQ跳转,所以只要在每条CMP指令上设置一个断点就可以了。 我们这里找到了9个地方,所以断点很多。 我们慢慢分析一下:
在第一条CMP指令上设置断点,然后运行这里查看R3寄存器值是否为0:
为0,那么第一次退出就没有问题。 然后往下按F9直接到下一个CMP判断指令断点:
发现第二次CMP中R3寄存器值也为0,所以没有问题,直接F9到下一个断点即可:
到了第三点,你发现R3发送的值不是0,而是1,所以为了继续往下走,只要修改R3寄存器的值就可以了。 右键单击右栏寄存器中的R3寄存器,然后单击修改值:
将1改为0并保存:
修改成功,运行后发现判断通过:
继续向下到下一个断点:
这里有一个问题。 如果我们直接F9到第四个CMP,发现直接退出调试,说明在位置3和位置4的判断中间有问题,最后发现问题出在这条跳转指令上,需要多次点击。 一步步调试F7键定位问题,我们输入这个跳转地址:
然后我发现里面有一条BL指令,出了问题。 我继续深入查了一下:
看,我们在这里找到了问题的原因。 有一个类,这个类应该在Java层。 该层应使用反射机制来获取全局变量。 我们直接在Jadx中搜索这个类:
那么问题就清楚了,因为我们的demo工程中根本没有这个类,所以无法获取全局变量,所以退出失败,退出。 解决办法也很简单,直接在demo工程中构造这个类,然后在Just初始化即可:
构建的时候一定要注意包名一致,然后在demo中的类中设置:
然后再次运行项目,可惜还是不行,只好调试功能了。 方法步骤与上面类似,不再赘述。 不过,上面的获取失败的问题到这里应该就结束了。 继续往下走,发现重要信息:
这里有一个类似于MD5的值,继续往下看BL:
查看R0寄存器中的值,发现是demo应用程序的签名信息。 继续下去BLX看看:
这里大致就清楚了,获取应用签名信息,即签名验证:
那么,在这个退出函数的判断中,应该通过反射的方式获取到Java层的值,然后获取到应用程序的签名信息,并与原来已经保存的抖音签名信息进行比较。 如果不正确,则退出。 进行签名验证也非常方便。 就用我之前的原理,将hook代码复制到项目中,拦截并获取签名信息,然后返回正确的签名信息:
具体的hook代码请看我的实现原理: 那么hook代码一定要在第一行代码中调用,否则没有效果。 这个操作完成后,数据实际上就已经输出了。 不过为了能够进入加密函数调试分析具体的加密算法,我们继续调试该函数:
继续往下走,你会发现第五次退出判断后,有一个函数出现了问题,就是这个BL。 进去查看:
哈哈,我找到了这个字符串信息。 做过调试的同学都大致猜到这是一个反调试操作。 继续往下走:
这里你可以100%确定读取文件中的字段值进行反调试检测。 在以下两条 CMP 指令上设置断点:
发现R3寄存器确实不为0,所以为了通过反调试,只需将R3寄存器值修改为0即可:
这样,反调试检测就已经通过了。 步退到下一个退出判断断点。 最后,还有一个地方需要处理,就是第七条CMP指令:
处理方法是直接将R3寄存器中的值修改为0。这样我们就成功通过了所有的退出判断点:
然后在加密函数上设置断点:
只需点击即可进入:
4. 加密数据结果输出
我们还成功到达了加密函数断点。 这里没有判断逻辑。 这只是一个简单的加密功能。 不过这里我们不再进行调试和分析。 有兴趣的同学可以自己动手做一下,因为我们的目的已经达到了。 即成功获取到加密数据:
可以看到,我们成功获取到了as和cp值,然后将它们构造到了请求url中,同时也成功获取了返回数据。 这里我们只需要多一步解析json数据即可。 原来的json数据是这样的:
之所以要分析一下,是为了为后续的项目做好准备。 到时候我会公开该项目的开发过程。 不管怎么样,到这里我们已经成功获取到了抖音的加密信息了。 主要是通过动态调试功能来解决so调用崩溃问题,正如文章开头提到的,其实本文可以直接用一种简单粗暴的方式来解决,这就是万能的方法:全局搜索字符串信息,包括在Jadx中搜索和在IDA中查看,因为字符串信息给我们带来了很多信息,有时我们只需要猜测就能定位到破解的位置。 比如这里我们使用快捷键+F12在IDA中打开字符串窗口:
根据这些关键字符串信息,我们可以判断so中执行了哪些操作。 记住这些敏感的字符串信息对于未来的逆向工程非常关键。
五、技术总结
以上已经解决了抖音请求数据加密信息的问题。 总结一下这次学到的技术:
6、火山视频加密分析
上面已经解决了抖音的加密问题。 我们来看一下霍山视频的加密信息。 突破点仍然是使用抓包查看数据:
通过抓包,你会发现和抖音的数据结构字段几乎一样。 原来他是他的弟弟。 继续查看他的加密字段:
这里就不多说了,加密字段都是一样的。 那么先不说用Jadx打开火山短视频看看有没有那种信息:
看来没有必要再去分析了。 完全相同,所以只需使用相同的so和相同的加密即可。 在demo工程中运行查看日志:
初始化是一样的,直接运行:
看到了,数据回来了,看他原来的json数据:
至此,我们已经成功破解了抖音和火山视频的数据请求协议。 有了这两个短视频数据,我们以后开发APP就很简单了。 当然,正如文章开头提到的,现阶段短视频的四小龙:抖音、火山、秒拍、快手。 现在我们已经杀死了前两个,那么下一个会是谁呢? 我们力争在今年年底前成功爆破所有四个应用程序,并能够请求他的数据。 它作为我们后续应用程序开发的基础。
认真解释
本文的目的只有一个,就是通过分析app来学习更多的逆向技术。 如果有人利用本文的知识和技术进行非法操作以获取利润,由此产生的任何法律责任将由操作者本人承担,与本文作者无关。 最后希望大家能够抱着学习的态度来阅读这篇文章。 鉴于安全问题,示例和源代码均可在 获取!
---点击立即进入小圈---
七、总结
通过这篇文章,我们可以发现,我们其实并没有真正的算法来破解它,但是结果就是我们想要的,这就足够了。 现在很多app都将加密算法放入SO中,并对SO做了一些保护,因此很难使用本文的技术来调用app的SO。 然而,无论我们如何保护SO,方法也只有那么几种,我们仍然可以使用动态调试来解决。 文中有人好奇直接修改so指令是否不能进行判断验证? 比如签名验证,就不需要在Java层进行hook。 我们可以直接修改CMP和BEQ指令吗? 确实可以这样做,但是这是下一篇文章的内容,因为在下一篇文章中我们将破解下一个短视频应用程序,我们将使用这种方法来通过验证。 敬请关注! 每次讲解调试都要截大量的截图,非常累人,所以如果你看完之后觉得不错,请多点击广告,分享给更多喜欢逆向工程的同学!
手机查看文章不方便,可以在网页上阅读
长按下方