C++实现支持32位和64位进程的模块枚举

C++实现支持32位和64位进程的模块枚举

使用 Visual Studio 2022 (VC++ 2022) 创建 MFC 对话框应用程序

支持查找32位和64位进程(使用TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32同时枚举两种模块)

输入进程名称(例如notepad.exe),点击“查找进程”按钮

在列表控件(ListCtrl)中显示该进程的所有模块名称、基址、大小、路径

1. 资源部分(在资源编辑器中添加控件)

在对话框资源(ID 为IDD_GETMODULEBASE_DIALOG)中添加以下控件:

类型IDCaption其他属性
Edit ControlIDC_EDIT_PROCESS(空)
ButtonIDC_BTN_SEARCH查找进程
List ControlIDC_LIST_MODULES(空)View: Report, 加四列(见代码)
StaticIDC_STATIC_TIP输入进程名(如 notepad.exe)

2. GetModuleBaseDlg.h

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

#pragma once

#include <tlhelp32.h>

#include <afxwin.h>

#include <afxcmn.h>

classCGetModuleBaseDlg :publicCDialogEx

{

public:

CGetModuleBaseDlg(CWnd* pParent = nullptr);

enum{ IDD = IDD_GETMODULEBASE_DIALOG };

protected:

virtualvoidDoDataExchange(CDataExchange* pDX);

virtualBOOLOnInitDialog();

DECLARE_MESSAGE_MAP()

public:

afx_msgvoidOnBnClickedBtnSearch();

private:

DWORDGetProcessIDByName(LPCTSTRlpProcessName);

BOOLGetAllModules(DWORDdwPID, CListCtrl& listCtrl);

CEdit m_editProcess;

CButton m_btnSearch;

CListCtrl m_listModules;

};

3. GetModuleBaseDlg.cpp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

#include "pch.h"

#include "GetModuleBase.h"

#include "GetModuleBaseDlg.h"

#include "afxdialogex.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

CGetModuleBaseDlg::CGetModuleBaseDlg(CWnd* pParent/*=nullptr*/)

: CDialogEx(IDD_GETMODULEBASE_DIALOG, pParent)

{

}

voidCGetModuleBaseDlg::DoDataExchange(CDataExchange* pDX)

{

CDialogEx::DoDataExchange(pDX);

DDX_Control(pDX, IDC_EDIT_PROCESS, m_editProcess);

DDX_Control(pDX, IDC_BTN_SEARCH, m_btnSearch);

DDX_Control(pDX, IDC_LIST_MODULES, m_listModules);

}

BEGIN_MESSAGE_MAP(CGetModuleBaseDlg, CDialogEx)

ON_BN_CLICKED(IDC_BTN_SEARCH, &CGetModuleBaseDlg::OnBnClickedBtnSearch)

END_MESSAGE_MAP()

BOOLCGetModuleBaseDlg::OnInitDialog()

{

CDialogEx::OnInitDialog();

// 设置列表控件为报告视图并添加列

m_listModules.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

m_listModules.InsertColumn(0, _T("模块名称"), LVCFMT_LEFT, 150);

m_listModules.InsertColumn(1, _T("基址"), LVCFMT_LEFT, 120);

m_listModules.InsertColumn(2, _T("大小"), LVCFMT_LEFT, 100);

m_listModules.InsertColumn(3, _T("路径"), LVCFMT_LEFT, 400);

returnTRUE;

}

// 根据进程名获取 PID(支持大小写不敏感)

DWORDCGetModuleBaseDlg::GetProcessIDByName(LPCTSTRlpProcessName)

{

DWORDdwPID = 0;

HANDLEhSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

if(hSnapshot == INVALID_HANDLE_VALUE)

return0;

PROCESSENTRY32 pe32 = {sizeof(pe32) };

if(Process32First(hSnapshot, &pe32))

{

do

{

if(_tcsicmp(pe32.szExeFile, lpProcessName) == 0)// 不区分大小写

{

dwPID = pe32.th32ProcessID;

break;

}

}while(Process32Next(hSnapshot, &pe32));

}

CloseHandle(hSnapshot);

returndwPID;

}

// 枚举指定进程的所有模块(同时支持 32/64 位模块)

BOOLCGetModuleBaseDlg::GetAllModules(DWORDdwPID, CListCtrl& listCtrl)

{

listCtrl.DeleteAllItems();

// 同时使用 TH32CS_SNAPMODULE 和 TH32CS_SNAPMODULE32 可兼容 WOW64 进程的 32 位模块

HANDLEhSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, dwPID);

if(hSnapshot == INVALID_HANDLE_VALUE)

returnFALSE;

MODULEENTRY32 me32 = {sizeof(me32) };

if(Module32First(hSnapshot, &me32))

{

intnItem = 0;

do

{

CString strBase, strSize;

strBase.Format(_T("0x%016I64X"), (ULONGLONG)me32.modBaseAddr);

strSize.Format(_T("0x%08X"), me32.modBaseSize);

listCtrl.InsertItem(nItem, me32.szModule);

listCtrl.SetItemText(nItem, 1, strBase);

listCtrl.SetItemText(nItem, 2, strSize);

listCtrl.SetItemText(nItem, 3, me32.szExePath);

nItem++;

}while(Module32Next(hSnapshot, &me32));

}

CloseHandle(hSnapshot);

returnTRUE;

}

voidCGetModuleBaseDlg::OnBnClickedBtnSearch()

{

CString strProcessName;

m_editProcess.GetWindowText(strProcessName);

strProcessName.Trim();

if(strProcessName.IsEmpty())

{

AfxMessageBox(_T("请输入进程名称!"));

return;

}

DWORDdwPID = GetProcessIDByName(strProcessName);

if(dwPID == 0)

{

AfxMessageBox(_T("未找到指定进程!请确认进程名称正确(包含.exe),且进程正在运行。"));

m_listModules.DeleteAllItems();

return;

}

CString strTitle;

strTitle.Format(_T("进程 %s (PID: %u) 的模块列表"), strProcessName, dwPID);

SetWindowText(strTitle);

if(!GetAllModules(dwPID, m_listModules))

{

AfxMessageBox(_T("枚举模块失败,可能没有足够权限。"));

m_listModules.DeleteAllItems();

}

}

4. 项目配置(VS2022)

项目使用Unicode字符集。

使用 MFC:项目属性 → 常规 → 使用 MFC → “在共享 DLL 中使用 MFC” 或 “在静态库中使用 MFC”。

5.使用方法

  • 运行程序
  • 在编辑框输入进程可执行文件名,例如:notepad.exechrome.exe
  • 点击“查找进程”
  • 列表中会显示该进程加载的所有模块(包括主模块和 DLL)

这样就完整实现了你要求的功能,支持 32 位和 64 位进程的模块枚举。