Ring3枚举进程

在Ring3枚举进程通常有一下几种方法:
  • ToolHelper32
  • Psapi
  • ZwQuerySystemInformation
  • WTSEnumerateProcesses

一、ToolHelper32

头文件:TlHelp32.h
关键函数:CreateToolhelp32Snapshot,Process32Next

BOOL EnumProcessesByToolHelper32()
{
    PROCESSENTRY32 ProcessEntry32 = { 0 };
    HANDLE hSnapshot = INVALID_HANDLE_VALUE;
    BOOL IsOk = FALSE;
    
    hSnapshot = CreateToolhelp32Snapshot(2, 0);
    if (INVALID_HANDLE_VALUE == hSnapshot)
    {
        return FALSE;
    }
    //不添加这句会出现 0x0018 错误
    ProcessEntry32.dwSize = sizeof(ProcessEntry32);
    //遍历名字查找
    _tprintf(TEXT("ProcessID\tProcessImageName\r\n"));
    if (Process32First(hSnapshot, &ProcessEntry32))
    {
        do
        {
            _tprintf(TEXT("%d\t%s\r\n"), ProcessEntry32.th32ProcessIDProcessEntry32.szExeFile);
        } while (Process32Next(hSnapshot, &ProcessEntry32));
    }
    CloseHandle(hSnapshot);
    getchar();
}

二、Psapi

头文件:Psapi.h
关键函数:EnumProcessesOpenProcess,EnumProcessModules,GetProcessImageFileName,GetModuleBaseName
总结:由于该方法需要进程句柄,如果得不到进程句柄,什么信息都得不到,不建议使用。

// 注意:32位程序只能枚举32位程序,枚举不出64位程序
BOOL  EnumProcessByPsapi()
{
    TCHAR ProcessDosPath[0x200] = {};
    TCHAR ProcessNtPath[MAX_PATH];
    TCHAR ProcessName[MAX_PATH];
    DWORD ProcessID[1024];
    DWORD ProcessesCount;
    DWORD CbNeeded;
    
    HANDLE ProcessHandle = NULL;
    HMODULE hMod = NULL;
    if (!EnumProcesses(ProcessIDsizeof(ProcessID), &CbNeeded))
    {
        return FALSE;
    }
    ProcessesCount = CbNeeded / sizeof(DWORD);
    _tprintf(TEXT("ProcessID\t ProcessImageName\t ProcessImageFullPath\r\n"));
    for (size_t i = 0; i < CbNeededi++)
    {
        if (0 != ProcessID[i])
        {
            // 没有PROCESS_VM_READ 权限是枚举不出来的
            ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                FALSEProcessID[i]);
            if (ProcessHandle != NULL)
            {
                // 完整路径
                if (GetProcessImageFileName(ProcessHandleProcessDosPath_countof(ProcessDosPath)) > NULL)
                {
                    // The GetProcessImageFileName function returns the path in device form, rather than drive letters.
                    // For example, the file name C:\Windows\System32\Ctype.nls would look as follows in 
                    // device form :\Device\Harddisk0\Partition1\Windows\System32\Ctype.nls
                    DosPathToNtPath(ProcessDosPathProcessNtPathMAX_PATH);
                }
                //进程名称()
                if (EnumProcessModules(ProcessHandle, &hModsizeof(hMod), &CbNeeded))
                {
                    GetModuleBaseName(ProcessHandlehModProcessNamesizeof(ProcessName) / sizeof(TCHAR));
                }
                else
                {
                    _stprintf_s(ProcessNameTEXT("%s"), TEXT(""));
                }
                _tprintf(TEXT("%d\t%s\t%s\r\n"), ProcessID[i], ProcessNameProcessNtPath);
                CloseHandle(ProcessHandle);
            }
        }
    }
    return TRUE;
}
BOOL DosPathToNtPath(IN LPTSTR DosPathOUT LPTSTR NtPath,IN ULONG CchNtPath)
{
    // DosPath: \Device\HarddiskVolume2\Windows\System32\sihost.exe
    TCHAR DosPathOfVolume[0x200];
    TCHAR DeviceName[3] = TEXT("A:");
    
    TCHAR COMDeviceName[5] = TEXT("COM0");
    ULONG StringLength = 0;
    while (DeviceName[0] <= 'Z')  //Z
    {
        // 如果指定DeviceName为NULL,那么该函数将输出所有存在的 MS-DOS device names 
        if (QueryDosDevice(DeviceNameDosPathOfVolume, 0x100 /sizeof(TCHAR)))
        {
            // C: 对应的DosPath是 \Device\HarddiskVolume2
            StringLength = lstrlen(DosPathOfVolume);
            // \Device\HarddiskVolume2 --> \Device\HarddiskVolume2\Windows\System32\sihost.exe
            lstrcat(DosPathOfVolumeDosPath + StringLength);
            // 判断是否是待转换的路径
            if (lstrcmpi(DosPathOfVolumeDosPath) == NULL)
            {
                lstrcpy(NtPathDeviceName);  // D:
                lstrcat(NtPathDosPath + StringLength);  // D:\Windows\system32
                return TRUE;
            }
        }
        DeviceName[0]++;
    }
    while (COMDeviceName[3] <= '9')  //9
    {
        if (QueryDosDevice(COMDeviceNameDosPathOfVolumeMAX_PATH * 2) > NULL)
        {
            StringLength = lstrlen(DosPathOfVolume);
            lstrcat(DosPathOfVolume, (DosPath + StringLength));
            if (lstrcmpi(DosPathOfVolumeDosPath) == NULL)
            {
                lstrcpy(NtPathCOMDeviceName);
                lstrcat(NtPath, (DosPath + StringLength));
                return TRUE;
            }
        }
        COMDeviceName[3]++;
    }
    return FALSE;
}

