应用层枚举进程及模块的两种方式
1.快照方式枚举进程
BOOL EnumProcesses(HWND hProcessList)
{
ListView_DeleteAllItems(hProcessList);
PROCESSENTRY32 pe = { 0 };
pe.dwSize = sizeof(pe);
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
int i = 0;
TCHAR buff[256] = { 0 };
while (Process32Next(hSnap, &pe))
{
ListInsertItem(hProcessList, i, 0, pe.szExeFile);
wsprintf(buff, L"%d", (int)pe.th32ParentProcessID);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%d", (int)pe.th32ProcessID);
ListSetItemText(hProcessList, i, 2, buff);
i++;
}
CloseHandle(hSnap);
return TRUE;
}
2.快照方式枚举进程模块
BOOL EnumModule(HWND hProcessList, DWORD pid)
{
ListView_DeleteAllItems(hProcessList);
MODULEENTRY32 me = { 0 };
me.dwSize = sizeof(me);
int i = 0;
TCHAR buff[256] = { 0 };
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, pid);
while (Module32Next(hSnap, &me))
{
ListInsertItem(hProcessList, i, 0, me.szModule);
wsprintf(buff, L"%p",me.modBaseAddr);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%08X", me.modBaseSize);
ListSetItemText(hProcessList, i, 2, buff);
}
CloseHandle(hSnap);
return TRUE;
}
3.通过NtQuerySystemInformation函数枚举进程
BOOL EnumProcesses(HWND hProcessList)
{
ListView_DeleteAllItems(hProcessList);
ULONG len = 0;
ULONG m_bsize = 1024;
BYTE* m_buff = new BYTE[1024];
HMODULE hNtdll = GetModuleHandle(L"ntdll.dll");
if (!hNtdll)
{
return FALSE;
}
pfNtQuerySystemInformation NtQuerySystemInformation = (pfNtQuerySystemInformation)GetProcAddress(hNtdll, "NtQuerySystemInformation");
NtQuerySystemInformation(SystemProcessInformation, m_buff, m_bsize, &len);
while (m_bsize < len)
{
delete[] m_buff;
m_bsize = len;
m_buff = new BYTE[m_bsize];
NtQuerySystemInformation(SystemProcessInformation, m_buff, m_bsize, &len);
}
SYSTEM_PROCESS_INFORMATION* ps = (SYSTEM_PROCESS_INFORMATION*)m_buff;
ps = (SYSTEM_PROCESS_INFORMATION*)((ULONG64)ps + ps->NextEntryOffset);
int i = 0;
WCHAR buff[256] = { 0 };
while (ps->NextEntryOffset)
{
ListInsertItem(hProcessList, i, 0, (LPCTSTR)(ps->ImageName.Buffer));
wsprintf(buff, L"%d", (int)ps->InheritedFromUniqueProcessId);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%d", (int)ps->UniqueProcessId);
ListSetItemText(hProcessList, i, 2, buff);
wsprintf(buff, L"%d", CriticalLevel((int)ps->UniqueProcessId));
ListSetItemText(hProcessList, i, 3, buff);
i++;
ps = (SYSTEM_PROCESS_INFORMATION*)((ULONG64)ps + ps->NextEntryOffset);
}
ListInsertItem(hProcessList, i, 0, (LPCTSTR)(ps->ImageName.Buffer));
wsprintf(buff, L"%d", (int)ps->InheritedFromUniqueProcessId);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%d", (int)ps->UniqueProcessId);
ListSetItemText(hProcessList, i, 2, buff);
wsprintf(buff, L"%d", CriticalLevel((int)ps->UniqueProcessId));
ListSetItemText(hProcessList, i, 3, buff);
return TRUE;
}
4.通过NtQueryInformationProcess函数枚举进程模块
BOOL EnumModule(HWND hProcessList,DWORD pid)
{
ListView_DeleteAllItems(hProcessList);
HMODULE hNtdll = GetModuleHandle(L"ntdll.dll");
if (!hNtdll)
{
return FALSE;
}
int i = 0;
pfNtOpenProcess NtOpenProcess = (pfNtOpenProcess)GetProcAddress(hNtdll, "NtOpenProcess");
pfNtQueryInformationProcess NtQueryInformationProcess = (pfNtQueryInformationProcess)GetProcAddress(hNtdll, "NtQueryInformationProcess");
pfNtReadVirtualMemory NtReadVirtualMemory = (pfNtReadVirtualMemory)GetProcAddress(hNtdll, "NtReadVirtualMemory");
BOOL source = FALSE;
BOOL target = FALSE;
IsWow64Process(GetCurrentProcess(), &source);
HANDLE hProcess = 0;
CLIENT_ID client = { 0 };
OBJECT_ATTRIBUTES oa = { 0 };
client.UniqueProcess = pid;
oa.Length = sizeof(OBJECT_ATTRIBUTES);
NtOpenProcess(&hProcess, GENERIC_ALL, &oa, &client);
if (NULL == hProcess)
{
return FALSE;
}
IsWow64Process(hProcess, &target);
if (source == FALSE && target == FALSE)
{
PROCESS_BASIC_INFORMATION64 pbi64 = { 0 };
NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi64, sizeof(pbi64), NULL);
DWORD64 Ldr64 = 0;
LIST_ENTRY64 ListEntry64 = { 0 };
LDR_DATA_TABLE_ENTRY64 LDTE64 = { 0 };
wchar_t buff[256] = { 0 };
NtReadVirtualMemory(hProcess, (PVOID64)(pbi64.PebBaseAddress + offsetof(PEB64, Ldr)), &Ldr64, sizeof(Ldr64), NULL);
NtReadVirtualMemory(hProcess, (PVOID64)(Ldr64 + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList)), &ListEntry64, sizeof(LIST_ENTRY64), NULL);
NtReadVirtualMemory(hProcess, (PVOID64)(ListEntry64.Flink), &LDTE64, sizeof(LDR_DATA_TABLE_ENTRY64), NULL);
while (LDTE64.InLoadOrderLinks.Flink != ListEntry64.Flink)
{
NtReadVirtualMemory(hProcess, (PVOID64)LDTE64.BaseDllName.Buffer, buff, sizeof(buff), NULL);
ListInsertItem(hProcessList, i, 0, buff);
wsprintf(buff, L"%p", (PVOID64)LDTE64.DllBase);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%08X", LDTE64.SizeOfImage);
ListSetItemText(hProcessList, i, 2, buff);
i++;
//printf("模块基址:0x%llX\t模块大小:0x%-10X\t模块路径:%ls\n", LDTE64.DllBase, LDTE64.SizeOfImage, ProPath64);
NtReadVirtualMemory(hProcess, (PVOID64)LDTE64.InLoadOrderLinks.Flink, &LDTE64, sizeof(LDR_DATA_TABLE_ENTRY64), NULL);
}
}
#ifndef _WIN64
else if (source == TRUE && target == FALSE)
{
PROCESS_BASIC_INFORMATION64 pbi64 = { 0 };
pfNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfNtWow64QueryInformationProcess64)GetProcAddress(hNtdll, "NtWow64QueryInformationProcess64");
NtWow64QueryInformationProcess64(hProcess, ProcessBasicInformation, &pbi64, sizeof(pbi64), NULL);
DWORD64 Ldr64 = 0;
LIST_ENTRY64 ListEntry64 = { 0 };
LDR_DATA_TABLE_ENTRY64 LDTE64 = { 0 };
wchar_t buff[256] = { 0 };
pfNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfNtWow64ReadVirtualMemory64)GetProcAddress(hNtdll, "NtWow64ReadVirtualMemory64");
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)(pbi64.PebBaseAddress + offsetof(PEB64, Ldr)), &Ldr64, sizeof(Ldr64), NULL);
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)(Ldr64 + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList)), &ListEntry64, sizeof(LIST_ENTRY64), NULL);
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)(ListEntry64.Flink), &LDTE64, sizeof(LDR_DATA_TABLE_ENTRY64), NULL);
while (LDTE64.InLoadOrderLinks.Flink != ListEntry64.Flink)
{
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)LDTE64.BaseDllName.Buffer, buff, sizeof(buff), NULL);
ListInsertItem(hProcessList, i, 0, buff);
wsprintf(buff, L"%08X%08X", *((ULONG*)&LDTE64.DllBase+1) ,*(ULONG*)&LDTE64.DllBase);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%08X", LDTE64.SizeOfImage);
ListSetItemText(hProcessList, i, 2, buff);
i++;
//printf("模块基址:0x%llX\t模块大小:0x%-10X\t模块路径:%ls\n", LDTE64.DllBase, LDTE64.SizeOfImage, ProPath64);
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)LDTE64.InLoadOrderLinks.Flink, &LDTE64, sizeof(LDR_DATA_TABLE_ENTRY64), NULL);
}
}
else if (source == TRUE && target == TRUE)
{
PROCESS_BASIC_INFORMATION64 pbi64 = { 0 };
pfNtWow64QueryInformationProcess64 NtWow64QueryInformationProcess64 = (pfNtWow64QueryInformationProcess64)GetProcAddress(hNtdll, "NtWow64QueryInformationProcess64");
NtWow64QueryInformationProcess64(hProcess, ProcessBasicInformation, &pbi64, sizeof(pbi64), NULL);
DWORD64 Ldr64 = 0;
LIST_ENTRY64 ListEntry64 = { 0 };
LDR_DATA_TABLE_ENTRY64 LDTE64 = { 0 };
wchar_t buff[256] = { 0 };
pfNtWow64ReadVirtualMemory64 NtWow64ReadVirtualMemory64 = (pfNtWow64ReadVirtualMemory64)GetProcAddress(hNtdll, "NtWow64ReadVirtualMemory64");
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)(pbi64.PebBaseAddress + offsetof(PEB64, Ldr)), &Ldr64, sizeof(Ldr64), NULL);
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)(Ldr64 + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList)), &ListEntry64, sizeof(LIST_ENTRY64), NULL);
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)(ListEntry64.Flink), &LDTE64, sizeof(LDR_DATA_TABLE_ENTRY64), NULL);
while (LDTE64.InLoadOrderLinks.Flink != ListEntry64.Flink)
{
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)LDTE64.BaseDllName.Buffer, buff, sizeof(buff), NULL);
ListInsertItem(hProcessList, i, 0, buff);
wsprintf(buff, L"%08X%08X", *((ULONG*)&LDTE64.DllBase + 1), *(ULONG*)&LDTE64.DllBase);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%08X", LDTE64.SizeOfImage);
ListSetItemText(hProcessList, i, 2, buff);
i++;
//printf("模块基址:0x%llX\t模块大小:0x%-10X\t模块路径:%ls\n", LDTE64.DllBase, LDTE64.SizeOfImage, ProPath64);
NtWow64ReadVirtualMemory64(hProcess, (PVOID64)LDTE64.InLoadOrderLinks.Flink, &LDTE64, sizeof(LDR_DATA_TABLE_ENTRY64), NULL);
}
PROCESS_BASIC_INFORMATION32 pbi32 = { 0 };
NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi32, sizeof(pbi32), NULL);
DWORD Ldr32 = 0;
LIST_ENTRY32 ListEntry32 = { 0 };
LDR_DATA_TABLE_ENTRY32 LDTE32 = { 0 };
//wchar_t buff[256] = { 0 };
NtReadVirtualMemory(hProcess, (PVOID)(pbi32.PebBaseAddress + offsetof(PEB32, Ldr)), &Ldr32, sizeof(Ldr32), NULL);
NtReadVirtualMemory(hProcess, (PVOID)(Ldr32 + offsetof(PEB_LDR_DATA32, InLoadOrderModuleList)), &ListEntry32, sizeof(LIST_ENTRY32), NULL);
NtReadVirtualMemory(hProcess, (PVOID)(ListEntry32.Flink), &LDTE32, sizeof(LDR_DATA_TABLE_ENTRY32), NULL);
while (LDTE32.InLoadOrderLinks.Flink != ListEntry32.Flink)
{
NtReadVirtualMemory(hProcess, (PVOID)LDTE32.BaseDllName.Buffer, buff, sizeof(buff), NULL);
ListInsertItem(hProcessList, i, 0, buff);
wsprintf(buff, L"%08X", LDTE32.DllBase);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%08X", LDTE32.SizeOfImage);
ListSetItemText(hProcessList, i, 2, buff);
i++;
//NtReadVirtualMemory(hProcess, (PVOID)LDTE32.FullDllName.Buffer, ProPath32, sizeof(ProPath32), NULL);
//printf("模块基址:0x%08X\t模块大小:0x%-08X\t模块路径:%ws\n", LDTE32.DllBase, LDTE32.SizeOfImage, ProPath32);
NtReadVirtualMemory(hProcess, (PVOID)LDTE32.InLoadOrderLinks.Flink, &LDTE32, sizeof(LDR_DATA_TABLE_ENTRY32), NULL);
}
}
#endif
else if (source == FALSE && target == TRUE)
{
PROCESS_BASIC_INFORMATION64 pbi64 = { 0 };
NtQueryInformationProcess(hProcess, ProcessBasicInformation, &pbi64, sizeof(pbi64), NULL);
DWORD64 Ldr64 = 0;
LIST_ENTRY64 ListEntry64 = { 0 };
LDR_DATA_TABLE_ENTRY64 LDTE64 = { 0 };
wchar_t buff[256] = { 0 };
NtReadVirtualMemory(hProcess, (PVOID64)(pbi64.PebBaseAddress + offsetof(PEB64, Ldr)), &Ldr64, sizeof(Ldr64), NULL);
NtReadVirtualMemory(hProcess, (PVOID64)(Ldr64 + offsetof(PEB_LDR_DATA64, InLoadOrderModuleList)), &ListEntry64, sizeof(LIST_ENTRY64), NULL);
NtReadVirtualMemory(hProcess, (PVOID64)(ListEntry64.Flink), &LDTE64, sizeof(LDR_DATA_TABLE_ENTRY64), NULL);
while (LDTE64.InLoadOrderLinks.Flink != ListEntry64.Flink)
{
NtReadVirtualMemory(hProcess, (PVOID64)LDTE64.BaseDllName.Buffer, buff, sizeof(buff), NULL);
ListInsertItem(hProcessList, i, 0, buff);
wsprintf(buff, L"%p", (PVOID64)LDTE64.DllBase);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%08X", LDTE64.SizeOfImage);
ListSetItemText(hProcessList, i, 2, buff);
i++;
//printf("模块基址:0x%llX\t模块大小:0x%-10X\t模块路径:%ls\n", LDTE64.DllBase, LDTE64.SizeOfImage, ProPath64);
NtReadVirtualMemory(hProcess, (PVOID64)LDTE64.InLoadOrderLinks.Flink, &LDTE64, sizeof(LDR_DATA_TABLE_ENTRY64), NULL);
}
ULONG_PTR peb32 = { 0 };//用来存储32位PEB地址
NtQueryInformationProcess(hProcess, ProcessWow64Information, &peb32, sizeof(peb32), NULL);
DWORD32 Ldr32 = 0;
LIST_ENTRY32 ListEntry32 = { 0 };
LDR_DATA_TABLE_ENTRY32 LDTE32 = { 0 };
//wchar_t buff[256] = { 0 };
NtReadVirtualMemory(hProcess, (PVOID)(peb32 + offsetof(PEB32, Ldr)), &Ldr32, sizeof(Ldr32), NULL);
NtReadVirtualMemory(hProcess, (PVOID)(Ldr32 + offsetof(PEB_LDR_DATA32, InLoadOrderModuleList)), &ListEntry32, sizeof(LIST_ENTRY32), NULL);
NtReadVirtualMemory(hProcess, (PVOID)(ListEntry32.Flink), &LDTE32, sizeof(LDR_DATA_TABLE_ENTRY32), NULL);
while (LDTE32.InLoadOrderLinks.Flink != ListEntry32.Flink)
{
NtReadVirtualMemory(hProcess, (PVOID)LDTE32.BaseDllName.Buffer, buff, sizeof(buff), NULL);
ListInsertItem(hProcessList, i, 0, buff);
wsprintf(buff, L"%08X", LDTE32.DllBase);
ListSetItemText(hProcessList, i, 1, buff);
wsprintf(buff, L"%08X", LDTE32.SizeOfImage);
ListSetItemText(hProcessList, i, 2, buff);
i++;
//NtReadVirtualMemory(hProcess, (PVOID)LDTE32.FullDllName.Buffer, ProPath32, sizeof(ProPath32), NULL);
//printf("模块基址:0x%lX\t模块大小:0x%-10X\t模块路径:%ls\n", LDTE32.DllBase, LDTE32.SizeOfImage, ProPath32);
NtReadVirtualMemory(hProcess, (PVOID)LDTE32.InLoadOrderLinks.Flink, &LDTE32, sizeof(LDR_DATA_TABLE_ENTRY32), NULL);
}
}
return TRUE;
}
5.总结
综上,第一种方法使用快照枚举进程和模块,优点是代码量少,缺点是32位进程无法枚举64位进程模块。第二种方法使用Nt函数枚举进程和模块,优点是32位进程可以枚举64位进程模块,缺点是代码量多且要使用未文档化的数据结构。