文章总结: 这篇文章详细介绍了作者对一个安卓应用中图片加密机制的分析过程。作者首先尝试了hook保存按钮,然后通过网络抓包获取图片URL,最终发现应用在缓存图片时使用了简单的加密方式——在JPEG文件中插入了重复的文件头。作者通过对比原始图片和加密图片的16进制数据,找出了加密原理,并编写了一个Python工具来解密这些图片。文章最后提供了工具下载链接。 综合评分: 91 文章分类: 逆向分析,移动安全,二进制安全
代码大致意思是,根据输入的字符串 str ,生成一个缓存图片文件对象( .jpg ),命名方式是图像的 MD5 值,再以固定后缀 _TRANSITION2.jpg 结尾,用于进行图像过渡或加密。但方法中并没有提到具体的加密算法。
那么我们如何逆向算法从而恢复文件呢?没错,我们可以把抓包得到的图片和这些损坏的图片进行对比,最后得出图片间的差异。
我们选取成对的图片进行比对,先用 MT管理器 的文本对比功能,发现损坏的文件比原始文件在数据开始部分新增了一段未知数据,其余的数据都是完全一致的,这与我们之前的推断重合。
那么究竟新增了哪些数据呢?直接比对文本全是乱码,我们无法直观清晰的看出。
这时我们还是要用到 16进制 。MT 虽然有16进制编辑器,但还未添加双文件16进制的比较功能。
(如果 Bin 能读到,希望能添加这个功能,目前安卓端好像还没有出现 16进制 比较软件,连在线网页好像都没有undefined)
那我们只能自己手搓脚本进行比对了。这里我们使用简单方便的 Python (实际上是不会写别的undefined) 来进行比对:代码传送门 (https://share.weiyun.com/aPuC1ZY2)
关于环境配置问题,这里稍微提几句。
安卓端可以下载 Termux 或 ZeroTermux,设置好了权限之后,安装 Python3 环境即可。
如果你不知道怎么设置和配置环境,这里强烈推荐 国光 大佬的 Termux 教程,当时我就是这样学会的,是目前我看到最系统最完整的 Termux 教程,而且完全免费,大佬牛逼!国光大佬教程链接:Termux 高级终端安装使用配置教程 (https://www.sqlsec.com/2018/05/termux.html),为方便各位学习,我也会将珍藏多年的 Pdf 离线版本放在文末,各位可以自由下载。
总之,配置好环境后,运行脚本,输入前后文件名,脚本就会自动比对16进制并输出结果。
照这样把三组文件比对完,我们就可以分析添加的数据了。
我们拿一份来举例:
这是损坏图片的部分16进制:
---------- 文件一(损坏图片) ----------16 进制:00000000: FF D8 FF DB 00 84 00 08 06 06 07 06 05 08 07 07 |................|00000010: 07 09 09 08 0A 0C 14 0D 0C 0B 0B 0C 19 12 13 0F |................|00000020: 14 1D 1A 1F 1E 1D 1A 1C 1C 20 24 2E 27 20 22 2C |......... $.' ",|00000030: 23 1C 1C 28 37 29 2C 30 31 34 34 34 1F 27 39 3D |#..(7),01444.'9=|00000040: 38 32 3C 2E 33 34 32 01 09 09 09 0C 0B 0C 18 0D |82<.342.........|00000050: 0D 18 32 21 1C 21 32 32 32 32 32 32 32 32 32 32 |..2!.!2222222222|00000060: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|00000070: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|00000080: 32 32 32 32 32 32 32 32 FF C0 00 11 08 03 7B 02 |22222222......{.|00000090: D0 03 01 22 00 02 FF D8 FF DB 00 84 00 08 06 06 |..."............|000000A0: 07 06 05 08 07 07 07 09 09 08 0A 0C 14 0D 0C 0B |................|000000B0: 0B 0C 19 12 13 0F 14 1D 1A 1F 1E 1D 1A 1C 1C 20 |............... |000000C0: 24 2E 27 20 22 2C 23 1C 1C 28 37 29 2C 30 31 34 |$.' ",#..(7),014|000000D0: 34 34 1F 27 39 3D 38 32 3C 2E 33 34 32 01 09 09 |44.'9=82<.342...|000000E0: 09 0C 0B 0C 18 0D 0D 18 32 21 1C 21 32 32 32 32 |........2!.!2222|000000F0: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|00000100: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222|00000110: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 FF C0 |22222222222222..|00000120: 00 11 08 03 7B 02 D0 03 01 22 00 02 11 01 03 11 |....{...."......|00000130: 01 FF C4 01 A2 00 00 01 05 01 01 01 01 01 01 00 |................|下方省略...
以下是损坏图片和正常图片的对比结果:
---------- 对比结果 ----------文件一 vs 文件二 块级差异: 偏移 0x00000096-0x00000121 (文件一) 0x00000096-0x00000096 (文件二,损坏图片) -> reduce 文件一减少部分: 00000096: FF D8 FF DB 00 84 00 08 06 06 07 06 05 08 07 07 |................| 000000A6: 07 09 09 08 0A 0C 14 0D 0C 0B 0B 0C 19 12 13 0F |................| 000000B6: 14 1D 1A 1F 1E 1D 1A 1C 1C 20 24 2E 27 20 22 2C |......... $.' ",| 000000C6: 23 1C 1C 28 37 29 2C 30 31 34 34 34 1F 27 39 3D |#..(7),01444.'9=| 000000D6: 38 32 3C 2E 33 34 32 01 09 09 09 0C 0B 0C 18 0D |82<.342.........| 000000E6: 0D 18 32 21 1C 21 32 32 32 32 32 32 32 32 32 32 |..2!.!2222222222| 000000F6: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222| 00000106: 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 |2222222222222222| 00000116: 32 32 32 32 32 32 32 32 FF C0 00 11 08 03 7B 02 |22222222......{.| 偏移 0x00000122-0x00000128 (文件一) 0x00000097-0x00000097 (文件二) -> reduce 文件一减少部分: 00000122: 08 03 7B 02 D0 03 01 22 00 02 11 01 03 11 01 FF |..{...."........| 偏移 0x00000129-0x0000012E (文件一) 0x00000098-0x00000098 (文件二) -> reduce 文件一减少部分: 00000129: 22 00 02 11 01 03 11 01 FF C4 01 A2 00 00 01 05 |"...............|
由于代码写的较烂,连续修改的地方输出时会中断,请各位谅解。
为了防止看不懂输出信息,这里也有必要普及一下 JPEG 编码协议的概念。
实际上,JPEG 文件就是许多“小盒子”摞起来
想象 JPEG 是一摞快递盒,每个盒子上都贴着标签(段标记,Marker),告诉你里面装的是啥:
有的装“照片基本信息”(宽、高、颜色分量)、有的装“缩略图”、有的装“真正的压缩图像流”、有的装“注释”。 每个标签都是两字节,十六进制表示,固定以 FF 开头。
假设有一张 JPEG 图片,你能看到这样的文件头:
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 01 00 48 00 48 00 00 …
-
FF D8—— 这是 SOI,永远打头,相当于“身份证照片页”。 -
FF E0—— 这是 APP0 段标记。 -
00 10—— 本段长度 16 字节(含长度本身占的 2 字节)。 -
4A 46 49 46 00—— ASCII 就是 “JFIF\0”,说明它符合 JFIF 标准(最普遍的 JPEG 子格式)。 -
后面几个字节告诉你版本号、密度单位、缩略图尺寸等,不重要先跳过。
继续往下,你大概率还会见到:
FF DB(量化表)、FF C0(SOF0,里面藏着宽高)、FF C4(哈夫曼表)、FF DA(SOS,紧跟着就是真正的压缩流,直到文件尾巴)。最后两个字节一定是 FF D9(EOI),表示“照片到此结束”。
那么现在你懂了吗?通过分析图片比对信息,我们可以发现,这张图片存在两个 SOI。
偏移 0x0000: FF D8 ← 第一个 SOI,正常偏移 0x0090: FF D8 ← 又一个 SOI,绝对不应该出现。损坏图片前面(0x8C-0x8F)刚好是上一个 SOF0 段的末尾。也就是说,第一个帧的语法还没结束就被强行截断,导致结构错位。从 0x0090 开始,某对把同一张图的 DQT、SOF0、DHT、SOS 又原样复制了一份,最后导致图片解析错误。
所以,0x0090 处的第二个 FF D8 是非法的,应把它连同后面那份完全重复的 DQT/SOF/DHT/SOS 全部删掉,只保留 0x0000–0x008B 那一段,再在后面接上原来真正的 SOS 数据(0x02D8 开始),文件才能合法。
后续分析其他的损坏图片文件,其实它们都是这样的。知道了解决方法,那现在就可以来解决问题了。
我们在 16进制编辑器 中,尝试将多余的文件头删去,发现图片复原。
在电脑上看,其实更加明显,这里使用的工具是 Beyond Compare 5 。
至此,整个逆向分析过程结束。
我们完全可以通过编写脚本或插件的方法,来还原某对加密的图片文件,从而达到保存图片至相册的效果。我自己写了一个 Python 小工具,名叫 kuai_jpg_recover ,支持命令行参数和互动,无需安装任何额外库即可使用。目前准备开源,待开源后我也会把仓库链接贴到本文。代码链接: https://share.weiyun.com/ioNt9OKR,大家也可以在文末下载。
这个功能也会集成在即将发布的 某对模块 中,请各位敬请期待
脚本演示:
解密前:
解密后:
可以看到,所有的图片均被解密成功。
感谢大家的阅读!虽然这种图片加密非常简单,但也是一次宝贵的经验。
我的模块预计再过几天才能完工,闲暇时先写个帖子分享一下自己的体验。
码字不易,点赞可有?
帖子内所有工具及原包都已放在下面,各位自取。
最后,恭祝各位国庆快乐!
Python工具 (kuai_jpg_recover和hexdiff):
https://jiguro.lanzouw.com/ivxzB37hc9od
Termux入门指南:
https://jiguro.lanzouw.com/iV55d37hca3i
原包和其他工具:
https://jiguro.lanzouw.com/iILwS37hc9mb
·今 日 推 荐·
本文内容来自网络,如有侵权请联系删除
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:逆向有你 JiGuro《安卓逆向 — 【解密实战】简单的图片加密分析》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论