VC++信息安全编程(11)安全删除NTFS磁盘数据文件

很多时候,为了保护商业秘密,一些文件仅仅许可出现一次,就必须删除。

但是Windows的删除是不完善的,可以通过回收站找回,即使Windows的彻底删除,也不是彻底删除。也可以通过数据恢复软件找回,

我们如何实现彻底删除,用二进制数据填充磁盘,来彻底清除相关数据呢

我们来亲身实践360自带的功能。

详细类源码如下,请见源码分析,安全删除NTFS

#include "stdafx.h"

#include "SecureDelNTFS.h"
#include <time.h>


#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#define OVERWRITE_PASSES 1
#define BUFFER_SIZE 1024
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CSecureDelNTFS::CSecureDelNTFS()
{
	Recurse = true;
	ZapFreeSpace = true;
	CleanCompressedFiles = FALSE;
	NumPasses = 1;
	FilesFound = 0;
	firstCall = false;
	deleteDirectories = false;
	//  以系统时间为种子构造随机数
	srand( (unsigned)time( NULL ));
}

CSecureDelNTFS::~CSecureDelNTFS()
{

}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  OverwriteFileName( PTCHAR FileName, PTCHAR LastFileName )
// 参数列表:PTCHAR FileName
//			 PTCHAR LastFileName
// 函数功能:该函数的功能是安全删除文件名
/////////////////////////////////////////////////////////////////////////////
VOID CSecureDelNTFS::OverwriteFileName( PTCHAR FileName, PTCHAR LastFileName )
{
	TCHAR		newName[MAX_PATH];
	PTCHAR		lastSlash;
	DWORD		i, j, index;

	_tcscpy( LastFileName, FileName );
	lastSlash = _tcsrchr( LastFileName, _T('\\'));
	index = (lastSlash - LastFileName)/sizeof(TCHAR);
	//  产生一个新的名称
	CString sz="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz";
	if(index>125)
		sz=sz.Left((130-(index-125)));
	CString NewName=((CString) LastFileName).Left(index)+"\\"+CryptString(sz);
	sprintf(LastFileName,"%s",NewName);
	MoveFile( FileName, NewName );
	
	_tcscpy( LastFileName, NewName );
	lastSlash = _tcsrchr( LastFileName, _T('\\'));
	index = (lastSlash - LastFileName)/sizeof(TCHAR);
	int k=_tcsclen( LastFileName );

	_tcscpy( newName, NewName );
	int number=rand()*20/32767+2;
	for( i = 0; i < number; i++ ) 
	{
		//	用随机产生的符号替换文件名中非'.'符号
		for( j = index+1 ; j < _tcsclen( LastFileName ); j++ ) 
		{
			if( LastFileName[j] != _T('.'))	
			{
				int random=int((rand()*74/32767));
				if(random>=10 && random<=16)	random=17;
				if(random>=43 && random<=48)	random=49;
				newName[j] = (TCHAR) random + _T('0');  
			}
		}
		//	用产生的新名称重命名
		MoveFile( LastFileName, newName );
		_tcscpy( LastFileName, newName );
	}
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  OverwriteDirectoryName( PTCHAR FileName, PTCHAR LastFileName )
// 参数列表:PTCHAR FileName
//			 PTCHAR LastFileName
// 函数功能:该函数的功能是安全删除文件名
/////////////////////////////////////////////////////////////////////////////
VOID CSecureDelNTFS::OverwriteDirectoryName( PTCHAR FileName, PTCHAR LastFileName )
{
	TCHAR		newName[MAX_PATH];
	PTCHAR		lastSlash;
	DWORD		i, j, index;

	_tcscpy( LastFileName, FileName );
	lastSlash = _tcsrchr( LastFileName, _T('\\'));
	index = (lastSlash - LastFileName)/sizeof(TCHAR);
	//  产生一个新的名称
	CString NewName=((CString) LastFileName).Left(index)+"\\"+CryptString("abcdefgh.XYZ");
	sprintf(LastFileName,"%s",NewName);
	MoveFile( FileName, NewName );
	
	_tcscpy( LastFileName, NewName );
	lastSlash = _tcsrchr( LastFileName, _T('\\'));
	index = (lastSlash - LastFileName)/sizeof(TCHAR);
	int k=_tcsclen( LastFileName );

	_tcscpy( newName, NewName );
	int number=rand()*20/32767+2;
	for( i = 0; i < number; i++ ) 
	{
		//	用随机产生的符号替换文件名中非'.'符号
		for( j = index+1 ; j < _tcsclen( LastFileName ); j++ ) 
		{
			if( LastFileName[j] != _T('.'))	
			{
				int random=int((rand()*74/32767));
				if(random>=10 && random<=16)	random=17;
				if(random>=43 && random<=48)	random=49;
				newName[j] = (TCHAR) random + _T('0');  
			}
		}
		//	用产生的新名称重命名
		MoveFile( LastFileName, newName );
		_tcscpy( LastFileName, newName );
	}
}
/////////////////////////////////////////////////////////////////////////////
// 函数名:  CryptString(CString string)
// 参数列表:CString string
// 函数功能:该函数的功能是根据已有的字符串产生一个加密的字符串
/////////////////////////////////////////////////////////////////////////////
CString CSecureDelNTFS::CryptString(CString string)
{
	TCHAR		FirstString[MAX_PATH];	
	_tcscpy( FirstString, string );
	srand( (unsigned)time( NULL ) );
	//	产生一个随机字符替换字符串中非'.'字符
	for( int j = 0 ; j < _tcsclen( FirstString ); j++ ) 
	{
		if( FirstString[j] != _T('.'))		
		{
			int random=int((rand()*74/32767));
			if(random>=10 && random<=16)	random=17;
			if(random>=43 && random<=48)	random=49;
			FirstString[j] = (TCHAR) random + _T('0');  
		}
	}
	return (CString) FirstString;
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  SecureOverwrite( HANDLE FileHandle, DWORD Length )
// 参数列表:HANDLE FileHandle
//			 DWORD Length
// 函数功能:该函数的功能是安全删除文件
/////////////////////////////////////////////////////////////////////////////
BOOLEAN CSecureDelNTFS::SecureOverwrite( HANDLE FileHandle, DWORD Length )
{
#define CLEANBUFSIZE 65536
	static PBYTE	cleanBuffer[3];
	static BOOLEAN	buffersAlloced = FALSE;

	DWORD		i, j, passes;
	DWORD		bytesWritten, bytesToWrite, totalWritten;
	LONG		seekLength;
	BOOLEAN		status;

	//	分配执行清除操作所需的缓冲区
	if( !buffersAlloced ) 
	{
		//	设置系统时间为随机数种子
		srand( (unsigned)time( NULL ) );
		for( i = 0; i < 3; i++ ) 
		{
			//  设置清除缓冲区内容
			cleanBuffer[i] = (unsigned char *)VirtualAlloc( NULL, CLEANBUFSIZE, MEM_COMMIT, PAGE_READWRITE );
			if( !cleanBuffer[i] ) 
			{
				for( j = 0; j < i; j++ ) 
				{
					VirtualFree( cleanBuffer[j], 0, MEM_RELEASE );
				}
				return FALSE;
			}
			switch( i ) 
			{

			case 0:
				// 缓冲区内容为0
				break;
			case 1:
				// 缓冲区内容为0 - 0xFF
				memset( cleanBuffer[i], 0x00, CLEANBUFSIZE );
				break;
			case 2:
				// 缓冲区内容为随机值
				for( j = 0; j < CLEANBUFSIZE; j++ ) cleanBuffer[i][j] = (BYTE) rand();
				break;
			}
		}	
		buffersAlloced = TRUE;
	}
	// 执行覆盖操作
	seekLength = (LONG) Length;
	for( passes = 0; passes < NumPasses; passes++ ) 
	{
		if( passes != 0 ) 
		{
			// 将指针设置为最开始
			SetFilePointer( FileHandle, -seekLength, NULL, FILE_CURRENT );
		}
		for( i = 0; i < 2; i++ ) 
		{
			// 将指针设置为最开始
			if( i != 0 ) 
			{
				SetFilePointer( FileHandle, -seekLength, NULL, FILE_CURRENT );
			}
			// 循环并覆盖
			bytesToWrite = Length;
			totalWritten = 0;
			while( totalWritten < Length ) 
			{
				bytesToWrite = Length - totalWritten;
				if( bytesToWrite > CLEANBUFSIZE ) bytesToWrite = CLEANBUFSIZE;

				status = WriteFile( FileHandle, cleanBuffer[i], bytesToWrite, &bytesWritten, NULL );
				if( !status ) return FALSE;
				totalWritten += bytesWritten;
			}
		}
	}
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  SecureDelete( PTCHAR FileName, DWORD FileLengthHi,	DWORD FileLengthLo )
// 参数列表:PTCHAR FileName
//			 DWORD FileLengthHi
//			 DWORD FileLengthLo
//			 DWORD Length
// 函数功能:该函数的功能是安全删除指定的文件
/////////////////////////////////////////////////////////////////////////////
VOID CSecureDelNTFS::SecureDelete( PTCHAR FileName, DWORD FileLengthHi,
					DWORD FileLengthLo ) 
{
	HANDLE	hFile;
	ULONGLONG bytesToWrite, bytesWritten;
	ULARGE_INTEGER fileLength;
	TCHAR   lastFileName[MAX_PATH];
	//	首先以覆盖的模式打开文件
	hFile = CreateFile( FileName, GENERIC_WRITE, 
						FILE_SHARE_READ|FILE_SHARE_WRITE,
						NULL, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, NULL );
	if( hFile == INVALID_HANDLE_VALUE ) 
		return;
	// 如果文件的长度不为零,则将文件所占的所有簇填入0
	if( FileLengthLo || FileLengthHi ) 
	{
		//  找文件的后一簇
		FileLengthLo--;
		if( FileLengthLo == (DWORD) -1 && FileLengthHi ) FileLengthHi--;
		SetFilePointer( hFile, FileLengthLo, (long *) &FileLengthHi, FILE_BEGIN );
		// 在文件中填入0
		if( !SecureOverwrite( hFile, 1 )) 
		{
			CloseHandle( hFile );
			return;
		}
		// 回到文件的头部,处理文件剩下的部分
		SetFilePointer( hFile, 0, NULL, FILE_BEGIN );
		fileLength.LowPart = FileLengthLo;
		fileLength.HighPart = FileLengthHi;
		bytesWritten = 0;
		while( bytesWritten < fileLength.QuadPart ) 
		{
			bytesToWrite = min( fileLength.QuadPart - bytesWritten, 65536 );
			if( !SecureOverwrite( hFile, (DWORD) bytesToWrite )) 
			{
				CloseHandle( hFile );
				return;
			}
			bytesWritten += bytesToWrite;
		}
	}
	//  完成后关闭文件
	CloseHandle( hFile );
	//  重命名文件
	OverwriteFileName( FileName, lastFileName );
	//  删除文件
	if( !DeleteFile( lastFileName ) ) 
		return;
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  BOOLEAN CSecureDelNTFS::ScanFile( HANDLE VolumeHandle,  DWORD ClusterSize,
//				  HANDLE FileHandle, PBOOLEAN ReallyCompressed, PBOOLEAN ZappedFile )
// 参数列表:ANDLE VolumeHandle
//           DWORD ClusterSize
//           HANDLE FileHandle
//           PBOOLEAN ReallyCompressed
//           PBOOLEAN ZappedFilePTCHAR
// 函数功能:该函数的功能是当NTFS卷是压缩、加密时调用进行文件扫描
/////////////////////////////////////////////////////////////////////////////
BOOLEAN CSecureDelNTFS::ScanFile( HANDLE VolumeHandle,  DWORD ClusterSize,
				  HANDLE FileHandle, PBOOLEAN ReallyCompressed, PBOOLEAN ZappedFile )
{
	DWORD						status;
	int							i;
	IO_STATUS_BLOCK				ioStatus;
	ULONGLONG					startVcn, prevVcn;
	LARGE_INTEGER				clusterOffset;
	ULONGLONG					endOfPrevRun;
	PGET_RETRIEVAL_DESCRIPTOR	fileMappings;
	ULONGLONG					fileMap[ FILEMAPSIZE ];
	int							lines = 0;
	// 假设文件位于MFT记录中
	*ReallyCompressed = FALSE;
	*ZappedFile = FALSE;
	startVcn = 0;
	endOfPrevRun = LLINVALID;
	fileMappings = (PGET_RETRIEVAL_DESCRIPTOR) fileMap;
	while( !(status = NtFsControlFile( FileHandle, NULL, NULL, 0, &ioStatus,
						FSCTL_GET_RETRIEVAL_POINTERS,
						&startVcn, sizeof( startVcn ),
						fileMappings, FILEMAPSIZE * sizeof(ULONGLONG) ) ) ||
			 status == STATUS_BUFFER_OVERFLOW ||
			 status == STATUS_PENDING ) 
	{
		// 如果操作正在进行,则等待完成
		if( status == STATUS_PENDING ) 
		{
			WaitForSingleObject( FileHandle, INFINITE ); 
			// 获取状态参数
			if( ioStatus.Status != STATUS_SUCCESS && ioStatus.Status != STATUS_BUFFER_OVERFLOW ) 
			{
				return ioStatus.Status == STATUS_SUCCESS;
			}
		}
		startVcn = fileMappings->StartVcn;
		prevVcn  = fileMappings->StartVcn;
		for( i = 0; i < (ULONGLONG) fileMappings->NumberOfPairs; i++ ) 
		{	 
			if( fileMappings->Pair[i].Lcn != LLINVALID ) 
			{
				// 压缩模式
				*ReallyCompressed = TRUE;
				// 覆盖所在的簇
				if( VolumeHandle != INVALID_HANDLE_VALUE ) 
				{
					clusterOffset.QuadPart = fileMappings->Pair[i].Lcn * ClusterSize;
					SetFilePointer( VolumeHandle, clusterOffset.LowPart,
									&clusterOffset.HighPart, FILE_BEGIN );
					if( !SecureOverwrite( VolumeHandle,
									ClusterSize * (DWORD) (fileMappings->Pair[i].Vcn - startVcn) )) 
						return TRUE;
				} 
				else 
					return TRUE;	
			}
			startVcn = fileMappings->Pair[i].Vcn;
		}
		if( !status ) break;
	}
	if( status == STATUS_SUCCESS ) *ZappedFile = TRUE;
	return status == STATUS_SUCCESS;
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  SecureDeleteCompressed( PTCHAR FileName )
// 参数列表:PTCHAR FileName
// 函数功能:该函数的功能是删除压缩磁盘中的文件
/////////////////////////////////////////////////////////////////////////////
BOOLEAN CSecureDelNTFS::SecureDeleteCompressed( PTCHAR FileName ) 
{
	HANDLE			hFile;
	BOOLEAN			reallyCompressed = FALSE;
	BOOLEAN			zappedFile = FALSE;
	TCHAR			lastFileName[MAX_PATH];
	static TCHAR	volumeName[] = _T("\\\\.\\A:");
	static TCHAR	volumeRoot[] = _T("A:\\");
	static HANDLE	hVolume = INVALID_HANDLE_VALUE;
	static DWORD	clusterSize;
	DWORD			sectorsPerCluster, bytesPerSector, freeClusters, totalClusters;
	// 打开卷
	if( hVolume == INVALID_HANDLE_VALUE ) 
	{
		volumeName[4] = FileName[0];
		hVolume = CreateFile( volumeName, GENERIC_READ|GENERIC_WRITE,
							FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
							0, 0 );
		volumeRoot[0] = FileName[0];
		GetDiskFreeSpace( volumeRoot, §orsPerCluster, &bytesPerSector,
						&freeClusters, &totalClusters );
		clusterSize = bytesPerSector * sectorsPerCluster;
	}
	// 打开文件
	hFile = CreateFile( FileName, GENERIC_READ, 
						0,NULL, OPEN_EXISTING, 0, NULL );
	if( hFile == INVALID_HANDLE_VALUE ) 
		return TRUE;
	// 确定文件的位置
	if( !ScanFile( hVolume, clusterSize, hFile, 
			&reallyCompressed, &zappedFile )) 
	{

		CloseHandle( hFile );
		return TRUE;
	}
	// 关闭文件
	CloseHandle( hFile );
	if( reallyCompressed ) 
	{
		// 重新命名文件名
		OverwriteFileName( FileName, lastFileName );
		//  文件长度修改为0
		FILE *fp=fopen(lastFileName,"w");
		fclose(fp);
		//  删除文件
		if( !DeleteFile( lastFileName )) 
		{
			MoveFile( lastFileName, FileName );
			return TRUE;
		}
		// 如果不能直接覆盖文件的簇,则通过清除磁盘的自由空间来覆盖
		if( !zappedFile ) CleanCompressedFiles = TRUE;
	}
	return reallyCompressed;
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  ProcessFile( PWIN32_FIND_DATA FindData, TCHAR *FileName )
// 参数列表:PWIN32_FIND_DATA FindData
//			 TCHAR *FileName
// 函数功能:该函数的功能是处理文件的删除
/////////////////////////////////////////////////////////////////////////////
VOID CSecureDelNTFS::ProcessFile( PWIN32_FIND_DATA FindData, TCHAR *FileName )
{
	// 如果是目录的删除,则直接返回
	if( FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) return;
	FilesFound++;
	// 如果文件是压缩的
	if( FindData->dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED ||
		FindData->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED  ||
		FindData->dwFileAttributes & FILE_ATTRIBUTE_SPARSE_FILE ) 
	{
		// 处理压缩磁盘中的文件
		if( SecureDeleteCompressed( FileName )) return;
	} 
	// 删除常规(非压缩、非加密磁盘)文件
	SecureDelete( FileName, FindData->nFileSizeHigh,
							FindData->nFileSizeLow );
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  ProcessDirectory( TCHAR *PathName, TCHAR *SearchPattern )
// 参数列表:TCHAR *PathName
//			 TCHAR *SearchPattern
// 函数功能:该函数的功能是处理目录的删除
/////////////////////////////////////////////////////////////////////////////
void CSecureDelNTFS::ProcessDirectory( TCHAR *PathName, TCHAR *SearchPattern )
{
	TCHAR			subName[MAX_PATH], fileSearchName[MAX_PATH], searchName[MAX_PATH];
	HANDLE			dirHandle, patternHandle;
	WIN32_FIND_DATA foundFile;
	TCHAR			lastFileName[MAX_PATH];
	// 遍历所有的文件和目录
	if( firstCall ) 
	{
		if( _tcsrchr( PathName, '*' ) ) 
		{
            if( _tcsrchr( PathName, '\\' ) ) 
			{
                _stprintf( SearchPattern, _tcsrchr( PathName, '\\' )+1 );
                _tcscpy( searchName, PathName );
                _tcscpy( _tcsrchr( searchName, '\\')+1, _T("*.*") );
				if( !_tcscmp( SearchPattern, _T("*.*")) || !_tcscmp( SearchPattern, _T("*"))) 
				{
					deleteDirectories = TRUE;
				}
            } 
			else 
			{
                _stprintf( SearchPattern, PathName );
                _tcscpy( searchName, PathName );
            }
            _stprintf( fileSearchName, _T("%s"), PathName );
		} 
		else 
		{
			_stprintf( SearchPattern, _T("*.*") );
			_stprintf( searchName, _T("%s"), PathName );
            _stprintf( fileSearchName, _T("%s"), PathName );
			deleteDirectories = TRUE;
		}
	} 
	else 
	{
		_stprintf( searchName, _T("%s\\*.*"), PathName );
		_stprintf( fileSearchName, _T("%s\\%s"), PathName, SearchPattern );
	}
	// 处理所有的文件
	if( (patternHandle = FindFirstFile( fileSearchName, &foundFile )) != 
		INVALID_HANDLE_VALUE  ) 
	{
		do 
		{
			if( _tcscmp( foundFile.cFileName, _T(".") ) &&	_tcscmp( foundFile.cFileName, _T("..") )) 
			{
				_tcscpy( subName, searchName );
				if( _tcsrchr( subName, '\\' ) ) 
					_tcscpy( _tcsrchr( subName, '\\')+1, foundFile.cFileName );
				else
					_tcscpy( subName, foundFile.cFileName );
				// 处理文件
				ProcessFile( &foundFile, subName );
			}
		} 
		while( FindNextFile( patternHandle, &foundFile ));
		FindClose( patternHandle );
	}
	// 进行递归删除
	if( Recurse ) 
	{
        if( firstCall && !_tcsrchr( searchName, L'\\') ) 
		{
            if( _tcsrchr( searchName, L'*' )) 
			{

                if( (dirHandle = FindFirstFile( _T("*.*"), &foundFile )) == INVALID_HANDLE_VALUE) 
                    return;
            } 
			else 
			{

                if( (dirHandle = FindFirstFile( searchName, &foundFile )) == INVALID_HANDLE_VALUE) 
                    return;
            }
        } 
		else 
		{
            if( (dirHandle = FindFirstFile( searchName, &foundFile )) == INVALID_HANDLE_VALUE) 
                return;
        }
        firstCall = FALSE;
		do 
		{

			if( (foundFile.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
				_tcscmp( foundFile.cFileName, _T(".") ) &&
				_tcscmp( foundFile.cFileName, _T("..") )) 
			{

				_tcscpy( subName, searchName );
				if( _tcsrchr( subName, '\\' ) ) 
					_tcscpy( _tcsrchr( subName, '\\')+1, foundFile.cFileName );
				else
					_tcscpy( subName, foundFile.cFileName );
				// 处理目录
				ProcessDirectory( subName, SearchPattern );
				// 删除目录
				if( deleteDirectories ) 
				{
					//  重新命名文件名
					OverwriteDirectoryName( subName, lastFileName );
					SetFileAttributes(lastFileName,FILE_ATTRIBUTE_NORMAL);
					RemoveDirectory( lastFileName ); 
				}
			}
		} 
		while( FindNextFile( dirHandle, &foundFile ));
		FindClose( dirHandle );
	}
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  CleanFreeSpace( PTCHAR DrivePath )
// 参数列表:PTCHAR DrivePath
// 函数功能:该函数的功能是清除磁盘的自由空间
/////////////////////////////////////////////////////////////////////////////
BOOLEAN CSecureDelNTFS::CleanFreeSpace( PTCHAR DrivePath )
{
	TCHAR		tempFileName[MAX_PATH];
	ULARGE_INTEGER bytesAvail, totalBytes, freeBytes;
	DWORD		sectorsPerCluster, bytesPerSector, totalClusters, freeClusters;
	ULONGLONG	tempSize = 0;
	HANDLE		hTempFile;
	BOOLEAN		createdFile;
	DWORD		cleanSize, mftFilesCreated;
	DWORD		prevSize;
	CString		strText;

	if( DrivePath[1] != ':' ) 
		return FALSE;
	// 磁盘分区路径
	DrivePath[3] = 0;
	if( !GetDiskFreeSpace( DrivePath, §orsPerCluster, &bytesPerSector,
		&freeClusters, &totalClusters )) 
		return FALSE;
#if UNICODE
	if( !(pGetDiskFreeSpaceEx = (int (__stdcall *)(const char *,union _ULARGE_INTEGER *,union _ULARGE_INTEGER *,union _ULARGE_INTEGER *)) GetProcAddress( GetModuleHandle( _T("kernel32.dll") ),
											"GetDiskFreeSpaceExW" ))) {
#else
	if( !(pGetDiskFreeSpaceEx = (int (__stdcall *)(const char *,union _ULARGE_INTEGER *,union _ULARGE_INTEGER *,union _ULARGE_INTEGER *)) GetProcAddress( GetModuleHandle( _T("kernel32.dll") ),
											"GetDiskFreeSpaceExA" ))) {
#endif
		bytesAvail.QuadPart = sectorsPerCluster * freeClusters * bytesPerSector;
        freeBytes.QuadPart = bytesAvail.QuadPart;
	} 
	else 
	{
		if( !pGetDiskFreeSpaceEx( DrivePath, &bytesAvail, &totalBytes, &freeBytes )) 
			return FALSE;
	}

	if( bytesAvail.QuadPart != freeBytes.QuadPart ) 
		return FALSE;
	_stprintf( tempFileName, _T("%sSDELTEMP"), DrivePath );
	hTempFile = CreateFile( tempFileName, GENERIC_WRITE, 
					0, NULL, CREATE_NEW, 
					FILE_FLAG_NO_BUFFERING|FILE_FLAG_SEQUENTIAL_SCAN|
					FILE_FLAG_DELETE_ON_CLOSE|FILE_ATTRIBUTE_HIDDEN, NULL );
	if( hTempFile == INVALID_HANDLE_VALUE ) 
		return FALSE;
	// 分配清除缓冲区
	cleanSize = sectorsPerCluster * bytesPerSector * 128;
	// 增大簇的容量直到超过极限
	while( cleanSize > bytesPerSector * sectorsPerCluster ) 
	{
		if( SecureOverwrite( hTempFile, cleanSize )) 
		{
			tempSize += cleanSize;
		} 
		else 
		{
			cleanSize -= bytesPerSector * sectorsPerCluster;
		}
	}
	// 最后存在一个小于一个完整簇的空间,利用另外一个临时文件覆盖
	_stprintf( tempFileName, _T("%sSDELTEMP1"), DrivePath );
	hTempFile = CreateFile( tempFileName, GENERIC_WRITE, 
					0, NULL, CREATE_NEW, 
					FILE_FLAG_SEQUENTIAL_SCAN|FILE_FLAG_DELETE_ON_CLOSE|
					FILE_ATTRIBUTE_HIDDEN|FILE_FLAG_WRITE_THROUGH, NULL );

	if( hTempFile != INVALID_HANDLE_VALUE ) 
	{
		while( cleanSize ) 
		{
			if( SecureOverwrite( hTempFile, cleanSize )) 
			{
				tempSize += cleanSize;
			}else
			{
				cleanSize--;
			}
		}
	}

	if( ZapFreeSpace ) 
	{
		mftFilesCreated = 0;
		// 最大的 MFT 记录大小
		prevSize = 4096; 
		while( 1 ) 
		{
			_stprintf( tempFileName, _T("%sSDELMFT%06d"), DrivePath, mftFilesCreated++ );
			hTempFile = CreateFile( tempFileName, GENERIC_WRITE, 
							0, NULL, CREATE_NEW, 
							FILE_FLAG_SEQUENTIAL_SCAN|FILE_FLAG_DELETE_ON_CLOSE|
							FILE_ATTRIBUTE_HIDDEN, NULL );
			if( hTempFile == INVALID_HANDLE_VALUE ) 
			{

				break;
			}
			cleanSize = prevSize;
			createdFile = FALSE;
			while( cleanSize ) 
			{
				if( !SecureOverwrite( hTempFile, cleanSize )) 
				{
					cleanSize--;
				} 
				else 
				{
					prevSize = cleanSize;
					createdFile = TRUE;
					tempSize += cleanSize;
				}
			}	
			if( !createdFile ) break;
		}
	}
	return TRUE;
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  LocateNativeEntryPoints()
// 参数列表:
// 函数功能:该函数的功能是定位NTDLL的入口点
/////////////////////////////////////////////////////////////////////////////
VOID CSecureDelNTFS::LocateNativeEntryPoints()
{
	// 如果当前的Windows版本是Win9x,则直接返回
	if( GetVersion() >= 0x80000000) return;
    // 装入所需的NTDLL入口点
	if( !(NtFsControlFile = (unsigned int (__stdcall *)(void *,void *,void (__cdecl *)(void *,struct _IO_STATUS_BLOCK *,unsigned long),void *,struct _IO_STATUS_BLOCK *,
		unsigned long,void *,unsigned long,void *,unsigned long)) GetProcAddress( GetModuleHandle(_T("ntdll.dll")),
			"NtFsControlFile" )) ) 
	{
		AfxMessageBox("Could not find NtFsControlFile entry point in NTDLL.DLL",MB_OK | MB_ICONERROR);
		exit(1);
	}
	if( !(RtlNtStatusToDosError = (unsigned long (__stdcall *)(unsigned int)) GetProcAddress( GetModuleHandle(_T("ntdll.dll")),
							"RtlNtStatusToDosError" )) ) 
	{
		AfxMessageBox("Could not find RtlNtStatusToDosError entry point in NTDLL.DLL",MB_OK | MB_ICONERROR);
		exit(1);
	}
}

/////////////////////////////////////////////////////////////////////////////
// 函数名:  WipeFileContent(LPCTSTR pFilePath)
// 参数列表:
// 函数功能:该函数主要用于将需要删除的文件全部清零
/////////////////////////////////////////////////////////////////////////////
BOOL CSecureDelNTFS::WipeFileContent(CString strfilename)
{
	char	filename[MAX_PATH];
	sprintf(filename, "%s", strfilename);

	HANDLE hFile = CreateFile(filename, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 
							NULL, OPEN_ALWAYS, FILE_FLAG_WRITE_THROUGH, NULL);
	if (hFile == INVALID_HANDLE_VALUE) 
		return false;

	DWORD fileSize = GetFileSize(hFile, 0);
	// 如果文件是空,则直接返回
	if (!fileSize)
	{
		CloseHandle(hFile);
		return false;
	}

	DWORD j=0;

	for (int passes = 0; passes < OVERWRITE_PASSES; passes++)
	{
		char newStorage[BUFFER_SIZE];
		srand((unsigned)time(NULL));
		if(passes<(OVERWRITE_PASSES-1))
			FillMemory((void*)newStorage, BUFFER_SIZE, rand() % 255);
		else
			FillMemory((void*)newStorage, BUFFER_SIZE, 0);

		SetFilePointer(hFile, 0, NULL, FILE_BEGIN);

		DWORD left = fileSize;
		int write = BUFFER_SIZE;
		DWORD written = 0;
		
		while (left)
		{
			j=j+1;
			if (left < BUFFER_SIZE) write = left;
			BOOL status = WriteFile(hFile, newStorage, write, &written, NULL);
			if (!status)
			{
				CloseHandle(hFile);
				return false;
			}

			left -= write;
		}
	}

	CloseHandle(hFile);
	return true;
}


类中的调用源码如下

void CSDeleteNTFSDlg::OnButtonSecuredel() 
{
	// TODO: Add your control notification handler code here
	if(m_filename!="")
	{
		//  采用全部清零的方法删除文件的内容
		m_SdelNTFS.WipeFileContent(m_filename);
		//  设置文件的长度为零
		FILE *fp=fopen(m_filename,"w");
		fclose(fp);
		//	删除该文件的文件名	
		TCHAR       searchPattern[MAX_PATH];
		TCHAR		searchPath[MAX_PATH];
		sprintf(searchPath, "%s", m_filename);
		m_SdelNTFS.firstCall = true;
		m_SdelNTFS.deleteDirectories =false;
		m_SdelNTFS.ProcessDirectory( searchPath, searchPattern );		
	
		AfxMessageBox("安全删除完毕!");
		m_filename="";
	}
	UpdateData(false);
	
}


 


原文链接: http://blog.csdn.net/yincheng01/article/details/7072573

你可能感兴趣的:(VC++信息安全编程(11)安全删除NTFS磁盘数据文件)