这是微软提供的一个windbg JavaScript插件例子:
12345678910111213 function FindTitleWithLINQ (){var isMainFrame = function ( frame ) { return frame.toString().includes( "__mainCRTStartup" ); };var isMainThread = function ( thread ) { return thread.Stack.Frames.Any( isMainFrame ); };var curProcess = host.currentProcess;var mainThread = curProcess.Threads.Where( isMainThread ).First();var mainFrame = mainThread.Stack.Frames.Where( isMainFrame ).First();var locals = mainFrame.LocalVariables;return host.memory.readWideString( locals.StartupInfo.lpTitle );}启动notepad.exe,cdb附加之,如果一切正常的话,应该这样测试插件:
12345 > .load jsprovider.dll> .scriptload TitleFinder.js> dx Debugger.State.Scripts.TitleFinder.Contents.FindTitleWithLINQ()说说这个插件的原始意图。针对所有线程查看调用栈回溯:
12345678910111213141516171819 > ~*kcn0 Id: 14e4.ff8 Suspend: 1 Teb: 000000a1`b7544000 Unfrozen# Call Site00 win32u!NtUserGetMessage01 USER32!GetMessageW02 notepad!WinMain03 notepad!__mainCRTStartup04 KERNEL32!BaseThreadInitThunk05 ntdll!RtlUserThreadStart# 1 Id: 14e4.1500 Suspend: 1 Teb: 000000a1`b7556000 Unfrozen# Call Site00 ntdll!DbgBreakPoint01 ntdll!DbgUiRemoteBreakin02 KERNEL32!BaseThreadInitThunk03 ntdll!RtlUserThreadStart在调用栈回溯信息中寻找”__mainCRTStartup”,定位相应线程的相应栈帧,在该栈帧上查看局部变量:
12345 > ~0s> .frame /c 3> dv它假设notepad.exe的PDB文件保留了局部变量,比如StartupInfo;实际上这些信息只可能出现在私有PDB中,上面的dv不会显示任何内容。
1234567891011121314 > dt *!*STARTUPINFOcombase!LPSTARTUPINFOcombase!STARTUPINFOurlmon!LPSTARTUPINFOurlmon!STARTUPINFOuxtheme!LPSTARTUPINFOuxtheme!STARTUPINFOwintypes!LPSTARTUPINFOwintypes!STARTUPINFO> dt combase!STARTUPINFO lpTitle+0x018 lpTitle : Ptr64 Wchar如果有StartupInfo,会从中析取lpTitle成员。
1234567891011 STARTUPINFO structurehttps://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspxlpTitleFor console processes, this is the title displayed in the title bar ifa new console window is created. If NULL, the name of the executablefile is used as the window title instead. This parameter must be NULLfor GUI or console processes that do not create a new console window.从MSDN的描述看,对于notepad.exe,析出来的lpTitle应该是可执行文件名。微软演示插件效果时,确实看到”C:\Windows\System32\notepad.exe”。微软写文档的人应该使用了私有PDB,否则只会得到报错:
> dx Debugger.State.Scripts.TitleFinder.Contents.FindTitleWithLINQ()
Error: Unable to get property ‘lpTitle’ of undefined or null reference关于无法获取notepad.exe局部变量,另有方案交叉印证:
1234567891011121314151617 > dx Debugger.Sessions.First().Processes.First().Threads[0xff8] : notepad!WinMainCRTStartup (00007ff7`782393e0)[0x1500] : ntdll!DbgUiRemoteBreakin (00007ffa`c8190160)> dx Debugger.Sessions.First().Processes.First().Threads.First().Stack.Frames[0x0] : win32u!NtUserGetMessage + 0x14[0x1] : USER32!GetMessageW + 0x26[0x2] : notepad!WinMain + 0x291[0x3] : notepad!__mainCRTStartup + 0x19f[0x4] : KERNEL32!BaseThreadInitThunk + 0x14[0x5] : ntdll!RtlUserThreadStart + 0x21> dx Debugger.Sessions.First().Processes.First().Threads.First().Stack.Frames[3].LocalVariables没有任何输出。
插件关于”__mainCRTStartup”的假设并不总是成立,比如Win7中的notepad.exe,入口函数并不是它。
测试该插件时发现一个引擎BUG:
12345678910 > dx Debugger.State.Scripts.TitleFinder.Contents.FindTitleWithLINQ()Error: Unable to get property 'lpTitle' of undefined or null reference> .scriptunload TitleFinder.jsJavaScript script unloaded from 'TitleFinder.js'> dx Debugger.State.ScriptsTitleFinder> .scriptlistCommand Loaded Scripts:“dx Debugger.State.Scripts”表明插件未被成功卸载,”.scriptlist”已经啥都看不到了。
重新加载插件,有异常现象:
12345678910 > .scriptload TitleFinder.jsJavaScript script successfully loaded from 'TitleFinder.js'> dx Debugger.State.ScriptsTitleFinderTitleFinder_1> .scriptlistCommand Loaded Scripts:JavaScript script from 'TitleFinder.js'“dx Debugger.State.Scripts”显示多出一个”TitleFinder_1″,且只能用它:
123456 > dx Debugger.State.Scripts.TitleFinder.Contents.FindTitle()Error: Unable to bind name 'FindTitle'> dx Debugger.State.Scripts.TitleFinder_1.Contents.FindTitle()Error: Unable to get property 'lpTitle' of undefined or null reference要想彻底恢复正常,只能:
123456 > .scriptunload TitleFinder.js> .unload jsprovider.dll> .load jsprovider.dll> .scriptload TitleFinder.js测试对象是10.0.15063.468版x64 windbg。