这是微软提供的一个windbg JavaScript插件例子:
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附加之,如果一切正常的话,应该这样测试插件:
> .load jsprovider.dll > .scriptload TitleFinder.js > dx Debugger.State.Scripts.TitleFinder.Contents.FindTitleWithLINQ()
说说这个插件的原始意图。针对所有线程查看调用栈回溯:
> ~*kcn 0 Id: 14e4.ff8 Suspend: 1 Teb: 000000a1`b7544000 Unfrozen # Call Site 00 win32u!NtUserGetMessage 01 USER32!GetMessageW 02 notepad!WinMain 03 notepad!__mainCRTStartup 04 KERNEL32!BaseThreadInitThunk 05 ntdll!RtlUserThreadStart # 1 Id: 14e4.1500 Suspend: 1 Teb: 000000a1`b7556000 Unfrozen # Call Site 00 ntdll!DbgBreakPoint 01 ntdll!DbgUiRemoteBreakin 02 KERNEL32!BaseThreadInitThunk 03 ntdll!RtlUserThreadStart
在调用栈回溯信息中寻找”__mainCRTStartup”,定位相应线程的相应栈帧,在该栈帧上查看局部变量:
> ~0s > .frame /c 3 > dv
它假设notepad.exe的PDB文件保留了局部变量,比如StartupInfo;实际上这些信息只可能出现在私有PDB中,上面的dv不会显示任何内容。
> dt *!*STARTUPINFO combase!LPSTARTUPINFO combase!STARTUPINFO urlmon!LPSTARTUPINFO urlmon!STARTUPINFO uxtheme!LPSTARTUPINFO uxtheme!STARTUPINFO wintypes!LPSTARTUPINFO wintypes!STARTUPINFO > dt combase!STARTUPINFO lpTitle +0x018 lpTitle : Ptr64 Wchar
如果有StartupInfo,会从中析取lpTitle成员。
STARTUPINFO structure https://msdn.microsoft.com/en-us/library/windows/desktop/ms686331(v=vs.85).aspx lpTitle For console processes, this is the title displayed in the title bar if a new console window is created. If NULL, the name of the executable file is used as the window title instead. This parameter must be NULL for 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局部变量,另有方案交叉印证:
> 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:
> dx Debugger.State.Scripts.TitleFinder.Contents.FindTitleWithLINQ() Error: Unable to get property 'lpTitle' of undefined or null reference > .scriptunload TitleFinder.js JavaScript script unloaded from 'TitleFinder.js' > dx Debugger.State.Scripts TitleFinder > .scriptlist Command Loaded Scripts:
“dx Debugger.State.Scripts”表明插件未被成功卸载,”.scriptlist”已经啥都看不到了。
重新加载插件,有异常现象:
> .scriptload TitleFinder.js JavaScript script successfully loaded from 'TitleFinder.js' > dx Debugger.State.Scripts TitleFinder TitleFinder_1 > .scriptlist Command Loaded Scripts: JavaScript script from 'TitleFinder.js'
“dx Debugger.State.Scripts”显示多出一个”TitleFinder_1″,且只能用它:
> 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
要想彻底恢复正常,只能:
> .scriptunload TitleFinder.js > .unload jsprovider.dll > .load jsprovider.dll > .scriptload TitleFinder.js
测试对象是10.0.15063.468版x64 windbg。