• 关于 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

  • 相关阅读:
    PHP+MYSQL单例模式的滑铁卢
    碰到一个安装SQl2008 Express Edition出错的怪异情况
    用虚拟并口解决向USB条码打印机发送ZPL指令的解决方案
    让excanvas支持动态创建的canvas标签(附演示文件)
    sql 检索语句
    c++ string 类基本用法样例
    Sqlite c/c++ api 学习
    最常见的20种VC++编译错误信息
    C#动态调用C++编写的DLL函数
    C++中将BYTE转16进制字符串
  • 原文地址:https://www.cnblogs.com/findumars/p/6143458.html
Copyright © 2020-2023  润新知