第3章进程
进程是正在运行的应用程序,是由系统管理的内核对象,进程由多个线程组成。 本章主要介绍进程的基本概念、进程枚举、进程的管理等。 3.1进程概述
当我们在使用“开始”菜单单击一个快捷方式的时候,应该意识到创建了一个新 的进程。进程是活动的,没有运行的应用程序不是进程。一个应用程序的多个实例将 构成多个进程,比如打开多个记事本程序。反过来,一个程序打开多个窗口或者打开 多个文档,但是仍然是一个进程。比如,使用WordXP打开两个不同的文档,或者使 用InternetExplorer打开多个新网页窗口,尽管这些窗口在任务栏出现了多个切换按 钮,每个窗口都拥有自己的菜单和工具栏,但是它们仍然是一个进程。当用户使用Ctrl +Alt+Del键调出任务管理器时会发现进程列表中这些文档属于同一进程。也就是说 有些应用程序通过菜单打开新文档或者新的浏览窗口,并不会创建新的进程。 并不是所有的进程都拥有用户界面,某些进程尽管在后台运行,却不提供用户界
面,比如服务就是这样的进程,它可以用于独特的启动/停止方式。有些小程序看起来 非常类似于进程,但是它们并不是进程,它们依附于进程而存在,比如控制面板小程 序。尽管用户可以在控制面板中加载多个选项,但是这些选项只是一个个的动态链接 库,它们属于一个进程。如果用户启动了两次控制面板,那么就会生成两个进程。 启动的进程一般情况下都会出现在类似于如图3-1所示的进程列表中。但是问题
没有绝对化,一些木马程序可能会采用某些技术逃避用户的跟踪,比如采用API拦截 的方法,以便在用户调出任务管理器时,动态链接库和进程内的COM组件本身不能 独立构成一个进程,它们只能依附于一个进程存在,作为进程代码的一部分被载入到 进程的地址空间中,但是它们可以创建新的进程。进程外服务的COM组件调用将会 创建一个新的进程,尽管这些进程没有显示用户界面,但是任务管理器中会找到它们 的身影。比如,利用Office应用程序和AutoCAD的自动化服务操作Office文档或者 绘制的图形。
不同的操作系统对进程的管理差别是很大的。对于Windows32位进程而言,一
般地,每个进程都会拥有属于它自己的进程空间,其中的每一个线程只能访问属于该 进程的内存,属于其他进程的内存由于操作系统的页面切换是无法访问的。进程空间 和物理内存的映射由操作系统来完成。进程之间的相互独立也给操作系统带来了无懈 可击的稳定性,可以想象多个进程如果能够互相存取对方的内存,势必会使操作系统 乱成“一锅粥”。
用户对进程的编程一般涉及以下一些内容: ●进程的创建。
●进程枚举,能够根据不同的操作系统列出当前正在运行的所有进程列表。 ●进程管理,能够根据需要暂停、杀死任何一个非系统进程。
●进程监视,能够通过编程,在一个新的进程创建时当前进程能够得到通知。
●进程隐藏,能够对进程进行隐藏,以便它能够消失在进程列表中,不被用户探测。 ●进程的排他运行,能够通过某些特殊的机制,保证当前进程运行时,不许运行 其他任何进程。
●进程间通信,能够通过窗口消息以及系统提供的内核对象实现两个进程间的相 互通信。
本章只探讨前面几个问题,对于最后一个问题留给下章介绍。 3.2进程的定向输入和输出
在Windows编程中,并非每一个应用程序都需要一个图形用户界面(GUI)。很多
情况下,可以编写一个控制台应用程序,这样程序更小,加载更快,传输时间也短, 同时也丝毫不牺牲程序应有的功能。这种程序特别适合那些在后台运行的程序,比如 压缩、杀毒、上传下载等。如果我们的确需要在GUI中执行这些程序,以完成某些比 如类似于磁盘格式化的功能,我们可以在GUI程序中创建一个新的进程,调用这些已 有的控制台应用程序,帮助完成这些功能。然而令人失望的是,每次加载这些控制台 应用程序时,图形程序总会在加载的过程中产生一个不受欢迎的控制台窗口,从而使 图形用户界面显得不伦不类。当用户看到这个界面时,尤其看到加载的是操作系统提 供的控制台应用程序,就会对产品的可信度表示怀疑,甚至大打折扣。因此,应该竭 力屏蔽这个窗口不让它显示出来,同时还需要把程序运行的结果定向到一个文本文件中,控制台程序的输入部分工作可以由交给GUI来完成。就像VisualC++编译一个程
序一样,由MsDev.exe(GUI程序)负责加载编译器cl.exe(控制台程序)进行后台编译, 然后把编译的结果定向到一个文件,并把编译结果输出到前台图形界面的一个窗口中, 而用户在编译的过程中根本不会察觉这个过程。
C++为应用程序加载提供了多个函数,比如_spawnlp、ShellExecute、system、_exec 等函数。这些函数除了system之外,都无法实现控制台程序的输出定向。而system 函数的缺点是会导致一个控制台窗口出现。如果计算机配置是一个全屏命令提示行模
式,它就会把你的GUI程序直接切换到全屏控制台窗口。显然这是一个很不体面的解 决方案。
_spawnlp(_P_WAIT,\ShellExecute(NULL,NULL,\SW_SHOWNORMAL);
system(\
_execlp(\NULL);
能够成功实现控制台应用程序输出定向的方法是调用CreateProcess函数。通过这 个函数可以创建一个进程,能够隐藏控制台窗口,并把控制台窗口的输出结果定向输 出到一个文本文件。
在Windows2000环境下,CreateProcess函数提供了一个名叫
CREATE_NO_WINDOW的标志。这个标志能够成功阻止控制台窗口出现,然而在
Windows98环境下,这个标志不被支持。为了实现在两种环境下隐藏控制台窗口,可 以通过设置STARTINFO结构成员并把它传递给CreateProcess函数来达到这个目的。 下面是程序实现部分的界面和部分代码: 例3-1控制台应用程序的定向输出。 UpdateData(); BYTEb1,b2,b3,b4;
if(m_IPAddressCtrl.GetAddress(b1,b2,b3,b4)<4){
//获得IP地址的内容,不能空缺 m_IPAddressCtrl.SetFocus(); return; }
charcmdLine[MAX_PATH];
wsprintf(cmdLine,\SECURITY_ATTRIBUTESsa={sizeof(sa),NULL,TRUE}; SECURITY_ATTRIBUTES*psa=NULL;
DWORDdwShareMode=FILE_SHARE_READ|FILE_SHARE_WRITE; OSVERSIONINFOosVersion={0};
osVersion.dwOSVersionInfoSize=sizeof(osVersion); if(GetVersionEx(&osVersion)){
if(osVersion.dwPlatformId==VER_PLATFORM_WIN32_NT){ psa=&sa;
dwShareMode|=FILE_SHARE_DELETE; } }
//根据版本设置共享模式和安全属性 HANDLEhConsoleRedirect=CreateFile( \GENERIC_WRITE, dwShareMode, psa,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
ASSERT(hConsoleRedirect!=INVALID_HANDLE_VALUE); STARTUPINFOs={sizeof(s)};
s.dwFlags=STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES; //使用标准柄和显示窗口
s.hStdOutput=hConsoleRedirect;//将文件作为标准输出句柄 s.wShowWindow=SW_HIDE;//隐藏控制台窗口 PROCESS_INFORMATIONpi={0};
if(CreateProcess(NULL,cmdLine,NULL,NULL,TRUE,NULL,NULL,NULL,&s,&pi)) {
//创建进程,执行Ping程序,测试网络是否连通 WaitForSingleObject(pi.hProcess,INFINITE); //等待进程执行完毕 CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
//关闭进程和主线程句柄 }
CloseHandle(hConsoleRedirect); //关闭控制台定向输出文件句柄
CFilemyFile(\ASSERT(myFile.m_hFile!=NULL);
char*pszNetStatus=newchar[myFile.GetLength()+1]; ZeroMemory(pszNetStatus,myFile.GetLength()+1); myFile.Read(pszNetStatus,myFile.GetLength()); myFile.Close();
//打开文件,把它读到一个字符缓冲区 DeleteFile(\//删除临时文件
m_EditNetStatus.SetWindowText(pszNetStatus); //把控制台程序输出信息写到编辑框中 deletepszNetStatus;
3.3进程运行的监视
为了实现对Shell程序运行的监视,微软实现了Shell钩子。这个钩子需要编写一 个COM组件,其中组件对象必须实现IShellExecuteHook接口。IShellExecuteHook接
口只是一个简单的COM方法,这个方法从InternetExplorer4.01开始得到所有Win32平台的支持。它可以实现的ShellExecute和ShellExecuteEx函数进行了扩展。每次用
户进行Shell操作或者调用一个Shell对象时,就会被注册的钩子组件所拦截。这个Shell 对象可以是一个目录、特殊文件夹、命名扩展或者是一个文件名。由于ShellExecute和 ShellExecuteEx在资源管理器中广泛使用,这个函数尽管最终是通过调用
CreateProcess函数实现进程的创建的,但是微软推荐使用在Win32环境下初始化进程。 ShellExecute钩子允许用户拦截Shell操作时程序的加载和运行。但是对于用户直
接调用CreateProcess或者WinExec函数的情况,IShellExecuteHook不会得到任何响应。 编写ShellExecute扩展,需要编写一个ATL组件,创建一个ATL对象,这个对象从
相关推荐: