首页 > 代码库 > 关于 win32 下磁盘的遍历方法

关于 win32 下磁盘的遍历方法

 最近要写个在线专杀的东东,虽然是专杀(本来只要清除几个特定的文件和杀几个特定的进程,然后把用户的注册表恢复正常,很多病毒木马最喜欢干的一件事情就是写 映像劫持 然后机器一重启,安全相关的软件全部玩完了,不过这也没什么技术含量,利用了操作系统的“漏洞”而已),但是因为是 磁碟机,这个病毒(木马)很恶心,是感染型的,你磁盘上的exe文件可以全部给你感染成一个个的“小磁碟机”,很恐怖,呵呵,所以没办法,要清除它,必须在杀掉磁碟机的进程之后,对全盘进行扫描,对每一个被感染的exe文件(好像com文件不能感染)进行修复,怎么进行磁盘遍历呢?请看下面的代码:(其实杀毒引擎工作的过程就是一个遍历磁盘上文件的过程,然后再对每个文件进行处理)

  1. // -------------------------------------------------------------------------
  2. // 函数       : ScanDirectory
  3. // 功能       : 遍历一个目录,然后做一些事情(想做什么做什么呗)
  4. // 返回值  : DWORD 
  5. // 参数       : const WCHAR *pwszPath
  6. // 附注       : 可以为磁盘根目录
  7. // -------------------------------------------------------------------------
  8. DWORD ScanDirectory(const WCHAR *pwszPath)
  9. {
  10.     USES_CONVERSION;
  11.     static int nCountFile = 0;
  12.     DWORD dwRet = 1;
  13.     WCHAR *s = NULL;
  14.     HANDLE hFind = NULL;
  15.     WIN32_FIND_DATAW fd = {0};
  16.     WCHAR wszFileName[MAX_PATH] = L"";
  17.     lstrcpyW(wszFileName, pwszPath);
  18.     s = wszFileName + wcslen(wszFileName);
  19.     if (*(s-1) != L‘//‘)
  20.         *s++ = L‘//‘;
  21.     // wcscpy_s(s, 4, L"*.*");
  22.     ::lstrcpyW(s, L"*.*");
  23.     hFind = FindFirstFileW(wszFileName, &fd);
  24.     if (hFind==INVALID_HANDLE_VALUE)
  25.         goto Exit0;
  26.     do 
  27.     {
  28.         // 过滤
  29.         if (_wcsicmp(L".", fd.cFileName) == 0 || _wcsicmp(L"..", fd.cFileName) == 0)
  30.             continue;
  31.         ::lstrcpyW(s, fd.cFileName);
  32.         *(s + lstrlenW(fd.cFileName)) = L‘/0‘;
  33.         // 如果是文件夹则递归
  34.         if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  35.         {
  36.             // 删除.svn目录,我做一个小工作,删文件,o(∩_∩)o...
  37.             WCHAR wszSvnCmd[MAX_PATH] = {0};
  38.             ::lstrcpyW(wszSvnCmd, L"rmdir /s/q ");
  39.             ::lstrcatW(wszSvnCmd, wszFileName);
  40.             ::lstrcatW(wszSvnCmd, L"//.svn");
  41.             system(W2A(wszSvnCmd));
  42.             ScanDirectory(wszFileName);
  43.         }
  44.         else
  45.         {
  46.             // 对文件进行扫描
  47.             // 这里你可以放入你对文件的处理代码
  48.         }
  49.     }while(::FindNextFileW(hFind, &fd));
  50.     dwRet = 0;
  51. Exit0:
  52.     if( hFind != INVALID_HANDLE_VALUE )
  53.     {
  54.         ::FindClose( hFind );
  55.         hFind = NULL;
  56.     }
  57.     return dwRet;
  58. }

  当然上面的代码还只能遍历一个磁盘,除非你知道自己的机器上有几个磁盘,然后调用几次就可以了,但是你不知道用户的机器上有几个什么磁盘咯,所以还须有下面的代码和上面配合:

  1. // -------------------------------------------------------------------------
  2. // 函数       : ParseDiskName
  3. // 功能       : 解析机器上能扫描的磁盘的名
  4. // 返回值  : DWORD 返回能扫描的磁盘数量
  5. // 参数       : TCHAR *pszDiskName  缓冲区 放入可扫描的磁盘的英文盘符名
  6. // 附注       : 
  7. // -------------------------------------------------------------------------
  8. DWORD ParseDiskName(TCHAR *pszDiskName)
  9. {
  10.     static TCHAR *pszWordTable = {"abcdefghijklmnopqrstuvwxyz"};
  11.     DWORD dwDisk;
  12.     DWORD dwBase = 0x1;
  13.     DWORD dwCount = 0;          // 记录磁盘数量
  14.     DWORD dwScanCount = 0;      // 要扫描的有效磁盘数量,用于返回
  15.     DWORD dwStyle;
  16.     TCHAR szDiskPath[4] = {0};                  // 缓存一个磁盘根目录名
  17.     TCHAR szDiskArray[26] = {0};                // 记录要扫描的所有磁盘名
  18.     dwDisk = GetLogicalDrives();
  19.     
  20.     while (dwDisk && dwCount <= ::lstrlen(pszWordTable))
  21.     {
  22.         memset(szDiskPath, 0, sizeof(szDiskPath));
  23.         if (dwDisk & dwBase)
  24.         {
  25.             ::lstrcpyn(szDiskPath, pszWordTable + dwCount, 2);
  26.             ::lstrcat(szDiskPath, TEXT("://"));
  27.             dwStyle = GetDriveType(szDiskPath);
  28.             // 是否可扫描的
  29.             if (DRIVE_REMOVABLE == dwStyle || DRIVE_FIXED == dwStyle)
  30.             {
  31.                 szDiskArray[dwScanCount] = pszWordTable[dwCount];
  32.                 dwScanCount++;
  33.             }
  34.         }   
  35.         dwDisk = dwDisk & ~dwBase;
  36.         dwBase = dwBase * 2;
  37.         dwCount++;
  38.     }
  39.     ::lstrcpy(pszDiskName, szDiskArray);
  40.     return dwScanCount;
  41. }

  呵呵,差不多了,不过上面的遍历文件用递归实现的,有可能出现堆栈溢出的情况,用迭代实现遍历磁盘也是可以的,不过我一直没有去写一个,还是觉得太麻烦了,递归多方便啊。再show点代码,对计算机进行重启的,不过这个重启是类似于掉电重启的,大家别随便试啊,一调你的机器得不到任何通知就重启了,为什么要这么用呢?是因为有些病毒再收到系统重启通知的时候会干些坏事情,用这种方法才能彻底清除它。

  1. // -------------------------------------------------------------------------
  2. // 函数       : ForceShutDown
  3. // 功能       : 强制重启
  4. // 返回值  : HRESULT 
  5. // 附注       : 
  6. // -------------------------------------------------------------------------
  7. HRESULT ForceShutDown()
  8. {
  9.     // 强制重启参数 函数指针声明
  10.     typedef enum _SHUTDOWN_ACTION
  11.     {
  12.         ShutdownNoReboot,
  13.         ShutdownReboot,
  14.         ShutdownPowerOff
  15.     } SHUTDOWN_ACTION;
  16.     typedef DWORD (WINAPI* lpNtShutdownSystem)(SHUTDOWN_ACTION Action);
  17.     LONG nRet = FALSE;
  18.     HANDLE hToken;
  19.     TOKEN_PRIVILEGES tkp;
  20.     HANDLE hProcess = NULL;
  21.     HMODULE hNTDLL = NULL;
  22.     hProcess = ::GetCurrentProcess();
  23.     if(hProcess == NULL)
  24.         goto Exit0;
  25.     if(!::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
  26.         goto Exit0;
  27.     if(!::LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid))
  28.         goto Exit0;
  29.     tkp.PrivilegeCount = 1;
  30.     tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  31.     ::AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
  32.     hNTDLL = LoadLibrary(_T("NTDLL.DLL"));
  33.     if (hNTDLL)
  34.     {
  35.         lpNtShutdownSystem NtShutdownSystem = (lpNtShutdownSystem)GetProcAddress(hNTDLL, "NtShutdownSystem");
  36.         if (NtShutdownSystem)
  37.         {
  38.             NtShutdownSystem(ShutdownReboot);
  39.         }
  40.         ::FreeLibrary(hNTDLL);
  41.         nRet = TRUE;
  42.     }
  43. Exit0:
  44.     if(hToken)
  45.     {
  46.         ::CloseHandle(hToken);
  47.         hToken = NULL;
  48.     }
  49.     if(hProcess)
  50.     {
  51.         ::CloseHandle(hProcess);
  52.         hProcess = NULL;
  53.     }
  54.     return nRet;
  55. }
 

  以后再说说那个堆栈溢出的情况吧。

 

http://blog.csdn.net/magictong/article/details/2784420

关于 win32 下磁盘的遍历方法