c's profilenetroc的共享空间BlogListsGuestbookMore Tools Help

netroc的共享空间

c c

Occupation

Windows Media Player

感谢访问!
Please wait...
Sorry, the comment you entered is too long. Please shorten it.
You didn't enter anything. Please try again.
Sorry, we can't add your comment right now. Please try again later.
To add a comment, you need permission from your parent. Ask for permission
Your parent has turned off comments.
Sorry, we can't delete your comment right now. Please try again later.
You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
Complete the security check below to finish leaving your comment.
The characters you type in the security check must match the characters in the picture or audio.
MZ Liuwrote:
Hi,我最近配置windbg双机调试在测试com线上有些困惑,方便留个联系方式详细说下不?多谢
Nov. 20
Niklas wrote:
Hi NetRoc!
 
I wonder if you mind mail me the xtrap project with sources?
I am wery annoyed by Xtrap and I have been looking at it
for along time to work around it but it fails. I need write SSDT
hooks and remove int1 in IDT.
 
regards /Niklas
Aug. 11
June 30

转一文,小平同志真是高瞻远瞩啊

从中共的“代际继替”,看邓小平的十点警告

原文地址

据中新社特稿,当57人的中国共产党拥有7500万以上党员的时候,中共的“代际继替”问题正成为世人广为关注的焦点。中共建党88周年之际,中央党校党建专家叶笃初教授详述这一世界第一大党的历史之维、现时之局、未来之预和悠远之思。

历史之维:不同时期的中国共产党

中共党员队伍构成,不同历史时期呈现出不同的特点:中共的创建主要依靠一批先进的知识分子,创始人陈独秀、李大钊是大学教授,中共一大代表均属于知识分子,其中有大学学历的9人,6人曾留学日本。

经历大革命时期的挫折,中共选择了“农村包围城市”的发展道路,农民党员比重不断增大,1949年新中国成立时,450万中共党员中,农民党员占到近六成,由于战争年代种种条件的限制,这一时期文盲党员近七成。

从着手建设新中国伊始,中共就开始不断调整党员队伍的结构,提高党员素质。

特别是改革开放以来,中共队伍建设思路渐趋稳定,党员的构成更趋多元化。1982年十二大修改后的党章明确规定:“年满18岁的中国工人、农民、军人、知识分子和其它革命分子,……,可以申请加入中国共产党。”这一规定延续到2002年中共十六大时做出微调——将“其它革命分子”改为“其他社会阶层的先进分子”。

现时之局:汇聚精英但不是要成为“精英党”

中共党员队伍构成,随着所处环境改变及形势发展,有相应具体变化,归根结底,都是一定历史发展的结果。叶笃初表示,在党的历史上,党员队伍从规模、构成及素质等方面都出现过几次重大而显著的进步,他认为,中共十六大以来至今,党的队伍不断发展壮大,党吸取了新鲜血液,党员队伍构成趋于高知和精英汇聚的特征,是建党来集中优秀人才资源最好最多的时期。

但使用“精英”这个词,并不是说中国共产党要发展成西方词汇里的“精英党”,叶笃初特别指出。他说,中共需要优秀的人才,尤其高端知识和技术人才,但同时也注重吸收第一线出类拔萃的人,比如新涌现的学有专长人员、进城务工人员等。

“坚持先进性与群众性的统一,这一点始终没有改变。”叶笃初强调。

未来之预:谋篇布局“代际继替”

中组部公布的统计数字显示,截至2007年6月,全国党员中,35岁以下的占23.7%;另外,从十六大到十七大五年间,学生党员增加了254.6%。年轻化是中共党员结构变化的另一显著特征。

“青年是祖国的未来和民族的希望,青年学生是国家的宝贵人才资源。”今年“五四”青年节前夕,中共中央总书记胡锦涛这番表述颇具深意。因为中国正在推行一项“十万大学生村官计划”,中共中央组织部部长李源潮称,这是“培养中国特色社会主义事业接班人的战略举措。”

“一个国家、一个民族、一个政党,都有‘代际继替’的问题。”叶笃初说,中共一贯地把先进青年视为党和国家之将来,认为干部要年轻化,党的整体就要年轻化,这样青年干部才会有大量的而不是勉强的来源“接班人”与“战略”这两个词,无疑透露出中国共产党正在为“代际继替”谋篇布局。 “要从党和国家事业薪火相传、后继有人的战略高度,对青年和青年学生高度重视、充分信任、热情关怀、严格要求。”胡锦涛如是说。

悠远之思:80后党员可堪重任

经常出现在高校学生党课课堂上的叶笃初,跟青年党员有很多交流。他说,到世纪交替时,已有成千上万青年干部走上各级领导岗位,一批又一批的青年党员加入党的队伍,其中,走上省部级岗位不乏被称为“60后”的,而大批新党员已是“80后”成为主流。同时,在大学甚至在高中学生中还有许多积极分子提出申请或在“业余党校”中学习党的知识。

对于外界有关当下青年入党动机带有功利色彩的质疑,叶笃初说,不可否认存在这种现象,但他认为不必过分夸大和担忧,这是一个长期引导和磨练的过程。现在对于年轻党员,最重要的是要让他们懂得党的历史,传承党的精神遗产,不倦学习马克思主义及其在当代中国的应用。在价值多元的时代,党要减少刻板的理论教条,以生动的实践和鲜活的思想来吸引和凝聚更多的人将之作为信仰。

“中国共产党正在向‘百年大党’迈进,本世纪前二十年正是党‘代际继替’的重要时刻。”叶笃初表示。

这位年近八旬的老共产党员对于“80后”党员“充满信心”。他说,等党迎来百年诞辰的时候,“80后”显然已成为中坚力量,“他们必将会将党的事业推向更美好的未来。”

邓小平给后世中国领导人十点警告

警告一 国民收入分配要使所有的人都得益

我们是社会主义国家,国民收入分配要使所有的人都得益,没有太富的人,也没有太穷的人,所以日子普遍好过。(《争取整个中华民族的大团结》1986 年P161~162)

警告二 如果搞两极分化,中国就会发生闹革命的问题

共同致富,我们从改革一开始就讲,将来总有一天要成为中心课题。社会主义不是少数人富起来、大多数人穷,不是那个样子。社会主义最大的优越性就是共同富裕,这是体现社会主义本质的一个东西。如果搞两极分化,情况就不同了,民族矛盾、区域间矛盾、阶级矛盾都会发展,相应地中央和地方的矛盾也会发展,就可能出乱子。(《善于利用时机解决发展问题》1990 年P364)

如果搞资本主义,可能有少数人富裕起来,但大量的人会长期处于贫困状态,中国就会发生闹革命的问题。(《吸取历史经验,防止错误倾向》1987 年P229)

警告三 如果改革导致两极分化,改革就算失败了

社会主义与资本主义不同的特点就是共同富裕,不搞两极分化。(《搞资产阶级自由化就是走资本主义道路》1985 年P123)

如果导致两极分化,改革就算失败了。(《改革是中国发展生产力的必由之路》1985年P139)

现在我们搞四个现代化,是搞社会主义的四个现代化,不是搞别的现代化。……社会主义的目的就是要全国人民共同富裕,不是两极分化。如果我们的政策导致两极分化,我们就失败了;如果产生了什么新的资产阶级,那我们就真是走了邪路了。我们提倡一部分地区先富裕起来,是为了激励和带动其他地区也富裕起来。……提倡人民中有一部分人先富裕起来,也是同样的道理。(《一靠理想二靠纪律才能团结起来》1985年P110~ 111)

警告四 20世纪末,就应突出解决两极分化的问题

走社会主义道路,就是要逐步实现共同富裕。共同富裕的构想是这样提出的:一部分地区有条件先发展起来,一部分地区发展慢点,先发展起来的地区带动后发展的地区,最终达到共同富裕。如果富的愈来愈富,穷的愈来愈穷,两极分化就会产生,而社会主义制度就应该而且能够避免两极分化。……什么时候突出地提出和解决这个问题,在什么基础上提出和解决这个问题,要研究。可以设想,在本世纪末达到小康水平的时候,就要突出地提出和解决这个问题。(《在武昌、深圳、珠海、上海等地的谈话要点》 1992 年P373~374)

警告五 城市搞得再漂亮,没有农村这一稳定的基础是不行的

中国有百分之八十的人口住在农村,中国稳定不稳定首先要看这百分之八十稳定不稳定。城市搞得再漂亮,没有农村这一稳定的基础是不行的。(《建设有中国特色的社会主义》 1984 年P65)

对内经济搞活,首先从农村着手。中国有百分之八十的人口在农村。中国社会是不是安定,中国经济能不能发展,首先要看农村能不能发展,农民生活是不是好起来。翻两番,很重要的是这百分之八十的人口能不能达到。(《我们的宏伟目标和根本政策》 1984 年P77~78)

警告六 思想文化教育卫生部门,都要以社会效益为一切活动的唯一准则

这种“一切向钱看”、把精神产品商品化的倾向,在精神生产的其他方面也有表现。(《党在组织战线和思想战线上的迫切任务》1983年 P43)

思想文化教育卫生部门,都要以社会效益为一切活动的唯一准则,它们所属的企业也要以社会效益为最高准则。(《在中国共产党全国代表大会上的讲话》1985年P145)

警告七 如果教育问题解决不好,就会误大事,应要负历史责任

我们多次说过,我国的经济,到建国一百周年时,可能接近发达国家的水平。我们这样说,根据之一,就是在这段时间里,我们完全有能力把教育搞上去,提高我国的科学技术水平,培养出数以亿计的各级各类人才。我们国家,国力的强弱,经济发展后劲的大小,越来越取决于劳动者的素质,取决于知识分子的数量和质量。一个十亿人口的大国,教育搞上去了,人才资源的巨大优势是任何国家比不了的。有了人才优势,再加上先进的社会主义制度,我们的目标就有把握达到。……中央提出要以极大的努力抓教育,并且从中小学抓起,这是有战略眼光的一着。如果现在不向全党提出这样的任务,就会误大事,就要负历史责任。

……还有相当一部分同志,包括一些高级干部,对于发展和改革教育的必要性,认识不足,缺乏紧迫感,或者口头上承认教育重要,到了解决实际问题时又变是不那么重要了。……忽视教育的领导者,是缺乏远见的、不成熟的领导者,就领导不了现代化建设。

各级党委和政府,对教育工作不仅要抓,并且要抓紧、抓好,严格要求,少讲空话,多干实事。(《把教育工作认真抓起来》1985 年P120~121)

警告八 中国要出问题,还是出在共产党内部

中国要出问题,还是出在共产党内部。(《在武昌、深圳、珠海、上海等地的谈话要点》1992年P380)

警告九 所有的改革最终能不能成功,还是决定于政治体制的改革

不搞政治体制改革不能适应形势。改革,应该包括政治体制改革,而且应该把它作为改革向前推进的一个标志。(《在听取经济情况汇报时的谈话》1986 年P160)

政治体制改革同经济体制改革应该相互依赖,相互配合。只搞经济体制改革,不搞政治体制改革,经济体制改革也搞不通,因为首先遇到人的障碍。事情要人来做,你提倡放权,他那里收权,你有什么办法?从这个角度来讲,我们所有的改革最终能不能成功,还是决定于政治体制的改革。(《在全体人民中树立法制观念》1986年 P164)

要得到发展,必须坚持对外开放、对内改革,包括上层建筑领域的政治体制的改革。(《加强四项基本原则教育,坚持改革开放政策》1987年 P202)

警告十 政治体制改革会触及许多人的利益,会遇到很多障碍

我们提出改革时,就包括政治体制改革。现在经济体制改革每前进一步,都深深感到政治体制改革的必要性。不改革政治体制,就不能保障经济体制改革的成果,不能使经济体制改革继续前进,就会阻碍生产力的发展,障碍四个现代化的实现。

……政治体制改革……触及许多人的利益,会遇到很多的障碍。

……要通过改革,处理好法治和人治的关系,处理好党和政府的关系。

不搞政治体制改革,经济体制改革难于贯彻。(《关于政治体制改革》 1986 年P176~177)

改革是全面的改革,包括经济体制改革,政治体制改革和相应的其他各个领域的改革。

政治体制改革的每一个措施都涉及到千千万万的人,主要是涉及广大干部,不仅是我们一批老人。(《改革的步子要加快》1987 年P237~240)

注:邓小平给后世中国领导人十点警告摘自《邓小平文选》

May 31

果然。。

我对d的本质真是判断得越来越准了。。。

新华网武汉5月31日电 由湖北省恩施州公安机关组织侦办的“邓玉娇案”已侦查终结,于5月31日依法向检察机关移送审查起诉。

公安机关经深入侦查,全面收集证据,认为邓玉娇在遭受到黄德智、邓贵大强迫要求陪其洗浴,被拒绝后又拉扯推搡、言词侮辱等不法侵害的情况下,持刀将邓贵大刺死、黄德智刺伤,其致人死伤的行为属于防卫过当

案发后,邓玉娇用自己的手机拨打110报警,主动向公安机关投案,如实供述自己的行为,具有自首情节。

公安机关根据律师的申请并考虑到邓玉娇的身体状况,对其变更了强制措施,实施监视居住。目前,邓玉娇由家人陪伴生活。

May 28

Microsoft Detours 2.1简介

NetRoc

http://www.DbgTech.net/

本文从主站点转贴过来的,附件和pdf请访问http://www.DbgTech.net/下载

一、简介

《Windows高级调试》第一章中提到了一个基于Microsoft Detours库的内存泄露检查工具LeakDiag。本文对这个库进行一些介绍。

一句话来说,Detours是一个用来在二进制级别上对程序中的函数(Function)或者过程(Procedure)进行修改的工具库。一般我们将这种技术称为"Hook"。Detours的实现原理是将目标函数的前几个字节改为jmp指令跳转到自己的函数地址,以此接管对目标函数的调用,并插入自己的处理代码。在现实中,这种技术可以应用在很多场景下。比如Hook某些Windows API,在实际调用到系统函数前进行一些过滤工作;软件中使用到了一些没有源代码的第三方库,但是又想增强其中某些函数的功能,等等。

图1 Hook前后的程序执行流程对比。

 

图2 Hook前后目标函数和跳板代码的改变

 

Detours相对其他一些Hook库和自己实现的代码来说,通常有以下这些优点:

  • 考虑全面,代码非常稳定,并且经过了微软自己众多产品的验证。
  • 可以简单的用纯C/C++代码实现对类的成员函数的Hook。
  • 购买版权之后的Detours Professional还可以支持x64和IA64处理器。以此为基础编写的代码拥有更强的可移植性。
  • 使用简单,不需要了解汇编指令以及技术细节。

二、使用方法

一般来说,使用Detours的代码都具有固定的模式。Detours 1.5和Detours 2.1的接口函数变了很多,这里按照2.1版本对基本的使用方法进行说明。

常用的函数有下面几个:

  • DetourTransactionBegin() :开始一次Hook或者Unhook过程。
  • DetourUpdateThread() :列入一个在DetourTransaction过程中要进行update的线程。这个函数的作用稍微有一些复杂,会在后面专门说明。
  • DetourAttach() :添加一个要Hook的函数。
  • DetourDetach () :添加一个要Unhook的函数。
  • DetourTransactionCommit() :执行当前的Transaction过程。在这个函数中才会真正进行Hook或者Unhook操作。前面三个函数都只是做一些记录工作。

在使用的时候,这几个函数的调用步骤基本上也是按照上面列出来的顺序。举例来说,现在想Hook掉API函数MessageBoxA,将消息框弹出的消息修改掉,可以按下面的方法做。

