引入动态内存分析的微信撤回消息恢复方法

2021-12-12 02:51倪雪莉梁广俊
计算机工程与应用 2021年23期
关键词:镜像文件字段字节

倪雪莉,梁广俊

1.江苏警官学院 计算机信息与网络安全系,南京 210031

2.江苏省电子数据取证分析工程研究中心,南京 210031

3.江苏省公安厅 数字取证重点实验室,南京 210031

根据微信团队发布的《2019年微信数据报告》统计,2019年微信平均月活跃账户数达到11.5亿,位居新型即时通信平台的首位[1]。作为一种广受用户青睐的网络传媒工具,微信整合了电子邮件、网上聊天、博客、网上购物、网络支付等众多通信功能,其功能越来越丰富,应用范围越来越广泛。与此同时,从信息安全的角度考虑,尤其针对电子数据取证,微信无疑成为一个庞大的证据库[2]。2019年12月26日,《最高人民法院关于修改<关于民事诉讼证据的若干规定>的决定》颁布并从2020年5月1日起生效,标志着国家最高审判机关正式在司法解释中确认了微信微博聊天记录的证据位,微信聊天记录等信息在诉讼中作为证据出现的频率将会越来越高。

相对于传统形式的证据,微信聊天记录作为一种电子数据要想具有相应的证明效力,成为认定案件事实的依据,必须满足真实性、合法性和关联性等基本要求[3]。微信自2014年发布的v5.3.1版本开始,便推出了消息撤回功能,用户可以选择撤回在2分钟内发送的消息,该特征在方便了用户的同时,却降低了微信证据内容的完整性,在诉讼中可能难以达到证据真实性的要求[4]。

近年来,研究人员开始从存储介质、事件日志、文件系统、数据库等方向着手研究微信消息的恢复方法。文献[5]提出了一种基于SQLite3文件格式的删除数据恢复方法,通过识别SQLite3文件格式,收集数据页中的自由块和未使用空间,最后选择不同类别的恢复算法实现了删除数据的恢复;文献[6]通过获取Android手机中的数据库文件和解密密钥,在SQLite数据库环境中提取出用户的微信信息,其中包括聊天记录、联系人列表等,但该方法无法还原被删除的聊天记录;文献[7]提出了一种基于KNN(K-Nearest Neighbor)算法的Android微信取证方法,该方法引入词语相似度计算会话间的距离,将会话表示成特征词的向量,用KNN算法对会话进行分类,迅速找到有关的聊天内容,但同样无法找到被删除或撤回的消息记录;文献[8]通过逆向分析技术研究,获知了微信等热门应用的密钥生成算法以期破解加密的SQLite数据库;类似的,文献[9]分析了微信数据库的加密算法和密钥推导原理,并给出了不同取证环境下的数据库解密过程,最终实现了语音和删除消息的恢复;文献[10]对微信内存文件中的特征变化进行分析,在一定程度上能够通过特征值盲搜恢复部分文字、表情类消息,但并未对撤回消息的存储原理进行研究,同时,该研究成果只适用于文本类消息,未实现图片类消息的恢复。

传统的移动智能终端即时通信应用的取证研究主要集中在取证流程和基础数据的提取上,这类取证分析存在流程规范不严谨、提取数据不完整等问题[11]。在微信取证技术的研究中,基于本地微信数据库的研究占据了主流,而对微信运行过程中动态内存的研究成果较少[12]。对于微信聊天记录恢复的研究,目前的讨论也大多集中在如何尽可能多地恢复被删除的记录,而对于被撤回消息恢复的理论研究和技术实践,目前尚未形成完善的体系。在针对微信平台的取证实践过程中,仅通过本地微信数据库恢复方法提取到的聊天记录往往是不完整的,其中并不包含用户的撤回消息,这显然无法满足诉讼中对于证据完整性、真实性的要求。

