介绍

本文针对 Android 平台的微信应用。

一般来说,手机闪存的路径为 storage/emulated/0/,微信文件夹位于闪存的 Tencent/MicroMsg/ 目录下。

Tencent/MicroMsg/ 目录下,有一个由字母和数字组成的长度为 32 字节的文件夹,消息里的图片和视频都会保存到这个文件夹中;

当你在微信聊天中长按图片或视频点击「保存」时,这些图片或视频又会被保存到 Tencent/MicroMsg/ 目录下的 WeiXin 文件夹中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Tencent
├─MicroMsg
│ ├─由 32 个字母和数字组成的目录
│ │ ├─image2 <-- 消息中的图片保存位置
│ │ │ ...
│ │ │
│ │ ├─video <-- 消息中的视频保存位置,包括自己录制的小视频
│ │ │ 191538241116e34a53c87982.jpg <-- 对应小视频的缩略图
│ │ │ 191538241116e34a53c87982.mp4
│ │ │ 202131031216e34a53c197510.jpg <-- 对应小视频的缩略图
│ │ │ 202131031216e34a53c197510.mp4
│ │ │ ...
│ │ └─...
│ ├─WeiXin
│ │ │ 1482227010527.mp4 <-- 手动保存的小视频
│ │ │ mmexport1482227010527.jpg <-- 手动保存的图片
│ │ │ wx_camera_1482227020527.mp4 <-- 自己拍摄的微信视频
│ │ │ ...
│ │ │
│ │ └─...
│ └─...
└─...

对于想备份的视频和图片,文件名看似杂乱无章,也不好区分个时间。如果像 Dropbox 备份的规则一样,把文件名改为 2016-12-21 12:30:55.jpg 这样多好啊!

接下来,重命名

其实 WeiXinvideo 两个文件夹下的文件命名是有规则的。

  1. 重命名 WeiXin 文件夹下的文件

WeiXin 文件夹下手动保存的视频文件其实是由 Unix 时间戳来命名的,1482227010527 转换为可读时间为 2016/12/20 17:43:30。图片文件无非就是在这个时间戳上又加了个 mmexport 前缀,自己拍摄的视频文件加了 wx_camera_ 前缀。

但是,手动保存的视频和图片的时间戳是你保存那一刻的时间,不是你收到这个图片或视频那一刻的时间。好吧,如果不在意这个时间的话,那就写个 Python 脚本 重命名吧。

  1. 重命名 video 文件夹下的文件

video 文件夹下图片和视频是成对存在的,同名的图片是视频的缩略图。如果发现只有一个图片而没有对应的视频,那是因为你在微信聊天中长按删除了视频。

这些视频和缩略图的命名也是有规则的,以 191538241116e34a53c87982.mp4 为例。

1
2
3
4
5
19 15 38 24 11 16 e34a53c87982.mp4
%H %M %S %d %m %y
翻译过来就是:
2016-11-24 19.15.38
这个时间是你收到小视频那一刻的时间

因为 video 中包含了微信聊天中收到的所有小视频,所以 WeiXin 文件夹下的视频是它的一个子集。而且!这里的小视频时间戳可以认为就是录制时的时间。 对于强迫症的我们,这是多么值得激动的事情!赶紧写个 Python 脚本 重命名吧!


以后备份,就可以只用备份微信 video 下的视频和 WeiXin 下的图片了。

一、理解旁路攻击

在前几年的工作里,对智能卡(或者说芯片卡、CPU 卡,比如 SIM 卡、芯片银行卡、社保卡等,另外 USBKEY 也属于智能卡的一种)的安全研究比较多,主要攻击智能卡中加密算法,获取算法密钥,验证智能卡安全性。用到的攻击手法就是本文要说的旁路攻击,英文名称是 Side Channel Attacks,也有的翻译成“侧信道攻击”或者“边道攻击”,它们都是一个意思。

首先谈谈我对旁路攻击中“旁路”的理解,不论是对硬件、系统还是网络的攻击,最方便也是最直接的攻击手段是直接读取其中的信息,比如账号的密码。若此路不通,则需另辟他路,这种通过“他路”进行攻击的手段就可以叫做“旁路”攻击。

以破解某人邮箱为例,如果碰巧通过社工库找到了他泄露过的密码而撞库成功,这是最理想的。而通过 XSS 获取到了其登录邮箱的 Cookie 从而登录其邮箱的途径,可以理解为“旁路”。

