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

 

 
 
posted @ 2020-01-14 12:27  L丶银甲闪闪  阅读(1013)  评论(0编辑  收藏  举报