pe工具01-獲取進程和模塊


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;
}

 

 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM