标题: windbg命令.load与!load没有区别 创建: 2018-03-15 17:05 链接: https://scz.617.cn/windows/201803151705.txt 以10.0.15063.468版windbg为例。 windbg帮助手册里指出.load用于加载扩展DLL,但有天bluerust用!load成功加载扩 展DLL,而且他是照着某篇微软文档中的示例做的。这引起我的好奇,帮助手册里从 来没有说!load有这个效果,甚至没有!load这个命令。 于是我跟bluerust讨论了一下,.load和!load有什么区别,二者对应的处理函数是什 么?针对第2个问题,现在我们当然知道很多办法去定位,但最初提出这个问题时, 尚无此积累。bluerust想到一个歪招: > !load nonexist.dll The call to LoadLibrary(nonexist.dll) failed, Win32 error 0n2 "The system cannot find the file specified." Please check your debugger configuration and/or network access. 他假设!load对应的处理流程会引用字符串"The call to LoadLibrary",在所有模块 中搜索它,然后用交叉引用或数据断点定位到: dbgeng!ExtensionInfo::Load+0x56e: 上面是当时bluerust的一些尝试,最近我又琢磨了一下原始问题,见下。 bp dbgeng!ProcessCommands 断下来时,对比".load jsprovider.dll"、"!load jsprovider.dll"在其中的执行过 程,发现ProcessCommands()有两处对DotCommand()的调用: case '.': case '!': 这样比较累,干脆拦截jsprovider.dll的加载,对比调用栈回溯,但是没有区别: ntdll!NtMapViewOfSection+0x14 ... KERNELBASE!LoadLibraryExW+0x14a dbgeng!ExtensionInfo::Load+0x3b2 dbgeng!ExtensionInfo::CheckAdd+0x6e dbgeng!ParseBangCmd+0x248 dbgeng!ProcessCommands+0xdbb dbgeng!ProcessCommandsAndCatch+0xa5 dbgeng!Execute+0x2bb dbgeng!DebugClient::ExecuteWide+0x83 cdb!MainLoop+0x516 cdb!wmain+0x46e 尽管我知道很多.命令与!命令不相同,但.load和!load给我带了一丝幻想: > .echo scz scz > !echo scz No export echo found 为什么load被特殊处理,echo就没有? -------------------------------------------------------------------------- ProcessCommands () { /* * 跳过前导字符,比如.或!号 */ g_CurCmd++; /* * 流程至此时,g_CurCmd已经没有前导.或!号,只剩"load jsprovider.dll"、 * "echo scz" */ switch ( 前导字符 ) { case '.': /* * ".echo scz"由DotCommand()成功处理,返回True * ".load jsprovider.dll"导致DotCommand()返回False * * bp dbgeng!DotCommand "du poi(dbgeng!g_CurCmd)" * * 尽管".echo scz"、"!echo scz"的流程进入DotCommand()时,g_CurCmd * 都是"echo scz",但是前者使得GetCurDotToken()返回非空指针,后者 * 使得GetCurDotToken()返回NULL,DotCommand()中的后续流程分了叉。 */ if ( !DotCommand() ) { /* * ParseBangCmd()中对"load"特别处理,使得".load"、"!load"在其 * 中的流程完全一致,不受第2形参影响。 */ ParseBangCmd( x, 1 ); } break; case '!': /* * "!echo scz"导致DotCommand()返回False * "!load jsprovider.dll"导致DotCommand()返回False */ if ( !DotCommand() ) { /* * ParseBangCmd()仍然处理不了"!echo scz",但可以处理 * ".load jsprovider.dll"、"!load jsprovider.dll" */ ParseBangCmd( x, 0 ); } break; } } -------------------------------------------------------------------------- 看得出来,windbg的命令分发流程有很多历史痕迹,未必是当下最优逻辑,估计也不 会对之优化重构了。