经研究发现,内存中存在大量的缓存应用数据,这些数据具有极大的取证价值[13]。通过实践发现用户的撤回消息在微信内存中有迹可循。因此,本文通过对微信内存的获取和分析技术展开研究,基于PC版微信撤回消息在动态内存中的存储原理,提出了一种针对微信文本、表情、图片等多种类型撤回消息进行恢复的方法,并通过Python语言开发的工具,验证了该方法的有效性和可行性。同时,该工具可直接应用于微信取证场景。

1 PC中微信运行内存的获取

内存分析在数字取证分析中扮演着越来越重要的角色,可以用来检索加密密钥或分析仅驻留在RAM中的恶意软件。一般情况下,在分析之前需要获取内存中的信息[14]。

针对微信内存镜像数据提取,目前通用的方法主要有两类:一是使用ProcDump工具提取,二是使用Windows操作系统自带的管理工具提取。将两种工具提取到的镜像文件进行对比分析,以确保提取到完整的动态内存文件。

1.1 利用ProcDump提取内存镜像

ProcDump是一个轻量级的命令行工具,可以嵌入到其他脚本中进行进程内存镜像的转储。使用该工具通过微信的进程号对微信进程进行转储,具体实现步骤如下:

(1)在命令提示符界面中输入“tasklist”命令,找到微信应用的PID(Process ID,进程ID号),如图1所示。

图1 微信进程号Fig.1 PID of WeChat

(2)使用ProcDump的“-ma”参数,创建一个进程的转储文件,包括该进程所有线程以及句柄等信息,如图2所示,此时ProcDump程序已经为微信创建了内存文件,存储在D盘Procdump目录下。

图2 微信内存转储文件Fig.2 Memory dump of WeChat

1.2 利用任务管理器提取内存镜像

Windows 10操作系统中自带的任务管理器也提供了转储程序内存、生成镜像文件的功能,其转储微信内存步骤如下:

(1)打开任务管理器并转到详细信息,选中需要转储的应用,右击创建微信内存转储文件。

(2)转储完成后微信内存文件的默认存放地址为C:Users[Administrator]AppDataLocalTemp,其中[Administrator]字段为当前计算机用户名,该文件的名称为WeChat.DMP。

1.3 两种内存镜像文件对比

将分别用ProcDump和Windows自带工具提取到的文件进行对比,发现利用Windows任务管理器创建的内存镜像比ProcDump创建的镜像文件略大一些,分别如图3(a)和(b)所示。究其原因,内存提取所使用的Windows操作系统为64位,该系统自带的任务管理器创建的转储文件也是64位,其中包含了WoW64子系统的信息。但是,ProcDump工具创建的内存转储文件默认为32位,不包含WoW64子系统的信息。而PC版微信是一个32位程序,在用两种方式创建内存转储文件时会产生差异,因而任务管理器创建的包含WoW64子系统信息的内存转储文件比ProcDump创建的不包含WoW64子系统信息的内存转储文件略大一些。

图3 三个镜像文件对比Fig.3 Comparison of three image files

使用ProcDump的“-64”参数再创建一个转储文件,如图3(c)所示,该文件为微信64位的转储文件。图3(a)和(c)对比略有差异,主要是因为创建转储文件的时间不同而致,由于内存的变化非常快,细小的时间差异产生的内存转储可能包含不一致的数据,如果同时创建,两个文件之间将不会存在差异[15]。

因此可见,文献[10]直接通过ProcDump得到的微信内存镜像文件并不完整,会对后续内存的分析和消息的恢复产生影响,本文对采用ProcDump创建的微信64位内存镜像文件进行分析。

不同应用程序的数据具有异构性,但在内存中以一种通用的与应用程序无关的方式表示,因此可以跨各种应用程序对内存镜像进行通用分析[16]。使用WinHex十六进制编辑器打开上述DMP内存镜像文件,查看其16进制数据,具体如图4所示。其中,文件头为MDMP,对应的十六进制值为“4D 44 4D 50”。

