winston 发表于 2012-3-8 15:04:43

[原]VC++信息安全编程(16)安全删除NTFS磁盘数据文件

很多时候,为了保护商业秘密,一些文件仅仅许可出现一次,就必须删除。
但是windows的删除是不完善的,可以通过回收站找回,即使windows的彻底删除,也不是彻底删除。也可以通过数据恢复软件找回,
我们如何实现彻底删除,用二进制数据填充磁盘,来彻底清除相关数据呢
我们来亲身实践360自带的功能。
详细类源码如下,请见源码分析,安全删除NTFS file:

#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;
        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 != _T('.'))       
                        {
                                int random=int((rand()*74/32767));
                                if(random>=10 && random<=16)        random=17;
                                if(random>=43 && random<=48)        random=49;
                                newName = (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;
        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 != _T('.'))       
                        {
                                int random=int((rand()*74/32767));
                                if(random>=10 && random<=16)        random=17;
                                if(random>=43 && random<=48)        random=49;
                                newName = (TCHAR) random + _T('0');
                        }
                }
                //        用产生的新名称重命名
                MoveFile( LastFileName, newName );
                _tcscpy( LastFileName, newName );
        }
}
/////////////////////////////////////////////////////////////////////////////
// 函数名:CryptString(CString string)
// 参数列表:CString string
// 函数功能:该函数的功能是根据已有的字符串产生一个加密的字符串
/////////////////////////////////////////////////////////////////////////////
CString CSecureDelNTFS::CryptString(CString string)
{
        TCHAR                FirstString;       
        _tcscpy( FirstString, string );
        srand( (unsigned)time( NULL ) );
        //        产生一个随机字符替换字符串中非'.'字符
        for( int j = 0 ; j < _tcsclen( FirstString ); j++ )
        {
                if( FirstString != _T('.'))               
                {
                        int random=int((rand()*74/32767));
                        if(random>=10 && random<=16)        random=17;
                        if(random>=43 && random<=48)        random=49;
                        FirstString = (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;
        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 = (unsigned char *)VirtualAlloc( NULL, CLEANBUFSIZE, MEM_COMMIT, PAGE_READWRITE );
                        if( !cleanBuffer )
                        {
                                for( j = 0; j < i; j++ )
                                {
                                        VirtualFree( cleanBuffer, 0, MEM_RELEASE );
                                }
                                return FALSE;
                        }
                        switch( i )
                        {

                        case 0:
                                // 缓冲区内容为0
                                break;
                        case 1:
                                // 缓冲区内容为0 - 0xFF
                                memset( cleanBuffer, 0x00, CLEANBUFSIZE );
                                break;
                        case 2:
                                // 缓冲区内容为随机值
                                for( j = 0; j < CLEANBUFSIZE; j++ ) cleanBuffer = (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, 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;
        //        首先以覆盖的模式打开文件
        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.Lcn != LLINVALID )
                        {
                                // 压缩模式
                                *ReallyCompressed = TRUE;
                                // 覆盖所在的簇
                                if( VolumeHandle != INVALID_HANDLE_VALUE )
                                {
                                        clusterOffset.QuadPart = fileMappings->Pair.Lcn * ClusterSize;
                                        SetFilePointer( VolumeHandle, clusterOffset.LowPart,
                                                                        &clusterOffset.HighPart, FILE_BEGIN );
                                        if( !SecureOverwrite( VolumeHandle,
                                                                        ClusterSize * (DWORD) (fileMappings->Pair.Vcn - startVcn) ))
                                                return TRUE;
                                }
                                else
                                        return TRUE;       
                        }
                        startVcn = fileMappings->Pair.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;
        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 = FileName;
                hVolume = CreateFile( volumeName, GENERIC_READ|GENERIC_WRITE,
                                                        FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
                                                        0, 0 );
                volumeRoot = FileName;
                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, fileSearchName, searchName;
        HANDLE                        dirHandle, patternHandle;
        WIN32_FIND_DATA foundFile;
        TCHAR                        lastFileName;
        // 遍历所有的文件和目录
        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;
        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 != ':' )
                return FALSE;
        // 磁盘分区路径
        DrivePath = 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;
        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;
                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;
                TCHAR                searchPath;
                sprintf(searchPath, "%s", m_filename);
                m_SdelNTFS.firstCall = true;
                m_SdelNTFS.deleteDirectories =false;
                m_SdelNTFS.ProcessDirectory( searchPath, searchPattern );               
       
                AfxMessageBox("安全删除完毕!");
                m_filename="";
        }
        UpdateData(false);
       
}

作者:yincheng01 发表于2011-12-15 7:53:30 原文链接

页: [1]
查看完整版本: [原]VC++信息安全编程(16)安全删除NTFS磁盘数据文件