1.目標
需要實現一個pe文件的查看工具;

左邊有兩個listview;
上方是進程列表,下方是模塊列表,進程列表中顯示當前運行的所有進程信息;
點擊進程列表中的某一個進程,在模塊列表中顯示該進程的所有模塊信息;
點擊右邊的pe查看,先選一個pe文件,然后會彈出另一個窗口,顯示該pe文件的信息;
2.需求分析
1)畫界面
建一個win32窗口程序;
可以用資源腳本來建窗口,在工程中新建-》資源腳本-》拖控件;
有兩個列表窗口,分別用來顯示進程信息和pe文件信息;需要兩個listview控件;
listview是win32通用控件,使用時需要加載comctl32.lib,並且要處理WM_NOTIFY消息;
2)進程遍歷
要得到進程信息,需要用windows提供的api函數獲取所有進程;
然后將進程信息寫到listview中;
獲取進程的步驟:
1】引入頭文件tlhelp32.h;
2】獲取進程快照
HWND pHandle = CreateToolhelp32Snapshot(0x2,0x0);
3】Process32Next(pHandle,&proc) 獲取進程信息;
進程信息保存在PROCESSENTRY32結構中,是函數的第二個out參數;
函數的第一個參數為進程快照句柄;
當進程快照中沒有下一個進程時,函數返回0;
PROCESSENTRY32 結構如下:
typedef struct tagPROCESSENTRY32 { DWORD dwSize; // 結構大小; DWORD cntUsage; // 此進程的引用計數; DWORD th32ProcessID; // 進程ID; DWORD th32DefaultHeapID; // 進程默認堆ID; DWORD th32ModuleID; // 進程模塊ID; DWORD cntThreads; // 此進程開啟的線程計數; DWORD th32ParentProcessID;// 父進程ID; LONG pcPriClassBase; // 線程優先權; DWORD dwFlags; // 保留; char szExeFile[MAX_PATH]; // 進程全名; } PROCESSENTRY32;
3)遍歷進程的模塊
點擊一個進程,需要在下方的listview中顯示該進程的所有模塊信息;
因此需要遍歷進程的模塊;
需要用到windows提供的api函數;函數需要的參數為進程的pid;
為了知道pid,首先要知道是進程列表的那一行被點擊;然后獲取該行中表示pid的那一列;
判斷那一行被點擊需要處理WM_NOTIFY消息,通用控件都需要處理WM_NOTIFY;
也就是判斷WM_NOTIFY消息的附加參數,條件為:進程的listview被點擊,並且是右鍵點擊時遍歷模塊;
遍歷模塊:
通過SendMessage發LVM_GETNEXTITEM消息,參數為LVNI_SELECTED,找到點擊的是那一行;
然后SendMessage發LVM_GETITEMTEXT消息,傳遞行號和列號,找到該列的值即PID;
得到了進程PID就可以得到該進程模塊信息,放到下方的listview即可;
通過進程pid獲取該進程的快照,然后用 Module32Next遍歷進程快照,模塊信息保存在MODULEENTRY32結構中;
MODULEENTRY32結構:
typedef struct tagMODULEENTRY32 { DWORD dwSize; DWORD th32ModuleID; DWORD th32ProcessID; DWORD GlblcntUsage; DWORD ProccntUsage; BYTE * modBaseAddr; DWORD modBaseSize; HMODULE hModule; TCHAR szModule[MAX_MODULE_NAME32 + 1]; TCHAR szExePath[MAX_PATH]; } MODULEENTRY32; typedef MODULEENTRY32 *PMODULEENTRY32;
4)坑
因為沒有權限,有一些進程無法得到模塊快照;
3.實現代碼
#include <windows.h> #include <stdio.h> #include <commctrl.h> #include <tlhelp32.h> #include "resource.h" #pragma comment(lib,"comctl32.lib") HINSTANCE hAppInstance; //提升進程權限 BOOL EnableDebugPrivilege() { HANDLE hToken; LUID Luid; TOKEN_PRIVILEGES tp; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))return FALSE; if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Luid)) { CloseHandle(hToken); return FALSE; } tp.PrivilegeCount = 1; tp.Privileges[0].Luid = Luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, false, &tp, sizeof(tp), NULL, NULL)) { CloseHandle(hToken); return FALSE; } CloseHandle(hToken); return TRUE; } //遍歷進程 void enumProc(HWND hListProcess){ ListView_DeleteAllItems(hListProcess); HANDLE pHandle; PROCESSENTRY32 proc; DWORD procId; pHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0x0); if(pHandle==INVALID_HANDLE_VALUE){ return; } proc.dwSize = sizeof(PROCESSENTRY32); //給listview添加行 int i = 0; while(Process32Next(pHandle,&proc)){ LV_ITEM vitem; //初始化 memset(&vitem,0,sizeof(LV_ITEM)); vitem.mask = LVIF_TEXT; //獲取進程名 vitem.pszText = proc.szExeFile; //值 vitem.iItem = i; //行 vitem.iSubItem = 0; //列 //ListView_InsertItem(hListProcess, &vitem); //一個宏和SendMessage作用一樣 SendMessage(hListProcess, LVM_INSERTITEM,0,(DWORD)&vitem); //如果用SendMessage,給第一列賦值用LVM_INSERTITEM,其它列用LVM_SETITEM,用ListView同理 //獲取進程ID TCHAR szPID[10] = {0}; sprintf(szPID,"%d",proc.th32ProcessID); //數字轉字符串 vitem.pszText = szPID; vitem.iItem = i; vitem.iSubItem = 1; ListView_SetItem(hListProcess, &vitem); TCHAR szImageBase[0x20]; //進程基址 memset(szImageBase, 0, 0x20); TCHAR szImageSize[0x20]; //進程大小 memset(szImageSize, 0, 0x20); MODULEENTRY32 me32 = { 0 }; me32.dwSize = sizeof(MODULEENTRY32); HANDLE hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, proc.th32ProcessID); if(hModuleSnap != INVALID_HANDLE_VALUE){ // 獲取模塊快照中第一條信息 if(Module32First(hModuleSnap, &me32)){ DWORD pProcessImageBase = (DWORD)me32.modBaseAddr; sprintf(szImageBase,"%08x",pProcessImageBase);; DWORD pProcessSize = (DWORD)me32.modBaseSize; sprintf(szImageSize,"%08x",pProcessSize); } } // 關閉句柄 ::CloseHandle(hModuleSnap); //獲取像基址 vitem.pszText = szImageBase; vitem.iItem = i; vitem.iSubItem = 2; ListView_SetItem(hListProcess, &vitem); //獲取鏡像大小 vitem.pszText = szImageSize; vitem.iItem = i; vitem.iSubItem = 3; ListView_SetItem(hListProcess, &vitem); i++; } CloseHandle(pHandle); return; } //初始化進程窗口,就是給ListView控件添加列 void initProcessView(HWND hDlg){ LV_COLUMN lv; HWND hListProcess; //初始化,局部變量堆棧中分配,不知道是什么數據所以先清零 memset(&lv,0,sizeof(LV_COLUMN)); //獲取listview控件句柄 hListProcess = GetDlgItem(hDlg,IDC_PROC); //設置整行選中,窗口是windows來管理的無法直接操作,程序能做的只能發送一個消息來讓windows直到該怎么做 SendMessage(hListProcess,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT); //第一列 lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; lv.pszText = TEXT("進程"); //列標題 lv.cx = 150; //列寬 lv.iSubItem = 0; //ListView_InsertColumn(hListProcess, 0, &lv); SendMessage(hListProcess,LVM_INSERTCOLUMN,0,(DWORD)&lv); //第二列 lv.pszText = TEXT("PID"); lv.cx = 90; lv.iSubItem = 1; //ListView_InsertColumn(hListProcess, 1, &lv); SendMessage(hListProcess,LVM_INSERTCOLUMN,1,(DWORD)&lv); //第三列 lv.pszText = TEXT("鏡像基址"); lv.cx = 100; lv.iSubItem = 2; ListView_InsertColumn(hListProcess, 2, &lv); //第四列 lv.pszText = TEXT("鏡像大小"); lv.cx = 115; lv.iSubItem = 3; ListView_InsertColumn(hListProcess, 3, &lv); enumProc(hListProcess); } //遍歷模塊 void enumModule(HWND hListModule, HWND hListProcess, WPARAM wParam, LPARAM lParam){ DWORD rowId; LV_ITEM lv; TCHAR pid[0x20]; memset(&lv, 0, sizeof(lv)); memset(pid, 0, 0x20); //獲取行 rowId = ::SendMessage(hListProcess, LVM_GETNEXTITEM, -1, LVNI_SELECTED); //獲取選中的listview行號 if(rowId == -1){ MessageBox(NULL, TEXT("請選擇進程"), TEXT("錯誤"), MB_OK); } //獲取pid lv.iSubItem = 1; lv.pszText = pid; lv.cchTextMax = 0x20; ::SendMessage(hListProcess, LVM_GETITEMTEXT, rowId, (DWORD)&lv); //獲取列的值 //MessageBox(NULL, pid, TEXT("進程id"), MB_OK); //根據pid獲取模塊信息並存儲到下方的list行中 DWORD procId; sscanf( pid, "%d", &procId ); ListView_DeleteAllItems(hListModule); HANDLE hModuleSnap = INVALID_HANDLE_VALUE; MODULEENTRY32 me32; hModuleSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, procId); if(hModuleSnap != INVALID_HANDLE_VALUE){ int i = 0; while(Module32Next(hModuleSnap, &me32)){ //模塊名 lv.pszText = me32.szModule; lv.iItem = i; lv.iSubItem = 0; ListView_InsertItem(hListModule, &lv); //模塊路徑 lv.pszText = me32.szExePath; lv.iItem = i; lv.iSubItem = 1; ListView_SetItem(hListModule, &lv); i++; } } return; } //初始化模塊窗口 void initModuleView(HWND hDlg){ LV_COLUMN lv; HWND hListModule; //初始化,局部變量堆棧中分配,不知道是什么數據所以先清零 memset(&lv,0,sizeof(LV_COLUMN)); //獲取listview控件句柄 hListModule = GetDlgItem(hDlg,IDC_DLL); //設置整行選中,窗口是windows來管理的無法直接操作,程序能做的只能發送一個消息來讓windows直到該怎么做 SendMessage(hListModule,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT); //第一列 lv.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; lv.pszText = TEXT("模塊名"); //列標題 lv.cx = 150; //列寬 lv.iSubItem = 0; //ListView_InsertColumn(hListProcess, 0, &lv); SendMessage(hListModule,LVM_INSERTCOLUMN,0,(DWORD)&lv); //第二列 lv.pszText = TEXT("模塊位置"); lv.cx = 305; lv.iSubItem = 1; //ListView_InsertColumn(hListProcess, 1, &lv); SendMessage(hListModule,LVM_INSERTCOLUMN,1,(DWORD)&lv); } //消息處理回調函數 BOOL CALLBACK DialogProc( HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { HICON hicon_big; HICON hicon_small; switch(uMsg) { case WM_INITDIALOG : //加載圖標 hicon_big = ::LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_ICON_BIG)); hicon_small = ::LoadIcon(hAppInstance, MAKEINTRESOURCE(IDI_ICON_SMALL)); SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (DWORD)hicon_big); SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (DWORD)hicon_small); //初始化列表 initProcessView(hwndDlg); initModuleView(hwndDlg); return TRUE; case WM_COMMAND : switch (LOWORD (wParam)) { case BTN_OUT: EndDialog(hwndDlg, 0); return TRUE; } break ; case WM_NOTIFY : { NMHDR* pNmhdr = (NMHDR*) lParam; if(wParam == IDC_PROC && pNmhdr->code == NM_CLICK){ enumModule(::GetDlgItem(hwndDlg, IDC_DLL), ::GetDlgItem(hwndDlg, IDC_PROC), wParam, lParam); //遍歷模塊,傳遞進程窗口句柄和兩個消息附加參數 } } break; case WM_CLOSE: EndDialog(hwndDlg, 0); return TRUE; } return FALSE ; } //主窗口 int CALLBACK WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){ hAppInstance = hInstance; //加載通用控件 INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_WIN95_CLASSES; InitCommonControlsEx(&icex); //提權 EnableDebugPrivilege(); //畫彈框 DialogBox( hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc ); return 0; }