图4 内存镜像十六进制数据Fig.4 Hexadecimal content of image file

2 微信撤回消息的存储原理

2.1 撤回消息的特征字符

在微信安装目录下有一个动态链接库文件WeChat-Win.dll,其中包含了消息撤回的函数,用于执行用户相关的撤回操作,撤回函数相关的关键词为“revokemsg”,如图5所示。

图5 “revokemsg”关键词Fig.5 Keyword“revokemsg”

因此,在微信的内存镜像文件中,撤回消息的特征字符为“revokemsg”,也就是说,每一段撤回消息在内存中的位置都与一对特征字符标签“<revokemsg>”“</revokemsg>”相关,如图6所示。

图6 特征字符在内存中的体现Fig.6 Representation of characters in memory

2.2 撤回消息字段结构

撤回消息在内存中的具体字段结构如图7所示,分为消息头与消息体。其中消息头中存放该条撤回消息的一些属性信息,如,消息的撤回方、ID、撤回状态等,消息体中则直接存放该消息的内容。

图7 撤回消息字段结构Fig.7 Field structure of revoking message

每段撤回消息都伴随<revokemsg>和</revokemsg>标签对出现,该标签对中间内容为消息撤回后用户的聊天窗口显示的提示消息。若为本用户撤回,则内容为:“<![CDATA[你撤回了一条消息<a href=“weixin://revoke_edit_click”>重新编辑</a>]]>”,其中“重新编辑”是一条指向性的链接,给本用户提供重新编辑撤回消息的接口。若消息为聊天对方用户撤回,则内容为:“"xxx(微信昵称)"撤回了一条消息”。因此,可以根据该字段内容的不同形式判断该消息是由本用户撤回还是他人撤回,尤其在微信群中,能直接定位群中的某个成员(昵称),如图8所示。

图8 revokemsg标签对间的消息解析Fig.8 Message parsing between revokemsg tag pairs

在<revokemsg>标签之前的字段为通信对方的微信ID或所在微信群的群ID,个人微信ID以字符“wxid”为开始标志,而微信群ID以字符“@chatroom”为结束标志,通常这个ID占18~20位。通过该字段的解析,能够获知该撤回消息属于哪个聊天对话窗口。

若为微信群,在</revokemsg>标签之后依次为消息撤回者的微信ID,及群属性信息,如该群中设置消息屏蔽的人数、该群的总人数等。若为聊天个人,在</revokemsg>标签之后直接为一段固定的32位Hash密文的字符串。其中对于消息撤回者微信ID的解析尤为重要,能准确定位到该群中的某个成员(较之昵称ID辨识性更高、更准确)。

值得注意的是,在微信内存中以字符“1A”为分隔符(见图9),分隔撤回消息的各字段,“1A”后一个字节表示该字段的总长度,单位为字节。其后为该字段含义的标志位,具体含义如表1所示,字段标志位后一个字节表示该字段内容的长度,单位为字节。由此,可得知每个字段的开始结束位置,如“08 04 12”标志后即为撤回消息的长度及内容。

图9 分隔符及标志位Fig.9 Separators and flag bits

表1 字段标志位含义Table 1 Meanings of flag bits

2.3 撤回消息在内存中的体现

微信聊天记录主要包含的消息类型有:文本、表情、图片等,而不同类型的撤回消息,在内存中的体现形式不一。

2.3.1 文本消息

对于文本类消息,微信在通信过程中使用UTF-8的编码方式编码文本字符。如图10中划线的十六进制字符:“E4 BA BA E7 94 9F E5 AE 9E E5 A6 82 E9 92 9F E6 91 86 EF BC 8C E5 9C A8 E7 97 9B E8 8B A6 E4 B8 8E E5 80 A6 E6 80 A0 E4 B9 8B E9 97 B4 E6 91 86 E5 8A A8 E3 80 82”,通过UTF-8解码得到中文字符“人生实如钟摆,在痛苦与倦怠之间摆动。”,如图11所示。

图10 撤回的中文字符在内存中的体现形式Fig.10 Representation of Chinese revoking message in memory

图11 撤回消息的UTF-8解码Fig.11 UTF-8 of revoking message

2.3.2 表情消息

对于表情类消息,微信将资源内部的表情转换为文本进行存储,转换形式为文本“[表情名字]”,如“[奸笑]”,再将此文本以UTF-8的编码方式编码。如图12所示,十六进制表情消息内容经过UTF-8解码后为“[奸笑][奸笑][奸笑]”,即为表情消息。

图12 撤回的表情消息在内存中的体现形式Fig.12 Representation of revoking emojis in memory

2.3.3 图片消息

对于图片类消息,与文本和表情类消息的存储方式完全不同,图片消息一经发送即以DAT数据文件形式存放在计算机本地文件中,而在内存相应字段位置仅仅存放着指向该本地文件的路径,如图13。

图13 撤回的图片消息在内存中的体现形式Fig.13 Representation of revoking pictures in memory

因此,根据内存相应字段中的路径找到该图片的DAT数据文件即可。经研究分析发现,微信在通信过程中对接收到的图片文件按字节进行了异或加密处理,然后保存为DAT文件。异或加密算法是密码学中一种简单的对称加密算法,当需要进行解密时,只需将加密后的结果与密钥再次进行异或运算即可,加解密过程如公式(1)所示:

其中,M为原文,K密钥,E为密文。

每一个微信账号对应的密钥不同,可以尝试通过已知明文攻击来获得密钥。具体方法为:将明文JPEG图片的文件头“FF D8”与加密后的DAT文件(如图14)的前两字节“B6 91”,通过按位异或操作得到两个字节“4949”,由此可以判断出该DAT文件是使用字节“49”作为密钥进行图片加密处理的,此后该微信账号下所有的撤回图片消息的DAT文件,都可使用该密钥进行解密。

图14 密文DAT文件的部分数据Fig.14 Part of ciphertext of DAT file

经研究发现,该内存字段中指向的路径中存放的为图片的缩略图,完整的图片数据存储位置和撤回机制对发送方与接收方来说略有不同。

作为发送方,会在本地的WeChat Files[wxid]FileStorageImage[date]和WeChat Files[wxid]FileStorageImageThumb[date]文件夹下(其中[wxid]是以用户微信ID命名的文件夹,[date]是以日期命名的一个文件夹)各产生一个DAT文件,经过字节异或操作,前者会恢复为发送的原图,后者为缩略图。当用户在聊天框中点开这张图片时,会在WeChat Files[wxid]FileStorageTemp临时文件夹下生成一个DAT文件,而当用户点开下一张图片时,该临时文件下的DAT文件会被图片文件覆盖。当用户发起撤回操作时,三个文件夹下产生的文件均无变化。

作为接收方,图片的存储方式与上述相同,但当对方用户发起撤回操作时,WeChat Files[wxid]FileStorageImage[date]和WeChat Files[wxid]FileStorageImageThumb[date]文件夹下的DAT文件会消失,而WeChat Files[wxid]FileStorageTemp文件下产生的DAT文件无变化。

3 微信撤回消息的恢复过程

根据微信撤回消息数据的存储和恢复原理,本文提出了一种基于动态内存结构分析的撤回消息恢复方法,其恢复流程为(如图15所示):

(1)遍历内存镜像文件数据,提取所有特征码<revokemsg>的索引值,每出现一次特征码<revokemsg>则表示出现了一条撤回消息,提取该特征码后的各字段标志位的索引值,如标志位“08 04 12”的索引值为lenghIndex,后面的内容为撤回消息的长度及撤回消息。

(2)定位<revokemsg>之前的内容,即为通信对方的微信ID或所在微信群的群ID,提取该ID。

(3)读取<revokemsg>和</revokemsg>标签之间的内容,即为用户聊天面板上的提示消息。解码该消息,形式为“<![CDATA[你撤回了一条消息<a href="weixin://revoke_edit_click">重新编辑</a>]]>”或“"xxx"撤回了一条消息”,根据该消息形式来判断该条消息是由本用户撤回还是对方用户撤回。

(4)标志位“08 04 12”后面的一个字节为撤回消息的长度,单位为字节,计算每条撤回消息的长度length-Message。

图15 撤回消息的恢复流程图Fig.15 Flow chart of recovery of revoking message

(5)根据标志位“08 04 12”的索引值lengthIndex及消息长度lengthMessage计算消息的结束位置message-End,如公式(2)。将提取到的原消息字符段进行UTF-8解码操作即得到原消息内容。

(6)判断得到的该原消息字符串表示的是否为路径,若为路径,则表示该条撤回消息为图片,打开该路径指向的本地文件。

(7)将该本地DAT数据文件的前两个字节分别与“FF D8”进行异或操作,即得到图片加密的字节密钥,对DAT文件的每个字节与密钥进行异或操作解密,最后保存为JPG文件,即为成功恢复后的图片文件。

4 实验结果与性能分析

本章通过具体程序的实现来验证本文提出的恢复方法的可行性和有效性。由于本文的恢复方法基于微信内存镜像文件,而镜像文件在所有操作系统上都是二进制一致的,因此,本文提出的恢复方法与操作系统类型无关。

4.1 实验准备

针对微信内存镜像的获取以及撤回消息批量恢复的实验程序设计,选用了Python编程语言,在集成开发环境PyCharm中完成程序的设计与调试。Python版本号为3.8.2,PyCharm的版本号为PyCharm 2019.3.3(Professional Edition),PC版微信的版本号为微信2.9.5.41。

在获取微信内存之前,首先进行对话测试,其中撤回消息类型包含文字、表情及图片,如图16所示。

图16 撤回消息的对话测试Fig.16 Dialogue test for revoking message

4.2 实验过程

4.2.1 微信内存镜像获取

微信内存镜像获取首先需要获取到当前计算机中微信的进程号。导入psutil模块,使用其中的pids方法获取到当前所有进程的进程号,结合微信的进程名称“WeChat.exe”进行判断,获取微信的进程号。

使用Python3的subprocess模块中的call方法,调用外部的ProcDump可执行程序,对微信运行内存进行转储。

4.2.2 提取所有的特征码索引值

根据图7撤回消息的字段结构,先获取<revokemsg>标签在内存文件中的索引值,再根据<revokemsg>标签之前出现的微信ID以及<revokemsg>标签之后出现的</revokemsg>标签进行特征结构筛选,从而获取到微信内存文件中所有撤回消息特征字段的索引值。借助Python中提供的find方法,通过循环的方式(即每次找到特定字符串在原字符串中第一次出现的索引值,然后将索引下标进行加一操作,进入下一轮索引,直至索引下标到达原字符串中最后一个字符)找到特定字符串在原字符串中所有的索引值。

4.2.3 提取并解码撤回消息字段

每段撤回消息的内容前会出现唯一字段标志位“08 04 12”,根据特征结构中是否出现了标志位“08 04 12”对特征结构进行二次判断,如果其中没有出现标志位,则此特征结构不符合撤回文字和表情消息恢复条件。

在特征结构中如果出现了标志位“08 04 12”,则根据其后的一个字节获取撤回消息在内存中的长度,利用公式(2)提取出该消息。使用utf-8编码的解码方式对提取到的撤回消息字段进行解码处理,从而得到原始的撤回消息。

4.2.4 读取消息的撤回状态等信息

类似地,可以获得微信ID、微信群ID、微信群属性等。如可以找到<revokemsg>和</revokemsg>标签之间的内容,定义flagMessage列表,存放消息撤回的提示字符,由此可以判断该消息是由发送方撤回还是接收方撤回,最后返回一个由提示字符值组成列表。

4.2.5 解密加密图片密钥并恢复图片数据

若撤回消息为图片,读取该路径指向的本地DAT数据文件,将DAT文件的前两字节与图片头特征字节进行异或操作,得到加密的密钥字节,并对DAT文件全部字节用密钥进行异或操作解密,最后保存为JPG文件。

4.3 实验结果

上述实验程序的测试恢复结果如图17所示,可以得到完整的撤回消息,并可以得到发起消息撤回的用户微信ID等信息。

图17 程序运行结果Fig.17 Running result of program

经过多次实验发现,内存中虽然没有记录每条撤回消息的时间,但按照撤回时间的先后,内存中的数据按地址偏移量依次递增分布。成功恢复撤回消息后,根据撤回方信息(如微信(群)ID、昵称等),将撤回消息与微信聊天窗口中的聊天记录消息作顺序比对,即可获得完整的用户聊天记录。

4.4 性能分析

本节主要从微信撤回信息的类型(文本、表情、图片)、撤回状态和撤回方微信ID等多个方面,对本文方法与文献[10]提出方法进行综合对比分析,表2、表3列出了两种方法的性能比较。

表2 不同方法的恢复范围比较Table 2 Comparison of recovery range between different methods

表3 文本类消息的恢复性能比较Table 3 Comparison of recovery performance for text messages

由表2可知,文献[10]只能恢复文本、表情类撤回消息,而本文提出的恢复方法适用的撤回消息类型范围更广,恢复结果更全面。

以均能恢复的文本类消息为例,实验共撤回100条文本消息,综合考虑时间对于两种恢复方法的恢复率影响。由表3可知,在24小时内,随着撤回时间的推移,两种方法的恢复率均有所下降,但本文方法总体恢复率均高于文献[10]。

综上,本文提出的恢复方法在恢复范围及恢复率方面都具有显著优势,这是因为本文综合考虑了以下内容:(1)考虑了撤回消息在内存中的字段结构,由此得出消息的撤回状态及撤回方信息。(2)考虑了微信个人聊天以及群聊的不同情况,群聊中的撤回消息在内存中的结构更为复杂,由此得到的内容更为丰富。(3)考虑了图片类消息与文本、表情类消息在内存中的体现的异同:①图片类消息在内存中仅存放指向本地的路径;②发送方和接收方发送、撤回的图片消息在本地的存储方式不同;③微信在通信过程中将图片文件进行了异或加密操作。

5 结束语

自2019年12月26日最高法确认微信聊天记录可作为法庭证据以来,法律界和取证界针对哪些聊天记录可作电子证据、聊天记录如何提取等方面展开了热烈讨论。可以看出,今后微信微博记录等作为电子证据出现在诉讼过程中的概率将会越来越高[17]。但目前提取微信通信信息的方法主要以拍照、截图为主,电子数据检验、鉴定等专业技术方法使用较少[18]。本文通过分析微信运行的动态内存,研究了撤回消息在内存中的特征字符和字段结构,根据文本、表情、图片等类型的数据在内存中的不同体现形式,提出了一种基于动态内存分析的PC版微信撤回消息的恢复方法。该方法除了可以恢复不同类型的撤回消息外,还可以通过分析撤回状态,获知消息的撤回方微信ID等信息。

本文方法还存在一些不足:(1)仅仅恢复了PC版微信中被撤回的文本、表情和图片类消息,对于移动端的恢复尚未取得有效的研究成果;(2)微信内存动态变化,实际的恢复效果根据撤回的时间长短存在差异。

猜你喜欢
镜像文件字段字节
图书馆中文图书编目外包数据质量控制分析
No.8 字节跳动将推出独立出口电商APP
新旧电脑资料迁移高效帮手
No.10 “字节跳动手机”要来了?
没光驱不要紧 装个免费虚拟的
简谈MC7字节码
开发闲置内存,为本本轻松提速
用RamOS降低公用机的维护工作量
CNMARC304字段和314字段责任附注方式解析
无正题名文献著录方法评述