PETOOL开发日记1 - 进程查看

本文最后更新于:2022年4月13日 下午

这是滴水逆向三期的第一个项目,我们将仿造LordPE制作自己的PE解析工具,从而提升Win32正向能力并对Win32 API有更深入的认识

本节将初步完成主界面的进程查看功能,上面的List Control控件列出了系统内的所有进程,当点击某一进程时,下面的List Control将会列出该进程使用的模块(DLL)。点击PE查看按钮可以打开磁盘上的PE文件并查看PE的详细内容。

主界面设计如下:

image-20220110210610950

在主界面中,我们需要在对话框初始化的时候填充数据,亦即在接收到WM_INITDIALOG消息时填充数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
BOOL CALLBACK MainDialogProc(
HWND hwndDlg, // handle to dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch(uMsg)
{
case WM_INITDIALOG :
{
InitProcessListView(hwndDlg);
InitProcessModuleView(hwndDlg);
return TRUE ;
}
...
}

其中两个函数如下:

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
VOID InitProcessListView(HWND hDlg){
//1、初始化列名信息:
LV_COLUMN lv;
HWND hListProcess;

//初始化
memset(&lv,0,sizeof(LV_COLUMN));
//获取IDC_LIST_PROCESS句柄
hListProcess = GetDlgItem(hDlg,IDC_LIST_PROCESS);
//设置整行选中
SendMessage(hListProcess,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);

//第一列
lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
lv.pszText = _T("PID");//列标题
lv.cx = 50;
lv.iSubItem = 0;
ListView_InsertColumn(hListProcess, 0, &lv);
//第二列
lv.pszText = _T("进程名");
lv.cx = 100;
lv.iSubItem = 1;
ListView_InsertColumn(hListProcess, 1, &lv);
//第三列
lv.pszText = _T("进程地址");
lv.cx = 100;
lv.iSubItem = 2;
ListView_InsertColumn(hListProcess, 2, &lv);
//第四列
lv.pszText = _T("镜像基址");
lv.cx = 100;
lv.iSubItem = 3;
ListView_InsertColumn(hListProcess, 3, &lv);
//第五列
lv.pszText = _T("镜像大小");
lv.cx = 100;
lv.iSubItem = 4;
ListView_InsertColumn(hListProcess, 4, &lv);



// 调用API获取所有的进程信息
DWORD procPid[1024], retnBytes, procCount, retnBytes2;
unsigned int i;
HMODULE hMod[1024];
HANDLE hProcess;
TCHAR szModAbsPath[MAX_PATH];

// 构造ListView使用的变量
LPSTR processData[5] = {0};
LPSTR moduleName;
TCHAR processId[100];
TCHAR imageBase[100];
TCHAR sizeOfImage[100];
LPSTR delim;

if (EnumProcesses(procPid, sizeof(procPid), &retnBytes))
{
procCount = retnBytes / sizeof(DWORD);
SetProcessPrivilege("SeDebugPrivilege", 1);
for (i = 0; i < procCount; i++)
{
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procPid[i]);
if (hProcess != NULL)
{
EnumProcessModules(hProcess, hMod, sizeof(hMod), &retnBytes2);
GetModuleFileNameEx(hProcess, hMod[0], szModAbsPath, sizeof(szModAbsPath));

if (strstr(szModAbsPath, _T("\\SystemRoot")) != NULL)
{
char* szModNameTemp = strrep(szModAbsPath,_T("\\SystemRoot"),_T("C:\\Windows"));
strcpy(szModAbsPath, szModNameTemp);
}

// 打开文件,获取可选PE头
ReadPEFile(szModAbsPath, &pFileBuffer);
pDosHeader = (PIMAGE_DOS_HEADER) pFileBuffer;
pNTHeader = (PIMAGE_NT_HEADERS) ((DWORD) pFileBuffer + pDosHeader->e_lfanew);
pFileHeader = (PIMAGE_FILE_HEADER) (((DWORD) pNTHeader) + 4);
pOptionHeader = (PIMAGE_OPTIONAL_HEADER32) ((DWORD) pFileHeader + IMAGE_SIZEOF_FILE_HEADER);


// 插入信息到ListView中
sprintf(processId, _T("%d"), procPid[i]);
processData[0] = processId;

delim = _T("\\");
moduleName = CutAndGetLast(szModAbsPath, delim);
processData[1] = moduleName;

processData[2] = szModAbsPath;

sprintf(imageBase, _T("0x%08X"), pOptionHeader->ImageBase);
processData[3] =imageBase;

sprintf(sizeOfImage, _T("0x%08X"), pOptionHeader->SizeOfImage);
processData[4] = sizeOfImage;

InsertRow(hListProcess, processData);
//printf("PID=%d Path=%s\n", procPid[i], szModName);

free(pFileBuffer);
}
CloseHandle(hProcess);
}
SetProcessPrivilege("SeDebugPrivilege", 0);
}

}

