格式化恢复之路
老板叫做一个格式化恢复工具,以前数据恢复知识没怎么用上,我开始对各大著名软件的格式化恢复功能进行了分析,以为大家都是逐扇区搜索,不过到目前为止我错了,因为他们居然可以解析出文件名,也就是他们利用的是硬盘上残留的目录信息,格式化的时候并没有删掉有些信息,对于目录恢复我暂时不做,不过打算以后有机会会研究。目前我的工作就是解析doc xls ppt pdf docx pptx xlsx这7种格式,然后做一个可以扩展的工具。我的这个工具无论未来多少人为特定格式编写dll给我的程序用,都不会有很大的性能损耗。目前的初步磁盘文件查找速度为30s/G 深度解析文件速度取决于文件格式和文件大小。下面是公共接口文件://由于该项目由于vc6的bug,不得不在vs2010编译
//此格式化恢复工具分几步:
//①程序搜索ext文件夹下的dll,dll的GetSupportExtension提供该dll能识别的文件类型,主模块将所有支持的类型给用户显示。
//②程序列出所有支持的(介质)磁盘类型,目前支持本地硬盘、移动硬盘、u盘、以后可能支持内存文件恢复,列出给用户显示的介质是各个非隐藏分区和所有硬盘的设备链接符号。
//③用户选择需要搜索的文件类型和要恢复的介质,点击搜索开始搜索。
//④主模块将用户选择的文件类型加入搜索,其中对于简单文件签名直接加入搜索树中,对于复杂文件签名则把函数地址加入一个链表。
//以下为初步文件搜索:
//⑤主模块打开设备,从0扇区开始搜索,先搜索简单签名树,如果没有则在复杂文件签名列表中搜索,如果都没有直接进入下一个扇区。如果找到则跳转到⑥。
//⑥将搜索到的初步信息显示到列表控件,如果能快速获取文件大小则可以加速遍历,否则按簇遍历(每次向后0x1000),记录每个找到的文件相关信息用于后面深度解析。
//以下为深度文件搜索:
//⑦对于搜到的每一项获取信息,定位到文件,把文件数据交给dll获取详细信息,这些信息包括精确后缀名,有效性,长度,和文件的特定信息。
//⑧深度文件搜索完成后,右键点击列表控件会弹出2个菜单,一个是恢复,点击就开始恢复所有选择的文件,文件名为序号,后缀为识别出来的后缀,目录为选择的目录。
//另一个菜单是查看文件信息,选择后可以查看dll在深度搜索时提供的特定文件信息
/*
Dll导出函数要求:
//告知主模块该dll对于给定buf(已验证过文件签名)是否能提供快速返回文件大小,和GetFileLenImmediately配套使用可以在初次文件格式识别中加快扇区遍历速度。
BOOL CanGetFileLenImmediately;
//此函数对应于CanGetFileLenImmediately,如果CanGetFileLenImmediately设为TRUE则应该提供此函数入口快速计算文件大小。用于初步文件搜索。
FORMAT_SFILESIZE GetFileLenImmediately(VOID);
//告知注模块文件签名是否简单(可以通过判断连续几个字符确定),此导出值需要和GetFileSig连用以获取文件签名信息
BOOL IsFileSigSimple;
//此函数用于获取dll中的文件签名信息,如果文件签名可以简单对比出来就直接将签名的那些字节考入FORMAT_SIMPLETYPE,设置相关信息即可,
//如果该种文件签名不可以通过简单逐头字节对照比较出来,则应提供文件签名判断的入口函数,其类型为FORMAT_GETCOMPLEXFILETYPE
BOOL GetFileSig(PVOID pData);//simplefile:pData=FORMAT_SIMPLETYPE* complexfile:pData=FORMAT_GETCOMPLEXFILETYPE*
//用于深度文件搜索,获取文件大小及扩展信息,获取唯一文件后缀
BOOL GetRawFileInfo(CONST FORMAT_DATAPOINTER pData,FORMAT_FILEINFO* pfileinfo);
//提供该dll支持的文件类型,可以返回文件描述,也可以返回类型后缀,不要含有不能作为文件名的非法字符
VOID GetSupportExtension(CHAR Ext);
*/
//我想到的优化法:①双缓冲区,充分利用io操作时间分给cpu并行处理内存数据
//②深度搜索查找占用时间太长可以利用列表项后一项位置为界,搜索超过此位置仍没结束(获取到大小和后缀)则强制结束
#ifndef FORMAT_COMMON
#define FORMAT_COMMON
//以下是我定义的,详细说明在FormatDefs.cpp和FormatDefs.h,这里只是挑出这2个文件里必备的声明和定义用于编写windows dll,
//由于和windows和mfc不兼容,没有直接用上面2个文件
#define FORMAT_API WINAPI
#define MAX_FILESIGLEN0x100
#define MAX_CHILDNUM0x100
#define FORMAT_FAILURE(DWORD)-1
#define FORMAT_INVALIDID (DWORD)-1
#define TREE_ADDFAILUREFALSE
#define TREE_ADDSUCCESSTRUE
#define MAX_EXTLEN 0x100
#define MAX_DESCIPTION0x1000
#define CLASS_BEGIN_DEFINETYPE//定义类结构
#define CLASS_END_DEFINETYPE
#define CLASS_BEGIN_DEFMEMBERVAR//定义类成员变量
#define CLASS_END_DEFMEMBERVAR
#define CLASS_BEGIN_DEFMEMFUNC//定义类成员函数
#define CLASS_END_DEFMEMFUNC
typedef LPCTSTR FORMAT_EXTENSION;
typedef BYTE FORMAT_DATA;
typedef DWORD FORMAT_SFILESIZE;
typedef LONGLONG FORMAT_FILESIZE;
typedef LONGLONG FORMAT_DISKSIZE;
typedef LONGLONG FORMAT_FILEPOSITION;
typedef HMODULE FORMAT_DLLHANDLE;
typedef HANDLE FORMAT_DISKHANDLE;
typedef INT FORMAT_DATATYPE;
typedef INT FORMAT_FILESIGLEN;
typedef BOOL FORMAT_ISSUCCESS;
typedef INT FORMAT_FILESIGID;//唯一对应Dll的序数,唯一对应一个Sig
typedef INT FORMAT_ERRORCODE;
typedef class CDiskMappingPointer
{//访问范围最大为m_dwBlockBytes
public:
CLASS_BEGIN_DEFMEMFUNC
CDiskMappingPointer(FORMAT_DISKHANDLE hDisk,FORMAT_FILEPOSITION Base=0);
CDiskMappingPointer(CONST CDiskMappingPointer& ObjPtr);//自动重载=()
virtual ~CDiskMappingPointer();
FORMAT_FILEPOSITION GetBase(VOID) CONST;
FORMAT_DISKSIZE GetDiskSize(VOID) CONST;
FORMAT_FILEPOSITION GetOffset(VOID) CONST;
int GetProgress(VOID);
BOOL IsEndOfDisk(VOID) CONST;
BOOL SetDiskPointer(FORMAT_FILEPOSITION pos);
FORMAT_DATA operator[](FORMAT_SFILESIZE delta) CONST;
VOID operator+=(FORMAT_SFILESIZE delta);
FORMAT_DATA operator*(VOID) CONST;
operator FORMAT_DATA*(VOID) CONST;
operator DWORD*(VOID) CONST;
operator int*(VOID) CONST;
operator WORD*(VOID) CONST;
//以下三个成员函数用于快速改变文件指针读取操作
VOID BeforeSeek();
VOID SeekFromOrigin(FORMAT_SFILESIZE delta);
VOID AfterSeek();
CLASS_END_DEFMEMFUNC
CLASS_BEGIN_DEFMEMBERVAR
FORMAT_SFILESIZE m_dwBlockBytes;
CLASS_END_DEFMEMBERVAR
private:
CLASS_BEGIN_DEFMEMBERVAR
FORMAT_DATA* m_Data;
FORMAT_FILEPOSITION m_Base;
FORMAT_FILEPOSITION m_CurrentPos;//m_CurrentPos < m_dwBlockBytes
CONST FORMAT_DISKHANDLE m_DiskHandle;
FORMAT_DISKSIZE m_DiskSize;
//以下三个成员变量用于快速改变文件指针读取操作
FORMAT_FILEPOSITION m_oBase;
FORMAT_FILEPOSITION m_oCurrentPos;
CLASS_END_DEFMEMBERVAR
}FORMAT_DATAPOINTER;
struct FORMAT_FILEINFO
{
BYTE cbSize;
BYTE bitmap;//获取了哪些其他成员变量
FORMAT_FILESIZE filesize;//0x01
CHAR fileextDeepscan;//0x02
BOOL IsFileValid;//0x04
CHAR Description;//0x08
PVOID reserved;
};
struct FORMAT_SIMPLETYPE
{
FORMAT_DATA FileSig;
FORMAT_FILESIGLEN FileSigLen;//AddTreeTrunk调用之前检测参数
};
typedef BOOL (*FORMAT_GETCOMPLEXFILETYPE)(CONST FORMAT_DATA DiskInfo);
CDiskMappingPointer::CDiskMappingPointer(FORMAT_DISKHANDLE hDisk,FORMAT_FILEPOSITION Base):m_DiskHandle(hDisk),m_Base(((Base)>>12)<<12)
{
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
DWORD dwGran=SysInfo.dwAllocationGranularity;
m_dwBlockBytes=1000*dwGran;
m_Data=new FORMAT_DATA;
LARGE_INTEGER li;
li.QuadPart=m_Base;
//获取指定头部数据
SetFilePointer(m_DiskHandle,li.LowPart,&li.HighPart,FILE_BEGIN);
DWORD retlen;
ReadFile(m_DiskHandle,m_Data,m_dwBlockBytes,&retlen,NULL);
//获取磁盘大小
m_DiskSize=0;
GET_LENGTH_INFORMATION getlen;
if(DeviceIoControl(hDisk,IOCTL_DISK_GET_LENGTH_INFO,NULL,0,(LPVOID)&getlen,sizeof(getlen),&retlen,NULL))
m_DiskSize=getlen.Length.QuadPart;
m_CurrentPos=(Base&0xFFF);
}
CDiskMappingPointer::CDiskMappingPointer(CONST CDiskMappingPointer& ObjPtr):m_Base(ObjPtr.m_Base),m_DiskHandle(ObjPtr.m_DiskHandle)
{//深拷贝对象
m_dwBlockBytes=ObjPtr.m_dwBlockBytes;
m_CurrentPos=ObjPtr.m_CurrentPos;
m_DiskSize=ObjPtr.m_DiskSize;
m_Data=new FORMAT_DATA;
memcpy(m_Data,ObjPtr.m_Data,m_dwBlockBytes);
}
CDiskMappingPointer::~CDiskMappingPointer()
{
delete []m_Data;
}
FORMAT_DATA CDiskMappingPointer::operator [](FORMAT_SFILESIZE delta) CONST//调用者需要保证参数合法
{
return m_Data;
}
VOID CDiskMappingPointer::operator+=(FORMAT_SFILESIZE delta)//调用者需要保证参数合法
{
SetDiskPointer(m_Base+m_CurrentPos+delta);
}
FORMAT_DATA CDiskMappingPointer::operator*() CONST
{
return m_Data;
}
CDiskMappingPointer::operator FORMAT_DATA*() CONST
{//强制转换为FORMAT_DATA*
return (m_Data+m_CurrentPos);
}
CDiskMappingPointer::operator DWORD*() CONST
{//强制转换为DWORD*
return (DWORD*)(m_Data+m_CurrentPos);
}
CDiskMappingPointer::operator int*() CONST
{//强制转换为int*
return (int*)(m_Data+m_CurrentPos);
}
CDiskMappingPointer::operator WORD*() CONST
{//强制转换为WORD*
return (WORD*)(m_Data+m_CurrentPos);
}
VOID CDiskMappingPointer::BeforeSeek()
{
m_oBase=m_Base;
m_oCurrentPos=m_CurrentPos;
}
VOID CDiskMappingPointer::SeekFromOrigin(FORMAT_SFILESIZE delta)
{
if(m_oCurrentPos+delta < m_dwBlockBytes/2 && m_Base == m_oBase)
{
}
else//如果指针发生过移动
{//移回原位置并读取数据
SetDiskPointer(m_oBase+m_oCurrentPos+delta);
}
}
VOID CDiskMappingPointer::AfterSeek()
{//恢复指针及数据
if(m_Base != m_oBase)
{
SetDiskPointer(m_oBase+m_oCurrentPos);
}
m_Base=m_oBase;
m_CurrentPos=m_oCurrentPos;
}
FORMAT_FILEPOSITION CDiskMappingPointer::GetBase() CONST
{
return m_Base;
}
FORMAT_FILEPOSITION CDiskMappingPointer::GetOffset() CONST
{
return m_CurrentPos;
}
int CDiskMappingPointer::GetProgress()
{
return int(1000*(float)(m_CurrentPos+m_Base)/m_DiskSize);
}
BOOL CDiskMappingPointer::IsEndOfDisk() CONST
{
return (m_Base+m_CurrentPos) > m_DiskSize;
}
BOOL CDiskMappingPointer::SetDiskPointer(FORMAT_FILEPOSITION pos)
{
if(pos>m_DiskSize)
{
m_CurrentPos=pos-m_Base;
return FALSE;
}
FORMAT_FILEPOSITION newpos=((pos>>12)<<12);//按簇为单位计算基址
if(m_Base <= newpos && newpos <= m_Base+m_dwBlockBytes/2-0x1000 && m_CurrentPos < m_dwBlockBytes/2)
{
m_CurrentPos=pos-m_Base;
}
else
{
m_Base=((pos>>12)<<12);
m_CurrentPos=(pos&0xFFF);//计算偏移,也就是去掉了基址的那部分
LARGE_INTEGER li;
li.QuadPart=m_Base;
SetFilePointer(m_DiskHandle,li.LowPart,&li.HighPart,FILE_BEGIN);
DWORD retlen;
ReadFile(m_DiskHandle,m_Data,m_dwBlockBytes,&retlen,NULL);
}
return TRUE;
}
FORMAT_DISKSIZE CDiskMappingPointer::GetDiskSize() CONST
{
return m_DiskSize;
}
#endif
下面以最简单的pdf格式作说明如何针对特定格式编写dll:
Portable_Document_Format.h
#include "..\common.h"
#ifndef PORTABLE_DOCUMENT_FORMAT
#define PORTABLE_DOCUMENT_FORMAT
#ifdef PORTABLE_DOCUMENT_FORMAT_EXPORTS
#define PORTABLE_DOCUMENT_FORMAT_API __declspec(dllexport)
#else
#define PORTABLE_DOCUMENT_FORMAT_API __declspec(dllimport)
#endif
extern "C"
{
extern PORTABLE_DOCUMENT_FORMAT_API BOOL CanGetFileLenImmediately;
extern PORTABLE_DOCUMENT_FORMAT_API BOOL IsFileSigSimple;
PORTABLE_DOCUMENT_FORMAT_API FORMAT_SFILESIZE GetFileLenImmediately(FORMAT_DATAPOINTER& pData);
PORTABLE_DOCUMENT_FORMAT_API BOOL GetFileSig(PVOID pData);
PORTABLE_DOCUMENT_FORMAT_API BOOL GetRawFileInfo(FORMAT_DATAPOINTER& pData,FORMAT_FILEINFO* pfileinfo);
PORTABLE_DOCUMENT_FORMAT_API VOID GetSupportExtension(CHAR Ext);
};
#endif
Portable_Document_Format.cpp
// Portable_Document_Format.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#ifndef PORTABLE_DOCUMENT_FORMAT_EXPORTS
#define PORTABLE_DOCUMENT_FORMAT_EXPORTS
#endif
#include "Portable_Document_Format.h"
//具体文件格式分析请自行用Winhex解决,看懂格式再看我的代码
BOOL APIENTRY DllMain( HANDLE hModule, DWORDul_reason_for_call,LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
PORTABLE_DOCUMENT_FORMAT_API BOOL CanGetFileLenImmediately=FALSE;//暂时没时间研究pdf格式,所以没有快速算法计算大小
PORTABLE_DOCUMENT_FORMAT_API BOOL IsFileSigSimple=TRUE;
PORTABLE_DOCUMENT_FORMAT_API FORMAT_SFILESIZE GetFileLenImmediately(FORMAT_DATAPOINTER& pData)
{
return 0;
}
PORTABLE_DOCUMENT_FORMAT_API BOOL GetFileSig(PVOID pData)
{
FORMAT_DATA sig[]={0x25,0x50,0x44,0x46};
FORMAT_SIMPLETYPE* data=(FORMAT_SIMPLETYPE*)pData;
memcpy(data->FileSig,sig,sizeof(sig));
data->FileSigLen=sizeof(sig);
return TRUE;
}
PORTABLE_DOCUMENT_FORMAT_API BOOL GetRawFileInfo(FORMAT_DATAPOINTER& pData,FORMAT_FILEINFO* pfileinfo)
{
SYSTEM_INFO SysInfo;
GetSystemInfo(&SysInfo);
DWORD dwGran=SysInfo.dwAllocationGranularity;
DWORD maxaccess=0x100*dwGran;
FORMAT_FILESIZE filesize=0;
int loopnum=0;
int loopmax=0x3FFFFFFF/maxaccess;//最大支持1G文件
pfileinfo->bitmap=0;
pfileinfo->IsFileValid=FALSE;
FORMAT_DATA* p=(FORMAT_DATA*)pData+5,*endv;
for(endv=p;*endv != 0x0A && *endv != 0x0D && *endv != '%';endv++);
*endv='\0';
pfileinfo->bitmap |= 0x08;
strcpy_s(pfileinfo->Description,"版本号:");
strncat_s(pfileinfo->Description,(CHAR*)p,16);
while(loopnum<loopmax && !pData.IsEndOfDisk())
{
p=(FORMAT_DATA*)pData;
for(int i=0;i<(int)maxaccess;i++)
{
if(*(DWORD*)(p+i) == 'FOE%')//'%EOF'为结束标志
{
if(*(p+i+4) != 0 && *(p+i+5) != 0 && *(p+i+6) != 0)//伪结束符
continue;
pfileinfo->bitmap |= 0x01;
pfileinfo->filesize=loopnum;
pfileinfo->filesize *= maxaccess;
pfileinfo->filesize += i+strlen((char*)p+i);
pfileinfo->bitmap |= 0x04;
pfileinfo->IsFileValid=TRUE;
pfileinfo->bitmap |= 0x02;
strcpy_s(pfileinfo->fileextDeepscan,"pdf");
goto END;
}
}
loopnum++;
pData+=maxaccess;
}
END:
return TRUE;
}
PORTABLE_DOCUMENT_FORMAT_API VOID GetSupportExtension(CHAR Ext)
{
strcpy_s(Ext,MAX_EXTLEN,"pdf");
}
页:
[1]