再看看下面这张图,直接拿到锁的钥匙打开抽屉,是最理想的攻击途径。而通过图中的方法拿到被锁抽屉中的东西,就是“旁路”攻击了。《研究人员利用旁路攻击窃取Android和iOS上的密钥》的这篇文章,也是属于旁路攻击的一种。

旁路攻击举例

对智能卡的旁路攻击,是上世纪 90 年代末提出的。攻击者在智能卡的 VCC 或 GND 上串联一个小的电阻,使用示波器测量该电阻上的电压降,测量的电压降和芯片的能量消耗成正比,因此可以将电压降作为能量消耗来处理,并将对应的曲线波形视为功耗曲线。同样的道理,探测电磁变化获取智能卡芯片的功耗曲线也能进行攻击。这类旁路攻击叫做能量分析攻击(Power Analysis Attack)。攻击设备的物理连接示意图如下所示:

能量分析攻击物理连接示意图

能量分析攻击的基本思想是通过分析密码设备的能量消耗获得其密钥。这种攻击利用了两类能量消耗依赖性:数据依赖性和操作依赖性。因为密码设备的瞬时能量消耗依赖于设备所处理的数据和设备所执行的操作。

现在进行旁路攻击需要一套价格不菲的攻击设备。经过十几年的发展,攻击设备厂商也不再局限在国外,源于上海交大的观源信息算是国内厂商的后起之秀,郁昱教授在多个安全大会上也演示了如何克隆 SIM 卡。

二、能量分析攻击

1. 定义

能量分析攻击又分为简单能量分析攻击差分能量分析攻击。在《智能卡安全与设计》一书中对这两种攻击方法的描述比较准确:

简单功耗分析(Simlpe Power Analysis, SPA)攻击:从密码芯片运算的功耗波形上能够直接找出一切密钥信息的攻击方法。因为在芯片中,密钥位为 0 时运算的功耗和密钥位为 1 时运算的功耗存在差异,通过这样的差异分析出密钥位的值,按照一定规律组合得到完整的密钥。

以下图为例,使用 SPA 就可以从芯片的功耗曲线中可以读出十六进制的关键数据。

SPA图示

差分功耗分析(Differential Power Analysis, DPA)攻击:需要知道算法的明文(输入)和密文(输出),通过对一系列的功耗轨迹进行分析和计算,重现加密密钥的攻击方法。

DPA 的主要任务在于找出密钥参与运算时的功耗和密钥位的相关性,而不是直接得到密钥位的值。这个解释起来比较复杂,下面以分析 DES 算法为例讲解 DPA 的原理。

2. DPA 攻击原理

在《能量分析攻击》一书中,作者以 AES 为例分析了 DPA 原理和攻击过程,下面以 DES 算法为例进行说明。

首先分析一次 DES 加密操作的功耗与明文第一个字节最高有效位 MSB 之间的依赖关系,记该比特为 d。为了确定 d 对功耗的影响,测量芯片分别加密 1000 个随机明文时的功耗。因为明文是随机的,d 也就是随机的,这样可以获得约 500 条 d = 0 时加密操作的功耗曲线,以及约 500 条 d = 1 时加密操作的功耗曲线。

确定 d 对功耗影响的一个简单方法就是计算平均值之差,即分别计算所有 d = 0 的功耗曲线的平均值与所有 d = 1 的功耗曲线的平均值,获得一条 d = 0 的平均功耗曲线和一条 d = 1 的平均功耗曲线。接下来,将这两条平均功耗曲线做减法运算,得到一条功耗曲线,称为差分功耗曲线。

观察差分功耗曲线,几乎这段时间内的所有时刻,其电压值都接近于零,但有几个特别突出的尖峰。这些尖峰表明了芯片功耗依赖于 d 中的那些时刻。在这一时刻,芯片所执行的指令要么直接对 d 进行处理,要么所处理的某些数据依赖于 d。在这一时刻,d 的相关性是最高的。

芯片的运算会直接或间接地依赖于 d 的指令,通过对上面尖峰出现位置的分析,说明芯片的能量消耗中包含它所处理数据的信息,在能量分析中利用这一特性,就可以确定出芯片使用的密钥。

3. DPA 分析过程

DES 加密共 16 轮,有效密钥 56 位,这 56 位密钥生成 16 轮子密钥参与各轮次的运算,每轮子密钥 48 位。如果已知 DES 前两轮或最后两轮的子密钥,就可以恢复出 DES 完整的密钥。

