JavaScript デバッガーのスクリプト例
このトピックでは、次のユーザー モードとカーネル モードの JavaScript コード サンプルを示します。
- プロセス アーキテクチャの決定
- データ フィルター処理: KD (カーネル モード) でのデバイス ツリーのプラグ アンド プレイ
- マルチメディアに固有のデバイスの拡張 (カーネル モード)
- _DEVICE_OBJECTへのバス情報の追加 (カーネル モード)
- アプリケーション タイトルの検索 (ユーザー モード)
Microsoft GitHub リポジトリのサンプル スクリプト
デバッガー チームは、JavaScript スクリプトと拡張機能の例を含む GitHub リポジトリをホストします。
- https://github.com/Microsoft/WinDbg-Samples で見つけることができます
readme ファイルには、使用可能な現在のコード例が記述されています。
サンプル実行
一般的なプロセスを使用して、いずれかのサンプルをテストします。
サンプル JavaScript がカーネル モードまたはユーザー モードのデバッグを目的としているかどうかを判断します。 次に、適切なダンプ ファイルを読み込むか、ターゲット システムへのライブ接続を確立します。
メモ帳などのテキスト エディターを使用して、名前の付いたテキスト ファイルを作成し、HelloWorld.js などの.jsファイル拡張子で保存します
// WinDbg JavaScript sample
// Says Hello World!
// Code at root will be run with .scriptrun and .scriptload
host.diagnostics.debugLog("***> Hello World! \n");
function sayHi()
{
//Say Hi
host.diagnostics.debugLog("Hi from JavaScript! \n");
}
- スクリプトを 読み込んで実行するには、.scriptrun (スクリプトの実行) コマンドを使用します。 .scriptrun コマンドは、ルート/先頭にコードを実行し、関数名 initializeScript と invokeScript の下のコードを実行します。
0:000> .scriptrun c:\WinDbg\Scripts\HelloWorld.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\HelloWorld.js'
***> Hello World!
- スクリプトに一意の名前の関数が含まれている場合は、dx コマンドを使用して、Debugger.State.Scripts.ScriptName.Contents.FunctionName にあるその関数を実行します。
0:001> dx Debugger.State.Scripts.HelloWorld.Contents.sayHi()
Hi from JavaScript!
Debugger.State.Scripts.HelloWorld.Contents.sayHi()
JavaScript の操作の詳細 については、 JavaScript デバッガースクリプトを 参照してください。
プロセス アーキテクチャの決定
この JavaScript コードは、プロセスが x86 または x64 であるかどうかを示すために、デバッガー オブジェクト モデルプロセス オブジェクトに 'ProcessArchitecture' というプロパティを追加します。
このスクリプトは、カーネル モードのデバッグをサポートすることを目的としています。
"use strict";
class __CheckArchitecture
{
//
// Add a property called 'ProcessArchitecture' on process.
//
get ProcessArchitecture()
{
var guestStates = this.Threads.Any(t=> (!(t.GuestState === undefined) && t.GuestState.Architecture =="x86"));
if(guestStates)
return "x86";
else
return "x64";
}
};
function initializeScript()
{
//
// Extends our notion of a process to place architecture information on it.
//
return [new host.namedModelParent(__CheckArchitecture, "Debugger.Models.Process")];
}
カーネル ダンプ ファイルを読み込むか、ターゲット システムへのカーネル モード接続を確立します。 次に、JavaScript プロバイダーとサンプル スクリプトを読み込みます。
0: kd> !load jsprovider.dll
0: kd> .scriptload c:\WinDbg\Scripts\processarchitecture.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\processarchitecture.js'
dx コマンドを使用して、現在のプロセスのプロセス アーキテクチャを表示します。
2: kd> dx @$curprocess
@$curprocess : System [Switch To]
KernelObject [Type: _EPROCESS]
Name : System
Id : 0x4
Handle : 0xf0f0f0f0
Threads
Modules
Environment
Devices
Io
ProcessArchitecture : x64
このサンプル コードでは、アーキテクチャを正しく判断できない場合があることに注意してください。 たとえば、32 ビット デバッガーを使用しているときにダンプ ファイルを操作する場合があります。
データ フィルター処理: KD (カーネル モード) でのデバイス ツリーのプラグ アンド プレイ
このサンプル コードでは、デバイス ノード ツリーをフィルター処理して、開始された PCI のパスを含むデバイスのみを表示します。
このスクリプトは、ライブ カーネル モード デバッグをサポートすることを目的としています。
!devnode 0 1 コマンドを使用すると、デバイス ツリーに関する情報を表示できます。 詳細については、「!devnode」を参照してください。
// PlugAndPlayDeviceTree.js
// An ES6 generator function which recursively filters the device tree looking for PCI devices in the started state.
//
function *filterDevices(deviceNode)
{
//
// If the device instance path has "PCI" in it and is started (state == 776), yield it from the generator.
//
if (deviceNode.InstancePath.indexOf("PCI") != -1 && deviceNode.State == 776)
{
yield deviceNode;
}
//
// Recursively invoke the generator for all children of the device node.
//
for (var childNode of deviceNode.Children)
{
yield* filterDevices(childNode);
}
}
//
// A function which finds the device tree of the first session in the debugger and passes it to our filter function.
//
function filterAllDevices()
{
return filterDevices(host.namespace.Debugger.Sessions.First().Devices.DeviceTree.First());
}
ターゲット システムへのカーネル モード接続を確立します。
0: kd> !load jsprovider.dll
0: kd> .scriptload c:\WinDbg\Scripts\PlugAndPlayDeviceTree.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\PlugAndPlayDeviceTree.js'
filterAllDevices() 関数を呼び出します。
0: kd> dx Debugger.State.Scripts.PlugAndPlayDeviceTree.Contents.filterAllDevices()
Debugger.State.Scripts.PlugAndPlayDeviceTree.Contents.filterAllDevices() : [object Generator]
[0x0] : PCI\VEN_8086&DEV_D131&SUBSYS_304A103C&REV_11\3&21436425&0&00
[0x1] : PCI\VEN_8086&DEV_D138&SUBSYS_304A103C&REV_11\3&21436425&0&18 (pci)
[0x2] : PCI\VEN_10DE&DEV_06FD&SUBSYS_062E10DE&REV_A1\4&324c21a&0&0018 (nvlddmkm)
[0x3] : PCI\VEN_8086&DEV_3B64&SUBSYS_304A103C&REV_06\3&21436425&0&B0 (HECIx64)
[0x4] : PCI\VEN_8086&DEV_3B3C&SUBSYS_304A103C&REV_05\3&21436425&0&D0 (usbehci)
[0x5] : PCI\VEN_8086&DEV_3B56&SUBSYS_304A103C&REV_05\3&21436425&0&D8 (HDAudBus)
...
上記の各オブジェクトは、DML を自動的にサポートし、他の dx クエリと同様に選択できます。
このスクリプトを使用する代わりに、LINQ クエリを使用して同様の結果を実現することもできます。
0: kd> dx @$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.InstancePath.Contains("PCI") && n.State == 776)
@$cursession.Devices.DeviceTree.Flatten(n => n.Children).Where(n => n.InstancePath.Contains("PCI") && n.State == 776)
[0x0] : PCI\VEN_8086&DEV_D131&SUBSYS_304A103C&REV_11\3&21436425&0&00
[0x1] : PCI\VEN_8086&DEV_D138&SUBSYS_304A103C&REV_11\3&21436425&0&18 (pci)
[0x2] : PCI\VEN_10DE&DEV_06FD&SUBSYS_062E10DE&REV_A1\4&324c21a&0&0018 (nvlddmkm)
[0x3] : PCI\VEN_8086&DEV_3B64&SUBSYS_304A103C&REV_06\3&21436425&0&B0 (HECIx64)
[0x4] : PCI\VEN_8086&DEV_3B3C&SUBSYS_304A103C&REV_05\3&21436425&0&D0 (usbehci)
[0x5] : PCI\VEN_8086&DEV_3B56&SUBSYS_304A103C&REV_05\3&21436425&0&D8 (HDAudBus)
...
マルチメディアに固有のデバイスの拡張 (カーネル モード)
この大規模な JavaScript の例では、マルチメディアに固有の情報のカーネル _DEVICE_OBJECTを拡張し、StreamingDevices をデバッガー セッションに追加します。
このスクリプトは、カーネル モードのデバッグをサポートすることを目的としています。
StreamingDevices とのセッションを拡張する選択は、たとえば目的でのみ行われることに注意してください。 これは、_DEVICE_OBJECTのみに残すか、既存の名前空間の下の深い方にする必要があります。Devices.* 階層。
// StreamingFinder.js
// Extends a kernel _DEVICE_OBJECT for information specific to multimedia
// and adds StreamingDevices to a debugger session.
//
"use strict";
function initializeScript()
{
// isStreamingDeviceObject:
//
// Returns whether devObj (as a _DEVICE_OBJECT -- not a pointer) looks like it is a device
// object for a streaming device.
//
function isStreamingDeviceObject(devObj)
{
try
{
var devExt = devObj.DeviceExtension;
var possibleStreamingExtPtrPtr = host.createPointerObject(devExt.address, "ks.sys", "_KSIDEVICE_HEADER **", devObj);
var possibleStreamingExt = possibleStreamingExtPtrPtr.dereference().dereference();
var baseDevice = possibleStreamingExt.BaseDevice;
if (devObj.targetLocation == baseDevice.dereference().targetLocation)
{
return true;
}
}
//
// The above code expects to fail (walking into invalid or paged out memory) often. A failure to read the memory
// of the target process will result in an exception. Catch such exception and indicate that the object does not
// match the profile of a "streaming device object".
//
catch(exc)
{
}
return false;
}
// findStreamingFDO(pdo):
//
// From a physical device object, walks up the device stack and attempts to find a device which
// looks like a streaming device (and is thus assumed to be the FDO). pdo is a pointer to
// the _DEVICE_OBJECT for the pdo.
//
function findStreamingFDO(pdo)
{
for (var device of pdo.UpperDevices)
{
if (isStreamingDeviceObject(device.dereference()))
{
return device;
}
}
return null;
}
// streamingDeviceList:
//
// A class which enumerates all streaming devices on the system.
//
class streamingDeviceList
{
constructor(session)
{
this.__session = session;
}
*[Symbol.iterator]()
{
//
// Get the list of all PDOs from PNP using LINQ:
//
var allPDOs = this.__session.Devices.DeviceTree.Flatten(function(dev) { return dev.Children; })
.Select (function(dev) { return dev.PhysicalDeviceObject; });
//
// Walk the stack up each PDO to find the functional device which looks like a KS device. This is
// a very simple heuristic test: the back pointer to the device in the KS device extension is
// accurate. Make sure this is wrapped in a try/catch to avoid invalid memory reads causing
// us to bail out.
//
// Don't even bother checking the PDO.
//
for (var pdo of allPDOs)
{
var fdo = findStreamingFDO(pdo);
if (fdo != null)
{
yield fdo;
}
}
}
}
// streamingDeviceExtension:
//
// An object which will extend "session" and include the list of streaming devices.
//
class streamingDeviceExtension
{
get StreamingDevices()
{
return new streamingDeviceList(this);
}
};
// createEntryList:
//
// An abstraction over the create entry list within a streaming device.
//
class createEntryList
{
constructor(ksHeader)
{
this.__ksHeader = ksHeader;
}
*[Symbol.iterator]()
{
for (var entry of host.namespace.Debugger.Utility.Collections.FromListEntry(this.__ksHeader.ChildCreateHandlerList, "ks!KSICREATE_ENTRY", "ListEntry"))
{
if (!entry.CreateItem.Create.isNull)
{
yield entry;
}
}
}
}
// streamingInformation:
//
// Represents the streaming state of a device.
//
class streamingInformation
{
constructor(fdo)
{
this.__fdo = fdo;
var devExt = fdo.DeviceExtension;
var streamingExtPtrPtr = host.createPointerObject(devExt.address, "ks.sys", "_KSIDEVICE_HEADER **", fdo);
this.__ksHeader = streamingExtPtrPtr.dereference().dereference();
}
get CreateEntries()
{
return new createEntryList(this.__ksHeader);
}
}
// createEntryVisualizer:
//
// A visualizer for KSICREATE_ENTRY
//
class createEntryVisualizer
{
toString()
{
return this.CreateItem.ObjectClass.toString();
}
get CreateContext()
{
//
// This is probably not entirely accurate. The context is not *REQUIRED* to be an IUnknown.
// More analysis should probably be performed.
//
return host.createTypedObject(this.CreateItem.Context.address, "ks.sys", "IUnknown", this);
}
}
// deviceExtension:
//
// Extends our notion of a device in the device tree to place streaming information on
// top of it.
//
class deviceExtension
{
get StreamingState()
{
if (isStreamingDeviceObject(this))
{
return new streamingInformation(this);
}
//
// If we cannot find a streaming FDO, returning undefined will indicate that there is no value
// to the property.
//
return undefined;
}
}
return [new host.namedModelParent(streamingDeviceExtension, "Debugger.Models.Session"),
new host.typeSignatureExtension(deviceExtension, "_DEVICE_OBJECT"),
new host.typeSignatureRegistration(createEntryVisualizer, "KSICREATE_ENTRY")]
}
前に説明したように、まずスクリプト プロバイダーを読み込みます。 次に、スクリプトを読み込みます。
0: kd> .scriptload c:\WinDbg\Scripts\StreamingFinder.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\StreamingFinder.js'
次に、dx コマンドを使用して、スクリプトによって提供される新しい StreamingDevices 機能にアクセスします。
0: kd> dx -r3 @$cursession.StreamingDevices.Select(d => d->StreamingState.CreateEntries)
@$cursession.StreamingDevices.Select(d => d->StreamingState.CreateEntries)
[0x0] : [object Object]
[0x0] : "e0HDMIOutTopo" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: CPortTopology]
[0x1] : [object Object]
[0x0] : "AnalogDigitalCaptureTopo" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: CPortTopology]
[0x1] : "AnalogDigitalCapture1Topo" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: CPortTopology]
[0x2] : "AnalogDigitalCapture2Topo" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: CPortTopology]
[0x3] : "AnalogDigitalCapture2Wave" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: CPortWaveRT]
[0x4] : "HeadphoneTopo" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: CPortTopology]
[0x5] : "RearLineOutTopo" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: CPortTopology]
[0x6] : "RearLineOutWave" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: CPortWaveRT]
[0x2] : [object Object]
[0x0] : "GLOBAL" [Type: KSICREATE_ENTRY]
[<Raw View>] [Type: KSICREATE_ENTRY]
CreateContext [Type: IUnknown]
_DEVICE_OBJECTへのバス情報の追加 (カーネル モード)
このスクリプトは、_DEVICE_OBJECTの視覚化を拡張して、その下に PCI 固有の情報を含む BusInformation フィールドを追加します。 このサンプルの方法と名前の扱いについては、現在も説明中です。 JavaScript プロバイダーの機能のサンプルと見なす必要があります。
このスクリプトは、カーネル モードのデバッグをサポートすることを目的としています。
"use strict";
/*************************************************
DeviceExtensionInformation.js:
An example which extends _DEVICE_OBJECT to add bus specific information
to each device object.
NOTE: The means of conditionally adding and the style of namespacing this
are still being discussed. This currently serves as an example of the capability
of JavaScript extensions.
*************************************************/
function initializeScript()
{
// __getStackPDO():
//
// Returns the physical device object of the device stack whose device object
// is passed in as 'devObj'.
//
function __getStackPDO(devObj)
{
var curDevice = devObj;
var nextDevice = curDevice.DeviceObjectExtension.AttachedTo;
while (!nextDevice.isNull)
{
curDevice = nextDevice;
nextDevice = curDevice.DeviceObjectExtension.AttachedTo;
}
return curDevice;
}
// pciInformation:
//
// Class which abstracts our particular representation of PCI information for a PCI device or bus
// based on a _PCI_DEVICE structure or a _PCI_BUS structure.
//
class pciInformation
{
constructor(pciDev)
{
this.__pciDev = pciDev;
this.__pciPDO = __getStackPDO(this.__pciDev);
this.__isBridge = (this.__pciDev.address != this.__pciPDO.address);
if (this.__isBridge)
{
this.__deviceExtension = host.createTypedObject(this.__pciPDO.DeviceExtension.address, "pci.sys", "_PCI_DEVICE", this.__pciPDO);
this.__busExtension = host.createTypedObject(this.__pciDev.DeviceExtension.address, "pci.sys", "_PCI_BUS", this.__pciPDO);
this.__hasDevice = (this.__deviceExtension.Signature == 0x44696350); /* 'PciD' */
this.__hasBus = (this.__busExtension.Signature == 0x42696350); /* 'PciB' */
if (!this.__hasDevice && !this.__hasBus)
{
throw new Error("Unrecognized PCI device extension");
}
}
else
{
this.__deviceExtension = host.createTypedObject(this.__pciPDO.DeviceExtension.address, "pci.sys", "_PCI_DEVICE", this.__pciPDO);
this.__hasDevice = (this.__deviceExtension.Signature == 0x44696350); /* 'PciD' */
this.__hasBus = false;
if (!this.__hasDevice)
{
throw new Error("Unrecognized PCI device extension");
}
}
}
toString()
{
if (this.__hasBus && this.__hasDevice)
{
return "Bus: " + this.__busExtension.toString() + " Device: " + this.__deviceExtension.toString();
}
else if (this.__hasBus)
{
return this.__busExtension.toString();
}
else
{
return this.__deviceExtension.toString();
}
}
get Device()
{
if (this.__hasDevice)
{
// NatVis supplies the visualization for _PCI_DEVICE
return this.__deviceExtension;
}
return undefined;
}
get Bus()
{
if (this.__hasBus)
{
// NatVis supplies the visualization for _PCI_BUS
return this.__busExtension;
}
return undefined;
}
}
// busInformation:
//
// Our class which does analysis of what bus a particular device is on and places information about
// about that bus within the _DEVICE_OBJECT visualization.
//
class busInformation
{
constructor(devObj)
{
this.__devObj = devObj;
}
get PCI()
{
//
// Check the current device object. This may be a PCI bridge
// in which both the FDO and PDO are relevant (one for the bus information
// and one for the bridge device information).
//
var curName = this.__devObj.DriverObject.DriverName.toString();
if (curName.includes("\\Driver\\pci"))
{
return new pciInformation(this.__devObj);
}
var stackPDO = __getStackPDO(this.__devObj);
var pdoName = stackPDO.DriverObject.DriverName.toString();
if (pdoName.includes("\\Driver\\pci"))
{
return new pciInformation(stackPDO);
}
return undefined;
}
}
// busInformationExtension:
//
// An extension placed on top of _DEVICE_OBJECT in order to provide bus analysis and bus specific
// information to the device.
//
class busInformationExtension
{
get BusInformation()
{
return new busInformation(this);
}
}
return [new host.typeSignatureExtension(busInformationExtension, "_DEVICE_OBJECT")];
}
前に説明したように、まずスクリプト プロバイダーを読み込みます。 次に、スクリプトを読み込みます。
0: kd> .scriptload c:\WinDbg\Scripts\DeviceExtensionInformation.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\DeviceExtensionInformation.js'
目的のデバイス オブジェクトのアドレスを見つける必要があります。 この例では、オーディオ HDAudBus ドライバーを調べます。
0: kd> !drvobj HDAudBus
Driver object (ffffb60757a4ae60) is for:
\Driver\HDAudBus
Driver Extension List: (id , addr)
(fffff8050a9eb290 ffffb60758413180)
Device Object list:
ffffb60758e21810 ffffb60757a67c60
スクリプトが読み込まれたら、dx コマンドを使用してデバイス オブジェクトのバス情報を表示します。
0: kd> dx -r1 (*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0))
(*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)) : Device for "\Driver\HDAudBus" [Type: _DEVICE_OBJECT]
[<Raw View>] [Type: _DEVICE_OBJECT]
Flags : 0x2004
UpperDevices : None
LowerDevices : Immediately below is Device for "\Driver\ACPI" [at 0xffffe000003d9820]
Driver : 0xffffe00001ccd060 : Driver "\Driver\HDAudBus" [Type: _DRIVER_OBJECT *]
BusInformation : [object Object]
0: kd> dx -r1 (*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)).@"BusInformation"
(*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)).@"BusInformation" : [object Object]
PCI : (d=0x14 f=0x2) Vendor=0x1022 Device=0x780d Multimedia Device / Unknown Sub Class
0: kd> dx -r1 (*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)).@"BusInformation".@"PCI"
(*((ntkrnlmp!_DEVICE_OBJECT *)0xffffe00001b567c0)).@"BusInformation".@"PCI" : (d=0x14 f=0x2) Vendor=0x1022 Device=0x780d Multimedia Device / Unknown Sub Class
Device : (d=0x14 f=0x2) Vendor=0x1022 Device=0x780d Multimedia Device / Unknown Sub Class [Type: _PCI_DEVICE]
0: kd> dx -r1 (*((pci!_PCI_DEVICE *)0xffffe000003fe1b0))
(*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)) : (d=0x14 f=0x2) Vendor=0x1022 Device=0x780d Multimedia Device / Unknown Sub Class [Type: _PCI_DEVICE]
[<Raw View>] [Type: _PCI_DEVICE]
Device : 0xffffe000003fe060 : Device for "\Driver\pci" [Type: _DEVICE_OBJECT *]
Requirements
Resources
0: kd> dx -r1 (*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)).@"Resources"
(*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)).@"Resources"
BaseAddressRegisters
Interrupt : Line Based -- Interrupt Line = 0x10 [Type: _PCI_DEVICE_INTERRUPT_RESOURCE]
0: kd> dx -r1 (*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)).@"Resources".@"BaseAddressRegisters"
(*((pci!_PCI_DEVICE *)0xffffe000003fe1b0)).@"Resources".@"BaseAddressRegisters"
[0x0] : Memory Resource: 0xf0340000 of length 0x4000 [Type: _CM_PARTIAL_RESOURCE_DESCRIPTOR]
アプリケーション タイトルの検索 (ユーザー モード)
この例では、デバッガーの現在のプロセス内のすべてのスレッドを反復処理し、__mainCRTStartup を含むフレームを見つけて、CRT のスタートアップ内の StartupInfo.lpTitle から文字列を返します。 このスクリプトは、JavaScript 内のイテレーション、文字列操作、および LINQ クエリの例を示しています。
このスクリプトは、ユーザー モードのデバッグをサポートすることを目的としています。
// TitleFinder.js
// A function which uses just JavaScript concepts to find the title of an application
//
function findTitle()
{
var curProcess = host.currentProcess;
for (var thread of curProcess.Threads)
{
for (var frame of thread.Stack.Frames)
{
if (frame.toString().includes("__mainCRTStartup"))
{
var locals = frame.LocalVariables;
//
// locals.StartupInfo.lpTitle is just an unsigned short *. We need to actually call an API to
// read the UTF-16 string in the target address space. This would be true even if this were
// a char* or wchar_t*.
//
return host.memory.readWideString(locals.StartupInfo.lpTitle);
}
}
}
}
//
// A function which uses both JavaScript and integrated LINQ concepts to do the same.
//
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;
//
// locals.StartupInfo.lpTitle is just an unsigned short *. We need to actually call an API to
// read the UTF-16 string in the target address space. This would be true even if this were
// a char* or wchar_t*.
//
return host.memory.readWideString(locals.StartupInfo.lpTitle);
}
0: kd> .scriptload c:\WinDbg\Scripts\TitleFinder.js
JavaScript script successfully loaded from 'c:\WinDbg\Scripts\TitleFinder.js'
findTitle() 関数を呼び出すと、notepad.exeが返されます
0:000> dx Debugger.State.Scripts.TitleFinder.Contents.findTitle()
Debugger.State.Scripts.TitleFinder.Contents.findTitle() : C:\Windows\System32\notepad.exe
LINQ バージョンを呼び出すと、findTitleWithLINQ() も notepad.exeを返します
0:000> dx Debugger.State.Scripts.TitleFinder.Contents.findTitleWithLINQ()
Debugger.State.Scripts.titleFinder.Contents.findTitleWithLINQ() : C:\Windows\System32\notepad.exe