Windbg 脚本命令简介 二, Windbg command
Windbg 脚本命令简介 二, Windbg script command
$<, $><, $$<, $$><, $$>a< (Run Script File)
Sample1.txt文件内容:
.echo The first argument is ${$arg1}. .echo The fifth argument is ${$arg5}. .echo The fourth argument is ${$arg4}.
0:000> $$>a<"E:\.net Memory Windbg drill into\scripts\sample1.txt" abc "I am ok" "how" "are you" ;rrax The first argument is abc. The fifth argument is ${$arg5}. The fourth argument is are you. rax=000007fefb309d01
脚本路径中带空格,需要加引号,参数中带空格,需要加引号,参数间以空格分开,分号是命令的分割,后面的rrax是第二个命令,而不是第五个参数,rrax或 r rax是显示rax寄存器的值。
第五个参数没有传入,则显示 “${$arg5}” 这个字面值
Token |
是否允许文件名中带分号 |
是否链接以分号分隔的其他命令 |
是否压缩到单一行的命令块 |
是否允许带参数 |
$< |
Yes |
No |
No |
No |
$>< |
Yes |
No |
Yes |
No |
$$< |
No |
Yes |
No |
No |
$$>< |
No |
Yes |
Yes |
No |
$$>a< |
No |
Yes |
Yes |
Yes |
1.把所有语句写在脚本文件的单行中,每个语句和命令之间用分号隔开,然后用$><命令去运行脚本
2.在脚本文件中输入所有语句,每条语句占一行,然后使用$><命令运行脚本,这些命令会打开脚本文件,用分号替换所有的回车符,然后把结果文件当作单一的命令块执行.
如果文件名中带分号,则后面就不允许带上以分号分隔的命令了。但有一种例外,就是
Sample1.txt:
.echo the first arg:${$arg1} .echo I am working kb !dumpheap -type HttpRuntime
0:000> $$>< c:\sample1.txt ;rrax
~s (Set Current Thread)
设置当前线程:
例如 ~2s,则切换到2号线程 提示变为:0:002>
0:002> ~#s:切换到默认线程,提示变为:0:000>
默认线程是dump时正在工作的线程,如果是Crash,则最后发生crash的线程是当前工作线程。
Using Aliases
使用别名:
Alias=Expression
as aS:设置别名,Alias Set
ad:删除别名 Alias Delete
al:列出所有别名 Aliases List
固定名字的内置别名:$u0, $u1, ..., $u9
内置系统别名:大小写敏感
0:000> .echo $ntnsym Ntdll 0:000> .echo $CurrentDumpFile E:\Ccppt.com\SVR858AppPoolHotel2\AppPoolHotel2.DMP 0:000> $CurrentDumpArchivePath E:\Ccppt.com\SVR858AppPoolHotel2\AppPoolHotel2.DMP 0:000> as my 5+1 0:000> .echo my 5+1
as, aS (Set Alias)
0:000> aS /x myAlias 5 + 1; .block{.echo myAlias}
//设置myAlias为64bit的 6(5+1结果)
l 如果不用 任何开关,as 会认为该行后面的都是表达式。
aS myAlias 5 + 1; .block{.echo myAlias}
new line 输入:.echo myAlias //windbg崩溃
如果不用 .block { },输出有问题,因为别名的值代入(展开别名的内容)发生在进入一个新的代码块时,使用 .block {} 使得产生一个新的代码block,.echo myAlias在新代码块中,则myAlias已经展开。
0:001> aS /x myAlias 5 + 1; .echo myAlias
myAlias
0:000> as /c my !eeversion 0:000> .echo my 4.0.30319.296 free Server mode with 8 gc heaps SOS Version: 4.0.30319.586 retail build
//等价于直接命令 !eeversion
C:\Sample1.txt
.echo the first arg:${$arg1} .echo I am working kb !dumpheap -type HttpRuntime
0:000> aS /f my c:\sample1.txt 0:000> .echo my .echo the first arg:${$arg1} .echo I am working kb !dumpheap -type HttpRuntime
//将别名设置为文件内容
:> ad my ^ No information found error in 'ad my' :> ad /q my //删除my别名,/q表示静默模式,不提示错误 :> ad /q * //删除所有别名
0:000> al
Alias Value
------- -------
my 0x5
// 列出所有别名
${ } (Alias Interpreter) 别名解释器
Text ${Alias} Text
Text ${/d:Alias} Text
//根据别名当前是否已经定义计算出1或者0
Text ${/f:Alias} Text
//如果别名当前已定义则等同于计算别名。如果别名已经定义,${/f:Alias} 被替换为等价的别名;如果别名没有定义,${/f:Alias}被替换为空字符串
Text ${/n:Alias} Text
//如果别名当前已定义则计算别名的名称。如果别名已经定义,${/n:Alias}被替换为别名名称;如果别名没有定义,${/n:Alias}保留它字面上的值不替换
Text ${/v:Alias} Text
//禁止对任何别名求值。不论别名是否已经定义,${/v:Alias} 总是保持它字面上的值
:> as /x my + :> .echo my 0x6 :> .echo i am myself i am myself :> .echo i am ${my}self //不需要空格 i am 0x6self :> .echo i am my self //需要有空格 i am 0x6 self :> .echo ${/d:my} // my被定义了,输出1,如果my没定义,则输出0 :> .echo ${/f:my} //解析别名 0x6 :> .echo ${/n:my} //解析别名 my :> .echo ${/v:my} //永不解析,永输出字面值 ${/v:my} :> ad /q * //删除所有别名 :> .echo ${/d:my} :> .echo ${/f:my} //没有定义别名,输出空字符串 :> .echo ${/n:my} //没有定义别名,输出字面值 ${/n:my} :> .echo ${/v:my} //永不解析,永输出字面值 ${/v:my}
Control Flow Tokens
.if
$$ 定义一个变量 as /x my .if (${my}>) { .printf "${my}"; } .elsif (…..) { } .else { .printf "my value is not greater than 5"; }
.foreach
:> .foreach /pS /ps /f ( place "d:\myfile.txt") { dds place }
`ffa9fc48 f37c5888
`ffa9fc4c 000007fe
`ffa9fc50
`ffa9fc54
…..
d:\myfile.txt的内容是:
00000000ffa50c98 00000000ffa9f9d8 00000000ffa9fc48
/pS:循环开始前,初始跳过的个数。
/ps: 循环中,每次迭代跳过的个数。
/f: 来自文件。
这里循环中 place的值是每次等于myfile.txt的一行,输出第一个是myfile.txt 第三行,跳过前面2行,第二次是跳过4行,取第8行,依次13行、18行、23行。
.foreach [Options] ( Variable { InCommands } ) { OutCommands }
//从命令中获取输入
.foreach [Options] /s ( Variable "InString" ) { OutCommands }
//从string中获取输入
.foreach [Options] /f ( Variable "InFile" ) { OutCommands }
//从文件中获取输入
.block
Commands ; .block { Commands } ; Commands
.printf
类似c语言的 printf
:> .printf /D "Click <link cmd=\".chain /D\">here</link> to see extensions DLLs." Click here to see extensions DLLs.:> .chain /D /D DML debug xml格式输出
.catch{ }
Commands ; .catch { Commands } ; Commands
类似.block 块,在catch中的command遇到错误时,catch块中的其他command不会执行,但花括号外面的紧接着catch块的代码还会继续执行。
如果不用.catch { } 整个commands都会停止执行。
.break .continue .leave
.catch { ... ; .if (Condition) .leave ; ... }
.leave :离开 catch块
.break //跳出循环
.for (...) { ... ; .if (Condition) .break ; ...}
.while (...) { ... ; .if (Condition) .break ; ...}
.do { ... ; .if (Condition) .break ; ...} (...)
.continue //继续下一次循环
.for (...) { ... ; .if (Condition) .continue ; ... }
.while (...) { ... ; .if (Condition) .continue ; ... }
.do { ... ; .if (Condition) .continue ; ... } (...)
$$ (Comment)
注释 comments
r eax; $$ some text; r ebx; * more text; r ecx
// * 号后的行内 内容全部是注释
r eax; $$ some text; r ebx; * more text; r ecx
// $$ 后 ; 前的行内 内容是注释。 // 黄色内容会执行
Pseudo-Register Syntax
(伪寄存器)
http://msdn.microsoft.com/en-us/library/ff553485(v=vs.85).aspx
许多寄存器的名字取决于处理器的架构, 因此对于那些偶尔使用调试器的用户来说很难记住所有平台上的寄存器名字. 为了克服这个问题, 调试器的开发团队引入了各种伪寄存器(Pseudo-Register), 由调试器将这些伪寄存器对应到不同的硬件架构上.
例如:
- $ip: 指令指针寄存器;
- x86上, $ip = eip
- x64上, $ip = rip
- Itanium上, $ip = iip
所有伪寄存器都以$符号开始,如果使用MASM(微软宏汇编语言),可以在$符号前加一个@符号。这个@符号告诉调试器,这是一个(伪)寄存器,它不是一个symbol符号。不需要到符号表里去查找这个符号。这样速度会快很多。
:> ? $exp
*** ERROR: Module load completed but symbols could not be loaded for … Evaluate expression: = 0000008f
:> ? @$exp
Evaluate expression: = 0000008f
这两个命令是一样的,但是第一个要慢很多,它会查找symbol,有时候会看到这样的提示:
*** ERROR: Module load completed but symbols could not be loaded for
说明它要查找symbol符号文件去找这个符号。
如果有一个符号跟这个伪寄存器的名字一样,那这里的伪寄存器必须你@符号必须添加。
如果调试器使用了C++的表达式结构,则这里的@符号也是必须的。调试器默认使用C++表达式结构。
:> r $t1 = @$t2 //将 $t2伪寄存器拷贝到$t1
User-Defined Pseudo-Registers
There are 20 user-defined pseudo-registers ($t0, $t1, ..., $t19). These pseudo-register are variables that you can read and write through the debugger. You can store any integer value in these pseudo-registers. They can be especially useful as loop variables.
使用r来写值
例子:
:> r $t0= //赋值
:> r $t1=
:> ? @$t0+@$t1 //计算,MASM表达式结构
Evaluate expression: = `
:> ?? @$t0+@$t1 //计算,C++表达式结构
unsigned int64 0n135 //10进制显示
:> n
base is
:> n //换进制
base is
:> ?? @$t0+@$t1
unsigned int64 0x87 //16进制显示 :> r? $t15 = * (UNICODE_STRING*) 0x12ffbc
伪寄存器的值总是Integer.可以使用 r 带上 ? 开关,并传入类型,这里的例子是将UNICODE_STRING**类型的0x12ffbc传入$t15伪寄存器。
kd> bp /t @$thread nt!ntopenfile
在当前线程的 ntopenfile函数上设置断点,每次当前线程调用该函数时都会触发断点,但其他线程运行该函数时不会触发断点。 $thread 是自动生成的系统伪寄存器。
.shell (Command Shell)
.shell -i InFile [-o OutFile [-e ErrFile]] [Options] ShellCommand
.shell -i - -ci "!do 0b62e790" FIND /c /i "<table" :说明,-i: 从文件输入,
- : 取消从文件输入
-ci:从后面的命令输出作为输入
Find: Dos 命令查找 <table 这个字符串
“-”代替InFile,表示没有输入文件,with no space before the hyphen.
“-”代替OutFile,表示没有输出,如果没有“-o OutFile”表示默认输出到Debug窗口, with no space before the hyphen.
-e ErrFile 类似
-ci "Commands"
将 debug的命令作为输入,多个命令以“;”分号分隔。
.shell命令之后的行内元素都被看作是windows shell命令,而不是debug命令,即使这些命令以分号分隔。Windows shell命令不应该以引号括起来。
exit 或 .shell_quit 是退出shell模式, .shell 后面不跟参数则windbg进入shell模式。
.shell -i - -ci "~* e!clrstack" FIND /I "Monitor.Enter"
//查找所有线程里的堆栈上是否有包含 Monitor.Enter的函数。一般可以用来看死锁。
.shell -ci "~* e!clrstack" python.exe "E:\Ccppt.com\.net Memory Windbg drill into\scripts\py.py"
py.py import sys for y in (,,,): print (y) for i in sys.argv[:]: print (i)
.writemem
实例中,通过lm命令列出内存中加载的模块列表,然后通过.writemem命令将其中的模块存成文件。
0:000> lm
start end module name
010a0000 01124000 fibo C (private pdb symbols)
75270000 753a0000 kernel32 (deferred)
754a0000 75546000 KERNELBASE (deferred)
774a0000 775f7000 ntdll (export symbols) ntdll.dll
0:000> ? 01124000-010a0000 //计算长度
Evaluate expression: 540672 = 00084000
0:000> .writemem c:\fibo.exe 010a0000 L 00084000
Writing 84000 bytes........................................................................................................................................................................................................................................................................
0:000> .writemem c:\fibo.exe 010a0000 (01124000-0x1)
Writing 84000 bytes........................................................................................................................................................................................................................................................................
.writemem可以通过以上两种方式存储文件,第一种是指定起始地址和长度,第二种是指定其实和终止地址。
参考资料:
http://hi.baidu.com/123_mu_tou_ren/item/62e2cf0590bb2b25a0312d16
http://hi.baidu.com/ju_feng/item/c61ab23d788c070bcfb9fe64
Windbg 脚本命令简介 二, Windbg command的更多相关文章
- Windbg 脚本命令简介 一
Windbg 脚本命令简介 一 Windbg command r: registers的简写,可以显示或修改寄存器的值.浮点寄存器的值.定义别名变量. 可以显示当前线程下的寄存器值. The r c ...
- MySQL优化Explain命令简介(二)
type列 MySQL手册上注明type列用于描述join type,不过我们认为把这一列视为对access type--即MySQL决定如何在表中寻找数据的方式的描述,更加合适一些,以下所示从最坏情 ...
- Oracle数据库常用脚本命令(二)
--创建学生信息表create table student( sid number(8,0), name varchar2(20), sex char(2), birthday date, addre ...
- Windbg内核调试之二: 常用命令
运用Windbg进行内核调试, 熟练的运用命令行是必不可少的技能. 但是面对众多繁琐的命令, 实在是不可能全部的了解和掌握. 而了解Kernel正是需要这些命令的指引, 不断深入理解其基本的内容. 下 ...
- Windbg调试命令详解
作者:张佩][原文:http://www.yiiyee.cn/Blog] 1. 概述 用户成功安装微软Windows调试工具集后,能够在安装目录下发现四个调试器程序,分别是:cdb.exe.ntsd. ...
- Windbg 基础命令 《第一篇》
Windbg.exe是Windows的一个调试工具,它支持两种调试模式,即“实时调试模式(Living)”和“事后调试模式(Postmortem)”. 实时模式:被调试的程序正在运行当中,调试器可以实 ...
- WinDbg常用命令系列---.cmdtree
.cmdtree 简介 使用形式 .cmdtree cmdfile 参数 cmdfile命令文件,包含多个你需要的命令.必须是一个文本档 使用步骤 1.使用命令创建文本文件test.wl,使用以下示例 ...
- WinDbg常用命令系列---.write_cmd_hist (写命令历史记录)
.write_cmd_hist 简介 .write_cmd_hist命令将调试器命令窗口的整个历史记录写入文件. 使用形式 .write_cmd_hist Filename 参数 Filename指定 ...
- WinDbg常用命令系列---源代码操作相关命令
lsf, lsf- (Load or Unload Source File) lsf和lsf-命令加载或卸载源文件. lsf Filename lsf- Filename 参数: Filename指定 ...
随机推荐
- “全栈2019”Java异常第二十二章:try-with-resources语句详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- httpclient post请求例子(无参数名与带参数名的例子),多线程并发处理
版本:4.1 带参数名的情况 HttpClient httpClient = new DefaultHttpClient(); HttpPost httpPost = new HttpPost(url ...
- 设置跨交换机VLAN
4台计算机,pc1 pc2 连接到交换机1的f1/1和f1/2.Pc3 pc4 连接到交换机2的f1/1和f1/2.pc1设置ip地址192.168.1.10,pc2 pc3 pc4设置ip地址192 ...
- 把序列中的N个元素赋值给多个变量
说明: python中序列和散列 序列:可通过偏移量来进行切片的对象.列表.元组.字符串都属于序列. 散列:无法通过偏移量来进行切片的对象.比如 集合.字典 一. 变量的数量跟序列元素的个数一样 1. ...
- springboot 使用itextpdf 框架实现多个图片合成一个pdf文件
以下两个方法引入头 import com.lowagie.text.*; import com.lowagie.text.pdf.PdfWriter; import org.apache.pdfbox ...
- random 模块常用方法学习
>>> import random#随机小数>>> random.random() # 大于0且小于1之间的小数0.7664338663654585>> ...
- java 面试大全
一.CoreJava 部分: 基础及语法部分: 1.面向对象的特征有哪些方面? [基础] 答:面向对象的特征主要有以下几个方面: 1)抽象:抽象就是忽略一个主题中与当前目标无关的那些方面,以便更充分地 ...
- [Alpha]Scrum Meeting#9
github 本次会议项目由PM召开,时间为4月11日晚上10点30分 时长10分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写每日例会报告 撰写每日例会报告撰写并整理任务分配博客 SiMrua ...
- HDU 4508 湫湫系列故事——减肥记I
原题链接:点击此处 解题思路: 思路与01背包差不多,思路用二维数组表示: dp[i][v]=max{dp[i-1][v-k*b[i]]+k*a[i]|0<=k*b[i]<=v} 其dp( ...
- 简单工厂模式&策略模式-简介与区别
不得不说,这两种模式真的很像. 相似点:都用到了面向对象的继承.多态.抽象,都拥有相似的结构. 不同点:工厂模式仅提供具体的实例对象,怎么使用这个对象是client的自由,策略模式client可以通过 ...