Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1614874
  • 博文数量: 441
  • 博客积分: 20087
  • 博客等级: 上将
  • 技术积分: 3562
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-19 15:35
文章分类

全部博文(441)

文章存档

2014年(1)

2012年(1)

2011年(8)

2010年(16)

2009年(15)

2008年(152)

2007年(178)

2006年(70)

分类: C/C++

2008-04-18 12:38:53

获取系统中进程列表

在DOS操作系统下,一个程序可以读写系统中的所有内存,所以可以方便地修改任何地方的代码和数据

,不管这些代码和数据是不是自己所有的,另外,程序可以自由存取所有的寄存器,自由设置所有的中

断,所以程序可以通过设置单步中断或断点中断来跟踪代码的执行。这些功能可以归结为对一个进程进

行调试。

在Windows操作系统中,不同进程之间的地址空间是隔离的,要用指令直接存取其他进程地址空间中的

代码和数据是不可能的,用户程序也没有权限去截获中断,甚至连在自己的代码段中写数据都是不合法

的,那么在Windows中还可以实现类似DOS中的调试功能吗?答案是肯定的,但必须通过专用的API

函数来完成。

要对进程进行某种操作,就必须首先知道该进程的进程句柄或者进程ID,否则一切无从谈起,对于程序

自己创建的子进程来说,CreateProcess函数返回了进程句柄和进程ID,但如果需要调试系统中已经

运行的进程,那就必须首先获取它们的句柄才行。

Win32中并没有直接获取其他进程句柄的函数,但如果知道进程ID,可以由此得到进程句柄,所以可以

首先通过某种途径获取进程ID。

1. 从窗口句柄获取进程句柄

获取进程ID的方法之一是使用GetWindowThreadProcessId函数,这个函数可以从一个窗口句柄获

得创建该窗口的进程的进程ID,而通过FindWindow函数得到窗口句柄是很简单的,所以

GetWindowThreadProcessId函数的用途相当广泛。该函数的用法是:

DWORD GetWindowThreadProcessId(
  HWND hWnd,             // handle to window
  LPDWORD lpdwProcessId  // process identifier
);

其中hWnd参数指定需要用来获取进程ID的窗口句柄,lpdwProcessId指向一个双字变量,函数在这

里返回创建窗口的进程ID,函数的返回值是目标进程中创建该窗口的线程的线程句柄(一个有用的副产

品!)。

得到了进程ID以后,就可以通过OpenProcess函数来获取该进程的句柄了:

HANDLE OpenProcess(
  DWORD dwDesiredAccess,  // access flag
  BOOL bInheritHandle,    // handle inheritance option
  DWORD dwProcessId       // process identifier
);

函数的参数定义如下:

●   dwDesiredAccess——指定需要对该进程进行的操作,要对目标进程进行某种操作,必须指定操作

代码,但是在Windows NT操作系统中,对其他进程操作需要有相应的权限,如需要结束目标进程就必

须有PROCESS_TERMINATE权限才行,当权限不够的时候,打开进程的操作就会失败。一般来说,

除了系统进程以外,可以对其他进程进行任何操作,操作码可以是以下取值的组合:

■   PROCESS_ALL_ACCESS——等于下面全部操作码的组合。

■   PROCESS_CREATE_THREAD——允许创建远程线程。

■   PROCESS_DUP_HANDLE——允许进程句柄被复制。

■   PROCESS_QUERY_INFORMATION——允许使用GetExitCodeProcess函数查询进程的退出

码或使用GetPriorityClass函数查询进程的优先级。

■   PROCESS_SET_INFORMATION——允许使用SetPriorityClass函数设置进程的优先级。

■   PROCESS_TERMINATE——允许终止进程。

■   PROCESS_VM_OPERATION—允许使用WriteProcessMemory函数或VirtualProtectEx函数

修改进程的地址空间。

■   PROCESS_VM_READ——允许对进程的地址空间进行读操作。

■   PROCESS_VM_WRITE——允许对进程的地址空间进行写操作。

●   bInheritHandle——指明返回的进程句柄是否可以被当前进程的子进程继承,如果参数指定为

TRUE,则句柄可以被继承。

●   dwProcessId——指定目标进程的进程ID。

如果函数执行成功,返回值是被打开的进程句柄。如果函数执行失败则返回NULL。一般打开失败的原因

是由权限不够引起的。当完成对目标进程的操作以后,必须使用CloseHandle将获得的句柄关闭。

2. 从快照函数获取进程句柄

使用GetWindowThreadProcessId获取进程ID的先决条件是进程必须创建了窗口,对于在后台运行

的没有窗口的进程该如何处理呢?这就要通过枚举系统中运行的进程来解决了,这个功能可以由

CreateToolhelp32Snapshot函数来实现。

通过CreateToolhelp32Snapshot函数可以获得一个进程的列表,可以从列表中得到进程的ID、进程

对应的可执行文件名和创建该进程的父进程ID等数据,这个函数支持Windows 9x系列和Windows

