最近做SQLite 3数据库的恢复,找了比较多相关方面的论文,在这里记录一下。
一、基于SQLite 文件系统的恢复
上一篇文章中,记录了SQLite 3的文件结构,里面提到了一点数据库中记录单元删除前后的底层变化,但是不太详细。在这里详细讲一下。
SQLite 3数据库的删除与PC的文件系统数据的删除有些类似,就是删除的过程中,原始数据是不会被删除的,它会存留在底层,直到新的数据存储时覆盖掉。另外,在删除的过程中,当删除的记录单元较多时,数据库会整合自由块,这样一个自由块就可能包含多个记录单元,当某个页的数据都被删除时,给页就会形成空闲页。总的来说,记录单元被删除后形成的自由块就可能有这几种情况:
1、一个自由块包含一个记录单元的一部分(部分覆盖的情况)
2、一个自由块包含一个完整的记录单元
3、一个自由块包含多个完整的记录单元
另外,就是形成空闲页的情况。
方法一
基于SQLite 3数据库文件系统结构的恢复步骤通常是:
准备阶段:读取数据库头,得到数据库的页大小和编码方式。
读取系统表,得到要恢复目标表的根页。
从根页开始,递归遍历所有的叶子页。
遍历所有的叶子页,找到该表所有的自由块。
判断阶段:针对上面提到的自由块情形2,判断阶段的目的就是确定是否一个自由块是一个完整的记录单元。判断的方法是:推算:n值+type区域的字节数+data区域的字节数是否和自由块记录的大小相同。(n的初始值为4,也就是两个字节的下一个自由块偏移和连个字节的本自由块大小,n最大为28)。当判断结果相同时,就进入下一个阶段,恢复数据。
在这一阶段中,关键的地方是要分析清楚记录单元变成自由块前后,原始记录单元的type区域有没有被覆盖。在这个问题上,白晋国、孙红胜、胡泽明《一种基于SQLite3文件格式的删除数据恢复方法》一文中做了详细分析,他们说,n的值范围在3-6之间,因此删除前后type区域是否被覆盖的情况就分三种情况:
1、单元大小+rowID+headersize=3个字节时,这种情况显示是数据库数据较少,这时n=4,type区域被覆盖一个字节,但是在追踪底层的时候,我发现,每个记录单元的type区域第一个字节的值始终为0x00,也就是对应的数据区域的长度为0,因此覆盖一个字节影响不大,但是计算type的字节数显示要从2开始。
2、单元大小+rowID+headersize=4个字节时,这时n=4,type区域没有被覆盖,并且计算整个自由块的时候,正好可以领type从1开始
3、第三种情况就是当数据库数据较多时,单元大小+rowID+headersize>4个字节时,这时n值就要大于4了,并且type区域同样没有被覆盖且从1开始
关于上述三点,只是记录了结论,没有具体的分析原因,可以看一下那篇论文,就很清楚了。
恢复阶段:恢复阶段要做的工作就是根据type区域的记录将data区域的每个元素进行编码,这一步比较麻烦的是type区域记录了后面相对应data域的长度和类型。
这种方式只能是针对上述的第二种情况,恢复的结果不是很理想。我做的实验结果是:
以上是几个表的恢复情况,可以看到,当表的记录量较小、删除数据较少的时候,恢复的情况还可以;但是当表的记录量增加、删除数据量较多时,符合第二种情况的自由块就没有那么多了,因此恢复的情况就不理想。
鉴于上述情况,继续查阅SQLite恢复方面的论文,发现有一篇论文中提到了一种方法:相似类型匹配估算方法。
方法二 相似类型匹配估算方法
这种方法本质上也是基于SQLite数据库的文件结构,准备阶段和方法一一样,也是要遍历所有的叶子页,以便找到所有的自由块,除此之外还需要得到正常的记录单元的type区域类型。但是在判断阶段,不再是针对一个单一的自由块,而是和存在的记录单元进行比较,从这里我们也能明白该方法名字的来源:比较自由块的type类型和记录单元的type类型是否相似。
判断阶段:从自由块第n个字节开始(n值在方法一种也做了讨论),相似类型匹配成功?恢复阶段:n++;在一个自由块恢复完成后,针对自由块的第三中情况,要判断自由块是否结束?存储恢复信息:继续相似类型匹配。
恢复阶段和方法一类型,就不在赘述。
这种方法是陈飞在他的论文《智能移动终端应用数据取证技术研究》中提出来的。后面我将尝试以这种方法恢复自由块,想来应该比方法一好很多。