这样一来,我们的目标拆分为攻击前两轮(或最后两轮)的子密钥。

先来分析第一轮的过程。32 位明文经过扩展变换后与 48 位轮密钥进行异或,然后进入 S 盒。S 盒共 8 个,每个 6 位输入,4 位输出。

S盒

我们关注第一个 S 盒:S1S1 的每一个输出位都可以通过明文的 6 位和密钥 6 位来获得。将参与 S1 运算的 6 位明文记为 p,6 位密钥记为 k。因此,S1 操作对应的输出可以记为 S(p⊕k)。在所给出的攻击实例中,都利用了如下事实:芯片在某个时刻的能量消耗依赖于这一输出字节的最高有效位 v,其中,v = MSB(S(p⊕k))

进行这个攻击与之前已经完成的对值 d 的分析过程非常相似。首先,加密 1000 个随机明文,记录相应的能量消耗。此后,将功耗曲线划分为两组:v = 1 的功耗曲线与 v = 0 的功耗曲线。与先前已经完成对明文比特d的分析不同,此时中间值 v 依赖于密钥字节 k

最初,攻击者并不知道 k。然而,攻击者可以对 k 进行猜测,实际上,k只有 64 个可能值。因此,攻击者能够很容易地遍历所有可能的 k 值,并使用这些值来计算 v。在实际的攻击中,这意味着首先猜测 k = 0。基于这一猜测,对于 1000 次加密操作的每一次,分别计算对应的 v。然后,攻击者分别计算 v = 1 的功耗曲线平均值和 v = 0 的功耗曲线平均值。这样就可以绘制出两条平均功耗曲线之间的差异曲线。对于所有其他 63 个可能的密钥值,重复同样的过程。这样,攻击者就可以获得 64 个差异曲线。对于每一个密钥猜测,都有一个与之对应的差分曲线。
在 64 个猜测中,当猜中 k 时,就已经正确计算出了 v。因此,该密钥猜测对应的差分曲线实际上说明了芯片能量消耗对 v 的依赖性。由于这种依赖性的存在,对应的差分曲线中就会有明显的尖峰。

一个重要的问题是:如果基于一个错误的密钥猜测计算 v,会出现什么情况呢?这种情况下,所计算出的v值将功耗曲线划分为两组(v = 1v = 0),但是芯片没有处理这些计算所得到的 v 值。因此,能量消耗就不会依赖于这些值,所以对应的差分曲线中就不会有大尖峰出现。

同理,依次猜测 S2、S3……S8 参与运算的密钥位,就可以获得第一轮的 48 位子密钥。

再同理获得第二轮子密钥,然后组合这两轮子密钥还原为 DES 完整密钥。

使用这种策略的攻击称为差分能量分析(DPA)。这种攻击利用了这样一个事实:密钥设备的能量消耗依赖于算法执行过程中所处理的中间值。上面的攻击分析中,已经利用过这样一个事实:芯片的能量消耗依赖于第 1 轮中 S 盒的输出数据的 MSB。同样,攻击者也可以利用其他的中间值来实施攻击。特别地,攻击者可以利用依赖于其他密钥字节的中间值来实施攻击,这样就可以很容易地恢复出完整的 DES 密钥。

4. 其他说明

对称算法与非对称算法的 DPA 攻击原理不同,CRT 方式实现的 RSA 算法攻击的是 CRT 的组合阶段。

另外,除 SPA 和 DPA 之外,其实还有一种叫做错误注入(DFA)的攻击手段,也属于能量分析攻击,这里不再介绍。

参考资料

  1. 张之津等著《智能卡安全与设计》,清华大学出版社
  2. [奥]Stefan Mangard 等著,冯登国等译《能量分析攻击》科学出版社

“It’s a good day, isn’t it?”

我们先从天气说起。

天气是不是随机的呢?如果让我们猜明天会不会下雨,我们十有八九能猜对,因为现有的科技可以做到精准预测,因此可以说明天的天气不是随机的。

如果让我们猜100年后的这一天会不会下雨,那就不好猜了,科技还无法做到,但这也不能认为100年后这一天的天气是随机的,因为不排除未来的科技能够预测。

在经典物理中,是不存在真随机的,因为经典物理量是可以测量和预测的。那在量子力学中呢?因为科技所限,也不能确定量子力学中是否存在真正的真随机。