InitProcessModuleView只是插入了列,具体的行将在点击某一列出的行时才会往其中填充数据。

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
VOID InitProcessModuleView(HWND hDlg){
//1、初始化列名信息:
LV_COLUMN lv;
HWND hModuleProcess;

//初始化
memset(&lv,0,sizeof(LV_COLUMN));
//获取IDC_LIST_MODULE句柄
hModuleProcess = GetDlgItem(hDlg,IDC_LIST_MODULE);
//设置整行选中
SendMessage(hModuleProcess,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);

//第一列
lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
lv.pszText = _T("模块名称");//列标题
lv.cx = 150;
lv.iSubItem = 0;
//ListView_InsertColumn(hListProcess, 0, &lv);
SendMessage(hModuleProcess,LVM_INSERTCOLUMN,0,(DWORD)&lv);
//第二列
lv.pszText = _T("模块位置");
lv.cx = 200;
lv.iSubItem = 1;
// 两个函数是一样的,ListView_InsertColumn是一个宏
//ListView_InsertColumn(hListProcess, 1, &lv);
SendMessage(hModuleProcess,LVM_INSERTCOLUMN,1,(DWORD)&lv);
}

当点击List Control中某一行时,将会产生一个WM_NOTIFY消息,通过该消息我们可以获得选中的行的信息,接下来就可以调用函数获取PID进而获取信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
BOOL CALLBACK MainDialogProc(
HWND hwndDlg, // handle to dialog box
UINT uMsg, // message
WPARAM wParam, // first message parameter
LPARAM lParam // second message parameter
)
{
switch(uMsg)
{
case WM_NOTIFY:
{
NMHDR* pNMHDR = (NMHDR*) lParam;
if(wParam == IDC_LIST_PROCESS && pNMHDR->code == NM_CLICK){
EnumModule(hwndDlg,wParam,lParam);
return TRUE;
}
return FALSE;
}
...
}

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
VOID EnumModule(HWND hDlg, WPARAM wParam, LPARAM lParam){
HWND hListProcess = GetDlgItem(hDlg,IDC_LIST_PROCESS);
DWORD dwRowId;
TCHAR szPid[0x20];
LV_ITEM lv;

// 初始化
memset(szPid, 0 ,0x20);
memset(&lv,0,1);
// 获取选择行
dwRowId = SendMessage(hListProcess, LVM_GETNEXTITEM, -1, LVNI_SELECTED);
if (dwRowId == -1)
{
MessageBox(NULL, _T("请选择进程"), _T("出错啦"), MB_OK);
return ;
}
// 获取PID
lv.iSubItem = 0;
lv.pszText = szPid;
lv.cchTextMax = 0x20;
SendMessage(hListProcess, LVM_GETITEMTEXT, dwRowId, (DWORD)&lv);


// 根据PID调用API获取进程模块
HWND hListModule = GetDlgItem(hDlg,IDC_LIST_MODULE);
HMODULE hMods[1024];
HANDLE hProcess;
DWORD cbNeeded;
unsigned int i;

LPSTR rowData[2] = {0};
LPSTR delim;
LPSTR moduleName;

// Get a handle to the process.
DWORD processID = atoi(szPid);
SetProcessPrivilege("SeDebugPrivilege", 1);
hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
PROCESS_VM_READ,
FALSE, processID );
if (NULL == hProcess)
MessageBox(NULL, _T("无法获取进程模块信息!"), _T("出错啦"), MB_OK);

// Get a list of all the modules in this process.

if( EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
for ( i = 0; i < (cbNeeded / sizeof(HMODULE)); i++ )
{
TCHAR szModName[MAX_PATH];

// Get the full path to the module's file.

if ( GetModuleFileNameEx( hProcess, hMods[i], szModName,
sizeof(szModName) / sizeof(TCHAR)))
{
delim = _T("\\");
moduleName = CutAndGetLast(szModName , delim);
rowData[0] = moduleName;


rowData[1] = szModName;
InsertRow(hListModule, rowData);
}
}
}

// Release the handle to the process.
SetProcessPrivilege("SeDebugPrivilege", 1);
CloseHandle( hProcess );
}

自此,枚举进程的功能已经大体完成,示意如下:

image-20220110212439217

具体的代码已经放到Github上了。


PETOOL开发日记1 - 进程查看
https://m0ck1ng-b1rd.github.io/2022/02/20/二进制/PE Tool 开发日记 1 - 进程查看/
作者
何语灵
发布于
2022年2月20日
许可协议