分享
 
 
 

定制调试诊断工具和实用程序——摆脱DLL"地狱"(DLL Hell)的困扰(二)

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

定制调试诊断工具和实用程序

——摆脱DLL"地狱"(DLL Hell)的困扰(二)

原著:Christophe Nasarre

编译:NorthTibet

下载源代码:Debugsrc0206.exe (583KB)

原文出处:Windows XP:Escape from DLL Hell with Custom Debugging and Instrumentation Tools and Utilities

本文假设你熟悉 Win32,DLL

定制调试诊断工具和实用程序——摆脱DLL"地狱"(DLL Hell)的困扰(一)

摘要

本文讨论用各种不同的方法来获取系统中运行的进程信息,比如,进程列表,枚举列表中的进程,然后获取关于进程的详细信息。

如何获取运行进程列表

有三种方法来获取Win32运行进程的信息,参见表一:

(表一)

方法

平台

备注

PSAPI

Windows NT,Windows2000,Windows

XP

获取进程,驱动器,模块,内存和工作集信息

性能计数器

Windows NT,Windows2000,Windows

XP

提供除进程清单以外的关于进程的更多信息,可在远程机器上使用。

TOOLHELP32

Windows 9x,Windows2000,Windows

XP

获取进程,线程,模块和堆信息

本文不打算讨论 TOOLHELP32,因为 MSDN 中提供了很多使用 TOOLHELP32

函数的例子代码。性能计数器提供的信息更多,不仅仅是进程清单。如果你想获取远程机器的信息,那么性能计数器是再好不过的工具了。如果你总是想得到另外一台机器的进程列表信息,那么就用性能计数器吧!

进程状态 API(PSAPI 全称是 Process Status API)是微软 SDK 中一个很有用的工具,在例子程序中有一个类 CProcessList,其实现文件 Process.cpp 对 PSAPI 进行了打包,用这个类可以获取进程清单。只要 Refresh 一被调用,通过某个进程的ID便可获得此进程的描述信息,并很容易用 GetFirst

和 GetNext 列举出其它进程:

//用 CProcessList 列出运行进程

// 一个挨一个获取进程

CProcess* pProcess = NULL;

POSITION Pos = 0;

for (

pProcess = ProcessList.GetFirst(Pos);

(pProcess != NULL);

pProcess = ProcessList.GetNext(Pos)

)

{

if (pProcess != NULL)

{

// 对进程信息进行处理

}

}

Refresh 的实现用到了 EnumProcesses 函数(在PSAPI中):

//刷新进程列表

void CProcessList::Refresh()

{

// 不要忘了重置和释放当前的进程列表

DefaultReset();

// 存储当前进程列表

DWORD aProcesses[MAX_PROCESS];

DWORD cbNeeded = 0;

// 获取进程快照

if (!g_PSAPI.EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded))

return;

// 计算返回了多少个进程IDs

DWORD cProcesses = cbNeeded / sizeof(DWORD);

// 将CProcess 对象捆绑到每一个进程ID

DWORD dwProcessID;

CProcess* pProcess;

for (

DWORD dwCurrentProcess = 0;

dwCurrentProcess AttachProcess(aProcesses[dwCurrentProcess]))

delete pProcess;

else

// 存到映射表中

m_ProcessMap[(LPVOID)dwProcessID] = pProcess;

}

}

// 第二次循环需要知道此进程的子进程清单

SetChildrenList();

}

如果你至今还在支持 Windows 的 16 位代码,比如在任务管理器的 ntvdm.exe

项下列出的应用程序就属于此列,那么枚举进程更棘手。有关细节参见本文参考资料中的知识库文章,以及 Matt Pietrek

的专栏文章:August 1998 和 September 1998。

如何获取进程信息

有了运行进程的列表,接下来就是根据 EnumProcesses

返回的进程IDs尽可能多的获取每一个进程的详细信息,然后根据这些信息建立有用的工具。用PROCESS_QUERY_INFORMATION |

PROCESS_VM_READ作为参数,调用OpenProcess获取进程句柄,然后用AttachProcess(参见Process.cpp文件中的CProcess类实现)方法创建进程描述。表二中列出的是CProcess用于获取进程细节信息的函数:

(表二)

方法

描述

GetName

以NULL作为参数,调用

GetModuleBaseName ,最后去掉扩展名 “.EXE”

GetFileName

以NULL作为参数,调用

GetModuleFileNameEx

GetMainWindowHandle

参见GetMainWindowHandle

GetMainWindowTitle

GetParentProcessID

用ProcessBasicInformation作为参数调用NtQueryInformationProcess

GetKERNELHandleCount

用ProcessHandleCount作为参数调用NtQueryInformationProcess

GetUSERHandleCount

用GR_USEROBJECTS作为参数调用GetGuiResources

GetGDIHandleCount

用GR_GDIOBJECTS作为参数调用GetGuiResources

GetWorkingSet

调用GetProcessMemoryInfo

GetCmdLine

参见GetProcessCmdLine

GetOwner

参见GetProcessOwner的细节

GetSessionID

ProcessIdToSessionId (参见对快速用户转换的讨论部分——Windows XP的一个新特性)

GetModuleList

CModuleList是一个对EnumProcessModules

