在用windbg调试程序的时候,有些命令会重复使用,因此想把这些命令封装为脚本文件,实现自动化。但是在对其“变量”(别名
)的使用中遇到了不少坑,致使出现意料之外的值,或者脚本在重复调用时出现前后结果不一致的状况。比如下面的脚本:
ad /q *;
aS ${/v:MyVar} 0x1;
.echo `MyVar` is ${MyVar};
aS ${/v:MyVar} 0x2;
.echo `MyVar` is ${MyVar};
al;
这个脚本先删除所有别名,然后指定MyVar
作为数字0x1
的别名,并打印MyVar
,接着将MyVar
作为数字0x2
的别名,再打印它,最后al
列出所有别名。按往常的编码思维,运行完这个脚本,预想打印的前两行应分别为 `MyVar` is 0x1 和 `MyVar` is 0x2,然而实际结果却是:
通过查阅使用手册及外网论坛,总结了关于windbg脚本中的别名
的如下几个要点:
- 别名相当于C语言中的宏。因此它出现的位置会在执行命令前替换成它的真实值。如果这个别名未被使用,则直接替换为别名的本名。
- windbg在遇到一个
.block {}
块时,会将块中所有别名同时展开。 - 不同
.block {}
块中的别名会各自展开。 - 一个脚本文件相当于一个
.block {}
块。
也就是说,上面的代码在执行前,先把.echo
语句中的${MyVar}
展开为它的真实值了,而这时MyVar
并未作为别名,所以打印出来的是${MyVar}
。
如果要让第一次"赋值"有效,从而让第二条.echo
语句打印出赋予了新值的${MyVar}
,则可以利用上述的第三个要点,即使用多个.block {}
块:
这样一来,脚本文件就不会在一开始展开所有的${MyVar}
,而是先展开第一个.block {}
块中的${MyVar}
,并运行完块中的指令。之后展开第二个.block {}
块中的${MyVar}
,这时${MyVar}
已经在第一个.block {}
块被“赋值”为0x1
,所以第二个块中的${MyVar}
便展开为0x1
。
还有一种吊诡的情况,如果ad /q *;
这行命令不在第一行(比如,在它前面加个空行),脚本的运行结果也不一样:
这意味着ad /q *;
这一行并没有生效,而因为我在执行脚本前先把MyVar
作为0x3
的别名,所以脚本中${MyVar}
直接以其已有的真实值0x3
展开。原因暂不明了,而这也导致我无法在文件开头加一些注释,无奈之下只能将注释放在文件结尾了。