美好的一天,
我有一个Windbg脚本,使用.do
循环迭代堆栈的帧。对于每一帧,它使用!for_each_local
和$spat ("@#Local","foo")
来匹配我有兴趣初步了解的内容。然后我使用dx @$t2 =
来分配并最终打印出我感兴趣的内容,即dx @$t2 = ((foobase*) this)->m_current->m_name
- 大多数情况下都可以。
每隔一段时间,就会有一个this
在一个框架中无法用dx
成功投射,所以它就像它需要的barbase
,而不是foobase
... dx
似乎没问题,因为我把它包裹在一个.foreach (output { dx @$t2 = ((foobase*) this)->m_current->m_name }) {}
所以它最终包含导致脚本退出的东西(尽管尝试了.catch
)。
起初我并没有真正意识到发生了什么,但做一个.printf "%ma\n", @$t2
帮助我确定内容是<HRESULT 0x80004002>
,我认为暗示无效的演员 - 如果是这样,那就完全有道理了。当需要foobase
时,我的脚本行正在使用barbase
。
如果我是正确的,我正在寻找的是一种方法来检查,在我进一步深入研究脚本并尝试访问我知道将导致脚本退出的细节之前。
我似乎想出了一个令人费解的方式......但我想问一下是否还有更好的......
.frame 0a $$ a frame with barbase, not foobase
dx @$t2 = ((foobase*) this)->m_name
.printf "%ma\n", @$t2 $$ prints <HRESULT 0x80004002>
as /c CastCheck .printf "%ma", @$t2
.if ($spat(@"${CastCheck}","<HRESULT 0x80004002>") = 1) { .printf "yes" } .else { .printf "no" } $$ prints yes
有没有办法检查$t2
是否包含无效转换的指示器而不使用别名?
我问这个因为使用别名引起了我很多困惑...在我的脚本中(为了它工作,它看起来确实很好)我必须使用aS
而不是as
(我可以使用as
罚款命令窗口,我真的不明白为什么我需要从阅读文档更改为aS
)我还需要用分号结束行(不像我的脚本中的任何其他行)我需要使用ad /q CastCheck;
紧接在aS
之前,然后很快之后,否则别名似乎迷路了,不知何故......所以你可以告诉使用这个别名已经给我带来了一点麻烦。
所以,有没有a)一个简单的方法来预先检查我正在看的是foobase
或barbase
,或b)在演员尝试后检查是否$t2
包含这个<HRESULT 0x80004002>
?如果我做一个.printf "%d", @$t2
它显示5
... 5
也代表什么?
或者,确实,任何其他想法(或问题)。
编辑:
我将尝试说明我在命令窗口中完成的两个短代码的意思...其中第00帧包含可以强制转换为this
的foobase
然后.printf
可以很好地工作,并且框架0a包含一个this
,这是一个barbase
(但我的脚本仍然不指望它,我希望能够满足它)... dx
仍然在$t10
...我希望能够发现它是垃圾(或预先检测我甚至不应该尝试dx
,如果this
是barbase
,因为它毫无意义,我无论如何我都不感兴趣)。
0:038> .frame 00
00 00000006`3e2bc930 00007ffe`926293a8 BlahBlahBlah
0:038> dx @$t10 = ((foobase *) this)->m_name
@$t10 = ((foobase *) this)->m_name : 0x869c7b8 : "nice string" [Type: char *]
0:038> .printf "%ma\n", @$t10
nice string
这是this
是barbase
的地方,甚至没有m_name
:
0:038> .frame 0a
0a 00000006`3e2bd220 00007ffe`91ec7780 BlahBlahBlah
0:038> dx @$t10 = ((foobase *) this)->m_name
@$t10 = ((foobase *) this)->m_name : 0x2265646f00000005 : "--- memory read error at address 0x2265646f`00000005 ---" [Type: char *]
0:038> .printf "%ma\n", @$t10
<HRESULT 0x80004002>
当放入循环中时,我发现当我尝试检查Memory access error
返回的字符串的长度时,脚本将在第0a帧以dx
退出。
基本上,在第二个块我想要一种方法来检查$t10
的东西不是一个很好的字符串(可能是这个<HRESULT 0x80004002>
?),或者更好的是,根本没有做dx
和.printf
,因为我能够在那之前检查this
是一个barbase
,而不是foobase
。
这是否更有意义,还是我应该重新开始?
你试过但它仍然含糊不清
你能解释做什么是必要的.frame 然后dx这??
您可以将任何地址转换为任何类型
例如,在第一次运行中,我将其转换为正确的类型并枚举所有帧
在下一次运行中,我正在进行伪造类型和枚举
在这两个帧中只有一个这个指针
当它是正确的类型时,它返回适当的成员
如果它是假的,它会返回伪造的东西
0:000> !for_each_frame dx ((Student *) this)->Name
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
00 000000c5`d6f6f8c0 00007ff7`2818117c thisptr!Student::PrintStudent+0x9 [f:\src\thisptr\thisptr.cpp @ 20]
((Student *) this)->Name : 0x7ff7282153e0 : "dave" [Type: char *]
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
01 000000c5`d6f6f8f0 00007ff7`281b6c20 thisptr!main+0x2c [f:\src\thisptr\thisptr.cpp @ 33]
Error: Unable to bind name 'this'
它找到了这个,但它找不到会员名
0:000> !for_each_frame dx ((ntdll!_EPROCESS *) this)->Name
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
00 000000c5`d6f6f8c0 00007ff7`2818117c thisptr!Student::PrintStudent+0x9 [f:\src\thisptr\thisptr.cpp @ 20]
Error: Unable to bind name 'Name' <<<<<<
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
01 000000c5`d6f6f8f0 00007ff7`281b6c20 thisptr!main+0x2c [f:\src\thisptr\thisptr.cpp @ 33]
Error: Unable to bind name 'this'
顺便问一下,你知道这个指针是什么类型的,所以为什么要把它投射?
你可以找到这个ptr的类型与各种命令,其中一些如下所示
0:000> dx this
this : 0xc5d6f6f910 [Type: Student *] <<<
[+0x000] Roll : 1 [Type: int]
[+0x008] Name : 0x7ff7282153e0 : "dave" [Type: char *]
[+0x010] Marks : 72.300000 [Type: double]
0:000> ?? this
class Student * 0x000000c5`d6f6f910 <<<
+0x000 Roll : 0n1
+0x008 Name : 0x00007ff7`282153e0 "dave"
+0x010 Marks : 72.299999999999997158
0:000> x /t this
000000c5`d6f6f8f0 class Student * this = 0x000000c5`d6f6f910 <<<
0:000> x /v /t this
prv local 000000c5`d6f6f8f0 8 class Student * this = 0x000000c5`d6f6f910
0:000> dt this
Local var @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910
+0x000 Roll : 0n1
+0x008 Name : 0x00007ff7`282153e0 "dave"
+0x010 Marks : 72.299999999999997158
0:000> dt /v this
Local var [AddrFlags 90 AddrOff 0000000000000030 Reg/Val rsp (7)] @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910 class Student, 5 elements, 0x18 bytes
+0x000 Roll : 0n1
+0x008 Name : 0x00007ff7`282153e0 "dave"
+0x010 Marks : 72.299999999999997158
<function> Student void (
int,
char*,
double)+000000c5`d6f6f910
<function> PrintStudent void ( void )+000000c5`d6f6f910
0:000> dt /v /t this
Local var [AddrFlags 90 AddrOff 0000000000000030 Reg/Val rsp (7)] @ 0xc5d6f6f8f0 Type Student*
0x000000c5`d6f6f910 class Student, 5 elements, 0x18 bytes
+0x000 Roll : 0n1
+0x008 Name : 0x00007ff7`282153e0 "dave"
+0x010 Marks : 72.299999999999997158
<function> Student void (
int,
char*,
double)+000000c5`d6f6f910
<function> PrintStudent void ( void )+000000c5`d6f6f910
添加另一个答案来强调javascript的使用而不是解析文本
javascript脚本支持被添加到windbg安静很长一段时间后,它正在改进很多
(尝试最新的javascript添加使用最新的Windows 10版本中的windbg预览)
x / v / t或dv / t提供this指针的类型
javascript为这些对象提供了targetType属性
这是如何使用它
使用以下内容创建一个.js文件foo.js
function typethis ( somevar )
{
host.diagnostics.debugLog( somevar.targetType , "\t" , JSON.stringify(somevar) , "\n" )
}
在windbg做
.load jsprovider
.scriptload x:\..\\..\foo.js
dx @$scriptcontents.functionname(argument) to run the script
结果将是
0:000> .load jsprovider
0:000> .scriptload f:\wdscr\typthis.js
JavaScript script successfully loaded from 'f:\wdscr\typthis.js'
0:000> dx @$scriptContents.typethis( this )
Student * {"Roll":1,"Name":{},"Marks":72.3}
@$scriptContents.typethis( this )