三、NtQuerySystemInformation

头文件:Winternl.h(头文件中的结构体都是不全的,需要自己定义,通常都是从ntdll.dll 中 Get 到函数地址)
关键函数:NtQuerySystemInformation
关键宏:SystemProcessInformation
关键结构:SYSTEM_PROCESS_INFORMATION

BOOL EnumProcessByZwQuerySystemInformation()
{
    LPFN_NtQuerySystemInformation __NtQuerySystemInformation;
    HMODULE hNtdll = LoadLibraryW(L"ntdll.dll");
    if (!hNtdll)
    {
        return FALSE;
    }
    __NtQuerySystemInformation = (LPFN_NtQuerySystemInformation)GetProcAddress(hNtdll"NtQuerySystemInformation");
    if (!__NtQuerySystemInformation)
    {
        return FALSE;
    }
    PSYSTEM_PROCESS_INFORMATION SystemProcessInfo = NULL;
    DWORD ReturnLength = 0;
    DWORD BufferLength = 1;
    // 将BufferLength置位1,查询需要的缓冲区大小
    if (STATUS_INFO_LENGTH_MISMATCH == __NtQuerySystemInformation(SystemProcessInformation, &SystemProcessInfoBufferLength, &ReturnLength))
    {
        BufferLength = ReturnLength;
        SystemProcessInfo = (PSYSTEM_PROCESS_INFORMATION)malloc(BufferLength);
        
        if (!SystemProcessInfo)
        {
            return FALSE;
        }
        if (__NtQuerySystemInformation(SystemProcessInformationSystemProcessInfoBufferLength, &ReturnLength) != STATUS_SUCCESS)
        {
            GetLastError();
            return FALSE;
        }
        while (SystemProcessInfo->NextEntryOffset != 0)
        {
            wprintf(L"%d\t%s\r\n"SystemProcessInfo->UniqueProcessIdSystemProcessInfo->ImageName.Buffer);
            SystemProcessInfo = (PSYSTEM_PROCESS_INFORMATION)((PUINT8)SystemProcessInfo + SystemProcessInfo->NextEntryOffset);
        }
    }
}

四、WTSEnumerateProcesses

头文件:Wtsapi32.h(该方法需要获得计算机名,局域网内的其它计算机应该也能枚举)
关键函数:GetComputerName,WTSOpenServer,WTSEnumerateProcesses
关键结构:PWTS_PROCESS_INFO 

int EnumProcessByWTSEnumerateProcesses()
{
    TCHAR ComputerName[MAX_COMPUTERNAME_LENGTH + 2];
    DWORD BufferSize;
    BufferSize = sizeof ComputerName - 1;
    GetComputerName(ComputerName, &BufferSize);
    PWTS_PROCESS_INFO wts;
    DWORD dwCount;
    HANDLE hWtsServer = WTSOpenServer(ComputerName);
    if (!WTSEnumerateProcesses(hWtsServer, 0, 1, &wts, &dwCount))
        return 0;
    for (DWORD i = 0; i < dwCounti++)
    {
        printf("%d\t%s\n"wts[i].ProcessIdwts[i].pProcessName);
    }
    getchar();
    return 0;
}

你可能感兴趣的:(Windows编程)