2000及以上的系统,不支持Windows NT 4.0(幸好使用NT 4.0的机会已经不多了)。

CreateToolhelp32Snapshot函数的名称比较奇怪,“Snapshot”是快照的意思,难道函数和拍快速

成像照片有某种联系吗?没有联系,“快照”只是函数执行方式的一种形像的比喻罢了。就像自然界中的

生命循环一样,系统中的进程也是生生不息的,随时都可能有进程被结束,也随时会有新的进程诞生。“

快照”保留了函数被调用时的进程列表,在以后读取“快照”数据的过程中如果有进程创建或结束,就不会

影响“快照”中的列表,就好比我们照了一张照片后走人,照片还是可以留下来慢慢地看。

下面的例子演示了这些函数的用法。
程序比较简单,就是获取系统中所有进程的列表,然后点击刷新按钮重新获取新的列表,点击终止,可以终止选中的进程。

新建一个VC6++的Win32应用程序,代码如下:

// ProcessList.c

#include
#include
#include "resource.h"

HWND    hWinList = NULL;
char    szTerminate[] = TEXT("无法结束指定进程");

void    GetProcessList(HWND hWnd);
LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(IN HINSTANCE hInstance, IN HINSTANCE hPrevInstance, IN LPSTR lpCmdLine, IN int nShowCmd )
{
    DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_MAIN), NULL, DialogProc, 0);
    return 0;
}


void GetProcessList(HWND hWnd)
{
    PROCESSENTRY32    stProcess;
    HANDLE     hSnapShot;
    DWORD    dwRtn;
    BOOL b;

    RtlZeroMemory(&stProcess, sizeof(stProcess));
    SendMessage(hWinList, LB_RESETCONTENT, 0, 0);
    stProcess.dwSize = sizeof(stProcess);
    hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    b = Process32First(hSnapShot, &stProcess);
    while ( b )
    {
        dwRtn = SendMessage(hWinList, LB_ADDSTRING, 0, (LPARAM)stProcess.szExeFile);
        SendMessage(hWinList, LB_SETITEMDATA, dwRtn, stProcess.th32ProcessID);
        b = Process32Next(hSnapShot, &stProcess);
    }        
    CloseHandle(hSnapShot);
    EnableWindow(GetDlgItem(hWnd, IDOK), FALSE);
}

LRESULT CALLBACK DialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    int nItem = 0;
    LRESULT lRes = 0;
    HANDLE hProcess = NULL;
    switch ( uMsg )
    {
    case WM_CLOSE:
        EndDialog(hWnd, 0);
        break;
    case WM_INITDIALOG:
        hWinList = GetDlgItem(hWnd, IDC_PROCESS);
        GetProcessList(hWnd);
        break;
    case WM_COMMAND:
        if ( LOWORD(wParam) == IDOK )
        {
            nItem = SendMessage(hWinList, LB_GETCURSEL, 0, 0);
            lRes = SendMessage(hWinList, LB_GETITEMDATA, nItem, 0);
            if ( ( hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, lRes) ) )
            {
                TerminateProcess(hProcess, -1);
                CloseHandle(hProcess);
                Sleep(200);
                GetProcessList(hWinList);
            }
            else
                MessageBox(hWnd, szTerminate, NULL, MB_OK | MB_ICONERROR);
        }
        else if ( LOWORD(wParam) == IDC_REFRESH )
        {
            GetProcessList(hWnd);
        }
        else if ( LOWORD(wParam) == IDC_PROCESS )
        {
            if ( HIWORD(wParam) == LBN_SELCHANGE )
            {
                EnableWindow(GetDlgItem(hWnd, IDOK), TRUE);
            }
        }
        break;
    default:
        return FALSE;
    }
    return TRUE;
}


// resource.h
#define IDD_MAIN                        101
#define IDC_REFRESH                     1000
#define IDC_PROCESS                     1001


// ProcessList.rc
#include "resource.h"
#include "afxres.h"

//
// Dialog
//

IDD_MAIN DIALOG DISCARDABLE  0, 0, 218, 145
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "进程列表"
FONT 10, "宋体"
BEGIN
    DEFPUSHBUTTON   "终止(&T)",IDOK,161,124,50,14
    PUSHBUTTON      "刷新(&R)",IDC_REFRESH,97,124,50,14
    LISTBOX         IDC_PROCESS,7,7,204,110,LBS_SORT | LBS_NOINTEGRALHEIGHT |
                    WS_VSCROLL | WS_TABSTOP
END

需要注意的是,程序运行之后,上面的很多进程不能随便的结束的,如果你结束了一些关键的系统进程,可能会立马导致系统崩溃。我曾经就试过结束WINLOGON.EXE这个进程,结果,系统立马重启了,还好没有什么东西需要保存,不然就惨了。

本文理论讲解部分来源于罗云彬32位汇编语言,源码也是由32位汇编程序改写而来。如果想知道更详细的内容或者是汇编版本,请看此书。

转载请注明出处:
author: cnhnyu
e-mail: cnhnyugmailcom
qq: 94483026

阅读(5899) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~