c's profilenetroc的共享空间BlogListsGuestbookMore ![]() | Help |
netroc的共享空间 |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
感谢访问!
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 本文从主站点转贴过来的,附件和pdf请访问http://www.DbgTech.net/下载 一、简介《Windows高级调试》第一章中提到了一个基于Microsoft Detours库的内存泄露检查工具LeakDiag。本文对这个库进行一些介绍。 一句话来说,Detours是一个用来在二进制级别上对程序中的函数(Function)或者过程(Procedure)进行修改的工具库。一般我们将这种技术称为"Hook"。Detours的实现原理是将目标函数的前几个字节改为jmp指令跳转到自己的函数地址,以此接管对目标函数的调用,并插入自己的处理代码。在现实中,这种技术可以应用在很多场景下。比如Hook某些Windows API,在实际调用到系统函数前进行一些过滤工作;软件中使用到了一些没有源代码的第三方库,但是又想增强其中某些函数的功能,等等。
图1 Hook前后的程序执行流程对比。
图2 Hook前后目标函数和跳板代码的改变
Detours相对其他一些Hook库和自己实现的代码来说,通常有以下这些优点:
二、使用方法一般来说,使用Detours的代码都具有固定的模式。Detours 1.5和Detours 2.1的接口函数变了很多,这里按照2.1版本对基本的使用方法进行说明。 常用的函数有下面几个:
在使用的时候,这几个函数的调用步骤基本上也是按照上面列出来的顺序。举例来说,现在想Hook掉API函数MessageBoxA,将消息框弹出的消息修改掉,可以按下面的方法做。 进行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库的代码是非常稳定的,但是如果使用方法不对,会造成一些问题。有下面一些地方需要特别注意:
Detours不支持9x内核的Windows系统。因为9x内核下的内存模型和NT内核下有非常大的差别。 May 19 《Windows高级调试》介绍 做程序员的人肯定听说过这句话:“世界上最痛苦的事情是加班,比加班更痛苦的事情是天天加班。”相信很多工作的朋友都体验过这种加班加得天昏地暗的日子吧?
天哪,我怎么才能少加点班?我想多一点自己的时间! 从我个人的经历来看,加班最常见的原因,就是程序发现严重BUG。一边是上级不断催着要解决问题,一边却找不出来出错原因,经常忙得焦头烂额。事实上,如果再花少许时间学习一些调试方法和调试工具的使用,会让我们花在调试BUG上的时间大大缩短。可能以前花几天时间还找不出来的问题,其实只需要半个小时就搞定了。 《Advanced Windows Debugging》这本书就是为了解决这个问题而问世的,但是因为大家只能看到英文版,让很多人望而生畏。很幸运的是,机械工业出版社即将推出它的中文版,更多人可以不因为语言的限制而错过这样一本好书了。 更幸运的是,机械工业出版社的编辑朋友联系到DbgTech,我们得以提前获得了这本书的一些资料。DbgTech立足于调试技术的宣传和推广,希望以此能为国产软件的稳定性和可靠性提高做出微薄的贡献。这本书可以说是目前市面上能找到的最好的一本为开发人员量身打造的调试书籍。包含对各种常用调试工具的使用介绍;内存溢出、资源泄露、同步、进程间通信等最典型BUG问题的调试介绍。我们希望以此为契机,跟大家共同学习这本书中的内容。后面会陆续推出一些典型的调试案例的文章,大家阅读的时候如果有心得体会或者疑问,也欢迎参加讨论! 后面本书的一些内容节选,更详细的内容请下载附件中的文档。 欢迎到我们的站点讨论:DbgTech April 08 关于Windows系统调用实现的笔记NetRoc 从Win XP开始,Windows的系统调用都是通过sysenter指令进入KiFastCallEntry或者_KiFastCallEntry2。最近稍微看了一下这部分的wrk代码实现,作了些笔记。
从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……
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
两个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被设置。
上面提到了,由于KiInitSystem的初始化,KeServiceDescriptorTableShadow[0]和KeServiceDescriptorTable[0]总是一样的,但是KeServiceDescriptorTableShadow[1]会被设置成win32k的服务。这应该是win32k加载之后调用KeAddSystemServiceTable添加的。
AMD64下的实现和i386不同,AMD64下的ShadowTable在_KTHREAD中专门有一个字段,ServiceTable保存KeServiceDescriptorTable,Win32kTable保存KeServiceDescriptorTableShadow[WIN32K_SERVICE_INDEX].Base。详见PsConvertToGuiThread等函数。
从上面记录的这些实现来看,很直接导致的结果就是,系统服务表可以比较容易的替换掉。这种替换有下面这些特点:
没有什么隐蔽性,呵呵。干坏事的同学慎用。当然,用的时候再改,用过之后马上改回去,或者配合内存隐藏之类的技术还是不错滴。干好事的同学也可以用,但是不适合对所有系统线程都用上去,因为要枚举所有线程,或者Hook线程创建函数之类比较麻烦,到不如直接去干KiFastCallEntry。用来保护自己线程的服务表安全倒是不错。 December 18 经济形势严峻受经济危机影响,劳动密集型产业受创严重。民工回流不止是经济问题,更是严重的政治问题。
闲散劳动力无法消化,习惯了在外打工生活的年轻人又很难安心回到农村生活,如果没有迅速安置他们解决就业问题的话,会严重动摇社会稳定。
大量中央和地方投资,正是为了解决这个问题吧。国内形势已经严峻到没有办法去考虑经济问题了。如此之大的投资,必然带来财政赤字和更恶劣的腐败问题。通涨压力在未来几年会增大,社会贫富差距也会进一步增大。由此会带来更多不稳定因素。
去年只是经济形势严峻,到今年已经掺入了更多政治问题进来。拆东墙补西墙的政策能支持多久? December 10 发现.NET的一个疑问COM中的一个事件,在非主线程中触发的。C#的事件处理过程中,又通过该COM接口调用了一个方法,结果发现该方法是在主线程环境中调用的。
这个特性在我的一段代码中出现了死锁。
空了研究一下,呵呵 December 03 Windows调试工具入门-2NetRoc 本篇介绍Windows调试工具的基本设置和基本操作方法。这里我们会用一个测试程序一步一步说明如何使用WinDbg开始调试工作。首先用VC建立一个名为TestDebug1的控制台项目,并生成它。
使用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这些调试器一样拥有强大的反汇编分析能力,所以仅仅靠这些看起来一团乱麻的反汇编代码,调试工作是很难开展下去的。
这里就已经可以看到TestDebug1.exe中的函数、变量名这样的符号了。而我们也可以通过bp main这样的命令直接使用符号来操作调试器。 另外,在Local、Watch等窗口中也可以直接使用符号名查看到变量的值、在Call Stack窗口中可以看到函数名,等等。
确定之后,如果当前指令指针在源文件的代码范围内,就会自动跳出源文件窗口。如果没有跳出,那么可以通过File->Open Source File…菜单手动打开源文件。由于刚才设置的断点还没有删除,所以在源码窗口也能口看到设断的行被高亮了:
之后就基本上可以完全通过源码窗口进行设置断点、查看变量、跟踪代码等操作。比只有符号的时候方便了很多。
注意位于764e8ccf处的那个call,现在只能看到调用了kernel32某个偏移处的地址。 使用命令.symfix+ d:\Symbols命令,注意加号要紧靠前面的文本。d:\Symbols是用来保存下载的符号文件的目录,可以修改成自己需要的路径。再来打开符号路径窗口,我们可以看到调试器自动添加了一些内容:
自己在源码路径中加入这些新的内容也可以实现相同的效果。详细的原理请参考WinDbg帮助文档关于符号服务器设置的部分内容。 接下来再次使用.reload命令重新加载符号,第一次使用到的符号文件会从网上自动下载下来,所以可能有时候会等待一会。完成之后,可以看到反汇编窗口中出现了新的符号内容:
764e8cd8处指令中可以看到这是调用了kernel32导入的函数NtOpenProcess。 微软提供的Windows符号是我们研究Windows实现的必备利器。首先,符号化的名字有助于调试过程中的记忆和对各种信息的识别;其次,通过名字就常常可以猜测出来函数或变量的作用,很大的方便调试。在各种调试应用中,都强烈建议添加微软公共符号的引用。
如果设置了符号路径的环境变量的话,可能在初期使用VS 2008调试MFC这样的有较多导入库的程序时会下载很多符号文件,使得启动调试的速度变慢。不过经过一段时间,大部分需要的符号都缓存到本地之后速度就会快起来。
进行调试时,有时候调试器命令窗口会变得很杂乱,所以常常想用.cls命令清空它。但是这样会无法再看到之前调试过程中输出的结果。另外,有时候想保存下整个调试过程的详细记录以备后面"回味"。这时,就需要用到日志文件了。可以将调试器命令窗口中出现过的所有内容都自动记录到日志文件中。 创建日志文件:
将日志添加到已有的文件末尾:
关闭日志文件:
工作空间(Workspace)是用来保存WinDbg中工作环境的工具。例如习惯的窗口布局方式、符号路径、异常处理的设置等等,都可以通过工作空间保存下来,在下次调试的时候就不用再次设置了。 相关的设置都可以通过WinDbg菜单来完成,有下面几个:
在没有调试目标的时候调整WinDbg的窗口布局等等设置的话,会保存为默认的工作空间。下一次打开新目标的时候,就会使用这个设置。通常我们可以设定一个默认的工作空间,然后为各个单独的任务保存另外的设置。 November 27 Windows调试工具入门—1NetRoc
Debugging Tools for Windows是微软发布的一套用于软件调试的工具包(后面如果没有指明,那么我会使用WinDbg来作为这一套调试工具的简称)。我第一次接触是在三年前的一个内核驱动项目,由于进行了IDT中键盘鼠标中断的Hook,使用Softice调试时造成会造成影响,只得使用WinDbg通过串口进行双机调试。自此之后这个Windows平台下最为强大的调试工具一直是开发过程中的必备。这里我毫不掩饰的说"最强",可能很多通过逆向工作而接触调试的朋友不会认同,但是我相信随着对WinDbg了解的加深,以及对这套工具在软件开发中应用的了解,他们也会和我有一样的观点。 一直以来,软件调试技术在软件开发者中都没有得到足够的普及和重视,互联网上能找到的系统描述的资料也较少。随着国内软件行业整体的发展和进步,这些技术慢慢开始得到推广。2008年出版的有关调试的数据比以往都要多。我有幸拜读了Raymond的《软件调试》,以及熊力的《Windows用户态程序高效排错》,获益良多。 这几年的工作中也积累了一些关于Windows调试工具的知识,希望能够将这些东西进行一些分享。因此,利用几个月空闲时间翻译了WinDbg文档中上半部调试器配置、使用和命令介绍的内容,同时准备写一些关于WinDbg调试工具的初级文章。希望能够为对调试技术感兴趣而又苦于没有资料的朋友提供一些帮助。 特别感谢我的前同事小喂。虽然他第一条串口线还是我焊的,但是他对于WinDbg的使用和了解程度很快就超过了我。在相当长时间的共事和讨论中,让我学到了很多。
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平台操作系统中运行。 另外,工具包中还有一些小工具,下面是常用的几个:
另外,Application Verifier虽然没有包含在软件包中,但是也是一个非常强大的工具。可以对程序运行时的很多状态进行监控,以发现一些普通调试难以找到的错误。下面是Application Verifier配置界面的一个截图:
Application Verifier可以在这个页面下载:http://go.microsoft.com/fwlink/?linkid=108353
可能很多已经习惯使用SoftICE、OllyDbg、IDE调试器的朋友会提出这样的疑问:在这么多调试器中,为什么要选择WinDbg?它究竟有什么特点? 设想一下下面几个场景:
在现实环境中,有很多复杂的调试场景,我们需要专业级的调试器来解决这些问题。而WinDbg恰恰提供了这种商业软件环境下的专业级软件调试功能,它和其他很多我们熟知的调试器的区别也在于此。 我们将WinDbg和其他调试器分作内核调试器和用户态调试器两类来进行比较。 内核调试方面:
由于SoftICE已经停止更新,WinDbg可以说是现在Windows平台上唯一好用的进行内核调试的工具,并且随着新版本的不断推出,不断地添加对新版操作系统的支持以及完善功能。强大的符号支持,方便的源码调试,使得内核级调试能够事半功倍。 用户态调试方面:
由于WinDbg功能相当复杂,有很多方面并不能一一比较,例如非侵入式调试、通过WinDbg控制CDB和NTSD来调试系统服务、创建和分析Dump文件等等。 总体来说,WinDbg更适合作为软件项目开发和维护过程中的调试工具使用,而OllyDbg更适合逆向工程。
根据我个人对WinDbg的使用经验来说,它更适合作为开发维护的辅助工具来使用。 如果要进行用户态的逆向工程,推荐使用OllyDbg、IDA这些拥有强大汇编程序分析能力的工具。 WinDbg更适用于以下这些场合:
November 22 许久不来,这里还是留来胡弹乱吹吧终于离开了tencent这个恶心的鸟地方。本来想把社保清单贴出来立此存照的,没想到前几天好像被我删掉了。
WinDbg文档,把已处理部分更新到6.10.3了,搞得头晕眼花。看来要说坚持不是那么容易的事情啊。。。几十w字,噢买嘎的。。 September 03 空间转移由于blog的形式查阅帮助文档不便,所以还是转移到了专门的空间中,做成了在线Help的形式。目前翻译的文档由于需要修复链接,以及更新新版WinDbg文档中的内容,所以还在陆续整理中。 另外还挂了一个论坛和另一个blog上去,刚刚开始做,所以各方面都还很不完善,正在努力中:) http://www.dbgtech.net/ August 18 WinDbg 文档翻译----91cc682/NetRoc http://netroc682.spaces.live.com/ !evlog!evlog 扩展命令用于显示、修改或者备份事件日志(event log)。 语法!evlog addsource [-d] [-s Source] [-t Type] [-f MsgFile] 参数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 clear,EventLog 指定要读取哪个事件日志。可能的值有Application、System、和Security。默认为Application。 对于!evlog option, EventLog 指定要设置最大数量(maximum count)的事件日志。可能的值有All、Application、System和 Security。默认为All。 BackupFile 指定备份文件的路径和文件名。默认位置是当前目录。默认文件名是EventLog_backup.evt,EventLog 是在该命令中使用的事件日志。如果文件已经存在,命令会终止执行。 Count 指定要获取的记录的最大数量。默认为20。 -+ 指定用后面的!evlog read命令获取的最大记录数量作为当前最大记录数量。(换句话说,只要前面没有进行过搜索就不会显示出记录来。) RecordBound 指定之后的!evlog read 命令能获取的最大记录数量。如果指定0,则不会有限制 — 这是默认。 Record 如果没有包含-n Count,-r Record 用于指定要获取的记录条数。如果包含了-n Count,Record用于指定显示从第几条记录开始。 Order 指定搜索顺序,可以是Forwards 或Backwards。默认为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
!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 -? !findstack!findstack 扩展命令用于在所有调用堆栈中定位包含指定符号或模块的位置。 语法!findstack Symbol [DisplayLevel] 参数Symbol 指定符号或者模块。 DisplayLevel 指定显示中要包含的内容。可以是下面这些值中的一个,默认值是1。 0 仅显示每个包含Symbol的线程的ID。 1 显示包含Symbol的每个线程的ID和frame。 2 显示每个包含Symbol的线程的整个调用堆栈。 -? 在调试器命令窗口中显示该扩展命令的简单帮助。 DLL
注释内核模式下的!stacks命令可以显示所有线程的调用堆栈和状态摘要信息。 下面是该扩展命令输出的示例: 0:023> !uext.findstack wininet 附加信息关于堆栈回溯和显示调用堆栈的其他方式的信息,查看查看调用堆栈和k, kb, kd, kp, kP, kv (Display Stack Backtrace) 命令。 !gatom!gatom 扩展用于显示全局atom表(global atom table)。 语法!gatom DLL
附加信息关于全局atom表的信息,查看Microsoft Windows SDK文档。 !igrep!igrep 扩展命令在反汇编中搜索指定的模板。 语法!igrep [Pattern [StartAddress]] 参数Pattern 指定要搜索的模板。如果省略,则使用前一次的Pattern。 StartAddress 指定开始搜索的16进制地址。如果省略,则使用当前程序计数器。 DLL
!locks (!ntsdexts.locks)Ntsdexts.dll中的!locks 扩展命令显示当前进程关联的临界区(critical section)的清单。 该扩展命令不要和!kdext*.locks 命令混淆。 语法!locks [Options] 参数Options 指定要显示的信息数量。可以是下面这些选项的任意组合: -v 显示所有临界区,包括当前没有被持有的那些。 -o (Windows XP和之后) 仅显示孤立的信息(orphaned information)(没有指向合法的临界区的指针)。 DLL
注释该扩展命令会显示所有通过调用RtlInitializeCriticalSection 初始化的临界区。如果没有临界区,那么不会产生输出。 示例如下: 0:000> !locks 附加信息关于可以显示临界区信息的其他命令和扩展命令,查看显示临界区。关于临界区的信息,查看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
!runaway 扩展命令只能在活动调试时,或者调试通过.dump /mt 或.dump /ma创建的dump文件时使用。 注释该扩展命令可以用来快速找出哪些线程循环失去控制消耗了太多CPU时间。 输出中以调试器的内部线程号和16进制线程ID来标识每个线程。还会显示调试器ID。 下面是示例:
附加信息关于用户模式下线程的信息,查看控制进程和线程。关于对进程和线程进行分析的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !threadtoken!threadtoken 扩展命令显示当前线程的模拟状态(impersonation state)。 语法!threadtoken DLL
注释!threadtoken 扩展命令在Windows XP和之后版本中已经废除。使用!token 来替代。 如果当前线程处于模拟状态下(impersonating),那么会显示它使用的令牌(token)。 否则,会出现"Thread is not impersonating"信息。并且显示进程的令牌。 令牌的显示的格式和使用!handle 来显示令牌句柄时一样。 下面是示例: 0:000> ~ 附加信息关于线程和模拟的信息,查看线程和模拟(impersonation)的信息,查看Microsoft Windows SDK 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !uniqstack!uniqstack 扩展命令显示当前进程中所有线程的调用堆栈,除开重复的那些。 语法!uniqstack [ b | v | p ] [ n ] 参数b 显示中包含传递给每个函数的前3个参数。 v 显示帧指针省略信息(frame pointer omission (FPO) information)。在x86处理器上,还会显示调用约定的信息。 p 显示调用堆栈中每个函数的完整参数。会列出每个参数的数据类型、名字和值。需要完整符号信息。 n 显示帧序号(frame number)。 DLL
注释除了不显示重复的调用堆栈之外,该命令和k, kb, kd, kp, kP, kv (Display Stack Backtrace) 命令类似。 例如: 0:000> !uniqstack 附加信息关于堆栈回溯的更多信息和其它显示调用堆栈的方法,查看查看调用堆栈。 !vadump!vadump 扩展命令显示所有的虚拟内存区域以及它们对应的保护信息。 语法!vadump [-v] 参数-v 显示中还包含每个原始分配区域(original allocation region)的信息。由于每个区域中的不同地址在分配之后可能改变成了自己的保护属性(例如使用VirtualProtect),所以大区域的原始保护属性可能和内部的子区域不一样。 DLL
注释下面是示例: 0:000> !vadump 输出重,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 使用-v时,AllocationProtect行显示整个区域被创建时的默认保护属性。Protect行显示指定地址处实际的保护属性。 附加信息要查看单个虚拟地址的内存保护信息,可以使用!vprot。关于内存保护的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !vprot!vprot 扩展命令显示虚拟内存保护信息。 语法!vprot [Address] 参数Address 指定要查看内存保护状态的16进制地址。 DLL
注释!vprot 扩展命令可以用于活动调试和dump文件调试。 下面是示例: 0:000> !vprot 30c191c 输出中, 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 文档翻译----90cc682/NetRoc http://netroc682.spaces.live.com/ 用户模式扩展命令本小节中的参考用于描述主要在用户模式调试时使用的扩展命令。 调试器会自动加载这些扩展命令的适当版本。如果不是自己已经加载了一个不同的版本,那么就不需要关心所使用的DLL版本。查看使用调试器扩展命令获得默认模块搜索顺序的说明。查看加载调试器扩展DLL获得关于加载扩展模块的说明。 每个扩展命令的参考部分都列出了导出该命令的DLL。可以用下面的规则来判断扩展DLL是从什么地方加载的:
另外,和操作系统不相关的那些用户模式扩展放在winext\Uext.dll中。 !avrf!avrf扩展用于控制Application Verifier的设置,并且显示由Application Verifier产生的各种输出。 语法!avrf 参数-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
注释不带参数使用!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.dll 和verifier.dll 的符号,那么!avrf 扩展会产生错误信息。关于如何定位这种问题的信息,查看Application Verifier 文档中的"Setting Up a Debugger for Application Verifier"。 附加信息关于如何下载和安装Application Verifier ,以及它的文档的信息,查看Application Verifier。 !critsec!critsec 扩展命令显示某个临界区(critical section)。 语法!critsec Address 参数Address 指定临界区的16进制地址。 DLL
注释如果不知道该临界区的地址,可以使用!ntsdexts.locks 扩展。它会显示由调用RtlInitializeCriticalSection 来初始化的所有临界区。 下面是示例: 0:000> !critsec 3a8c0e9c 附加信息关于其他可以显示临界区信息的命令,查看显示临界区。关于临界区的信息,查看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
注释该命令会显示进程地址、进程ID、序号(sequence number)、标志(flags)和引用计数。如果选择了详细模式,还会显示更多细节以及每个进程的线程信息。 如果没有指定进程,则会显示所有进程。 参见!dphdump!dphdump 扩展命令显示debug page heap。 语法!dphdump Address 参数Address 指定堆的基地址或者堆句柄。 DLL
注释如果在Windows 2000(Service Pack 1或之后)、Windows XP或之后版本Windows中查看page heap,应该使用!heap 扩展命令。 参见!dphfind!dphfind 扩展命令查找包含指定地址的debug page heap。 语法!dphfind Address 参数Address 指定debug page heap必须包含的16进制地址。 DLL
注释Address一般是应用程序尝试访问从debug page heap中分配的内存时出错的地址。 如果在Windows 2000(Service Pack 1或之后)、Windows XP或之后版本Windows中查看page heap,应该使用!heap 扩展命令。 参见!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 2000(Service Pack 1或之后)、Windows XP或之后版本Windows中查看page heap,应该使用!heap 扩展命令。 这里有一些示例。下面的命令在free build上启用调用堆栈的搜集。(默认情况下不会): !dphflags 0x03 下面的命令将不可访问的页面放到分配(allocation)的开始位置。并且启用调用堆栈的跟踪: !dphflags 0x13 下面的命令使得有48%可能性从page heap中分配。同样,如果可用内存低于48%,则所有分配都会从标准堆中进行: !dphflags 0x3000300F 参见!dphhogs!dphhogs 扩展用于显示debug page heap hogs。 语法!dphhogs Address [count] [reset] 参数Address 指定堆的基地址或者堆句柄。 count 列表按照count来排序(而不是按字节)。 reset 所有的allocation counts重置为0。 DLL
注释这个命令只能用于运行在x86处理器上的checked版本Windows NT 4.0。 如果在Windows 2000(Service Pack 1或之后)、Windows XP或之后版本Windows中查看page heap,应该使用!heap 扩展命令。 参见!dreg!dreg 扩展命令显示注册表信息。 语法!dreg [-d|-w] KeyPath[!Value] 参数-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
注释!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 [v] CSR-Thread 参数v 详细输出。 CSR-Thread 指定CSR线程的16进制地址。 DLL
注释该扩展命令显示CSR线程关联的线程、进程、client ID、标志和引用计数。如果使用了详细模式,输出中还包含list pointer、线程句柄和等待块(wait block)。 参见August 11 WinDbg 文档翻译----89cc682/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
注释下面是当Flags 为1时的简短输出的示例: kd> !vm 1 所有的内存使用都是以页面数和KB为单位。输出中最有用的信息如下:
附加信息!memusage 扩展命令可以用来分析物理内存的使用。关于内存管理的更多信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !vpb!vpb 扩展显示某个卷参数块(volume parameter block (VPB))。 语法!vpb Address 参数Address 指定VPB的16进制地址。 DLL
注释下面是一个例子。首先用!devnode 扩展显示设备树: kd> !devnode 0 1 列出的最后一个节点是一个volume。使用 !devobj 扩展查看它的物理设备对象(physical device object (PDO)): kd> !devobj 80e15cb8 列出的内容中包括VPB 地址。使用!vpb 扩展和这个地址: kd> !vpb 80e15c30 附加信息关于VPB的信息,查看Windows Driver Kit (WDK) 文档以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !vpdd!vpdd 扩展显示指定进程的物理地址、虚拟地址和内存内容。 语法!vpdd Process VirtualAddress 参数Process 指定要显示内存的进程的地址。 PID 指定要显示内存的进程的PID(process ID)。 VirtualAddress 指定要查看的页面的虚拟地址。 DLL
注释下面是一个示例。假设要查看cmd.exe进程保存在虚拟地址0x4AD00000处的内存内容。首先使用!process 来查看进程地址: kd> !process 0 0 !vpdd 的首个参数可以使用进程地址(0x810E0020)或者PID(0x4E4)。第二个参数是要显示的虚拟地址: kd> !vpdd 810e0020 4ad00000 输出中,第一列是物理地址,第二列是虚拟地址。每行中剩下的内容是该位置保存的内容,以DWORD的形式。 附加信息相关主题,查看!vtop、 !ptov、以及将虚拟地址转换成物理地址。关于页表和页目录的信息,查看 Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !vtop!vtop 扩展命令将虚拟地址转换成对应的物理地址,并且显示其他的页表和页目录信息。 语法Windows 2000的语法 !vtop PFN VirtualAddress Windows XP和之后的语法 !vtop PFN VirtualAddress 参数DirBase 指定进程页目录的基址。每个进程都有自己的虚拟地址空间。使用!process扩展命令来查看进程的页目录基址。 PFN 指定进程页目录基址的页面帧序号(PFN)。 0 (Windows XP和之后)让!vtop 使用当前的进程上下文进行地址转换。 VirtualAddress 指定要转换的页面的虚拟地址。 DLL
注释要使用这个命令,首先应该用!process扩展来查看进程的页目录基址。页目录基址的页面帧序号(PFN)可以通过将它的地址最后三个16进制0数字去掉来获得(换句话说,就是右移12位)。 下面是一个示例: kd> !process 0 0 如果页目录基地址为0x098FD000,那么它的PFN 为0x098FD。 kd> !vtop 98fd 12f980 注意最后三个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 但是,最好还是使用PFN,因为有些页目录基址在这种情况下不会被转换。 附加信息关于获得这些结果的其他方法,查看将虚拟地址转换成物理地址。还可以查看!ptov 和!vpdd。关于页表和页目录的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !walklist!walklist 扩展命令在当前会话的会话链表中搜索某个地址。 语法!walklist [-a] [-o Offset] StartAddress SearchAddress 参数-a 搜索所有会话列表。 -o Offset 指定链表中next字段的偏移。 StartAddress 指定会话链表的起始地址。 SearchAddress 指定要在链表中搜索的地址。 -? 在调试器命令窗口中显示该扩展命令的帮助。 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
注释附加到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
注释输出以HH:MM:SS.mmm的格式。下面是示例: kd> !whattime 29857ae4 !whatperftime!whatperftime 扩展命令将高分辨率性能计数器值(high-resolution performance counter value)转换成标准的时间格式。 语法!whatperftime Count 参数Count performance counter clock的值。 DLL
注释可以用 !whatperftime 来转换通过调用QueryPerformanceCounter 获得的值。性能计数器时间值也能在软件跟踪(software trace)中看到。 输出按照HH:MM:SS.mmm格式,下面是示例: kd> !whatperftime 304589 !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 Server 2003系统的x86目标机上的示例: kd> !wsle 3 附加信息关于工作集的信息,查看Windows Driver Kit (WDK) 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !xpoolmap(仅Windows XP)!xpoolmap 扩展命令显示内存池使用的map。 语法!xpoolmap [Pool] 参数Pool 指定分页或非分页池。使用0 或者1。0 代表非分页池。1代表分页池。默认值是0。 -? 在调试器命令窗口中显示该命令的帮助。 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 !zombies!zombies扩展命令显示所有僵死("僵尸")进程或线程。 语法!zombies [Flags [RestartAddress]] 参数Flags 指定要显示的内容。可能的值如下: 1 显示所有僵尸进程。(这是默认值) 2 显示所有僵尸线程。 RestartAddress 指定搜索开始位置的16进制地址。当前一次搜索过早结束时有用。默认值为0。 DLL
注释僵尸进程是已经死亡但是还没有从进程列表中摘除的进程。僵尸线程也是类似这样。 该扩展命令仅在Windows 2000中可用。 附加信息查看所有进程和线程的列表,使用!process扩展。. 关于内核模式下进程和线程的概要信息,查看改变上下文。关于分析进程和线程的信息,查看Mark Russinovich 和David Solomon编写的 Microsoft Windows Internals。 WinDbg 文档翻译----88cc682/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 2000系统上的示例: kd> !thread ff8632c0 !thread 输出中的重要信息在下表中描述。
附加信息关于内核模式下线程的信息,查看改变上下文。关于分析进程和线程的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !threadfields!threadfields 扩展命令显示执行线程块(ETHREAD)中的名字和偏移字段。 语法!threadfields DLL
注释该扩展命令在Windows XP和之后的系统中不能使用。可以用dt (Display Type)命令来直接显示ETHREAD结构: kd> dt nt!_ETHREAD 下面是在Windows 2000系统上的!threadfields 示例: kd> !threadfields 附加信息关于ETHREAD块的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !time!time 扩展命令已经废除。使用.time (Display System Time)命令来替代。 !timer!timer 命令显示所有系统定时器使用的详细列表。 语法!timer DLL
注释!timer 扩展会显示保存了系统中所有定时器对象的定时器树(timer tree)。 下面是示例: kd> !timer 附加信息关于定时器对象的信息,查看Windows Driver Kit (WDK)文档。 !tokenfields!tokenfields 扩展命令显示访问令牌对象(TOKEN结构)中的名字和偏移字段。 语法!tokenfields DLL
注释该命令在Windows XP和之后版本中都不支持。可以使用dt (Display Type) 命令来直接显示TOKEN结构: kd> dt nt!_TOKEN 要查看某个特定的TOKEN结构的实例,可以使用!token扩展。 下面是Windows 2000系统上!tokenfields 的示例: kd> !tokenfields 附加信息关于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
注释任何时候都可以通过按下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
附加信息要查看系统的电源特性,可以使用!pocaps 扩展命令。要查看系统的电源策略,可以使用!popolicy 扩展命令。关于电源特性和电源策略的信息,查看Windows Driver Kit (WDK) 文档,以及Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !ubc!ubc 扩展命令清除一个用户空间的断点。 语法!ubc BreakpointNumber 参数BreakpointNumber 指定要清除的断点号。星号(*)表示所有断点。 DLL
注释该命令可以永久的删除用!ubp设置的断点。 参见!ubd!ubd 扩展命令暂时禁用用户空间的断点。 语法!ubd BreakpointNumber 参数BreakpointNumber 指定要禁用的断点号。星号(*)表示所有断点。 DLL
注释被禁用的断点会被忽略。使用!ube来重新启用断点。 参见!ube!ube扩展命令重新启用用户空间断点。 语法!ube BreakpointNumber 参数BreakpointNumber 指定要启用的断点号。星号(*)表示所有断点。 DLL
注释该命令用于重新启用被!ubd禁止的断点。 参见!ubl!ubl 列出所有用户空间断点以及它们的当前状态。 语法!ubl DLL
注释下面是一个使用和显示用户空间断点的示例: kd> !ubp 8014a131 列出的每一行都包括断点号、状态(启用为e,禁用为d)、设置断点的虚拟地址、实际断点的物理地址、字节位置,以及设置断点时该内存位置原来的内容。 参见!ubp!ubp 扩展命令在用户内存空间设置一个断点。 语法!ubp Address 参数Address 指定要设置断点的用户空间内的16进制虚拟地址。 DLL
注释!ubp 扩展命令在用户空间设置一个断点。该断点实设置在实际的物理页面上,而不仅仅在虚拟页面上的。 设置物理断点(physical breakpoint)会同时改变页面的所有虚拟拷贝(virtual copy), 造成不可预知的结果。一种可能的情况就是破坏系统状态,造成bug check或者其他的系统崩溃的情况。因此,如果必须要使用这种断点的话,要非常慎重。 该命令不能用来在已经换出的页面上设置断点。如果页面在断点设置之后被换出内存,那么断点不再存在。 不能再页表或页目录中设置断点。 每个断点都有一个关联的断点号。可以使用!ubl来查看指派的断点号。断点创建时是起用的。要步过断点,必须先使用!ubd来禁用它。使用!ubc清除断点。 参见!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
注释使用!process 命令可以找到任何进程的VAD的根地址。 下面是!vad 扩展的示例: kd> !vad 824bc2f8 附加信息关于虚拟地址描述符的信息,查看Mark Russinovich 和David Solomon 编写的Microsoft Windows Internals。 !validatelist!validatelist 扩展验证双链表的正反方向链接的正确性。 语法!validatelist Address 参数Address 指定双链表的地址。 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]] 参数Flags 指定命令输出中显示哪些信息。如果Flags的值等于4、 8、 0x20、0x40、 0x80、或者0x100,那么!verifier 其他的参数是根据这些标志指定的值来解析的。如果Flags 是任何其他的值,即使设置了这些位中的一个或几个,也只允许使用Flags 和Image参数。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 选项相关的信息。如果指定了CompletionTime、 CancelTime、和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。CancelTime 为0时,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
注释用驱动程序验证器来测试图形驱动程序时,要使用!gdikdx.verifier 扩展命令来替代!verifier。 4、 8、0x20、 0x40、 0x80和0x100 是Flags 的特殊值。使用这些值的时候,会用到参数部分列出的特殊参数,并且只会显示和这些标志值相关的信息。 如果Flags使用了任何其他值,即使设置了这些特殊位的一个或者多个,也只允许使用Flags 和Image参数。这种情况下,除了其他信息之外,!verifier还会显示激活的驱动程序验证器选项,以及内存池分配、IRQL提升、自旋锁和 trims 的统计。 如果Flags 等于0x20,驱动程序验证器的Driver Hang Verification选项将使用CompletionTime、CancelTime和ForceCancellation。这些新的值会立即生效并且持续到下一次启动。重新启动计算机时,它们会恢复到默认值。 同样,如果Flags 等于0x20 (使用或不使用附加参数),则打印Driver Hang Verification日志。关于对这个日志的解读,查看Windows Driver Kit (WDK)文档中驱动程序验证器文档的Driver Hang Verification小节。 下面是Windows XP计算机上!verifier 扩展命令的示例。注意输出是按照驱动程序名排序: kd> !verifier 0xf 下面是!verifier 扩展命令在Windows Vista计算机上打开了bit 7并且指定Address的示例。 0: kd> !verifier 80 a2b1cf20 附加信息关于驱动程序验证器的信息,查看Windows Driver Kit (WDK)文档。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|