和GetModuleFileNameEx的打包类

GetChildrenCount 以及子进程清单

要获取某个进程的子进程列表,目前还没这样的API(即便有也未公开)可供使用。但是,因为某个进程的父进程是已知的,所以将某个进程加到其父进程的子进程列表中不难(参见SetChildrenList的实现)

这里有几个关于AttachProcess的细节问题需要解释一下。首先,为了避免与PSAPI或 NTDLL这样的操作系统特有的DLLs进行静态链接,编写一个类对我们需要的从这些DLLs中输出的函数进行打包是值的得--有关细节可以参考例子代码中的Wrappers.h和Wrappers.cpp文件。这样的话,你只需要定义一个CPSAPIWrapper对象并调用它的GetModuleFileNameEx方法即可,不用链接到PSAPI库。另外,你应该调用IsValid方法来检查这些DLLs在你运行系统中是可用的。如此一来你的代码便可以运行在任何Windows平台而不会产生诸如某某函数未定义之类的链接错误。注意在使用某个专门的特性之前,你应该检查一下Windows的版本或IsValid的返回结果(参见DllSpy例子代码中的DllSpyApp::InitInstance部分)。

注意PSAPI中的GetModuleFileNameEx函数返回的文件名很奇怪:如:"\SystemRoot\ System32\

smss.exe"或者"\??\C:\WINNT\system32\winlogon.exe"等等。谁知道这是什么意思?在Helper.cpp中有一个函数TranslateFilename专门对此进行转换,将这些文件名转换成更容易理解的名字。稍候会我们还会谈到这个函数。

接下来我们讨论如何寻找某个进程的主窗口,EnumWindows有一个参数是回调函数,此回调函数的作用是接收顶层窗口句柄,在这个问调函数中,我们要调用GetWindowThreadProcessId来获取创建相应窗口的进程ID,如果找到这个窗口(可见的)便停止枚举(详情请参见GetMainWindow实现)。函数GetWindowText可以被用来获取某个不同进程的窗口标题。

在Windows NT 和Windows 2000里,为了获取与创建某个特定窗口的进程对应的文件名字,不能像以前那样用GetWindowModuleFileName函数,你会毫无所获,这个函数总是返回当前运行进程的路径名。

获取某个进程主窗口的详细过程描述可以参考Jeff Prosise在MSJ Aug99上的Wicked

Code专栏文章。现在你已经知道了如何通过某个已知的进程ID,调用PSAPI函数来获取全路径名。然后利用这个路径名并调用GetWindowThreadProcessID函数获取创建某个特定窗口的进程文件名。

在AttachProcess中必须调用OpenProcess来获取大多数的进程信息,但是有可能出现拒绝访问的错误。如果出现这种情况,我用了一个Keith

Brown给出的方法,参见他在MSJ Aug99中的"Security

Briefs"专栏文章,其中详细讨论了如何用高级别权限获取进程句柄。细节请参见例子代码的Helpers.cpp文件,其中有一个函数名叫GetProcessHandleWithEnoughRights,就是出自Keith

Brown之手。

当某个进程是作为另外一个用户账号计划任务而运行的时候,就会出现上述提到的拒绝访问问题。即便是Windows任务管理器都无法终止这样的进程,它只显示一个象下面这样的对话框。如图九:

图九 无法终止的进程

如果你在ProcessSpy例子程序里的某个进程上双击鼠标按键,它将终止这个进程。你看一下在例子代码中的SlayProcess函数就会知道。此辅助函数调用了GetProcessHandleWithEnoughRights来获取进程句柄,但访问权限参数是PROCESS_TERMINATE,而不是在AttachProcess里所用的PROCESS_QUERY_INFORMATION

| PROCESS_VM_READ。

最后是用GetProcessOwner获取进程运行的用户账号(格式为\\Domain\User),通过用TokenUser作为参数调用GetTokenInformation,然后用LookupAccountSid将返回的用户SID转换为人可读的域名和用户名。有时OpenProcessToken会因为遇到象System这样的进程而调用失败,甚至是Windows

2000 资源开发包中的PULIST.EXE遇到这种情况都无法显示出拥有进程的用户。只有ProcessExplorer(Sysinterals公司开发的一个工具软件)能成功找到此"安全的"应用的所有者。本文稍后会讨论Windows

XP中如何用WTS APIs(也就是Windows Terminal Services

API--Windows终端服务API)来获取进程的宿主。

参考资料

如何用 Win32 APIs 枚举应用程序窗口和进程

如何在 Windows NT、Windows 2000 和 Windows XP 中使用VDMDBG函数?

如何从程序中调用外壳的文件属性对话框?

Windows NT 系统中如何启动和终止 16 位 Windows 应用程序?

下回我们将讨论如何获取 Win32 系统中运行进程的命令行信息。

(待续)

作者简介

Christophe Nasarre 是法国 Business Objects 公司的技术经理(technical

manager)。他在 Windows 平台上(3.0 以后的版本)编写了若干个低级工具。他的联系方式:cnasarre@montataire.net.

.

本文出自 MSDN Magazine

June 2002 期刊,可通过当地报摊获得,或者最好是

订阅

本文由 VCKBASE MTT 翻译

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有