也就是说,真正的真随机存在性还不确定。我们通常说的真随机数是指另外一个意思,满足统计意义上的随机,一般是由硬件的随机数产生器生成的。在能够提供随机数的智能卡中,一般会有一个硬件的随机数发生器。在计算机中,操作系统可以根据非确定的设备事件来生成真随机数,比如时钟、IO请求的响应时间、特定硬件中断的时间间隔、键盘敲击速度、鼠标位置变化等等。

这样一来,我们可以说自己使用的随机数发生器(硬件或软件)是真随机的,那怎么让别人信服呢?因此需要一个判定随机数是否满足真随机条件的标准。比如应用较广的随机序列统计测试方法—— NIST(National Institute of Standards and Technology,美国国家标准与技术研究所)Special Publication(800 Series),简称 NSP 800。

NSP 800 测试程序是一个统计学包,可以到 NIST 官网下载,该工具包括 15 种测试手段。这些测试手段可测试由用作保密随机或者伪随机数发生器的硬件和软件产生的任意长的二进制序列的随机性。每个测试项都是针对被测序列的某一特性进行检测的,其中一些测试又可以分解成多种子测验。

这 15 种测试手段及其对应的检测目的如下:

  1. 频率测试:检测整个序列中的 0、1 是否趋于等概率,如果是,则序列是随机的。
  2. 块内频率测试:检测每个子序列中的 0、1 是否趋于等概率,如果是,则序列是随机的。
  3. 累积和测试:检测序列的正向、反向累加和以反映0、1在序列中的分布是否均匀,太大或太小都是非随机的。
  4. 游程测试:检测序列中游程(一个没有间断的相同数序列,或者是 “1111…” 或者 “0000…”)的数目是否如真随机序列期望的那样,接近序列长度的一半,如果是,则序列是随机的。
  5. 块内最长游程测试:检测子序列中最大长 “1” 游程的长度是否与真随机序列中的长度近似一致,如果是,则序列是随机的。
  6. 二元矩阵秩测试:检测序列中固定长度子序列的线性相关性,如果线性相关性较小,则序列是随机的。
  7. 离散傅立叶变换测试:检测序列进行离散傅立叶变换后的频谱是否趋于均匀分布;做法是观察超过95%阈值的峰值数目与低于 5% 峰值的数目是否有显著不同,如果接近,则序列是随机的。
  8. 非重叠模块匹配测试:检测序列中的子序列是否与太多的非周期模板相匹配,太多就意味着序列是非随机的。
  9. 重叠模块匹配测试:检测序列中重叠模块(特定长度的连续 “1”)出现的次数,是否与真随机序列的情况偏离太大,太大则是非随机的。
  10. 通用统计测试:检测序列是否能在信息不丢失的条件下明显压缩,一个不可被明显压缩的序列是随机的。
  11. 近似熵测试:检测序列中相邻长度(m 和 m+1)的重叠子块的频数,是否与随机情况下预期的频数相近似。
  12. 随机游动测试:统计各个游程中某个特定状态出现的次数,检测其是否远远超过真随机序列中的情况,如果是,则序列是非随机的。
  13. 随机游动状态频数测试:检测序列中,某一特定状态在一个随机游程中出现的次数与真随机序列的偏离程度,如果偏离程度较大,则序列是非随机的。
  14. 序列测试:检测指定长度的所有子序列出现的次数是否趋于等概率,如果是,则序列是随机的。
  15. 线性复杂度测试:检测每个子序列的线性复杂度是否达到可视为是随机序列的程度。

李璞根据 NIST 官方网站的说明书编译了中文的《NIST随机数测试》,详细介绍了每种测试手段的数学原理,有兴趣的朋友可以去了解一下。

NSP 800 随机数测试套件需要在 Linux 中使用 make 编译,生成 access 可执行文件后使用,测试完成后会在 experiments 目录中生成测试报告。该套件的使用方法请见本文附件。

有意思的现象是,由同一个随机数生成器产生的不同批次的随机数测试结果有可能不同。第一组随机数有一项未通过,第二组有可能全部通过,因此在实际操作中,同一个随机数生成器会产生三组随机数,只要有两组通过了测试,那就可以判断这个随机数生成器是满足条件的。

附上曾经整理的 NSP 800 套件的使用文档
https://github.com/gymgle/gnotes/blob/master/attachments/NSP800-Guide.pdf

0%