进行Hook的步骤:

  1. 首先需要定义目标函数的原型。如果目标函数是Windows API,可以到MSDN中查阅,但是需要注意ANSI版本和Unicode版本的区别。如果没有确切的原型声明,或者目标函数是通过逆向工程找出来的,那么需要定义一个和目标函数原型兼容的声明,即参数个数和调用约定要相同。如MessageBoxA的原型是:

    int MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

    使用typedef定义如下:

    typedef int (WINAPI *pfnMessageBoxA)( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

  2. 声明一个指向目标函数的函数指针:

    pfnMessageBoxA g_pMessageBoxA = ::MessageBoxA;

  3. 编写Hook函数的代码,用于替换目标函数。
  4. 调用DetourTransactionBegin开始一次Detours事务。
  5. 对进程中每个可能调用到目标函数的线程,都需要使用DetourUpdateThread加入到update队列中。这是因为Hook时修改目标函数的前几个字节,如果某个线程刚好执行到这几个字节的位置时,粗暴的修改掉会造成该线程出现异常。Detours事务处理时,会先枚举并暂停update队列中所有线程,获取它们的指令指针,如果发现这种情况,则将指令指针修改到跳板代码的对应字节上。这样就避免出现崩溃的问题。
  6. 对每个需要Hook的函数,调用DetourAttach加入到事务列表中。
  7. 调用DetourTransactionCommit进行实际的Hook操作。

Unhook的过程和上面的流程基本一样,只是第6步改为调用DetourDetach函数。

Hook MessageBoxA的完整示例代码如下:

//Hook函数的向前声明

int WINAPI Hook_MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

 

//目标函数原型声明

typedef int (WINAPI *pfnMessageBoxA)( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType);

 

//指向目标函数的指针

pfnMessageBoxA g_pMessageBoxA = ::MessageBoxA;

 

BOOL StartHook()

{//开始Hook

    DetourTransactionBegin();

 

    //只有一个线程,所以GetCurrentThread

    DetourUpdateThread( GetCurrentThread());

 

    //添加MessageBoxA的Hook

    if( DetourAttach( &(PVOID&)g_pMessageBoxA, Hook_MessageBoxA) != NO_ERROR)

    {

        printf( "Hook MessageBoxA fail.\n");

    }

 

    //完成事务

    if( DetourTransactionCommit() != NO_ERROR)

    {

        printf( "DetourTransactionCommit fail\n");

        return FALSE;

    }

    else

    {

        printf( "DetourTransactionCommit ok\n");

        return TRUE;

    }

}

 

BOOL StopHook()

{//停止Hook

    DetourTransactionBegin();

    DetourUpdateThread( GetCurrentThread());

 

    if( DetourDetach( &(PVOID&)g_pMessageBoxA, Hook_MessageBoxA) != NO_ERROR)

    {

        printf( "Hook MessageBoxA fail.\n");

    }

 

    if( DetourTransactionCommit() != NO_ERROR)

    {

        printf( "DetourTransactionCommit fail\n");

        return FALSE;

    }

    else

    {

        printf( "DetourTransactionCommit ok\n");

        return TRUE;

    }

}

 

int WINAPI Hook_MessageBoxA( HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)

{

    //需要调用原函数时,可以直接使用前面定义的指针变量

    return g_pMessageBoxA( hWnd, "MessageBox after hook.", "TestDetours", MB_OK);

}

在附件的示例代码中还包含了Hook类成员函数的代码。流程和上面基本一致,只是需要用一些强制转换来对付编译器的类型检查。

另外,Detours还包含一系列其他函数,如果需要使用的话,可以参考Detours安装目录下的示例。

三、使用Detours的注意事项

总体来说,Detours库的代码是非常稳定的,但是如果使用方法不对,会造成一些问题。有下面一些地方需要特别注意:

  1. 一定要枚举线程并调用DetourUpdateThread函数。否则可能出现很低几率的崩溃问题,这种问题很难被检查出来。
  2. 如果Hook函数在DLL中,那么绝大多数情况下不能在Unhook之后卸载这个DLL,或者卸载存在造成崩溃的危险。因为某些线程的调用堆栈中可能还包含Hook函数,这时卸载掉DLL,调用堆栈返回到Hook函数时内存位置已经不是合法的代码了。
  3. Detours库设计时并没有考虑到卸载的问题,这是因为钩子的卸载本身是不安全的。当Detours库代码存在于DLL中的时候,即使Unhook了所有函数,清理了所有自己使用到的函数,还是会占用一些内存。卸载这个DLL会造成内存泄露,特别是反复的进行加载DLL->Hook->Unhook->卸载DLL的过程,会让这个问题变得非常严重。后面会用一篇专题文章来讨论Detours内存泄露问题的调试和解决。
  4. 有一些非常短的目标函数是无法Hook的。因为jmp指令需要占用一定空间,有些函数太过短小,甚至不够jmp指令的长度,自然是没有办法Hook掉的。

Detours不支持9x内核的Windows系统。因为9x内核下的内存模型和NT内核下有非常大的差别。

May 19

《Windows高级调试》介绍

    做程序员的人肯定听说过这句话:“世界上最痛苦的事情是加班,比加班更痛苦的事情是天天加班。”相信很多工作的朋友都体验过这种加班加得天昏地暗的日子吧?
    天哪,我怎么才能少加点班?我想多一点自己的时间!
    从我个人的经历来看,加班最常见的原因,就是程序发现严重BUG。一边是上级不断催着要解决问题,一边却找不出来出错原因,经常忙得焦头烂额。事实上,如果再花少许时间学习一些调试方法和调试工具的使用,会让我们花在调试BUG上的时间大大缩短。可能以前花几天时间还找不出来的问题,其实只需要半个小时就搞定了。
    《Advanced Windows Debugging》这本书就是为了解决这个问题而问世的,但是因为大家只能看到英文版,让很多人望而生畏。很幸运的是,机械工业出版社即将推出它的中文版,更多人可以不因为语言的限制而错过这样一本好书了。
    更幸运的是,机械工业出版社的编辑朋友联系到DbgTech,我们得以提前获得了这本书的一些资料。DbgTech立足于调试技术的宣传和推广,希望以此能为国产软件的稳定性和可靠性提高做出微薄的贡献。这本书可以说是目前市面上能找到的最好的一本为开发人员量身打造的调试书籍。包含对各种常用调试工具的使用介绍;内存溢出、资源泄露、同步、进程间通信等最典型BUG问题的调试介绍。我们希望以此为契机,跟大家共同学习这本书中的内容。后面会陆续推出一些典型的调试案例的文章,大家阅读的时候如果有心得体会或者疑问,也欢迎参加讨论!
    后面本书的一些内容节选,更详细的内容请下载附件中的文档。
     欢迎到我们的站点讨论:DbgTech
April 08

关于Windows系统调用实现的笔记

NetRoc

http://www.DbgTech.net/

从Win XP开始,Windows的系统调用都是通过sysenter指令进入KiFastCallEntry或者_KiFastCallEntry2。最近稍微看了一下这部分的wrk代码实现,作了些笔记。

  1. KiFastCallEntry中如何引用SSDT和SSDT Shadow

从sysenter进入KiFastCallEntry后,系统取得SSDT和SSDT Shadow的地址并不是直接通过内核导出的KeServiceDescriptorTable和未导出的KeServiceDescriptorTableShadow变量来引用的。而是从PCR取得_KTHREAD地址,通过KTHREAD中的ServiceTable来获得服务表地址的。I386处理器的KiFastCallEntry相关代码片段如下:

mov ebx, PCR[PcSelfPcr] ; 取得PRCB地址

push KGDT_R3_TEB OR RPL_MASK ; Push user mode FS

mov esi, [ebx].PcPrcbData+PbCurrentThread ; 获得当前线程地址

……

add edi, [esi]+ThServiceTable ; 计算出服务表的地址

通过这里,我们可以知道系统调用所使用的的服务表来自_KTHREAD这种"动态"数据,而非KeServiceDescriptorTable这种相对"静态"的数据。这一点在很多情况下都有较强的利用价值。比如XXX……

  1. nt!_KTHREAD中ServiceTable字段的设置

NtCreateThread内部是通过PspCreateThread创建线程的。进行了线程的相关结构内存分配后,会调用KeInitThread初始化这些结构。KeInitThread中就会设置nt!_KTHREAD的ServiceTable字段。如下:

#if defined(_AMD64_)

Thread->ServiceTable = KeServiceDescriptorTable[SYSTEM_SERVICE_INDEX].Base;

Thread->KernelLimit = KeServiceDescriptorTable[SYSTEM_SERVICE_INDEX].Limit;

#else

Thread->ServiceTable = (PVOID)&KeServiceDescriptorTable[0];

#endif

I386下,线程的初始服务表就是KeServiceDescriptorTable。这可能会被改变。后面如果这个线程调用了ShadowTable中的服务,ServiceTable会被转变成ShadowTable。KiFastCallEntry会判断系统调用的服务号,如果发现是GUI服务,则调用PsConvertToGuiThread将线程转换成GUI线程。

PsConvertToGuiThread中如下处理:

#if defined(_AMD64_)

Thread->Tcb.Win32kTable = KeServiceDescriptorTableShadow[WIN32K_SERVICE_INDEX].Base;

Thread->Tcb.Win32kLimit = KeServiceDescriptorTableShadow[WIN32K_SERVICE_INDEX].Limit;

#else

Thread->Tcb.ServiceTable = (PVOID)&KeServiceDescriptorTableShadow[0];

#endif

  1. SSDT和SSDT Shadow的初始化

两个SDT的初始化在KiInitSystem函数中:

KeServiceDescriptorTable[0].Base = &KiServiceTable[0];

KeServiceDescriptorTable[0].Count = NULL;

KeServiceDescriptorTable[0].Limit = KiServiceLimit;

KeServiceDescriptorTable[0].Number = KiArgumentTable;

for (Index = 1; Index < NUMBER_SERVICE_TABLES; Index += 1) {

KeServiceDescriptorTable[Index].Limit = 0;

……

RtlCopyMemory(KeServiceDescriptorTableShadow,

KeServiceDescriptorTable,

sizeof(KeServiceDescriptorTable));

ShadowTable的第一项被在这个时候初始化成和KeServiceDescriptorTable一样。而第二项会在后面的初始化过程中通过调用KeAddSystemServiceTable被设置。

  1. ShadowTable的设置时机

上面提到了,由于KiInitSystem的初始化,KeServiceDescriptorTableShadow[0]和KeServiceDescriptorTable[0]总是一样的,但是KeServiceDescriptorTableShadow[1]会被设置成win32k的服务。这应该是win32k加载之后调用KeAddSystemServiceTable添加的。

  1. AMD64和i386中的区别

AMD64下的实现和i386不同,AMD64下的ShadowTable在_KTHREAD中专门有一个字段,ServiceTable保存KeServiceDescriptorTable,Win32kTable保存KeServiceDescriptorTableShadow[WIN32K_SERVICE_INDEX].Base。详见PsConvertToGuiThread等函数。

  1. 有什么意义?

从上面记录的这些实现来看,很直接导致的结果就是,系统服务表可以比较容易的替换掉。这种替换有下面这些特点:

  • 只会影响指定的线程,对整个系统来说影响小。
  • 由于和传统SSDT Hook一样只需要改掉一个指针,比inline hook更加稳定。
  • 传统的SSDT Hook被用得太滥,大家都在搞,某些人还敢卸载掉并且恢复Hook之前的指针,很容易造成崩溃。这种方法因为只针对单独线程,被使用得也少,相对来说比传统SSDT Hook和Hook KiFastCallEntry都要安全。
  • 对可能转变成GUI线程的线程进行替换就需要特别的处理了。比如构造自己的ShadowTable并Hook掉PsConvertToGuiThread之类的方法。

没有什么隐蔽性,呵呵。干坏事的同学慎用。当然,用的时候再改,用过之后马上改回去,或者配合内存隐藏之类的技术还是不错滴。干好事的同学也可以用,但是不适合对所有系统线程都用上去,因为要枚举所有线程,或者Hook线程创建函数之类比较麻烦,到不如直接去干KiFastCallEntry。用来保护自己线程的服务表安全倒是不错。

December 18

经济形势严峻

受经济危机影响,劳动密集型产业受创严重。民工回流不止是经济问题,更是严重的政治问题。
闲散劳动力无法消化,习惯了在外打工生活的年轻人又很难安心回到农村生活,如果没有迅速安置他们解决就业问题的话,会严重动摇社会稳定。
大量中央和地方投资,正是为了解决这个问题吧。国内形势已经严峻到没有办法去考虑经济问题了。如此之大的投资,必然带来财政赤字和更恶劣的腐败问题。通涨压力在未来几年会增大,社会贫富差距也会进一步增大。由此会带来更多不稳定因素。
去年只是经济形势严峻,到今年已经掺入了更多政治问题进来。拆东墙补西墙的政策能支持多久?
December 10

发现.NET的一个疑问

COM中的一个事件,在非主线程中触发的。C#的事件处理过程中,又通过该COM接口调用了一个方法,结果发现该方法是在主线程环境中调用的。
这个特性在我的一段代码中出现了死锁。
空了研究一下,呵呵
December 03

Windows调试工具入门-2

NetRoc

http://www.DbgTech.net

本篇介绍Windows调试工具的基本设置和基本操作方法。这里我们会用一个测试程序一步一步说明如何使用WinDbg开始调试工作。首先用VC建立一个名为TestDebug1的控制台项目,并生成它。

  1. 符号、源码和可执行映像路径设置

使用WinDbg开始调试工作之前,最重要的就是配置好各种环境了。这使得调试器可以正确识别调试目标中的各种变量、函数等等,使得我们能够进行符号化调试或者源码调试,而不是只能在一堆汇编代码中转圈。

首先来看一下未设置环境之前的样子。使用刚才说的TestDebug1项目,为了对比更清晰,用Release进行编译,链接选项中选中生成map文件和调试信息,如下:

在C/C++选项卡中设置如下:

程序代码如下:

#include "stdafx.h"

#include <stdio.h>

int main(int argc, char* argv[])

{

    printf( "TestDebug1.cpp");

    return 0;

}

编译之后,将Release目录下的TestDebug1.pdb剪切到其他目录下(如果没有这样做,由于编译出来的程序中包含了符号文件路径,调试器可以直接使用exe中的信息找到pdb文件,而不需要设置路径)。在map文件中可以看到像下面这样的内容:

0001:00000000 _main 00401000 f TestDebug1.obj

说明main函数位于401000地址处。

通过WinDbg的File->Open Executeable菜单打开TestDebug1.exe,可以在调试器命令窗口中看到下面的内容:

可以看到,调试器自动中断下来的位置并不是程序入口点,这是由WinDbg实现造成的,这里先不管它。

调试器命令窗口中可以看到,我们还没有设置符号路径,所以WinDbg目前还找不到TestDebug1.exe的任何符号文件。如果想在main函数下断,这时就不能使用符号,而只能直接使用main的地址。

使用命令bp 00401000在main函数设置断点,然后F5执行就可以中断到main的入口处了。断点设置和基本操作我们将在后面介绍。可以在反汇编窗口中看到这样的内容:

由于没有加载任何符号,所以我们看到的都是一堆反汇编代码和地址。在上一篇中已经介绍过,WinDbg不像OllyDbg这些调试器一样拥有强大的反汇编分析能力,所以仅仅靠这些看起来一团乱麻的反汇编代码,调试工作是很难开展下去的。

  • 符号路径的设置

    要想在WinDbg中看到程序中的符号,必须通过命令或者WinDbg菜单设置符号路径。如果还设置了Microsoft公共符号存储的话,我们不但能够看到自己程序中的符号,还能够看到Windows平台代码中的符号,这对于调试会提供很好的帮助。

    所谓符号路径,就是包含了程序符号信息的符号文件所在的目录路径。通常我们接触到的符号文件都是以pdb作为后缀名的。TestDebug1.exe项目如果在项目设置的Link选项中选中了生成调试信息的话(如上图中的Generate debug info),那么可以在Debug或者Release目录中找到它的符号文件TestDebug1.pdb。

    我们通过WinDbg的File->Symbol File Path…菜单,或者命令.sympath设置符号路径为TestDebug1.pdb所在的目录。例如刚才我把生成的pdb文件移动到桌面上了,所以在我的机器上就设置为:

  

  • 完成之后在命令窗口输入.reload命令,我们可以看到反汇编窗口的内容发生改变:

这里就已经可以看到TestDebug1.exe中的函数、变量名这样的符号了。而我们也可以通过bp main这样的命令直接使用符号来操作调试器。

另外,在Local、Watch等窗口中也可以直接使用符号名查看到变量的值、在Call Stack窗口中可以看到函数名,等等。

  • 源码路径的设置

    通过上面的设置,我们可以对程序进行符号化调试。如果拥有程序的代码,还可以通过设置源码路径来进行源码级调试。

    继续上面的工作,我们通过WinDbg的File->Source File Path…菜单或者.srcpath命令设置源代码保存的路径,比如我的机器上是这样:

 

确定之后,如果当前指令指针在源文件的代码范围内,就会自动跳出源文件窗口。如果没有跳出,那么可以通过File->Open Source File…菜单手动打开源文件。由于刚才设置的断点还没有删除,所以在源码窗口也能口看到设断的行被高亮了:

之后就基本上可以完全通过源码窗口进行设置断点、查看变量、跟踪代码等操作。比只有符号的时候方便了很多。

  • 可执行映像路径的设置

    可执行映像路径一般在调试dump文件时才用得上。需要将这个路径设置成要调试的exe、dll、sys等可执行文件的路径。可以通过File->Image File Path…菜单或者.exepath命令设置。

  • 使用微软公共符号存储

    除了使用自己程序的符号之外,调试时还可以使用微软提供的Windows系统代码的符号。这需要修改一下我们设置的符号路径。最方便的办法是使用.symfix命令。

    现在我们来看一下kernel32.dll中的代码,在反汇编窗口的Offset栏中填入kernel32!OpenProcess,在我的机器上代码如下:

注意位于764e8ccf处的那个call,现在只能看到调用了kernel32某个偏移处的地址。

使用命令.symfix+ d:\Symbols命令,注意加号要紧靠前面的文本。d:\Symbols是用来保存下载的符号文件的目录,可以修改成自己需要的路径。再来打开符号路径窗口,我们可以看到调试器自动添加了一些内容:

自己在源码路径中加入这些新的内容也可以实现相同的效果。详细的原理请参考WinDbg帮助文档关于符号服务器设置的部分内容。

接下来再次使用.reload命令重新加载符号,第一次使用到的符号文件会从网上自动下载下来,所以可能有时候会等待一会。完成之后,可以看到反汇编窗口中出现了新的符号内容:

764e8cd8处指令中可以看到这是调用了kernel32导入的函数NtOpenProcess。

微软提供的Windows符号是我们研究Windows实现的必备利器。首先,符号化的名字有助于调试过程中的记忆和对各种信息的识别;其次,通过名字就常常可以猜测出来函数或变量的作用,很大的方便调试。在各种调试应用中,都强烈建议添加微软公共符号的引用。

  • 设置环境变量

    上面介绍的各种路径都可以通过环境变量来进行设置。将一些常用的路径保存在环境变量中,就可以避免每次在新的工作空间中进行调试时都要重新设置的麻烦。另外,Visual Studio 2008也共享一些环境变量的设置,这样在使用IDE调试的时候也能方便的查看到各种符号了。常用的有下面几个:

环境变量

作用

_NT_SOURCE_PATH = Path

指定包含调试目标的源代码的路径。Path可以包含后跟一个冒号(:)的驱动器符。用分号分隔多个目录(;)。

_NT_SYMBOL_PATH = Path

指定包含符号文件的目录树的根目录。Path可以包含后跟一个冒号(:)的驱动器符。用分号分隔多个目录(;)。

_NT_EXECUTABLE_IMAGE_PATH = Path

指定包含二进制可执行文件的路径。Path可以包含后跟一个冒号(:)的驱动器符。用分号分隔多个目录(;)。

_NT_DEBUG_LOG_FILE_OPEN = Filename

(仅CDB和KD) 指定调试器用来记录输出的日志文件。

_NT_DEBUG_LOG_FILE_APPEND = Filename

(仅CDB和KD) 指定调试器用来添加输出的日志文件。新的内容每次会添加到这个文件末尾,而不是覆盖整个文件。

如果设置了符号路径的环境变量的话,可能在初期使用VS 2008调试MFC这样的有较多导入库的程序时会下载很多符号文件,使得启动调试的速度变慢。不过经过一段时间,大部分需要的符号都缓存到本地之后速度就会快起来。

  1. 配置日志文件

进行调试时,有时候调试器命令窗口会变得很杂乱,所以常常想用.cls命令清空它。但是这样会无法再看到之前调试过程中输出的结果。另外,有时候想保存下整个调试过程的详细记录以备后面"回味"。这时,就需要用到日志文件了。可以将调试器命令窗口中出现过的所有内容都自动记录到日志文件中。

创建日志文件:

  • (仅CDB 和KD) 启动调试器之前,设置_NT_DEBUG_LOG_FILE_OPEN环境变量。
  • 启动调试器时,使用-logo 命令行选项。 如-logo d:\logs\mylogfile.txt
  • 使用.logopen命令。如.logopen /t d:\logs\mylogfile.txt
  • (仅WinDbg) 使用Edit->Open/Close Log File菜单命令。

将日志添加到已有的文件末尾:

  • (仅CDB 和KD) 启动调试器之前,设置_NT_DEBUG_LOG_FILE_APPEND环境变量。
  • 启动调试器时,使用-loga命令行选项。如-loga d:\logs\mylogfile.txt
  • 使用.logappend命令。 如. logappend/t d:\logs\mylogfile.txt
  • (仅WinDbg) 使用Edit->Open/Close Log File菜单命令,然后选择Append。

关闭日志文件:

  • 使用.logclose命令
  • (仅WinDbg) 使用Edit->Open/Close Log File菜单命令,然后选择Close Open Log File。
  1. 设置工作空间

工作空间(Workspace)是用来保存WinDbg中工作环境的工具。例如习惯的窗口布局方式、符号路径、异常处理的设置等等,都可以通过工作空间保存下来,在下次调试的时候就不用再次设置了。

相关的设置都可以通过WinDbg菜单来完成,有下面几个:

  • Open Workspace:这里只能打开自己通过SaveAs保存的工作空间。
  • Save Workspace:按默认的方式保存当前的工作空间。下次再打开相同的调试目标时,就会自动打开这个Workspace。
  • Save Workspace As:可以自己设置工作空间的名字,这样就能通过Open Workspace来手动打开。
  • Clear Workspace:可以选择保存工作空间时要保存哪些设置。
  • Delete Workspace:删除当前保存的工作空间。这里可以查看到所有默认保存和另存为的工作空间,用来进行清理是很方便的。
  • Save Worlspace in File和Open Workspace in File:将工作空间保存到文件或者从文件打开。可以把自己的工作空间保存下来,这样通过U盘之类的就能在多台机器之间方便的使用相同的设置了。

    在没有调试目标的时候调整WinDbg的窗口布局等等设置的话,会保存为默认的工作空间。下一次打开新目标的时候,就会使用这个设置。通常我们可以设定一个默认的工作空间,然后为各个单独的任务保存另外的设置。

November 27

Windows调试工具入门—1

NetRoc

http://www.DbgTech.net

  1. 引子

Debugging Tools for Windows是微软发布的一套用于软件调试的工具包(后面如果没有指明,那么我会使用WinDbg来作为这一套调试工具的简称)。我第一次接触是在三年前的一个内核驱动项目,由于进行了IDT中键盘鼠标中断的Hook,使用Softice调试时造成会造成影响,只得使用WinDbg通过串口进行双机调试。自此之后这个Windows平台下最为强大的调试工具一直是开发过程中的必备。这里我毫不掩饰的说"最强",可能很多通过逆向工作而接触调试的朋友不会认同,但是我相信随着对WinDbg了解的加深,以及对这套工具在软件开发中应用的了解,他们也会和我有一样的观点。

一直以来,软件调试技术在软件开发者中都没有得到足够的普及和重视,互联网上能找到的系统描述的资料也较少。随着国内软件行业整体的发展和进步,这些技术慢慢开始得到推广。2008年出版的有关调试的数据比以往都要多。我有幸拜读了Raymond的《软件调试》,以及熊力的《Windows用户态程序高效排错》,获益良多。 这几年的工作中也积累了一些关于Windows调试工具的知识,希望能够将这些东西进行一些分享。因此,利用几个月空闲时间翻译了WinDbg文档中上半部调试器配置、使用和命令介绍的内容,同时准备写一些关于WinDbg调试工具的初级文章。希望能够为对调试技术感兴趣而又苦于没有资料的朋友提供一些帮助。

特别感谢我的前同事小喂。虽然他第一条串口线还是我焊的,但是他对于WinDbg的使用和了解程度很快就超过了我。在相当长时间的共事和讨论中,让我学到了很多。

  1. Windows调试工具的简介和组成

WinDbg是专门为Windows NT系列操作系统设计的调试器,最早是作为Windows NT 3.1的工具发布的。其后也一直跟随NT操作系统的发展而不断发展完善。如果用一句话来概括,可以说WinDbg是为了软件开发而存在的调试工具。软件包中的调试器和小工具的各种功能都是为了配合软件的开发而设计的,并且覆盖到了Windows平台下各种不同类型项目的调试(传统的SDK或MFC应用程序、.NET平台应用、COM应用、软硬件驱动程序等等)。

Windows调试工具包中的调试器包括WinDbg、KD、CDB和NTSD。其中, KD用于内核调试;CDB和NTSD用于用户态调试,在功能和使用上几乎完全一致;WinDbg是内核调试器和用户态调试器的综合体,由于功能完善并且具有图形界面,所以是最常用的工具。它们能够在x86、Itanium和x64机器上的所有NT平台操作系统中运行。

另外,工具包中还有一些小工具,下面是常用的几个:

  • KDbgCtrl:用于控制和配置内核调试的一些参数。例如是否只有当发生异常时才会启用内核调试、设置DbgPrint缓冲区大小、如何处理用户模式异常等等。
  • ADPlus:这是一个VB脚本,可以为一个或多个进程自动创建内存dump。
  • SymStore:用于创建符号存储。当需要创建自己的符号存储时就要用到它了。
  • SymProxy:用于在网络中创建单独的HTTP符号服务器,以供所有调试器使用。该工具特别适合企业级应用的环境,可以将多个符号存储通过单一的接入点提供使用。
  • DbgSrv、KdSrv、Remote.exe:用于远程调试。
  • GFlags:用于编辑Global Flags。
  • UMDH:用于对用户模式堆分配的情况进行转储和分析。
  • USBView:这是WinDbg 6.10.3版本才加入到软件包中的工具,可以查看当前连接到系统中的USB设备信息。

另外,Application Verifier虽然没有包含在软件包中,但是也是一个非常强大的工具。可以对程序运行时的很多状态进行监控,以发现一些普通调试难以找到的错误。下面是Application Verifier配置界面的一个截图:

AppVerifier

Application Verifier可以在这个页面下载:http://go.microsoft.com/fwlink/?linkid=108353

  1. Windows调试器和其他熟知的调试器比较

可能很多已经习惯使用SoftICE、OllyDbg、IDE调试器的朋友会提出这样的疑问:在这么多调试器中,为什么要选择WinDbg?它究竟有什么特点?

设想一下下面几个场景:

  • 公司的软件针对企业级用户,该客户在地球另一半的美国。有一天客户抱怨了一个BUG,但是从抓取的dump又没办法看出个所以然,想进行动态调试查找原因。公司预算有限,不能让你过去出差顺便旅游、对方公司有防火墙,不允许外部连接,等等等等。。。怎么办?
  • 项目规模很大,涉及到的模块多,版本也多,并且是由不同部门开发的。这些部门可能遍布五湖四海。如何在调试其中某个模块时,能够快速获得它的符号和源文件,而不用每次都从一大堆不同版本的文件中辛苦找寻?调试到某个阶段,突然发现这不是自己的模块出现问题,如何快速知道这个问题应该找谁解决?项目某些重要模块有保密需要,如何控制调试人员访问符号和源文件的权限?
  • 驱动程序怎么才能源码调试?SoftICE不支持新系统,我要在Vista上调试怎么办?
  • 软件中包含一个Windows服务组件,但是每次还没有登陆到桌面之前就崩溃了,怎么进行动态调试?
  • 我想调试Explorer,调试IE,调试CSRSS,调试……,但是调试器一附加上去,系统就会出问题。怎么办?
  • 公司发布的软件,有用户反馈和XXX安全软件冲突老是造成系统崩溃,但是搭建环境之后却又没有办法重现;对方是个普通用户,鼠标都抓得不太稳。用户很火大,闹着要抓个老虎到公司来找你上司做俯卧撑,后果很严重,怎么办?

在现实环境中,有很多复杂的调试场景,我们需要专业级的调试器来解决这些问题。而WinDbg恰恰提供了这种商业软件环境下的专业级软件调试功能,它和其他很多我们熟知的调试器的区别也在于此。

我们将WinDbg和其他调试器分作内核调试器和用户态调试器两类来进行比较。

内核调试方面:

 

WinDbg

SoftICE

原理

Windows操作系统内置调试支持

Hook中断,接管系统

系统和平台支持

x86、Itanium和x64机器上的所有NT平台操作系统

x86,由于已停止更新,新版本操作系统中支持不佳,老系统中也常常遇到兼容性问题

符号和源码支持

完美支持符号调试和源码调试,可直接使用微软公共符号

支持符号调试和源码调试,但是需要先转换符号格式

远程调试

通过和远程工具、转发器的配合,实现各种灵活的远程调试方式,以支持不同的网络环境

通过Virtual SoftICE支持基于网络的远程调试

硬件需求

通过串口、1394、USB 2.0接口的双机调试;通过Pipe连接的虚拟机调试;或者功能有诸多限制的本地内核调试

单机或者通过Virtual SoftICE的双机调试

用户界面

由于是双机调试,调试器只是主控机上运行的一个普通软件。拥有GUI界面,可以同时进行其他应用。

单机调试时完全接管系统,字符界面,操作不是很方便。

扩展性

支持脚本和插件,并且软件包本身提供了大量非常有用的插件

支持插件

由于SoftICE已经停止更新,WinDbg可以说是现在Windows平台上唯一好用的进行内核调试的工具,并且随着新版本的不断推出,不断地添加对新版操作系统的支持以及完善功能。强大的符号支持,方便的源码调试,使得内核级调试能够事半功倍。

用户态调试方面:

 

Windows调试工具包

OllyDbg

Visual Studio调试器

原理

Windows的用户程序调试支持

Windows的用户程序调试支持

Windows的用户程序调试支持

系统和平台支持

主要基于NT系统,9x内核下支持不佳并且需要安装附加模块

主要支持NT系统,9x下也可以使用

新版本的VisualStudio不支持在9x系统下安装。VC6之前可以在9x下调试

符号和源码支持

完美支持符号调试和源码调试,可直接使用微软公共符号

支持符号调试和源码调试

支持。VS2008开始可以直接使用微软公共符号

远程调试

通过和远程工具、转发器的配合,实现各种灵活的远程调试方式,以支持不同的网络环境

不支持

较新版本Visual Studio中支持

无源码调试

反汇编分析能力较弱,GUI界面偏弱,无源码时调试比较困难

强大的代码分析能力,无符号和源码时也能很好的进行调试

无源码调试的支持很弱,使用不便

用户界面

GUI界面不是很丰富,大量操作需要通过命令

GUI界面强大,能够实现大多数调试操作

介于WinDbg和OllyDbg之间。

扩展性

支持脚本和插件,并且软件包本身提供了大量非常有用的插件

支持脚本和插件,有大量可用的资源

支持插件扩展

Dump文件调试

支持,分析功能强大

不支持

支持,但是不够强大

.NET调试

通过SOS.dll支持,进行高级调试比较方便

不能直接支持

功能强大易用,绝大多数情况下都能解决问题

由于WinDbg功能相当复杂,有很多方面并不能一一比较,例如非侵入式调试、通过WinDbg控制CDB和NTSD来调试系统服务、创建和分析Dump文件等等。

总体来说,WinDbg更适合作为软件项目开发和维护过程中的调试工具使用,而OllyDbg更适合逆向工程。

  1. 何时使用Windows调试工具

根据我个人对WinDbg的使用经验来说,它更适合作为开发维护的辅助工具来使用。

如果要进行用户态的逆向工程,推荐使用OllyDbg、IDA这些拥有强大汇编程序分析能力的工具。

WinDbg更适用于以下这些场合:

  • 商业软件的Debug和客户支持
  • 内核驱动的调试,以及对驱动进行逆向工程时进行动态调试
  • 研究Windows本身的内核或者软件
  • 疑难BUG的调试,如死锁、COM调用、资源泄露、堆栈或者堆溢出
  • 以性能优化为目的的调试
  • 对调试目标基本不造成影响的非侵入式调试

November 22

许久不来,这里还是留来胡弹乱吹吧

终于离开了tencent这个恶心的鸟地方。本来想把社保清单贴出来立此存照的,没想到前几天好像被我删掉了。
WinDbg文档,把已处理部分更新到6.10.3了,搞得头晕眼花。看来要说坚持不是那么容易的事情啊。。。几十w字,噢买嘎的。。
September 03

空间转移

由于blog的形式查阅帮助文档不便,所以还是转移到了专门的空间中,做成了在线Help的形式。目前翻译的文档由于需要修复链接,以及更新新版WinDbg文档中的内容,所以还在陆续整理中。
另外还挂了一个论坛和另一个blog上去,刚刚开始做,所以各方面都还很不完善,正在努力中:)
http://www.dbgtech.net/
 
August 18

WinDbg 文档翻译----91

cc682/NetRoc

http://netroc682.spaces.live.com/

!evlog

!evlog 扩展命令用于显示、修改或者备份事件日志(event log)。

语法

!evlog addsource [-d] [-s Source] [-t Type] [-f MsgFile
!evlog backup [-d] [-l EventLog] [-f BackupFile
!evlog clear [-!] [-d] [-l EventLog] [-f BackupFile
!evlog info 
!evlog option [-d] [-!] [-n Count] [ -l EventLog [ -+ | -r RecordBound ]] [-o Order] [-w Width
!evlog read [-d] [-l EventLog] [-s Source] [-e ID] [-c Category] [-t Type] [-n Count] [-r Record
!evlog report [-s Source] [-e ID] [-c Category] [-t TypeMessage 
!evlog [Option-? 

参数

addsource

将一个事件源(event source)加入到注册表中。默认情况下,只会添加来自DebuggerExtensions 的事件(用于支持!evlog report)。

backup

对指定的事件日志创建一个备份,并且写入到文件中。

clear

清除指定的事件日志,并且选择性的创建一个文件用于保存它的旧内容。

info

显示事件日志的摘要信息。

option

设置默认的搜索选项。这些选项用于之后的!evlog read 命令。

read

显示记录到指定的事件日志中的事件清单。输出的详细程度 — 例如要显示的记录条数和排序方式 — 可以通过!evlog read 的参数或者之前使用!evlog option 来控制。

report

将某个事件记录写入应用程序事件日志(application event log)中。

-d

指定要使用的所有默认值。-d 选项仅在省略了其他所有参数时需要使用。但是,和!evlog option 一起使用时可以用来显示已存在的默认设置。

-!

!evlog option一起使用来重置为默认选项。和!evlog clear一起使用 阻止创建备份文件。

Source

指定事件源。默认值为DebuggerExtensions

Type

指定成功类型(success type)。可能的Type值有 1 (Error)、 2 (Warning)、 4 (Information)、 8 (Audit_Success)、或者16 (Audit_Failure)。值为0表示成功。对于 !evlog read!evlog report,默认是成功Success (0)。对于!evlog addsource,可以结合使用这些位,并且默认设置了所有位(31)。

MsgFile

指定消息文件的路径和文件名。如果省略路径,则使用当前Uext.dll所在目录。

EventLog

对于!evlog read!evlog backup、和!evlog clearEventLog 指定要读取哪个事件日志。可能的值有ApplicationSystem、和Security。默认为Application

对于!evlog optionEventLog 指定要设置最大数量(maximum count)的事件日志。可能的值有AllApplicationSystemSecurity。默认为All

BackupFile

指定备份文件的路径和文件名。默认位置是当前目录。默认文件名是EventLog_backup.evtEventLog 是在该命令中使用的事件日志。如果文件已经存在,命令会终止执行。

Count

指定要获取的记录的最大数量。默认为20。

-+

指定用后面的!evlog read命令获取的最大记录数量作为当前最大记录数量。(换句话说,只要前面没有进行过搜索就不会显示出记录来。)

RecordBound

指定之后的!evlog read 命令能获取的最大记录数量。如果指定0,则不会有限制 — 这是默认。

Record

如果没有包含-n Count-r Record 用于指定要获取的记录条数。如果包含了-n CountRecord用于指定显示从第几条记录开始。

Order

指定搜索顺序,可以是ForwardsBackwards。默认为Forwards。反向搜索会从最近一次记录到事件日志中的记录开始,并且反方向进行搜索直到找到匹配项。

Width

指定数据显示的宽度,以字符为单位。这是在Data部分的显示宽度。默认为8个字符。

ID

指定事件之前要显示的前缀。可以使用的值有 0 (no prefix)、 1000 (Information)、2000 (Success)、 3000 (Warning)、和 4000 (Error)。默认为0。

Category

指定事件种类。可使用的值有0 (no category)、 1 (Devices)、 2 (Disk)、 3 (Printers)、 4 (Services)、 5 (Shell)、6 (System_Event)和 7 (Network)。默认为0。

Message

指定要添加到事件描述中的文本消息。

Option

指定要显示某个!evlog 选项的帮助文本。

-?

在调试器命令窗口中显示该扩展命令的简短帮助。

DLL

Windows NT 4.0

Uext.dll

Windows 2000

Uext.dll

Windows XP和之后

Uext.dll

 

!evlog 扩展只能在活动调试时使用。

注释

使用!evlog addsource 在注册表中添加了事件源之后,可以使用!dreg命令来查看它的值。例如:

0:000> !dreg hklm\system\currentcontrolset\services\eventlog\Application\<source>!* 

!evlog option 命令用于为!evlog read 设置新的默认值。这可以避免在重复使用!evlog read 时每次都需要输入所有参数。使用-+参数或者-r Records 参数可以为搜索进行限制,在搜索了指定数量的记录之后终止命令。如果仅对某个事件之后的记录感兴趣,那么这种限制是很有用的。

使用!evlog report前,应该用!evlog addsource 来在注册表中配置事件源。这种配置之后,事件查看器就可以识别各种事件ID了。

下面是!evlog info 扩展命令的示例:

0:000> !evlog info -?
--------------------------------
Application Event Log:
  # Records       : 4362
  Oldest Record # : 1
  Newest Record # : 4362
  Event Log Full  : false
--------------------------------
System Event Log:
  # Records       : 2296
  Oldest Record # : 1
  Newest Record # : 2296
  Event Log Full  : false
--------------------------------
Security Event Log:
  # Records       : 54544
  Oldest Record # : 1
  Newest Record # : 54544
  Event Log Full  : false
--------------------------------

0:000> !evlog option -n 4
Default EvLog Option Settings:
--------------------------------
Max Records Returned: 4
Search Order:         Backwards
Data Display Width:   8
--------------------------------
Bounding Record Numbers:
  Application Event Log: 0
  System Event Log:      0
  Security Event Log:    0
--------------------------------

0:000> !evlog read -l application
-------------- 01 --------------
Record #: 4364

Event Type:      Error (1)
Event Source:    Userenv
Event Category:  None (0)
Event ID:        1000 (0xC00003E8)
Date:            06/06/2002
Time:            18:03:17
Description:     (1 strings)
The Group Policy client-side extension Security was passed flags (17) and returned a failure status code of (87).

-------------- 02 --------------
Record #: 4363

Event Type:      Warning (2)
Event Source:    SceCli
Event Category:  None (0)
Event ID:        1202 (0x800004B2)
Date:            06/06/2002
Time:            18:03:17
Description:     (1 strings)
0x57 : The parameter is incorrect.
Please look for more details in TroubleShooting section in Security Help.

-------------- 03 --------------
Record #: 4362

Event Type:      Error (1)
Event Source:    Userenv
Event Category:  None (0)
Event ID:        1000 (0xC00003E8)
Date:            06/06/2002
Time:            16:04:08
Description:     (1 strings)
The Group Policy client-side extension Security was passed flags (17) and returned a failure status code of (87).

-------------- 04 --------------
Record #: 4361

Event Type:      Warning (2)
Event Source:    SceCli
Event Category:  None (0)
Event ID:        1202 (0x800004B2)
Date:            06/06/2002
Time:            16:04:08
Description:     (1 strings)
0x57 : The parameter is incorrect.
Please look for more details in TroubleShooting section in Security Help.
WARNING: Max record count (4) exceeded, increase record count to view more

!findstack

!findstack 扩展命令用于在所有调用堆栈中定位包含指定符号或模块的位置。

语法

!findstack Symbol [DisplayLevel]
!findstack -? 

参数

Symbol

指定符号或者模块。

DisplayLevel

指定显示中要包含的内容。可以是下面这些值中的一个,默认值是1。

0

仅显示每个包含Symbol的线程的ID。

1

显示包含Symbol的每个线程的ID和frame。

2

显示每个包含Symbol的线程的整个调用堆栈。

-?

在调试器命令窗口中显示该扩展命令的简单帮助。

DLL

Windows NT 4.0

Uext.dll

Windows 2000

Uext.dll

Windows XP和之后

Uext.dll

注释

内核模式下的!stacks命令可以显示所有线程的调用堆栈和状态摘要信息。

下面是该扩展命令输出的示例:

0:023> !uext.findstack wininet
Thread 009, 2 frame(s) match
        * 06 03eaffac 771d9263 wininet!ICAsyncThread::SelectThread+0x22a
        * 07 03eaffb4 7c80b50b wininet!ICAsyncThread::SelectThreadWrapper+0xd
 
Thread 011, 2 frame(s) match
        * 04 03f6ffb0 771cda1d wininet!AUTO_PROXY_DLLS::DoThreadProcessing+0xa1
        * 05 03f6ffb4 7c80b50b wininet!AutoProxyThreadFunc+0xb
 
Thread 020, 6 frame(s) match
        * 18 090dfde8 771db73a wininet!CheckForNoNetOverride+0x9c
        * 19 090dfe18 771c5e4d wininet!InternetAutodialIfNotLocalHost+0x220
        * 20 090dfe8c 771c5d6a wininet!ParseUrlForHttp_Fsm+0x135
        * 21 090dfe98 771bcb2c wininet!CFsm_ParseUrlForHttp::RunSM+0x2b
        * 22 090dfeb0 771d734a wininet!CFsm::Run+0x39
        * 23 090dfee0 77f6ad84 wininet!CFsm::RunWorkItem+0x79
 
Thread 023, 9 frame(s) match
        * 16 0bd4fe00 771bd256 wininet!ICSocket::Connect_Start+0x17e
        * 17 0bd4fe0c 771bcb2c wininet!CFsm_SocketConnect::RunSM+0x42
        * 18 0bd4fe24 771bcada wininet!CFsm::Run+0x39
        * 19 0bd4fe3c 771bd22b wininet!DoFsm+0x25
        * 20 0bd4fe4c 771bd706 wininet!ICSocket::Connect+0x32
        * 21 0bd4fe8c 771bd4cb wininet!HTTP_REQUEST_HANDLE_OBJECT::OpenConnection_Fsm+0x391
        * 22 0bd4fe98 771bcb2c wininet!CFsm_OpenConnection::RunSM+0x33
        * 23 0bd4feb0 771d734a wininet!CFsm::Run+0x39
        * 24 0bd4fee0 77f6ad84 wininet!CFsm::RunWorkItem+0x79
 
0:023> !uext.findstack wininet!CFsm::Run 0
Thread 020, 2 frame(s) match
Thread 023, 3 frame(s) match

0:023> !uext.findstack wininet!CFsm 0
Thread 020, 3 frame(s) match
Thread 023, 5 frame(s) match

附加信息

关于堆栈回溯和显示调用堆栈的其他方式的信息,查看查看调用堆栈k, kb, kd, kp, kP, kv (Display Stack Backtrace) 命令。

!gatom

!gatom 扩展用于显示全局atom表(global atom table)。

语法

!gatom 

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

Ntsdexts.dll

Windows XP和之后

Ntsdexts.dll

附加信息

关于全局atom表的信息,查看Microsoft Windows SDK文档。

!igrep

!igrep 扩展命令在反汇编中搜索指定的模板。

语法

!igrep [Pattern [StartAddress]] 

参数

Pattern

指定要搜索的模板。如果省略,则使用前一次的Pattern

StartAddress

指定开始搜索的16进制地址。如果省略,则使用当前程序计数器。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

Ntsdexts.dll

Windows XP和之后

不可用

!locks (!ntsdexts.locks)

Ntsdexts.dll中的!locks 扩展命令显示当前进程关联的临界区(critical section)的清单。

该扩展命令不要和!kdext*.locks 命令混淆。

语法

!locks [Options

参数

Options

指定要显示的信息数量。可以是下面这些选项的任意组合:

-v

显示所有临界区,包括当前没有被持有的那些。

-o

(Windows XP和之后) 仅显示孤立的信息(orphaned information)(没有指向合法的临界区的指针)。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

Ntsdexts.dll

Windows XP和之后

Ntsdexts.dll

注释

该扩展命令会显示所有通过调用RtlInitializeCriticalSection 初始化的临界区。如果没有临界区,那么不会产生输出。

示例如下:

0:000> !locks

CritSec w3svc!g_pWamDictator+a0 at 68C2C298
LockCount          0
RecursionCount     1
OwningThread       d1
EntryCount         1
ContentionCount    0
*** Locked

CritSec SMTPSVC+66a30 at 67906A30
LockCount          0
RecursionCount     1
OwningThread       d0
EntryCount         1
ContentionCount    0
*** Locked

附加信息

关于可以显示临界区信息的其他命令和扩展命令,查看显示临界区。关于临界区的信息,查看Microsoft Windows SDK文档、Windows Driver Kit (WDK)文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!runaway

!runaway扩展命令显示每个线程消费的时间。

语法

!runaway [Flags

参数

Flags

指定要显示哪些信息。Flags 可以是下面这些位的任意组合。默认值为0x1:

Bit 0 (0x1)

让调试器显示每个线程消耗的用户模式时间(user time)。

Bit 1 (0x2)

显示每个线程消耗的内核时间(kernel time)。

Bit 2 (0x4)

显示每个线程从创建开始经历了多少时间。

DLL

Windows NT 4.0

Uext.dll

Windows 2000

Uext.dll
Ntsdexts.dll

Windows XP和之后

Uext.dll
Ntsdexts.dll

!runaway 扩展命令只能在活动调试时,或者调试通过.dump /mt.dump /ma创建的dump文件时使用。

注释

该扩展命令可以用来快速找出哪些线程循环失去控制消耗了太多CPU时间。

输出中以调试器的内部线程号和16进制线程ID来标识每个线程。还会显示调试器ID。

下面是示例:


0:001> !runaway 7

 User Mode Time
 Thread       Time
 0:55c        0:00:00.0093
 1:1a4        0:00:00.0000

 Kernel Mode Time
 Thread       Time
 0:55c        0:00:00.0140
 1:1a4        0:00:00.0000

 Elapsed Time
 Thread       Time
 0:55c        0:00:43.0533
 1:1a4        0:00:25.0876

附加信息

关于用户模式下线程的信息,查看控制进程和线程。关于对进程和线程进行分析的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!threadtoken

!threadtoken 扩展命令显示当前线程的模拟状态(impersonation state)。

语法

!threadtoken 

DLL

Windows NT 4.0

不可用

Windows 2000

Ntsdexts.dll

Windows XP和之后

不可用

注释

!threadtoken 扩展命令在Windows XP和之后版本中已经废除。使用!token 来替代。

如果当前线程处于模拟状态下(impersonating),那么会显示它使用的令牌(token)。

否则,会出现"Thread is not impersonating"信息。并且显示进程的令牌。

令牌的显示的格式和使用!handle 来显示令牌句柄时一样。

下面是示例:

0:000> ~
.  0  id: 1d0.55c   Suspend: 1 Teb 7ffde000 Unfrozen
#  1  id: 1d0.1a4   Suspend: 1 Teb 7ffdd000 Unfrozen

0:000> !threadtoken

***Thread is not impersonating, using process token***
    Auth Id    0 : 0x1c93d
    Type       Primary
    Imp Level  Anonymous
     Token Id  0 : 0x5e8c19
     Mod Id    0 : 0x5e8c12
     Dyn Chg   0x1f4
     Dyn Avail 0x1a4
     Groups    26
     Privs     17
     User      S-1-5-21-2127521184-1604012920-1887927527-74790
     Groups    26
               S-1-5-21-2127521184-1604012920-1887927527-513
               S-1-1-0
               S-1-5-32-544
               S-1-5-32-545
               S-1-5-21-2127521184-1604012920-1887927527-277551
               S-1-5-21-2127521184-1604012920-1887927527-211604
               S-1-5-21-2127521184-1604012920-1887927527-10546
               S-1-5-21-2127521184-1604012920-1887927527-246657
               S-1-5-21-2127521184-1604012920-1887927527-277552
               S-1-5-21-2127521184-1604012920-1887927527-416040
               S-1-5-21-2127521184-1604012920-1887927527-96548
               S-1-5-21-2127521184-1604012920-1887927527-262644
               S-1-5-21-2127521184-1604012920-1887927527-155802
               S-1-5-21-2127521184-1604012920-1887927527-158763
               S-1-5-21-2127521184-1604012920-1887927527-279132
               S-1-5-21-2127521184-1604012920-1887927527-443952
               S-1-5-21-2127521184-1604012920-1887927527-175772
               S-1-5-21-2127521184-1604012920-1887927527-388472
               S-1-5-21-2127521184-1604012920-1887927527-443950
               S-1-5-21-2127521184-1604012920-1887927527-266975
               S-1-5-21-2127521184-1604012920-1887927527-158181
               S-1-5-21-2127521184-1604012920-1887927527-279435
               S-1-5-5-0-116804
               S-1-2-0
               S-1-5-4
               S-1-5-11
     Privileges    17
               SeUndockPrivilege ( Enabled Default )
               SeTakeOwnershipPrivilege ( )
               SeShutdownPrivilege ( )
               SeDebugPrivilege ( )
               SeIncreaseBasePriorityPrivilege ( )
               SeAuditPrivilege ( )
               SeSyncAgentPrivilege ( )
               SeLoadDriverPrivilege ( )
               SeSystemEnvironmentPrivilege ( Enabled )
               SeRemoteShutdownPrivilege ( )
               SeProfileSingleProcessPrivilege ( )
               SeCreatePagefilePrivilege ( )
               SeCreatePermanentPrivilege ( )
               SeSystemProfilePrivilege ( Enabled )
               SeBackupPrivilege ( )
               SeMachineAccountPrivilege ( )
               SeEnableDelegationPrivilege ( Enabled )

附加信息

关于线程和模拟的信息,查看线程和模拟(impersonation)的信息,查看Microsoft Windows SDK 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!uniqstack

!uniqstack 扩展命令显示当前进程中所有线程的调用堆栈,除开重复的那些。

语法

!uniqstack [ b | v | p ] [ ]

参数

b

显示中包含传递给每个函数的前3个参数。

v

显示帧指针省略信息(frame pointer omission (FPO) information)。在x86处理器上,还会显示调用约定的信息。

p

显示调用堆栈中每个函数的完整参数。会列出每个参数的数据类型、名字和值。需要完整符号信息

n

显示帧序号(frame number)。

DLL

Windows NT 4.0

Uext.dll

Windows 2000

Uext.dll

Windows XP和之后

Uext.dll

注释

除了不显示重复的调用堆栈之外,该命令和k, kb, kd, kp, kP, kv (Display Stack Backtrace) 命令类似。

例如:

0:000> !uniqstack
Processing 14 threads, please wait

.  0  Id: f0f0f0f0.15c Suspend: 1 Teb: 00000000`7fff8000 Unfrozen
      Priority: 0
Child-SP          Child-BSP         RetAddr           Call Site
00000000`0006e5e0 00000000`00070420 00000000`6b009840 wow64!Wow64NotifyDebugger+0x40 [d:\xpclient\base\wow64\wow64\wow64.c @ 581]
00000000`0006e600 00000000`000703d0 00000000`6b03db00 wow64!Wow64KiRaiseException+0x1a0 [d:\xpclient\base\wow64\wow64\wow64.c @ 649]
00000000`0006e950 00000000`000703b0 00000000`6b008520 wow64!whNtRaiseException+0x40
00000000`0006e950 00000000`00070368 00000000`6b1845e0 wow64!Wow64SystemService+0x220 [d:\xpclient\base\wow64\wow64\wow64.c @ 1100]
00000000`0006e9b0 00000000`00070310 00000000`6b009980 wow64cpu!CpuSimulate+0x3a0 [d:\xpclient\base\wow64\cpu\ia64\cpu\cpumain.c @ 730]
00000000`0006e9d0 00000000`000702d0 00000000`6b009ff0 wow64!RunCpuSimulation+0x60 [d:\xpclient\base\wow64\wow64\wow64.c @ 1168]
00000000`0006e9e0 00000000`00070248 00000000`77ea4a10 wow64!Wow64LdrpInitialize+0x5d0 [d:\xpclient\base\wow64\wow64\wow64.c @ 248]
00000000`0006f290 00000000`000700e0 00000000`77ea5d60 ntdll!LdrpInitializeProcess+0x2150 [d:\xpclient\base\ntdll\ldrinit.c @ 1817]
00000000`0006f4c0 00000000`00070028 00000000`77ed6000 ntdll!LdrpInitialize+0x560 [d:\xpclient\base\ntdll\ldrinit.c @ 553]
00000000`0006f550 00000000`00070000 00000000`77ed9000 ntdll!LdrInitializeThunk+0x20 [D:\xpclient\base\ntdll\daytona\..\ia64\ldrthunk.s @ 80]
00000000`0006f550 00000000`00070000 00000000`77ca78a0 ntdll!KiUserApcDispatch+0x50 [D:\xpclient\base\ntos\rtl\user\..\ia64\trampoln.s @ 203]
00000000`0006fff0 00000000`00070000 00000000`00000000 0x77ca78a0

.  1  Id: f0f0f0f0.718 Suspend: 1 Teb: 00000000`7fff4000 Unfrozen
      Priority: 0
Child-SP          Child-BSP         RetAddr           Call Site
00000000`0043eb50 00000000`00440250 00000000`6b008520 wow64!whNtDelayExecution+0x150 [d:\xpclient\base\wow64\whnt32\obj\ia64\whnt32.c @ 24541]
00000000`0043eb80 00000000`00440208 00000000`6b1845e0 wow64!Wow64SystemService+0x220 [d:\xpclient\base\wow64\wow64\wow64.c @ 1100]
00000000`0043ebe0 00000000`004401a8 00000000`6b009980 wow64cpu!CpuSimulate+0x3a0 [d:\xpclient\base\wow64\cpu\ia64\cpu\cpumain.c @ 730]
00000000`0043ec00 00000000`00440168 00000000`6b009ff0 wow64!RunCpuSimulation+0x60 [d:\xpclient\base\wow64\wow64\wow64.c @ 1168]
00000000`0043ec10 00000000`004400e0 00000000`77ea5f50 wow64!Wow64LdrpInitialize+0x5d0 [d:\xpclient\base\wow64\wow64\wow64.c @ 248]
00000000`0043f4c0 00000000`00440028 00000000`77ed6000 ntdll!LdrpInitialize+0x750 [d:\xpclient\base\ntdll\ldrinit.c @ 626]
00000000`0043f550 00000000`00440000 00000000`77ed9000 ntdll!LdrInitializeThunk+0x20 [D:\xpclient\base\ntdll\daytona\..\ia64\ldrthunk.s @ 80]
00000000`0043f550 00000000`00440000 00000000`7de05690 ntdll!KiUserApcDispatch+0x50 [D:\xpclient\base\ntos\rtl\user\..\ia64\trampoln.s @ 203]
00000000`0043fff0 00000000`00440000 00000000`00000000 kernel32!MulDiv+0x110 [D:\xpclient\base\win32\client\i386\critsect.asm @ 550]

. 13  Id: f0f0f0f0.494 Suspend: 1 Teb: 00000000`7ef98000 Unfrozen
      Priority: 0
Child-SP          Child-BSP         RetAddr           Call Site
00000000`00feffe0 00000000`00ff0040 00000000`77e94f30 ntdll!DbgBreakPoint+0x10 [D:\xpclient\base\ntos\rtl\user\..\ia64\debugstb.s @ 66]
00000000`00feffe0 00000000`00ff0040 00000000`00000000 ntdll!DbgUiRemoteBreakin+0x90 [d:\xpclient\base\ntdll\dlluistb.c @ 269]

Total threads: 14
Duplicate callstacks: 11 (windbg thread #s follow):
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12

附加信息

关于堆栈回溯的更多信息和其它显示调用堆栈的方法,查看查看调用堆栈

!vadump

!vadump 扩展命令显示所有的虚拟内存区域以及它们对应的保护信息。

语法

!vadump [-v

参数

-v

显示中还包含每个原始分配区域(original allocation region)的信息。由于每个区域中的不同地址在分配之后可能改变成了自己的保护属性(例如使用VirtualProtect),所以大区域的原始保护属性可能和内部的子区域不一样。

DLL

Windows NT 4.0

Uext.dll

Windows 2000

Uext.dll

Windows XP和之后

Uext.dll

注释

下面是示例:

0:000> !vadump
BaseAddress:       00000000
RegionSize:        00010000
State:             00010000  MEM_FREE
Protect:           00000001  PAGE_NOACCESS

BaseAddress:       00010000
RegionSize:        00001000
State:             00001000  MEM_COMMIT
Protect:           00000004  PAGE_READWRITE
Type:              00020000  MEM_PRIVATE
.........

输出重,State 行显示从BaseAddress 开始的内存范围的状态。可能的状态值有MEM_COMMIT、MEM_FREE和MEM_RESERVE。

Protect 行显示内存区域的保护状态。可能的值有PAGE_NOACCESS、PAGE_READONLY、PAGE_READWRITE、PAGE_EXECUTE、PAGE_EXECUTE_READ、PAGE_EXECUTE_READWRITE、PAGE_WRITECOPY、PAGE_EXECUTE_WRITECOPY和PAGE_GUARD。

Type 行显示内存种类。可能的值有MEM_IMAGE、MEM_MAPPED和MEM_PRIVATE。

下面是使用-v参数的示例:

0:000> !vadump -v
BaseAddress:       00000000
AllocationBase:    00000000
RegionSize:        00010000
State:             00010000  MEM_FREE
Protect:           00000001  PAGE_NOACCESS

BaseAddress:       00010000
AllocationBase:    00010000
AllocationProtect: 00000004  PAGE_READWRITE
RegionSize:        00001000
State:             00001000  MEM_COMMIT
Protect:           00000004  PAGE_READWRITE
Type:              00020000  MEM_PRIVATE
.........

使用-v时,AllocationProtect行显示整个区域被创建时的默认保护属性。Protect行显示指定地址处实际的保护属性。

附加信息

要查看单个虚拟地址的内存保护信息,可以使用!vprot。关于内存保护的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!vprot

!vprot 扩展命令显示虚拟内存保护信息。

语法

!vprot [Address

参数

Address

指定要查看内存保护状态的16进制地址。

DLL

Windows NT 4.0

Uext.dll

Windows 2000

Uext.dll
Ntsdexts.dll

Windows XP和之后

Uext.dll

注释

!vprot 扩展命令可以用于活动调试和dump文件调试。

下面是示例:

0:000> !vprot 30c191c
BaseAddress: 030c1000
AllocationBase: 030c0000
AllocationProtect: 00000080 PAGE_EXECUTE_WRITECOPY
RegionSize: 00011000
State: 00001000 MEM_COMMIT
Protect: 00000010 PAGE_EXECUTE
Type: 01000000 MEM_IMAGE

输出中, AllocationProtect 行显示整个区域被创建时设置的默认保护属性。注意该区域中各个单独的地址可能在之后更改了保护属性(例如调用了VirtualProtect)。Protect行显示指定地址处实际的保护属性。保护属性的值有PAGE_NOACCESS、PAGE_READONLY、PAGE_READWRITE、PAGE_EXECUTE、 PAGE_EXECUTE_READ、PAGE_EXECUTE_READWRITE、PAGE_WRITECOPY、PAGE_EXECUTE_WRITECOPY和 PAGE_GUARD。

State行对应传递给 !vprot 的虚拟地址。可能的状态有MEM_COMMIT、MEM_FREE、和MEM_RESERVE。

Type行显示内存类型。可能的值有MEM_IMAGE、MEM_MAPPED和 MEM_PRIVATE。

附加信息

要查看目标进程拥有的所有内存区域的保护信息,可以使用!vadump。关于内存保护的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

August 12

WinDbg 文档翻译----90

cc682/NetRoc

http://netroc682.spaces.live.com/

用户模式扩展命令

本小节中的参考用于描述主要在用户模式调试时使用的扩展命令。

调试器会自动加载这些扩展命令的适当版本。如果不是自己已经加载了一个不同的版本,那么就不需要关心所使用的DLL版本。查看使用调试器扩展命令获得默认模块搜索顺序的说明。查看加载调试器扩展DLL获得关于加载扩展模块的说明。

每个扩展命令的参考部分都列出了导出该命令的DLL。可以用下面的规则来判断扩展DLL是从什么地方加载的:

  • 目标程序运行在Windows NT 4.0发行版上,使用的是nt4fre\Ntsdexts.dll
  • 目标程序运行在Windows NT 4.0 checked版上,使用nt4chk\Ntsdexts.dll
  • 目标程序运行在Windows 2000 发行版商,使用w2kfre\Ntsdexts.dll
  • 目标程序运行于Windows 2000 checked版本上,使用w2kchk\Ntsdexts.dll
  • 目标程序运行于Windows XP和之后版本中时,使用 winxp\Ntsdexts.dll

另外,和操作系统不相关的那些用户模式扩展放在winext\Uext.dll中。

!avrf

!avrf扩展用于控制Application Verifier的设置,并且显示由Application Verifier产生的各种输出。

语法

!avrf 
!avrf -a Address 
!avrf -cs { Length | -a Address } 
!avrf -hp { Length | -a Address } 
!avrf -vs { Length | -a Address } 
!avrf -dlls [ Length ] 
!avrf -ex [ Length ] 
!avrf -cnt 
!avrf -trm 
!avrf -threads [ThreadID
!avrf -trace TraceIndex 
!avrf -brk [BreakEventType
!avrf -flt 
!avrf -flt EventType Probability 
!avrf -flt break EventType 
!avrf -flt stacks Length 
!avrf -trg [ Start End | dll Module | all ] 
!avrf -skp [ Start End | dll Module | all | Time ] 

参数

-a Address

指定一个地址。会显示包含这个地址的内存分配记录、以这个地址为开始的内存释放操作记录。如果该选项前面没有 –cs-hp或者 –vs,那么会搜索light heap。

-cs

显示临界区(critical section)的删除日志。详细信息查看Application Verifier 文档中的"Critical Section Delete Logs"。

-hp

显示堆操作日志。详细信息查看Application Verifier 文档中的"Heap Operation Logs"。

-vs

显示虚拟地址空间(virtual space)操作日志。详细信息,查看Application Verifier 文档中的"Virtual Space Operation Logs"。

-dlls

显示DLL的加载/卸载日志。详细信息查看Application Verifier 文档中的"DLL Load/Unload Logs"。

-ex

显示异常日志。详细信息查看Application Verifier 文档中的"Exception Logs"。

Length

指定要显示的记录数量。如果使用了-dlls 或者-ex 选项,则可以省略Length来显示所有的DLL 加载/卸载操作或者所有异常记录。

-cnt

显示全局计数器(global counter)的清单。

-trm

显示所有终止和挂起线程的日志。

-threads

显示目标进程中线程的信息。对于子线程,还会显示堆栈大小和由父线程指定的CreateThread 标志。

ThreadID

指定要显示的线程ID。省略时显示所有线程。

-trace TraceIndex

显示指定的TraceIndex 的调用堆栈。一些结构用到了这个16位索引来标识调用堆栈。这个索引指向调用堆栈数据库(stack trace database)中的位置。如果正在分析这样的结构,那么这个选项非常有用。

-brk

表明这是一个break-event命令。不带参数适用 !avrf -brk 时,会显示break event设置。可以在 文档的 "Requesting Breaks on Certain Events" 中查看示例。

BreakEventType

指定break event 的type number 。查看Application Verifier 文档的"Requesting Breaks on Certain Events"获得可用type的列表。

-flt

表示这是一个fault-injection 命令。不带参数使用!avrf –flt时,显示当前的fault injection 设置。查看Application Verifier 文档中的"Choosing Which Events to Fault"获得示例。

EventType

指定event的type number。查看Application Verifier 文档中的"Choosing Which Events to Fault"获得可能的type的列表。

Probability

指定该event将会失败的频率。可以是从0到100(0x64)之间的任意整数。

break

让每次该fault 被inject时,Application Verifier 都中断到调试器中。这种中断的示例,查看Application Verifier 文档中的"Choosing Which Events to Fault"。

stacks

显示最近一次fault-injected 操作的调用堆栈。查看Application Verifier 文档的"Choosing Which Events to Fault"获得示例。

-trg

表明这是一个target range 命令。 不带参属使用 –trg时,显示当前的target range。详细信息查看Application Verifier 文档中的"Choosing Where to Fault"。

-skp

表示这是一个exclusion range 命令。不带参数使用-trg时,显示当前的target range。详细信息查看Application Verifier 文档中的"Choosing Where to Fault"。

Start

指定target range 或者exclusion range 的开始地址。

End

指定target range 或者exclusion range 的结束地址。

Module

指定要targeted 或者excluded 的模块名。Module是完整的模块名,包括.exe.dll 扩展名。不能含有路径信息。

all

使得所有的target range或者exclusion range重置。

Time

恢复执行后的Time毫秒内消除任何fault。

DLL

Windows NT 4.0

不可用

Windows 2000

不可用

Windows XP和之后

Exts.dll

 

注释

不带参数使用!avrf 扩展时,会显示当前的Application Verifier选项。如果已经启用了Full page heap 或者Fast fill heap选项,那么还会显示active page heap的信息。查看Application Verifier 文档中的 "Heap Operation Logs"获得示例。

如果发生了Application Verifier Stop,不带参数的!avrf 扩展会显示停止的类型以及原因。查看Application Verifier 文档中的"Debugging Application Verifier Stops" 获得示例。

如果没有ntdll.dllverifier.dll 的符号,那么!avrf 扩展会产生错误信息。关于如何定位这种问题的信息,查看Application Verifier 文档中的"Setting Up a Debugger for Application Verifier"。

附加信息

关于如何下载和安装Application Verifier ,以及它的文档的信息,查看Application Verifier

!critsec

!critsec 扩展命令显示某个临界区(critical section)。

语法

!critsec Address 

参数

Address

指定临界区的16进制地址。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

Ntsdexts.dll

Windows XP和之后

Ntsdexts.dll

注释

如果不知道该临界区的地址,可以使用!ntsdexts.locks 扩展。它会显示由调用RtlInitializeCriticalSection 来初始化的所有临界区。

下面是示例:

0:000> !critsec 3a8c0e9c

CritSec +3a8c0e9c at 3A8C0E9C
LockCount          1
RecursionCount     1
OwningThread       99
EntryCount         472
ContentionCount    1
*** Locked

附加信息

关于其他可以显示临界区信息的命令,查看显示临界区。关于临界区的信息,查看Microsoft Windows SDK文档、Windows Driver Kit (WDK) 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!dp (!ntsdexts.dp)

Ntsdexts.dll中的!dp 扩展命令显示一个CSR进程。

不要将该命令和dp (Display Memory) 命令或者 !kdext*.dp扩展命令混淆。

语法

!dp [v] [ PID | CSR-Process ]

参数

v

详细模式。显示中包含结构和线程列表。

PID

指定CSR进程的进程ID。

CSR-Process

指定CSR进程的16进制地址。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

Ntsdexts.dll

Windows XP和之后

Ntsdexts.dll

注释

该命令会显示进程地址、进程ID、序号(sequence number)、标志(flags)和引用计数。如果选择了详细模式,还会显示更多细节以及每个进程的线程信息。

如果没有指定进程,则会显示所有进程。

参见

!dt

!dphdump

!dphdump 扩展命令显示debug page heap。

语法

!dphdump Address 

参数

Address

指定堆的基地址或者堆句柄。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

不可用

Windows XP和之后

不可用

注释

如果在Windows 2000(Service Pack 1或之后)、Windows XP或之后版本Windows中查看page heap,应该使用!heap 扩展命令。

参见

!dphfind, !dphflags, !dphhogs

!dphfind

!dphfind 扩展命令查找包含指定地址的debug page heap。

语法

!dphfind Address 

参数

Address

指定debug page heap必须包含的16进制地址。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

不可用

Windows XP和之后

不可用

注释

Address一般是应用程序尝试访问从debug page heap中分配的内存时出错的地址。

如果在Windows 2000(Service Pack 1或之后)、Windows XP或之后版本Windows中查看page heap,应该使用!heap 扩展命令。

参见

!dphdump, !dphflags, !dphhogs

!dphflags

!dphflags 扩展命令显示或设置global page heap flags。

语法

!dphflags [FLAGS

参数

FLAGS

可以是下面这些位的任意组合:

Bit 0 (0x1)

使得调试器启用page heap。(99%的情况下都会希望设置这一位。如果为0,则使用标准堆。)

Bit 1 (0x2)

使得调试器搜集调用堆栈。(一般只在checked build上面才会设置。)

Bit 2 (0x4)

让调试器最小化对内存的影响。

Bit 3 (0x8)

指定最小化(minimization)方法。如果设置了这一位,最小化是随机进行的。如果为0,则基于大小范围(size range)进行最小化。(如果没有设置bit 2(0x4),则这个设置被忽略。)

Bit 4 (0x10)

让调试器捕获反向溢出(backward overrun)。

Bits 15 to 8

指定可用内存的百分比(相对于总内存),低于可以从标准堆中进行分配的大小。仅当设置了bit 2(0x4)时起效。

Bits 31 to 16

指定在page heap中分配的机率。只有当bit 2(0x4)和bit 3(0x8)设置时起效。需要指定两个大小:小一点的位于bit 31到bit 24,大一点的在bit 23到bit 16。大小处于这两个值之间的内存分配将从page heap中分配。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

不可用

Windows XP和之后

不可用

注释

如果在Windows 2000(Service Pack 1或之后)、Windows XP或之后版本Windows中查看page heap,应该使用!heap 扩展命令。

这里有一些示例。下面的命令在free build上启用调用堆栈的搜集。(默认情况下不会):

!dphflags 0x03

下面的命令将不可访问的页面放到分配(allocation)的开始位置。并且启用调用堆栈的跟踪:

!dphflags 0x13

下面的命令使得有48%可能性从page heap中分配。同样,如果可用内存低于48%,则所有分配都会从标准堆中进行:

!dphflags 0x3000300F

参见

!dphdump, !dphfind, !dphhogs

!dphhogs

!dphhogs 扩展用于显示debug page heap hogs。

语法

!dphhogs Address [count] [reset

参数

Address

指定堆的基地址或者堆句柄。

count

列表按照count来排序(而不是按字节)。

reset

所有的allocation counts重置为0。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

不可用

Windows XP和之后

不可用

注释

这个命令只能用于运行在x86处理器上的checked版本Windows NT 4.0。

如果在Windows 2000(Service Pack 1或之后)、Windows XP或之后版本Windows中查看page heap,应该使用!heap 扩展命令。

参见

!dphdump, !dphfind, !dphflags

!dreg

!dreg 扩展命令显示注册表信息。

语法

!dreg [-d|-wKeyPath[!Value
!dreg 

参数

-d

二进制数据显示为DWORD。

-w

二进制数据显示为WORD。

KeyPath

指定注册表路径。可以使用下面这些缩写:

hklm

HKEY_LOCAL_MACHINE

hkcu

HKEY_CURRENT_USER

hkcr

HKEY_CLASSES_ROOT

hku

HKEY_USERS

如果没有使用缩写,则假定使用HKEY_LOCAL_MACHINE。

Value

指定要显示的注册表值。星号(*)可以代表任何值。如果省略Value,则显示所有子键。

DLL

Windows NT 4.0

不可用

Windows 2000

Ntsdexts.dll

Windows XP和之后

Ntsdexts.dll

注释

!dreg 扩展用于在用户模式调试时显示注册表。

在远程调试时由于可以查看远程机器的注册表,所以非常有用。从内核调试器控制用户模式调试器时也很有用,因为目标机冻结的时候是不能运行标准的注册表编辑器的。(这时也可以使用.sleep 命令。查看从内核调试器控制用户模式调试器获得详细信息。)

由于信息是按照容易阅读的格式显示的,所以本地调试时也有用。

如果在内核模式调试时使用!dreg结果显示的是主控机上面的,而不是目标机上的。要显示目标机上的原始注册表信息,可以使用!reg扩展命令来替代。.

这里有一些示例。下面这个显示指定的注册表键下面所有子键:

!dreg hkcu\Software\Microsoft

下面显示指定的注册表键下面所有值:

!dreg System\CurrentControlSet\Services\Tcpip!*

这条命令显示指定的注册表键下面的Start键值:

!dreg System\CurrentControlSet\Services\Tcpip!Start

不带参数使用!dreg 会在调试器命令窗口中显示该命令的简单帮助。

附加信息

关于注册表的信息,查看Windows Driver Kit (WDK) 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!dt

!dt 扩展命令显示某个CSR线程的信息。

该命令不能和dt (Display Type)命令混淆。

语法

!dt [vCSR-Thread 

参数

v

详细输出。

CSR-Thread

指定CSR线程的16进制地址。

DLL

Windows NT 4.0

Ntsdexts.dll

Windows 2000

Ntsdexts.dll

Windows XP和之后

Ntsdexts.dll

注释

该扩展命令显示CSR线程关联的线程、进程、client ID、标志和引用计数。如果使用了详细模式,输出中还包含list pointer、线程句柄和等待块(wait block)。

参见

!dp (!ntsdexts.dp)

August 11

WinDbg 文档翻译----89

cc682/NetRoc

http://netroc682.spaces.live.com/

!vm

!vm扩展命令显示目标系统中虚拟内存使用统计的摘要信息。

语法

Windows NT 4.0的语法

!vm 

Windows 2000和之后的语法

!vm [Flags

参数

Flags

(Windows 2000和之后) 指定命令输出中要显示哪些信息。可以是下面这些位的任意的和。默认值是0,会显示系统范围的内存使用统计,以及每个进程的内存统计。

Bit 0 (0x1)

不显示进程相关的统计。

Bit 1 (0x2)

显示内存管理线程的调用堆栈。

Bit 2 (0x4)

(Windows XP和之后) 显示终端服务器(terminal server)的内存使用情况。

Bit 3 (0x8)

(Windows XP和之后) 显示页面文件写日志(page file write log)。

Bit 4 (0x10)

(Windows XP和之后) 显示工作集所有者线程的调用堆栈(working set owner thread stacks)。

Bit 5 (0x20)

(Windows XP和之后) 显示内核的虚拟内存使用情况。

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

下面是当Flags 为1时的简短输出的示例:

kd> !vm 1

*** Virtual Memory Usage ***
      Physical Memory:     16270   (   65080 Kb)
      Page File: \??\E:\pagefile.sys
         Current:     98304Kb Free Space:     61044Kb
         Minimum:     98304Kb Maximum:       196608Kb
      Available Pages:      5543   (   22172 Kb)
      ResAvail Pages:       6759   (   27036 Kb)
      Locked IO Pages:       112   (     448 Kb)
      Free System PTEs:    45089   (  180356 Kb)
      Free NP PTEs:         5145   (   20580 Kb)
      Free Special NP:       336   (    1344 Kb)
      Modified Pages:        714   (    2856 Kb)
      NonPagedPool Usage:    877   (    3508 Kb)
      NonPagedPool Max:     6252   (   25008 Kb)
      PagedPool 0 Usage:     729   (    2916 Kb)
      PagedPool 1 Usage:     432   (    1728 Kb)
      PagedPool 2 Usage:     436   (    1744 Kb)
      PagedPool Usage:      1597   (    6388 Kb)
      PagedPool Maximum:   13312   (   53248 Kb)
      Shared Commit:        1097   (    4388 Kb)
      Special Pool:          229   (     916 Kb)
      Shared Process:       1956   (    7824 Kb)
      PagedPool Commit:     1597   (    6388 Kb)
      Driver Commit:         828   (    3312 Kb)
      Committed pages:     21949   (   87796 Kb)
      Commit limit:        36256   (  145024 Kb)

所有的内存使用都是以页面数和KB为单位。输出中最有用的信息如下:

参数

含义

physical memory

系统中总的物理内存。

available pages

系统中可用内存的页面数,包括虚拟和物理内存。

nonpaged pool usage

非分页池中分配的页面总数。非分页池是不会换出到页面文件中的内存,所以它必须一直占用物理内存。如果这个数字过大,通常表示系统中某个地方存在内存泄露。

 

附加信息

!memusage 扩展命令可以用来分析物理内存的使用。关于内存管理的更多信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!vpb

!vpb 扩展显示某个卷参数块(volume parameter block (VPB))。

语法

!vpb Address 

参数

Address

指定VPB的16进制地址。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

下面是一个例子。首先用!devnode 扩展显示设备树:

kd> !devnode 0 1
Dumping IopRootDeviceNode (= 0x80e203b8)
DevNode 0x80e203b8 for PDO 0x80e204f8
  InstancePath is "HTREE\ROOT\0"
  State = DeviceNodeStarted (0x308)
  Previous State = DeviceNodeEnumerateCompletion (0x30d)
  DevNode 0x80e56dc8 for PDO 0x80e56f18
    InstancePath is "Root\dmio\0000"
    ServiceName is "dmio"
    State = DeviceNodeStarted (0x308)
    Previous State = DeviceNodeEnumerateCompletion (0x30d)
  DevNode 0x80e56ae8 for PDO 0x80e56c38
    InstancePath is "Root\ftdisk\0000"
    ServiceName is "ftdisk"
    State = DeviceNodeStarted (0x308)
    Previous State = DeviceNodeEnumerateCompletion (0x30d)
    DevNode 0x80e152a0 for PDO 0x80e15cb8
      InstancePath is "STORAGE\Volume\1&30a96598&0&Signature5C34D70COffset7E00Length60170A00"
      ServiceName is "VolSnap"
      TargetDeviceNotify List - f 0xe1250938  b 0xe14b9198
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
    .....

列出的最后一个节点是一个volume。使用 !devobj 扩展查看它的物理设备对象(physical device object (PDO)):

kd> !devobj 80e15cb8
Device object (80e15cb8) is for:
 HarddiskVolume1 \Driver\Ftdisk DriverObject 80e4e248
Current Irp 00000000 RefCount 14 Type 00000007 Flags 00001050
Vpb 80e15c30 DevExt 80e15d70 DevObjExt 80e15e40 Dope 80e15bd8 DevNode 80e152a0 
ExtensionFlags (0000000000)  
AttachedDevice (Upper) 80e14c60 \Driver\VolSnap
Device queue is not busy.

列出的内容中包括VPB 地址。使用!vpb 扩展和这个地址:

kd> !vpb 80e15c30
Vpb at 0x80e15c30
Flags: 0x1 mounted 
DeviceObject: 0x80de5020
RealDevice:   0x80e15cb8
RefCount: 14
Volume Label:           MY-DISK-C

附加信息

关于VPB的信息,查看Windows Driver Kit (WDK) 文档以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!vpdd

!vpdd 扩展显示指定进程的物理地址、虚拟地址和内存内容。

语法

!vpdd Process VirtualAddress 
!vpdd PID VirtualAddress 

参数

Process

指定要显示内存的进程的地址。

PID

指定要显示内存的进程的PID(process ID)。

VirtualAddress

指定要查看的页面的虚拟地址。

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

不可用

Windows XP和之后

不可用

注释

下面是一个示例。假设要查看cmd.exe进程保存在虚拟地址0x4AD00000处的内存内容。首先使用!process 来查看进程地址:

kd> !process 0 0
.......
PROCESS 810e0020  SessionId: 0  Cid: 04e4    Peb: 7ffdf000  ParentCid: 014c
    DirBase: 0268a000  ObjectTable: 810db008  TableSize:  22.
    Image: CMD.EXE

!vpdd 的首个参数可以使用进程地址(0x810E0020)或者PID(0x4E4)。第二个参数是要显示的虚拟地址:

kd> !vpdd  810e0020 4ad00000
00fcf000 4ad00000  00905a4d 00000003 00000004 0000ffff
00fcf010 4ad00010  000000b8 00000000 00000040 00000000
00fcf020 4ad00020  00000000 00000000 00000000 00000000
00fcf030 4ad00030  00000000 00000000 00000000 000000d0
00fcf040 4ad00040  0eba1f0e cd09b400 4c01b821 685421cd
00fcf050 4ad00050  70207369 72676f72 63206d61 6f6e6e61
00fcf060 4ad00060  65622074 6e757220 206e6920 20534f44
00fcf070 4ad00070  65646f6d 0a0d0d2e 00000024 00000000

输出中,第一列是物理地址,第二列是虚拟地址。每行中剩下的内容是该位置保存的内容,以DWORD的形式。

附加信息

相关主题,查看!vtop!ptov、以及将虚拟地址转换成物理地址。关于页表和页目录的信息,查看 Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!vtop

!vtop 扩展命令将虚拟地址转换成对应的物理地址,并且显示其他的页表和页目录信息。

语法

Windows 2000的语法

!vtop PFN VirtualAddress 

Windows XP和之后的语法

!vtop PFN VirtualAddress 
!vtop 0 VirtualAddress 

参数

DirBase

指定进程页目录的基址。每个进程都有自己的虚拟地址空间。使用!process扩展命令来查看进程的页目录基址。

PFN

指定进程页目录基址的页面帧序号(PFN)。

0

(Windows XP和之后)!vtop 使用当前的进程上下文进行地址转换。

VirtualAddress

指定要转换的页面的虚拟地址。

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

要使用这个命令,首先应该用!process扩展来查看进程的页目录基址。页目录基址的页面帧序号(PFN)可以通过将它的地址最后三个16进制0数字去掉来获得(换句话说,就是右移12位)。

下面是一个示例:

kd> !process 0 0
**** NT ACTIVE PROCESS DUMP ****
....
PROCESS ff779190  SessionId: 0  Cid: 04fc    Peb: 7ffdf000  ParentCid: 0394
    DirBase: 098fd000  ObjectTable: e1646b30  TableSize:   8.
    Image: MyApp.exe

如果页目录基地址为0x098FD000,那么它的PFN 为0x098FD。

kd> !vtop 98fd 12f980
Pdi 0 Pti 12f
0012f980 09de9000 pfn(09de9)

注意最后三个0是可选的(貌似原文有错漏Notice how the trailing three zeros are optional.)。!vtop扩展命令会显示页目录索引(page directory index (PDI))、页表索引(page table index (PTI))、输入的虚拟地址、物理页面开始位置的物理地址、以及页表项(PTE)的页面帧序号(PFN)。

如果要将虚拟地址0x0012F980 转换成物理地址,只需要简单的将最后三个16进制数字 (0x980)加到页面开始处的物理地址(0x09DE9000)上。得到的物理地址为0x09DE9980。

如果忘记去掉那三个0,并且将完整的页目录基址传递给了!vtop,而不是 使用PFN,那么结果通常都会是正确的。这是由于!vtop 接收到一个太大的PFN数字时,会将它右移16位后再使用:

kd> !vtop 98fd 12f980
Pdi 0 Pti 12f
0012f980 09de9000 pfn(09de9)

kd> !vtop 98fd000 12f980
Pdi 0 Pti 12f
0012f980 09de9000 pfn(09de9)

但是,最好还是使用PFN,因为有些页目录基址在这种情况下不会被转换。

附加信息

关于获得这些结果的其他方法,查看将虚拟地址转换成物理地址。还可以查看!ptov!vpdd。关于页表和页目录的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!walklist

!walklist 扩展命令在当前会话的会话链表中搜索某个地址。

语法

!walklist [-a] [-o OffsetStartAddress SearchAddress
!walklist -? 

参数

-a

搜索所有会话列表。

-o Offset

指定链表中next字段的偏移。

StartAddress

指定会话链表的起始地址。

SearchAddress

指定要在链表中搜索的地址。

-?

在调试器命令窗口中显示该扩展命令的帮助。

DLL

Windows NT 4.0

不可用

Windows 2000

不可用

Windows XP和之后

Kdexts.dll

附加信息

关于会话的信息,查看改变上下文。关于内存池和pool tag的信息,查看Windows Driver Kit (WDK) 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!wdmaud

显示各种WDM Audio (WDMAud)结构。

语法

!wdmaud Address Flags 

参数

Address

指定要显示的结构地址。

Flags

指定要显示的信息。必须只包含bits 0x1、0x2、0x4和0x8中的一个。0x100 可以和它们中任何一个共同使用。

Bit 0 (0x1)

显示已经发送给wdmaud.sys过的IOCTL的列表。使用时,Address 需要指定WdmaIoctlHistoryListHead的地址。如果设置了0x100这个位,还会显示每个IOCTL发送的pContext

Bit 1 (0x2)

显示标记为pending的IRP列表。Address指定WdmaPendingIrpListHead的地址。如果设置了0x100这个位,还会显示每个IRP分配时的context。

Bit 2 (0x4)

显示WDMAud 分配的MDL列表。Address 指定WdmaAllocatedMdlListHead的地址。如果设置了0x100位,还显示每个MDL分配时的context。

Bit 3 (0x8)

显示附加到wdmaud.sys 上的所有活动context的列表。Address需要指定 WdmaContextListHead的地址。如果设置了0x100位,还会显示每个context结构中的数据成员。

Bit 8 (0x100)

显示详细信息。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

不可用

注释

附加到wdmaud.sys 的context(pContext)包含了每个device的大多数状态数据。每次wdmaud.drv 被加载进一个新的进程时,会通报wdmaud.sys。当wdmaud.drv 被卸载时, wdmaud.sys 会清理在这个context下分配的所有资源。

附加信息

关于WDM音频架构和音频驱动,查看Windows Driver Kit (WDK)文档。

!whattime

!whattime 扩展命令将tick count转换成标准的时间值。

语法

!whattime Ticks 

参数

Ticks

Tick的次数。

DLL

Windows NT 4.0

不可用

Windows 2000

不可用

Windows XP和之后

Kdexts.dll

注释

输出以HH:MM:SS.mmm的格式。下面是示例:

kd> !whattime 29857ae4
696613604 Ticks in Standard Time:  15:02:16.040s

!whatperftime

!whatperftime 扩展命令将高分辨率性能计数器值(high-resolution performance counter value)转换成标准的时间格式。

语法

!whatperftime Count 

参数

Count

performance counter clock的值。

DLL

Windows NT 4.0

不可用

Windows 2000

不可用

Windows XP和之后

Kdexts.dll

注释

可以用 !whatperftime 来转换通过调用QueryPerformanceCounter 获得的值。性能计数器时间值也能在软件跟踪(software trace)中看到。

输出按照HH:MM:SS.mmm格式,下面是示例:

kd> !whatperftime 304589
3163529 Performance Counter in Standard Time: .004.313s

!wsle

!wsle 扩展命令显示所有的工作集列表项(working set list entries (WSLEs))。

语法

Windows NT 4.0 和Windows 2000的语法

!wsle [DisplayMode [Address]] 

Windows XP和之后的语法

!wsle [Flags [Address]] 

参数

DisplayMode

(仅Windows NT 4.0 和Windows 2000) 指定显示中包含的信息。可以是下面这些值中的一个(默认值为0):

0

仅显示工作集列表的基本信息。

7

显示工作集列表的基本信息,以及WSLE地址的信息、存在时间、锁定状态,以及引用计数。如果WSLE具有关联的无效页表项(PTE)或者页目录项(PDE),也会一起显示。

8

显示工作集列表的基本信息,以及索引和每个WSLE的值。

Flags

(Windows XP和之后) 指定显示中包含的信息。可以是下面这些位的任意组合。默认为0。如果使用了这个标志,则只会显示基本的工作集信息。

Bit 0 (0x1)

显示中包括每个WSLE的地址、存在时间、加锁状态以及引用计数。如果WSLE具有关联的无效页表项(PTE)或者页目录项(PDE),也会一起显示。

Bit 1 (0x2)

显示有效WSLE(valid WSLE)的总数、最后一个WSLE的索引,以及第一个空闲WSLE(free WSLE)的索引。

Bit 2 (0x4)

显示空闲WSLE的总数,以及每个空闲WSLE的索引。如果还设置了bit 1,那么还会检查空闲WSLE个数和有效WSLE的个数加起来是否等于WSLE的总个数。

Address

指定工作集列表的地址。如果省略,则使用默认工作集列表。(在Windows NT 4.0 和Windows 2000中,Address指定-1和省略的效果一样。 在Windows XP和之后版本的Windows中,Address指定0和省略的效果一样。)

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

该扩展命令可能需要很长时间来执行。

下面是在一个运行Windows Server 2003系统的x86目标机上的示例:

kd> !wsle 3

Working Set @ c0503000
    FirstFree:       a7  FirstDynamic:          4
    LastEntry      23d  NextSlot:         4  LastInitialized      259
    NonDirect       65  HashTable:        0  HashTableSize:         0

Reading the WSLE data...

Virtual Address           Age  Locked  ReferenceCount
        c0300203          0        1        1
        c0301203          0        1        1
        c0502203          0        1        1
        c0503203          0        1        1
        c01ff201          0        0        1
        77f74d19          3        0        1
        7ffdfa01          2        0        1
        c0001201          0        0        1

.....

Reading the WSLE data...
Valid WSLE entries = 0xa7
found end @ wsle index 0x259

.....

附加信息

关于工作集的信息,查看Windows Driver Kit (WDK) 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!xpoolmap

(仅Windows XP)!xpoolmap 扩展命令显示内存池使用的map。

语法

!xpoolmap [Pool
!xpoolmap -? 

参数

Pool

指定分页或非分页池。使用0 或者10  代表非分页池。1代表分页池。默认值是0

-?

在调试器命令窗口中显示该命令的帮助。

DLL

Windows NT 4.0

不可用

Windows 2000

不可用

Windows XP和之后

Kdexts.dll

该扩展命令只能用于x86目标机。

注释

!xpoolmap 扩展仅在Windows XP上支持。在Windows 2000 和Windows NT 4.0上,使用 !kdex2x86.xpool –map。这个扩展命令是OEM支持扩展包(OEM Support Extensions package)的一部分。关于这个包的安装,查看OEM 支持扩展(kdex2x86.dll)

下面是一个部分的例子:

0: kd> !xpoolmap
unable to get nt!MmSubsectionTopPage
unable to get nt!MmNonPagedMustSucceed
.....................................................
Status Map of Pool Area Pages
==============================
'O': one page in use                              ('P': paged out)
'<': start page of contiguous pages in use        ('{': paged out)
'>': last page of contiguous pages in use         ('}': paged out)
'=': intermediate page of contiguous pages in use ('-': paged out)
'.': one page not used

Non-Paged Pool Area Summary
----------------------------
Maximum Number of Pages  = 52691 pages
Number of Pages In Use   = 52689 pages (100.0%)

          +00000  +08000   +10000  +18000   +20000  +28000   +30000  +38000
81653000: OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO
81693000: OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO
816d3000: OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO

...

86753000: OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO
86793000: OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO
867d3000: OOOOOOOOOOOOOOOO OOOOOOOOOOOOOOOO OOOOOOOOOOOO<
f7fba000: .>OOOOOOOOO<==== >O<=><>OOOO<><>O O<=======>OOOO<= >OO<>OOOOOOOOOOO
f7ffa000: OOOO<=><><=><=== >OOOO<>OO<=><>OO OOO<><=>O<=====> <=>OOOOO<>O<==><
f803a000: >O<===><==>OOOOO OOOOOOOOOOOOO<=> OOOOO<=>O<==><>O OOO<>OO<=====><=
f807a000: ><>OOOOO<=>O<=>O <>OOOOOOOO<==>OO <>OOOOOOO<====>O <>OO<><>OOOOO<>O

...

ffafa000: >OOO<>OOOOOOOOOO OOO<==>OOO<>O<>O OO<=======>OOOOO O<===>OOOOOOOOOO
ffb3a000: O<>OO<>OOOOOOOOO O<==>OOOOO<>OO<> OO<=>O<=><>OOOO< >OOOOOOOOOOO<><>
ffb7a000: <==>OO<>OOOOO<=> OOOO<=>O<==><=== ====>OOOO<>OOOOO OOO<>O<>OOO<==><
ffbba000: =>OOO<=====>O<== >OOO<=><=>OOOO<= >OO<=.

!zombies

!zombies扩展命令显示所有僵死("僵尸")进程或线程。

语法

!zombies [Flags [RestartAddress]] 

参数

Flags

指定要显示的内容。可能的值如下:

1

显示所有僵尸进程。(这是默认值)

2

显示所有僵尸线程。

RestartAddress

指定搜索开始位置的16进制地址。当前一次搜索过早结束时有用。默认值为0。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

不可用

注释

僵尸进程是已经死亡但是还没有从进程列表中摘除的进程。僵尸线程也是类似这样。

该扩展命令仅在Windows 2000中可用。

附加信息

查看所有进程和线程的列表,使用!process扩展。.

关于内核模式下进程和线程的概要信息,查看改变上下文。关于分析进程和线程的信息,查看Mark Russinovich 和David Solomon编写的 Microsoft Windows Internals

WinDbg 文档翻译----88

cc682/NetRoc

http://netroc682.spaces.live.com/

!thread

!thread 扩展显示目标系统中线程包括ETHREAD块在内的摘要信息。该命令只能在内核模式调试下使用。

这个扩展命令和.thread (Set Register Context)命令不同。

语法

Windows NT 4.0 和Windows 2000的语法:

!thread [Address [Flags]] 

Windows XP的语法:

!thread [-p] [-t] [Address [Flags]] 

参数

-p

显示拥有该线程的进程的摘要信息。

-t

包含这个选项时,Address是线程ID,而不是线程地址。

Address

指定目标机上线程的16进制地址。如果Address为-1或省略,则表示当前线程。

Flags

指定显示的详细级别。Flags可以是下面这些位的任意组合。如果Flags为0,只会显示最少量的信息。默认为0x6:

Bit 1 (0x2)

显示线程的等待状态。

Bit 2 (0x4)

如果不和Bit 1(0x2)一起使用则不会起作用。如果和Bit 1一起使用,线程会和调用堆栈一起显示出来。

Bit 3 (0x8)

(Windows XP和之后)

在每个函数的显示信息中加入返回地址、堆栈指针、以及bsp寄存器的值(在Itanium系统中),但是不显示函数的参数。

Bit 4 (0x10)

(Windows XP和之后) 在这个命令持续期间,将进程上下文设置为拥有指定线程的那个进程。这回使得线程调用堆栈的显示更加精确。

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

 

注释

下面是Windows 2000系统上的示例:

kd> !thread ff8632c0
THREAD ff8632c0  Cid 38c.380  Teb: 7ffde000  Win32Thread: e1bc1a08 WAIT: (WrUserRequest) UserMode Non-Alertable
    ff8543e0  SynchronizationEvent
Not impersonating
Owning Process ff89c7a0
WaitTime (seconds)      16923
Context Switch Count    67                   LargeStack
UserTime                  0:00:00.0000
KernelTime                0:00:00.0093
Start Address 0x77e878c1
Win32 Start Address 0x01003dd0
Stack Init fd536000 Current fd535c20 Base fd536000 Limit fd531000 Call 0
Priority 12 BasePriority 8 PriorityDecrement 0 DecrementCount 0

ChildEBP RetAddr  Args to Child
fd535c38 8012d61c 00000000 e1bc1a08 00000001 ntoskrnl!KiSwapThread+0xc5
fd535cbc 801672a2 00000001 00000001 000021bf ntoskrnl!KeWaitForSingleObject+0x1a1
fd535d4c 80161691 0006ff08 00000000 00000000 ntoskrnl!ExFreePool+0xb
fd535d4c a01772a8 0006ff08 00000000 00000000 ntoskrnl!KiSystemService+0xc4
ffffffff 00000000 00000000 00000000 00000000 +0xa01772a8

!thread 输出中的重要信息在下表中描述。

参数

含义

Thread address

单词THREAD 后面的16进制数字是ETHREAD 块的地址。前面例子中,线程地址为0xFF8632C0。

Thread ID

Cid 后面的两个16进制数字是进程ID和线程ID:进程ID.线程ID。前面例子中,进程ID为0x38C,或者10进制的908,线程ID为0x380,10进制是896。

Thread Environment Block (TEB)

Teb 后面的16进制数字是线程环境块(TEB)的地址。前面例子中的TEB地址为0x7FFDE000。

System Service Dispatch Table

Win32Thread 后面的16进制地址是系统服务分配表(system service dispatch table)的地址。前面例子中位于0xE1BC1A08。

Thread State

线程状态显示在以WAIT 开头的行的末尾。前面例子中线程是在non-alertable 状态下。

Owning Process

Owning Process 后的16进制地址是拥有该线程的进程的EPROCESS地址。

Start Address

Start Address后的16进制数字是线程的起始地址。可能是以符号化的形式显示的。

User Thread Function

Win32 Start Addres后面的16进制数字是用户的线程函数的地址。

Priority

Priority 后面是线程的优先级信息。

Stack trace

输出的末尾是线程的调用堆栈。

 

附加信息

关于内核模式下线程的信息,查看改变上下文。关于分析进程和线程的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!threadfields

!threadfields 扩展命令显示执行线程块(ETHREAD)中的名字和偏移字段。

语法

!threadfields 

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

Kdextx86.dll

Windows XP和之后

不可用(查看注释部分)

注释

该扩展命令在Windows XP和之后的系统中不能使用。可以用dt (Display Type)命令来直接显示ETHREAD结构:

kd> dt nt!_ETHREAD 

下面是在Windows 2000系统上的!threadfields 示例:

kd> !threadfields
 ETHREAD structure offsets:

    Tcb:                           0x0
    CreateTime:                    0x1b0
    ExitTime:                      0x1b8
    ExitStatus:                    0x1c0
    PostBlockList:                 0x1c4
    TerminationPortList:           0x1cc
    ActiveTimerListLock:           0x1d4
    ActiveTimerListHead:           0x1d8
    Cid:                           0x1e0
    LpcReplySemaphore:             0x1e8
    LpcReplyMessage:               0x1fc
    LpcReplyMessageId:             0x200
    ImpersonationInfo:             0x208
    IrpList:                       0x20c
    TopLevelIrp:                   0x214
    ReadClusterSize:               0x21c
    ForwardClusterOnly:            0x220
    DisablePageFaultClustering:    0x221
    DeadThread:                    0x222
    HasTerminated:                 0x224
    GrantedAccess:                 0x228
    ThreadsProcess:                0x22c
    StartAddress:                  0x230
    Win32StartAddress:             0x234
    LpcExitThreadCalled:           0x238
    HardErrorsAreDisabled:         0x239

附加信息

关于ETHREAD块的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!time

!time 扩展命令已经废除。使用.time (Display System Time)命令来替代。

!timer

!timer 命令显示所有系统定时器使用的详细列表。

语法

!timer 

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

!timer 扩展会显示保存了系统中所有定时器对象的定时器树(timer tree)。

下面是示例:

kd> !timer
Dump system timers

Interrupt time: 9f760774 00000000 [12/ 8/2000 10:59:22.685 (Pacific Standard Time)]

List Timer    Interrupt Low/High     Fire Time              DPC/thread
  0 8016aea0 P 9fbd8e00 00000000 [12/ 8/2000 10:59:23.154]  ntoskrnl!PopScanIdleList 
  1 8257f118   e4e4225a 00000000 [12/ 8/2000 11:01:19.170]  thread 8257f030 
  3 80165fc0   286be1c9 0000594a [ 4/ 1/2001 01:59:59.215]  ntoskrnl!ExpTimeZoneDpcRoutine 
    80165f40   2a7bf8d9 006f105e [12/31/2099 23:59:59.216]  ntoskrnl!ExpCenturyDpcRoutine 
  5 825a0bf8   a952e1c2 00000000 [12/ 8/2000 10:59:39.232]  thread 825a0b10 
 10 8251c7a8   41f54d84 00000001 [12/ 8/2000 11:03:55.310]  thread 8251c6c0 
    8249fe88   41f54d84 00000001 [12/ 8/2000 11:03:55.310]  thread 8249fda0 
 11 8250e7e8   bc73ffde 00000000 [12/ 8/2000 11:00:11.326]  thread 8250e700 

.....

237 82757070   9f904152 00000000 [12/ 8/2000 10:59:22.857]  +f7a56f2e 
    82676348   9f904152 00000000 [12/ 8/2000 10:59:22.857]  +fe516352 
    82728b78   9f904152 00000000 [12/ 8/2000 10:59:22.857]  +fe516352 
238 fe4b5d78   9f92a3ac 00000000 [12/ 8/2000 10:59:22.873]  thread 827ceb10 
    801658f0   9f92a3ac 00000000 [12/ 8/2000 10:59:22.873]  ntoskrnl!CcScanDpc 
239 8259ad40   765a6f19 00000bba [12/23/2000 09:07:22.900]  thread 825d3670 
250 826d42f0   1486bed8 80000000 [         NEVER         ]  thread 825fa030 

Total Timers: 193, Maximum List: 7
Current Hand: 226, Maximum Search: 0

Wakeable timers:

附加信息

关于定时器对象的信息,查看Windows Driver Kit (WDK)文档。

!tokenfields

!tokenfields 扩展命令显示访问令牌对象(TOKEN结构)中的名字和偏移字段。

语法

!tokenfields 

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

Kdextx86.dll

Windows XP和之后

不可用(查看注释部分)

注释

该命令在Windows XP和之后版本中都不支持。可以使用dt (Display Type) 命令来直接显示TOKEN结构:

kd> dt nt!_TOKEN 

要查看某个特定的TOKEN结构的实例,可以使用!token扩展。

下面是Windows 2000系统上!tokenfields 的示例:

kd> !tokenfields
 TOKEN structure offsets:
    TokenSource:           0x0
    AuthenticationId:      0x18
    ExpirationTime:        0x28
    ModifiedId:            0x30
    UserAndGroupCount:     0x3c
    PrivilegeCount:        0x44
    VariableLength:        0x48
    DynamicCharged:        0x4c
    DynamicAvailable:      0x50
    DefaultOwnerIndex:     0x54
    DefaultDacl:           0x6c
    TokenType:             0x70
    ImpersonationLevel:    0x74
    TokenFlags:            0x78
    TokenInUse:            0x79
    ProxyData:             0x7c
    AuditData:             0x80
    VariablePart:          0x84

附加信息

关于TOKEN结构的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。(Microsoft Windows SDK文档中描述的用户模式令牌结构会有少许不同。)

!trap

!trap 扩展命令已经废除。使用.trap (Display Trap Frame)命令来替代。

!tss

!tss扩展命令已经废除。使用.tss (Display Task State Segment)命令替代。

!tz

!tz 扩展用于显示指定的power thermal zone结构。

语法

!tz [Address] 

参数

Address

要显示的power thermal zone的地址。如果省略该参数,则显示目标机中所有thermal zones。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

任何时候都可以通过按下CTRL+BREAK (WinDbg) 或CTRL+C (KD)来中止命令执行。

附加信息

要查看系统的电源特性,可以使用!pocaps 扩展命令。要查看系统的电源策略,可以使用!popolicy 扩展命令。关于电源特性和电源策略的信息,查看Windows Driver Kit (WDK) 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!tzinfo

!tzinfo 扩展显示指定的thermal zone information 结构的内容。

语法

!tzinfo Address 

参数

Address

要显示的thermal zone information结构地址。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

附加信息

要查看系统的电源特性,可以使用!pocaps 扩展命令。要查看系统的电源策略,可以使用!popolicy 扩展命令。关于电源特性和电源策略的信息,查看Windows Driver Kit (WDK) 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!ubc

!ubc 扩展命令清除一个用户空间的断点。

语法

!ubc BreakpointNumber 

参数

BreakpointNumber

指定要清除的断点号。星号(*)表示所有断点。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

该命令可以永久的删除用!ubp设置的断点。

参见

!ubd!ube!ubl!ubp

!ubd

!ubd 扩展命令暂时禁用用户空间的断点。

语法

!ubd BreakpointNumber 

参数

BreakpointNumber

指定要禁用的断点号。星号(*)表示所有断点。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

被禁用的断点会被忽略。使用!ube来重新启用断点。

参见

!ubc!ube!ubl!ubp

!ube

!ube扩展命令重新启用用户空间断点。

语法

!ube BreakpointNumber 

参数

BreakpointNumber

指定要启用的断点号。星号(*)表示所有断点。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

该命令用于重新启用被!ubd禁止的断点。

参见

!ubc!ubd!ubl!ubp

!ubl

!ubl 列出所有用户空间断点以及它们的当前状态。

语法

!ubl 

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

下面是一个使用和显示用户空间断点的示例:

kd> !ubp 8014a131
This command is VERY DANGEROUS, and may crash your system!
If you don't know what you are doing, enter "!ubc *" now!

kd> !ubp 801544f4

kd> !ubd 1

kd> !ubl
 0: e ffffffff`8014a131 (ffffffff`82deb000) 1 ffffffff
 1: d ffffffff`801544f4 (ffffffff`82dff000) 0 ffffffff

列出的每一行都包括断点号、状态(启用为e,禁用为d)、设置断点的虚拟地址、实际断点的物理地址、字节位置,以及设置断点时该内存位置原来的内容。

参见

!ubc!ubd!ube!ubp

!ubp

!ubp 扩展命令在用户内存空间设置一个断点。

语法

!ubp Address 

参数

Address

指定要设置断点的用户空间内的16进制虚拟地址。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

!ubp 扩展命令在用户空间设置一个断点。该断点实设置在实际的物理页面上,而不仅仅在虚拟页面上的。

设置物理断点(physical breakpoint)会同时改变页面的所有虚拟拷贝(virtual copy), 造成不可预知的结果。一种可能的情况就是破坏系统状态,造成bug check或者其他的系统崩溃的情况。因此,如果必须要使用这种断点的话,要非常慎重。

该命令不能用来在已经换出的页面上设置断点。如果页面在断点设置之后被换出内存,那么断点不再存在。

不能再页表或页目录中设置断点。

每个断点都有一个关联的断点号。可以使用!ubl来查看指派的断点号。断点创建时是起用的。要步过断点,必须先使用!ubd来禁用它。使用!ubc清除断点。

参见

!ubc!ubd!ube!ubl

!urb

!urb 扩展命令已经废除。使用dt URB命令替代。

!vad

!vad 扩展显示一个或多个虚拟地址详细的虚拟地址描述符(virtual address descriptor (VAD))。

语法

!vad VAD-Root [Flags

参数

VAD-Root

指定要显示的VAD树的根的16进制地址。

Flags

指定显示的格式。可能的值如下:

0

显示基于VAD-Root 的整个VAD树。(这是默认情况。)

1

仅显示由VAD-Root 指定的VAD。这种显示会包含更详细的分析。

DLL

Windows NT 4.0

Kdextx86.dll

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

使用!process 命令可以找到任何进程的VAD的根地址。

下面是!vad 扩展的示例:

kd> !vad 824bc2f8
VAD     level      start      end    commit
82741bf8 ( 1)      78000    78045         8 Mapped  Exe  EXECUTE_WRITECOPY
824ef368 ( 2)      7f6f0    7f7ef         0 Mapped       EXECUTE_READ
824bc2f8 ( 0)      7ffb0    7ffd3         0 Mapped       READONLY
8273e508 ( 2)      7ffde    7ffde         1 Private      EXECUTE_READWRITE
82643fc8 ( 1)      7ffdf    7ffdf         1 Private      EXECUTE_READWRITE

Total VADs:     5  average level:    2  maximum depth: 2

kd> !vad 824bc2f8 1

VAD @ 824bc2f8
  Start VPN:         7ffb0  End VPN:    7ffd3  Control Area:  827f1208
  First ProtoPte: e1008500  Last PTE e100858c  Commit Charge         0 (0.)
  Secured.Flink          0  Blink           0  Banked/Extend:        0 Offset 0
   ViewShare NoChange READONLY

SecNoChange 

附加信息

关于虚拟地址描述符的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals

!validatelist

!validatelist 扩展验证双链表的正反方向链接的正确性。

语法

!validatelist Address 

参数

Address

指定双链表的地址。

DLL

Windows NT 4.0

不可用

Windows 2000

不可用

Windows XP和之后

Kdexts.dll

注释

使用Ctrl+Break (WinDbg) 或者Ctrl+C (KD)来停止执行。

!verifier

!verifier 扩展命令显示驱动程序验证器(Driver Verifier)的状态和它的行为。

Driver Verifier在Windows 2000和之后版本的Windows中都包含。它在调试版和发行版系统中都可以使用。关于Driver Verifier的信息,查看Windows Driver Kit (WDK) 文档中的Driver Verifier 主题。

语法

Windows 2000的语法

!verifier [Flags [Image]] 

Windows XP和之后的语法

!verifier [Flags [Image]] 
!verifier 4 [Quantity
!verifier 8 [Quantity
!verifier 0x20 [CompletionTime CancelTime ForceCancellation
!verifier 0x40 [Quantity
!verifier 0x80 [Quantity]
!verifier 0x80 Address
!verifier 0x100 [Quantity]
!verifier 0x100 Address
!verifier ? 

参数

Flags

指定命令输出中显示哪些信息。如果Flags的值等于4、 8、 0x20、0x40、 0x80、或者0x100,那么!verifier 其他的参数是根据这些标志指定的值来解析的。如果Flags 是任何其他的值,即使设置了这些位中的一个或几个,也只允许使用FlagsImage参数。Flags 可以是这些bit值的和,默认为0:

Bit 0 (0x1)

显示被验证的所有驱动程序的名字。同时还会显示当前分配给每个驱动的分页和非分页池的字节数。

Bit 1 (0x2)

显示内存池的信息(pool size、 headers和pool tags),以及已卸载驱动遗留下来的还未释放掉(outstanding)的内存。如果没有同时设置bit 0(0x1),则这个flag无效

Bit 2 (0x4)

(Windows XP和之后) 显示fault injection information。每个分配(each allocation)的代码的返回地址、符号名字和偏移都会显示出来。如果Flags 刚好是0x4 并且使用了Quantity 参数,则可以选择显示的记录的数量。否则,会显示4条记录。

Bit 3 (0x8)

(Windows XP和之后) 显示被验证的驱动程序最近的一次IRQL改变。包括旧IRQL、新IRQL、处理器和时间戳。如果Flags 刚好是0x8并且包含了Quantity 参数,则可以选择显示出来的记录个数,否则会显示4条记录。

Bit 5 (0x20)

(Windows Vista和之后) 显示和驱动程序验证器的Driver Hang Verification 选项相关的信息。如果指定了CompletionTimeCancelTime、和ForceCancellation 参数,它们会替换先前的Driver Hang Verification 设置。

Bit 6 (0x40)

(Windows Vista和之后) 显示驱动程序验证器的Force Pending I/O Requests 选项的信息,包括从forced pending IRP日志中获得的纪录。

Quantity 参数指定要显示的记录个数。默认情况下会显示整个日志。

Bit 7 (0x80)

(Windows Vista和之后) 显示kernel pool Allocate/Free log 的信息。

Quantity 参数指定显示的记录数量。默认情况下显示整个日志。

如果指定了Address,则只显示kernel pool Allocate/Free log 中和这个地址相关的信息。

Bit 8 (0x100)

(Windows Vista和之后) 显示IoAllocateIrp 、IoCompleteRequest 和IoCancelIrp 调用的日志信息。

Quantity 参数指定要显示的记录条数,默认显示所有记录。

如果指定了Address,则只显示和指定的IRP关联的记录。

Image

如果使用了Flags,并且不等于4、 8或0x10, Image 用于指定驱动程序的名字。Image 用来过滤Flags值为0x1和0x2时显示的信息:只保留指定的驱动程序。这个驱动程序必须当前是被验证状态。

Quantity

(Windows XP和之后) 如果Flags恰好等于0x4, Quantity 指定要显示的fault injection records的数量。如果Flags恰好等于0x8, Quantity 指定要显示的IRQL日志的条数。如果Flags 刚好为0x40,Quantity 指定显示的forced pending IRP日志中的记录条数。如果Flags刚好为0x80,Quantity 指定要显示的kernel pool Allocate/Free log 记录条数。如果 Flags等于0x100,Quantity 指定要显示的IoAllocateIrp 、IoCompleteRequest 和IoCancelIrp 调用日志的记录条数。

CompletionTime

(Windows Vista和之后)  指定IRP完成的时间限制,以毫秒为单位。默认值为0x2710 (10 秒)。如果驱动程序超出了这个限制,则会在 Driver Hang Verification 日志中记录completion routine。当CompletionTime0时,Driver Verifier 不会监视IRP完成。Driver Hang Verification 参数仅在Flags 设置为0x20时才支持。

CancelTime

(Windows Vista和之后) 指定取消(canceling)一个IRP的时间限制,以毫秒为单位。默认值为0x1388 (5 秒)。如果驱动超出这个限制,则Driver Hang Verification日志中会记录cancellation routine。CancelTime0时,Driver Verifier不会监视IRP的取消。 Driver Hang Verification参数仅在 Flags 设置为0x20时支持。

ForceCancellation

(Windows Vista和之后) 启用或禁用对CompletionTime时间内没有完成的IRP的取消(cancellation)。 将ForceCancellation 设置为1来启用强制取消(forced cancellation)。ForceCancellation 设置为0来禁用强制取消。默认值为0。Driver Hang Verification参数仅在Flags为 0x20时可用。

?

(Windows XP和之后) 在调试器命令窗口中显示该扩展命令的简单帮助。

DLL

Windows NT 4.0

不可用

Windows 2000

Kdextx86.dll

Windows XP和之后

Kdexts.dll

注释

用驱动程序验证器来测试图形驱动程序时,要使用!gdikdx.verifier 扩展命令来替代!verifier

4、 8、0x20、 0x40、 0x80和0x100 是Flags 的特殊值。使用这些值的时候,会用到参数部分列出的特殊参数,并且只会显示和这些标志值相关的信息。

如果Flags使用了任何其他值,即使设置了这些特殊位的一个或者多个,也只允许使用FlagsImage参数。这种情况下,除了其他信息之外,!verifier还会显示激活的驱动程序验证器选项,以及内存池分配、IRQL提升、自旋锁和 trims 的统计。

如果Flags 等于0x20,驱动程序验证器的Driver Hang Verification选项将使用CompletionTimeCancelTimeForceCancellation。这些新的值会立即生效并且持续到下一次启动。重新启动计算机时,它们会恢复到默认值。

同样,如果Flags 等于0x20 (使用或不使用附加参数),则打印Driver Hang Verification日志。关于对这个日志的解读,查看Windows Driver Kit (WDK)文档中驱动程序验证器文档的Driver Hang Verification小节。

下面是Windows XP计算机上!verifier 扩展命令的示例。注意输出是按照驱动程序名排序:

kd> !verifier 0xf

Verify Level 1f ... enabled options are:
      special pool
      special irql
      inject random pool failures
      all pool allocations checked on unload
      Io subsystem checking enabled

Summary of All Verifier Statistics

RaiseIrqls                             0x0
AcquireSpinLocks                       0x22a
Synch Executions                       0xbcd7
Trims                                  0x20e

Pool Allocations Attempted             0x48
Pool Allocations Succeeded             0x48
Pool Allocations Succeeded SpecialPool 0x48
Pool Allocations With NO TAG           0x0
Pool Allocations Failed                0x0
Pool Allocations Failed Deliberately   0x0

Current paged pool allocations         0x8 for 000002D8 bytes
Peak paged pool allocations            0xa for 00000494 bytes
Current nonpaged pool allocations      0xb for 00003038 bytes
Peak nonpaged pool allocations         0xb for 00003038 bytes

Driver Verification List

Entry     State           NonPagedPool   PagedPool   Module

fe527df8 Loaded           00002094       000002b8    ftdisk.sys

Current Pool Allocations  00000007    00000005
Current Pool Bytes        000002b8    00002094
Peak Pool Allocations     00000009    00000005
Peak Pool Bytes           00000338    00002094

PoolAddress  SizeInBytes    Tag       CallersAddress
f7b1bff0     0x00000010     ScFt      fdbac7af
f7b1df88     0x00000078     ScFt      fdbb6e9f
f7bfbfd0     0x00000030     ScFt      fdbac7af
fe4e4000     0x00002000     ScFt      fdba01e6
f7c19ff8     0x00000004     ScFt      fdba2677
f7c2bfb0     0x00000050     ScFt      fdbac2c1
f7c2df60     0x000000a0     ScFt      fdba672e
f7c47fe0     0x00000020     ScFt      fdba6968
f7c73f60     0x000000a0     ScFt      fdba672e
f7c8dfe0     0x00000020     ScFt      fdba6968
f7cb9f60     0x000000a0     ScFt      fdba672e
f7cd3fe0     0x00000020     ScFt      fdba6968

fe527d68 Loaded           00000f84       00000000    i8042prt.sys

Current Pool Allocations  00000000    00000005
Current Pool Bytes        00000000    00000f84
Peak Pool Allocations     00000002    00000005
Peak Pool Bytes           000001bc    00000f84

PoolAddress  SizeInBytes    Tag       CallersAddress
f8a6ff40     0x000000c0     8042      fdde2eec
f8a71f88     0x00000074     8042      fdde2f3e
f8cf1b50     0x000004b0     8042      fdddf64c
f93bb6a0     0x00000960     8042      fdde0990
f93b9fc0     0x00000040     8042      fdddfd0e

fe527cd8 Loaded           00000020       00000020    flpydisk.sys

Current Pool Allocations  00000001    00000001
Current Pool Bytes        00000020    00000020
Peak Pool Allocations     00000001    00000001
Peak Pool Bytes           00000020    00000020

PoolAddress  SizeInBytes    Tag       CallersAddress
f93abfe0     0x00000020     Flop      fdf5dcb5
f93affe0     0x00000020     Flop      fdf5b75d

----------------------------------------------- 
Fault injection trace log                       
----------------------------------------------- 
No fault injection traces found. 
----------------------------------------------- 
Track irql trace log                            
----------------------------------------------- 

Size of track irql queue is 0x80 

Thread:             FFFFFFFFFE4FA880
Old irql:           0
New irql:           2
Processor:          0
Time stamp:         5B97C

    FFFFFFFF80535D9E ntoskrnl!VerifierKfAcquireSpinLock+0x28
    FFFFFFFFFDB9ED56 +0xfffffffffdb9ed56
    FFFFFFFFFDB9F2CA +0xfffffffffdb9f2ca
    FFFFFFFF804175BD ntoskrnl!IopfCallDriver+0x31
    FFFFFFFFFDBEA69B +0xfffffffffdbea69b

Thread:             FFFFFFFFFE4FA880
Old irql:           2
New irql:           0
Processor:          0
Time stamp:         5B979

    FFFFFFFF80535E57 ntoskrnl!VerifierKfReleaseSpinLock+0x67
    FFFFFFFFFDB9EEED +0xfffffffffdb9eeed
    FFFFFFFFFDB9F2CA +0xfffffffffdb9f2ca
    FFFFFFFF804175BD ntoskrnl!IopfCallDriver+0x31
    FFFFFFFFFDBEA69B +0xfffffffffdbea69b

Thread:             FFFFFFFFFE4FA880
Old irql:           0
New irql:           2
Processor:          0
Time stamp:         5B979

    FFFFFFFF80535D9E ntoskrnl!VerifierKfAcquireSpinLock+0x28
    FFFFFFFFFDB9ED56 +0xfffffffffdb9ed56
    FFFFFFFFFDB9F2CA +0xfffffffffdb9f2ca
    FFFFFFFF804175BD ntoskrnl!IopfCallDriver+0x31
    FFFFFFFFFDBEA69B +0xfffffffffdbea69b

Thread:             FFFFFFFFFE4FA880
Old irql:           2
New irql:           0
Processor:          0
Time stamp:         5B974

    FFFFFFFF80535E57 ntoskrnl!VerifierKfReleaseSpinLock+0x67
    FFFFFFFFFDB9EEED +0xfffffffffdb9eeed
    FFFFFFFFFDB9F2CA +0xfffffffffdb9f2ca
    FFFFFFFF804175BD ntoskrnl!IopfCallDriver+0x31
    FFFFFFFFFDBEA69B +0xfffffffffdbea69b

下面是!verifier 扩展命令在Windows Vista计算机上打开了bit 7并且指定Address的示例。

0: kd> !verifier 80 a2b1cf20
Parsing 00004000 array entries, searching for address a2b1cf20.
=======================================
Pool block a2b1ce98, Size 00000168, Thread a2b1ce98
808f1be6 ndis!ndisFreeToNPagedPool+0x39
808f11c1 ndis!ndisPplFree+0x47
808f100f ndis!NdisFreeNetBufferList+0x3b
8088db41 NETIO!NetioFreeNetBufferAndNetBufferList+0xe
8c588d68 tcpip!UdpEndSendMessages+0xdf
8c588cb5 tcpip!UdpSendMessagesDatagramsComplete+0x22
8088d622 NETIO!NetioDereferenceNetBufferListChain+0xcf
8c5954ea tcpip!FlSendNetBufferListChainComplete+0x1c
809b2370 ndis!ndisMSendCompleteNetBufferListsInternal+0x67
808f1781 ndis!NdisFSendNetBufferListsComplete+0x1a
8c04c68e pacer!PcFilterSendNetBufferListsComplete+0xb2
809b230c ndis!NdisMSendNetBufferListsComplete+0x70
8ac4a8ba test1!HandleCompletedTxPacket+0xea
=======================================
Pool block a2b1ce98, Size 00000164, Thread a2b1ce98
822af87f nt!VerifierExAllocatePoolWithTagPriority+0x5d
808f1c88 ndis!ndisAllocateFromNPagedPool+0x1d
808f11f3 ndis!ndisPplAllocate+0x60
808f1257 ndis!NdisAllocateNetBufferList+0x26
80890933 NETIO!NetioAllocateAndReferenceNetBufferListNetBufferMdlAndData+0x14
8c5889c2 tcpip!UdpSendMessages+0x503
8c05c565 afd!AfdTLSendMessages+0x27
8c07a087 afd!AfdTLFastDgramSend+0x7d
8c079f82 afd!AfdFastDatagramSend+0x5ae
8c06f3ea afd!AfdFastIoDeviceControl+0x3c1
8217474f nt!IopXxxControlFile+0x268
821797a1 nt!NtDeviceIoControlFile+0x2a
8204d16a nt!KiFastCallEntry+0x127

附加信息

关于驱动程序验证器的信息,查看Windows Driver Kit (WDK)文档。