在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.th32ProcessID, ProcessEntry32.szExeFile);
} while (Process32Next(hSnapshot, &ProcessEntry32));
}
CloseHandle(hSnapshot);
getchar();
}
二、Psapi
头文件:Psapi.h
关键函数:EnumProcesses,OpenProcess,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(ProcessID, sizeof(ProcessID), &CbNeeded))
{
return FALSE;
}
ProcessesCount = CbNeeded / sizeof(DWORD);
_tprintf(TEXT("ProcessID\t ProcessImageName\t ProcessImageFullPath\r\n"));
for (size_t i = 0; i < CbNeeded; i++)
{
if (0 != ProcessID[i])
{
// 没有PROCESS_VM_READ 权限是枚举不出来的
ProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, ProcessID[i]);
if (ProcessHandle != NULL)
{
// 完整路径
if (GetProcessImageFileName(ProcessHandle, ProcessDosPath, _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(ProcessDosPath, ProcessNtPath, MAX_PATH);
}
//进程名称()
if (EnumProcessModules(ProcessHandle, &hMod, sizeof(hMod), &CbNeeded))
{
GetModuleBaseName(ProcessHandle, hMod, ProcessName, sizeof(ProcessName) / sizeof(TCHAR));
}
else
{
_stprintf_s(ProcessName, TEXT("%s"), TEXT(""));
}
_tprintf(TEXT("%d\t%s\t%s\r\n"), ProcessID[i], ProcessName, ProcessNtPath);
CloseHandle(ProcessHandle);
}
}
}
return TRUE;
}
BOOL DosPathToNtPath(IN LPTSTR DosPath, OUT 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(DeviceName, DosPathOfVolume, 0x100 /sizeof(TCHAR)))
{
// C: 对应的DosPath是 \Device\HarddiskVolume2
StringLength = lstrlen(DosPathOfVolume);
// \Device\HarddiskVolume2 --> \Device\HarddiskVolume2\Windows\System32\sihost.exe
lstrcat(DosPathOfVolume, DosPath + StringLength);
// 判断是否是待转换的路径
if (lstrcmpi(DosPathOfVolume, DosPath) == NULL)
{
lstrcpy(NtPath, DeviceName); // D:
lstrcat(NtPath, DosPath + StringLength); // D:\Windows\system32
return TRUE;
}
}
DeviceName[0]++;
}
while (COMDeviceName[3] <= '9') //9
{
if (QueryDosDevice(COMDeviceName, DosPathOfVolume, MAX_PATH * 2) > NULL)
{
StringLength = lstrlen(DosPathOfVolume);
lstrcat(DosPathOfVolume, (DosPath + StringLength));
if (lstrcmpi(DosPathOfVolume, DosPath) == NULL)
{
lstrcpy(NtPath, COMDeviceName);
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, &SystemProcessInfo, BufferLength, &ReturnLength))
{
BufferLength = ReturnLength;
SystemProcessInfo = (PSYSTEM_PROCESS_INFORMATION)malloc(BufferLength);
if (!SystemProcessInfo)
{
return FALSE;
}
if (__NtQuerySystemInformation(SystemProcessInformation, SystemProcessInfo, BufferLength, &ReturnLength) != STATUS_SUCCESS)
{
GetLastError();
return FALSE;
}
while (SystemProcessInfo->NextEntryOffset != 0)
{
wprintf(L"%d\t%s\r\n", SystemProcessInfo->UniqueProcessId, SystemProcessInfo->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 < dwCount; i++)
{
printf("%d\t%s\n", wts[i].ProcessId, wts[i].pProcessName);
}
getchar();
return 0;
}