r:
registers的简写,可以显示或修改寄存器的值、浮点寄存器的值、定义别名变量。
可以显示当前线程下的寄存器值。
The r command displays or modifies registers, floating-point registers, flags, pseudo-registers, and fixed-name aliases.
0:000> ~2 r
//显示 2号线程的寄存器值
0:000> ~* r eax
//显示所有线程的 eax寄存器值
设置默认显示的数字进制(Radix)
0:000> n
base is 16
//显示默认进制
0:000> n 10
base is 10
//改成10进制
Value |
Description |
8 |
Octal |
10 |
Decimal |
16 |
Hexadecimal |
In all MASM expressions, numeric values are interpreted as numbers in the current radix (16, 10, or 8). You can override the default radix by specifying the 0x prefix (hexadecimal), the 0n prefix (decimal), the 0t prefix (octal), or the 0y prefix (binary).
dc 00cc07c8 00cc07c8+0n4344
Windbg默认的数值进制一般是16, 可以通过n命令查看和设置当前进制,
, 0n(十进制), 0x(十六进制), 0t(8进制), 0y(2进制), 比如0n20表示20, 0x14表示20等
计算表达式
0:000> as fn c:\dir\name.txt //定义一个别名,设置别名,Alias Set
0:000> $spat("c:\dir\name.txt","*name*") //没有输出
0:000> ?$spat("c:\dir\name.txt","*name*") //计算结果,\n被转义,所以结果是0.
Evaluate expression: 0 = 00000000`00000000
0:000> ?$spat(@"c:\dir\name.txt","*name*") //在字符串前面加 @符号
Evaluate expression: 1 = 00000000`00000001
0:000> ?$spat("c:\dir\","*name*")
Syntax error at '("c:\dir\","*name*")' //有错误,因为dir\” 这里被转义
0:000> ?$spat(@"c:\dir\","*name*") //使用@,防止被转义
Evaluate expression: 0 = 00000000`00000000
0:000> ?$spat(@"c:\\name","*name")
Evaluate expression: 1 = 00000000`00000001 //找到结果,输出1,表示true
0:000> ?$spat(@"c:\dir\","*d*")
Evaluate expression: 1 = 00000000`00000001
0:000> ?$spat(${fn},"*d*")
Syntax error at '(c:\dir\name.txt,"*d*")' //定义别名就是类似C++ 里的宏
0:000> ?$spat("${fn}","*d*")
Evaluate expression: 1 = 00000000`00000001
0:000> ?$spat("${fn}","*name*")
Evaluate expression: 0 = 00000000`00000000 // fn 中的\n 被转义,所以找不到
0:000> ?$spat(@"${fn}","*name*")
Evaluate expression: 1 = 00000000`00000001
$spat 是MASM里的一个命令,检查第一个string参数是否符合第二个参数的模式(大小写敏感),
要注意 转移字符 \n, \", \r, and \b
?? 是c++表达式格式的,对应MASM的 ? 功能。
下面的2个是等价的,dd是读取双字,即4个字节,2个字节(byte)为一个字(word)。
当一个存放于0x00123456 的指针指向地址0x00420000,我们想显示位于地址0x00420000的内容时,可以有如下选择:
0:000> dd 420000 //直接打印位于该地址的值
0:000> dd poi(123456)
//取得0x00123456地址上指针的值,以poi函数(point to int)取值,即32位平台取4字节,64位平台取8字节,取的都是一个完整指针大小的长度,32位平台指针长度为4字节,64位平台指针长度是8字节。额外一点,int/Int32无论在32还是64位平台都是4字节。
读取开始地址为0x00001000 的8字节:这里假设对象长度是1字节,L指定是对象个数,它跟对象的大小有关系
Dd 0x00001000 0x00001007 //指定开始地址,结束地址
Dd 0x00001000 L8 //指定开始地址,对象个数8,假设对象是1字节长度
Dd 0x00001000 L2 //指定开始地址,对象个数2,假设对象是双字长度(4字节)
Dd 80000000 L20 // the range from 0x80000000 through 0x8000001F
Dd 80000000 L-20 //specifies the range from 0x7FFFFFE0 through 0x7FFFFFFF.
MASM parser treats all symbols as addresses, the example must have the poi operator to dereference MyVar
MASM解析器把所有的symbol符号都用地址的方式来表示,所以必须用poi函数来解析出地址里面的值。
实例:
0:000> !do 0x0000000122a8b110 Name: InternalEntity.CityInfoEntity MethodTable: 000007ff00283908 EEClass: 000007ff00293c18 Size: 48(0x30) bytes File: C:\ SearchService.InternalEntity.dll Fields: |
||||||||||||||||
MT |
Field |
Offset |
Type |
VT |
Attr |
Value |
Name |
|||||||||
000007fee4abc7e8 |
4000534 |
10 |
System.Int32 |
1 |
instance |
30138 |
city |
|||||||||
000007fee4abc7e8 |
4000535 |
14 |
System.Int32 |
1 |
instance |
10082 |
province |
|||||||||
000007fee4abc7e8 |
4000536 |
18 |
Sstem.Int32 |
1 |
instance |
28 |
country |
|||||||||
000007fee4abd618 |
4000537 |
20 |
System.Boolean |
1 |
instance |
1 |
hasMemoryCacheConfig |
|||||||||
000007ff00463810 |
4000538 |
8 |
...ityTimeZoneEntity |
0 |
instance |
0000000122a8b140 |
<CityTimeZone>k__BackingField |
|||||||||
000007fee4abc7e8 |
4000539 |
1c |
System.Int32 |
1 |
instance |
0 |
<CityhotelCount>k__BackingField |
|||||||||
0:000> dc 0x0000000122a8b110 00000001`22a8b110 00283908 000007ff 22a8b140 00000001 .9(.....@..".... 00000001`22a8b120 000075ba 00002762 0000001c 00000000 .u..b'.......... 00000001`22a8b130 00000001 00000000 00000000 00000000 ................ 00000001`22a8b140 00463810 000007ff 000075ba 00000e10 .8F......u...... 00000001`22a8b150 00000e10 00000001 d266c000 08cffbb9 ..........f..... 00000001`22a8b160 9d264000 08d0a0be 20c3c000 08d119c2 .@&........ .... 00000001`22a8b170 eb834000 08d1bec6 00000000 00000000 .@.............. 00000001`22a8b180 00256438 000007ff 22a8b110 00000001 8d%........".... |
ß 这里一行的长度是0n16 4字节*4组=16字节 的计算方式。 这里看一下这里Offset=8的地方是CityTimeZone对象,确实是Offset在8字节处。 |
|||||||||||||||
0:000> dc 0x0000000122a8b110+0x10 //0x000075ba=0n30138 00000001`22a8b120 000075ba 00002762 0000001c 00000000 .u..b'.......... 00000001`22a8b130 00000001 00000000 00000000 00000000 ................ 00000001`22a8b140 00463810 000007ff 000075ba 00000e10 .8F......u...... 00000001`22a8b150 00000e10 00000001 d266c000 08cffbb9 ..........f..... 00000001`22a8b160 9d264000 08d0a0be 20c3c000 08d119c2 .@&........ .... 00000001`22a8b170 eb834000 08d1bec6 00000000 00000000 .@.............. 00000001`22a8b180 00256438 000007ff 22a8b110 00000001 8d%........".... 00000001`22a8b190 00000000 00000000 00000085 000075ba .............u.. |
ß 这根据上面的Offset 0x10来直接用内存看,得到的结果是一样的,0x000075ba = 0n30138,使用?0x75ba 直接计算表达式可以得到值,如下所示。 |
|||||||||||||||
0:000> n16 base is 16 0:000> ?0x75ba //? 计算表达式的值 Evaluate expression: 30138 = 00000000`000075ba |
|
|||||||||||||||
0:000> !do 0000000122a8b140 Name: CityTimeZoneEntity MethodTable: 000007ff00463810 EEClass: 000007ff00475880 Size: 64(0x40) bytes File: C:\Hotel.Product.SearchService.InternalEntity.dll Fields: |
||||||||||||||||
MT |
Field |
Offset |
Type |
VT |
Attr |
Value |
Name |
|||||||||
000007fee4abc7e8 |
4000490 |
8 |
System.Int32 |
1 |
instance |
30138 |
<City>k__BackingField |
|||||||||
000007fee4abc7e8 |
4000491 |
c |
System.Int32 |
1 |
instance |
3600 |
<DstOffset>k__BackingField |
|||||||||
000007fee4abd618 |
4000492 |
14 |
System.Boolean |
1 |
instance |
1 |
<IsSupportDst>k__BackingField |
|||||||||
000007fee4ad96d8 |
4000493 |
18 |
System.DateTime |
1 |
instance |
0000000122a8b158 |
<CurDstStartDate>k__BackingField |
|||||||||
000007fee4ad96d8 |
4000494 |
20 |
System.DateTime |
1 |
instance |
0000000122a8b160 |
<CurDstEndDate>k__BackingField |
|||||||||
000007fee4ad96d8 |
4000495 |
28 |
System.DateTime |
1 |
instance |
0000000122a8b168 |
<NextDstStartDate>k__BackingField |
|||||||||
000007fee4ad96d8 |
4000496 |
30 |
System.DateTime |
1 |
instance |
0000000122a8b170 |
<NextDstEndDate>k__BackingField |
|||||||||
000007fee4abc7e8 |
4000497 |
10 |
System.Int32 |
1 |
instance |
3600 |
<UTCOffset>k__BackingField |
|||||||||
0:000> dd 0000000122a8b140 00000001`22a8b140 00463810 000007ff 000075ba 00000e10 00000001`22a8b150 00000e10 00000001 d266c000 08cffbb9 00000001`22a8b160 9d264000 08d0a0be 20c3c000 08d119c2 |
<-- 查看offset=8的地方,发现值确实是30138,查看offset=12,16进制 0xc的地方值确实为3600 |
|||||||||||||||
0:000> ?0x75ba Evaluate expression: 30138 = 00000000`000075ba 0:000> ?0xe10 Evaluate expression: 3600 = 00000000`00000e10 |
|
|||||||||||||||
0:000> dd poi(0x0000000122a8b110+8) 00000001`22a8b140 00463810 000007ff 000075ba 00000e10 00000001`22a8b150 00000e10 00000001 d266c000 08cffbb9 00000001`22a8b160 9d264000 08d0a0be 20c3c000 08d119c2 00000001`22a8b170 eb834000 08d1bec6 00000000 00000000 00000001`22a8b180 00256438 000007ff 22a8b110 00000001 00000001`22a8b190 00000000 00000000 00000085 000075ba 00000001`22a8b1a0 00000000 00000000 4aea67f9 08d0b971 00000001`22a8b1b0 00000000 00000000 e4ab6900 000007fe 0:000> !do poi(0x000000122a8b110+8) Name: Hotel.Product.SearchService.InternalEntity.CityTimeZoneEntity MethodTable: 000007ff00463810 EEClass: 000007ff00475880 Size: 64(0x40) bytes |
<--直接将CityInfoEntity 对象Offset=8位置处的地址通过poi函数得到该地址上的值0000000122a8b140 ,运行!do <object address> 看到的是CityTimeZoneEntity这个对象的内容。如果不加poi函数,dd 看到的还是CityInfoEntity对象的内容, 运行 !do 0x000000122a8b110+8 看到的将不是一个有效的对象。 |
|||||||||||||||
下面来看看如果不小心输入了下面的命令会是什么结果: |
|
|||||||||||||||
0:000> dd poi(0x0000000122a8b110)+8 000007ff`00283910 00050011 00000004 e4ab5a58 000007fe 000007ff`00283920 0025ed18 000007ff 00283978 000007ff 000007ff`00283930 00293c18 000007ff 00000000 00000000 000007ff`00283940 00000000 00000000 00283958 000007ff |
<--这里右括号括号的位置与上面的命令位置不一样。 看到前面正确命令的基地址是00000001`22a8b140,而这里变成了000007ff`00283910 ,差距很大。 |
|||||||||||||||
原因是什么呢? Poi命令把0x0000000122a8b110地址上的值作为另外一个地址,0x0000000122a8b110 后续的几个字节的那一段东西其实是内容,而不是地址。它表示的是CityInfoEntity这个对象的有实际意义的内容,而不是地址。Poi命令简单粗暴的将内容作为地址来对待。 |
|
|||||||||||||||
0:000> dd 0x0000000122a8b110 00000001`22a8b110 00283908 000007ff 22a8b140 00000001 00000001`22a8b120 000075ba 00002762 0000001c 00000000 |
<--通过dd 查看到以16进制表示的一串数字,这些数字是代表了CityInfoEntity的内容,00283908 000007ff 是内容,而poi把它作为地址来使用了。 |
|||||||||||||||
0:000> dd 000007ff00283908 000007ff`00283908 00080000 00000030 00050011 00000004 000007ff`00283918 e4ab5a58 000007fe 0025ed18 000007ff 000007ff`00283928 00283978 000007ff 00293c18 000007ff |
<--通过查看00283908 000007ff 这个地址的内容,我们找到offset=8的地方的内容,可以发现下划线的东西是一样的。 |
|||||||||||||||
|
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
设置当前线程:
例如 ~2s,则切换到2号线程 提示变为:0:002>
0:002> ~#s:切换到默认线程,提示变为:0:000>
默认线程是dump时正在工作的线程,如果是Crash,则最后发生crash的线程是当前工作线程。
使用别名:
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
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
//将别名设置为文件内容
0:000> ad my ^ No information found error in 'ad my' 0:000> ad /q my //删除my别名,/q表示静默模式,不提示错误 0:000> ad /q * //删除所有别名
0:000> al
Alias Value
------- -------
my 0x5
// 列出所有别名
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} 总是保持它字面上的值
0:000> as /x my 5+1 0:000> .echo my 0x6 0:000> .echo i am myself i am myself 0:000> .echo i am ${my}self //不需要空格 i am 0x6self 0:000> .echo i am my self //需要有空格 i am 0x6 self 0:000> .echo ${/d:my} // my被定义了,输出1,如果my没定义,则输出0 1 0:000> .echo ${/f:my} //解析别名 0x6 0:000> .echo ${/n:my} //解析别名 my 0:000> .echo ${/v:my} //永不解析,永输出字面值 ${/v:my} 0:000> ad /q * //删除所有别名 0:000> .echo ${/d:my} 0 0:000> .echo ${/f:my} //没有定义别名,输出空字符串 0:000> .echo ${/n:my} //没有定义别名,输出字面值 ${/n:my} 0:000> .echo ${/v:my} //永不解析,永输出字面值 ${/v:my}
$$ 定义一个变量 as /x my 4 .if (${my}>5) { .printf "${my}"; } .elsif (…..) { } .else { .printf "my value is not greater than 5"; }
0:000> .foreach /pS 2 /ps 4 /f ( place "d:\myfile.txt") { dds place } 00000000`ffa9fc48 f37c5888 00000000`ffa9fc4c 000007fe 00000000`ffa9fc50 00000000 00000000`ffa9fc54 00000000 …..
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 }
//从文件中获取输入
Commands ; .block { Commands } ; Commands
类似c语言的 printf
0:000> .printf /D "Click <link cmd=\".chain /D\">here</link> to see extensions DLLs." Click here to see extensions DLLs.0:000> .chain /D /D DML debug xml格式输出
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 ; ... } (...)
注释 comments
r eax; $$ some text; r ebx; * more text; r ecx // * 号后的行内 内容全部是注释 r eax; $$ some text; r ebx; * more text; r ecx // $$ 后 ; 前的行内 内容是注释。 // 黄色内容会执行
http://msdn.microsoft.com/en-us/library/ff553485(v=vs.85).aspx
许多寄存器的名字取决于处理器的架构, 因此对于那些偶尔使用调试器的用户来说很难记住所有平台上的寄存器名字. 为了克服这个问题, 调试器的开发团队引入了各种伪寄存器(Pseudo-Register), 由调试器将这些伪寄存器对应到不同的硬件架构上.
例如:
所有伪寄存器都以$符号开始,如果使用MASM(微软宏汇编语言),可以在$符号前加一个@符号。这个@符号告诉调试器,这是一个(伪)寄存器,它不是一个symbol符号。不需要到符号表里去查找这个符号。这样速度会快很多。
0:000> ? $exp *** ERROR: Module load completed but symbols could not be loaded for … Evaluate expression: 143 = 0000008f 0:000> ? @$exp Evaluate expression: 143 = 0000008f
这两个命令是一样的,但是第一个要慢很多,它会查找symbol,有时候会看到这样的提示:
*** ERROR: Module load completed but symbols could not be loaded for
说明它要查找symbol符号文件去找这个符号。
如果有一个符号跟这个伪寄存器的名字一样,那这里的伪寄存器必须你@符号必须添加。
如果调试器使用了C++的表达式结构,则这里的@符号也是必须的。调试器默认使用C++表达式结构。
0:000> r $t1 = @$t2 //将 $t2伪寄存器拷贝到$t1
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来写值
例子:
0:000> r $t0=7 //赋值 0:000> r $t1=128 0:000> ? @$t0+@$t1 //计算,MASM表达式结构 Evaluate expression: 135 = 00000000`00000087 0:000> ?? @$t0+@$t1 //计算,C++表达式结构 unsigned int64 0n135 //10进制显示 0:000> n base is 10 0:000> n 16 //换进制 base is 16 0:000> ?? @$t0+@$t1 unsigned int64 0x87 //16进制显示 0:000> r? $t15 = * (UNICODE_STRING*) 0x12ffbc
伪寄存器的值总是Integer.可以使用 r 带上 ? 开关,并传入类型,这里的例子是将UNICODE_STRING**类型的0x12ffbc传入$t15伪寄存器。
kd> bp /t @$thread nt!ntopenfile
在当前线程的 ntopenfile函数上设置断点,每次当前线程调用该函数时都会触发断点,但其他线程运行该函数时不会触发断点。 $thread 是自动生成的系统伪寄存器。
.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 (0,1,2,3): print (y) for i in sys.argv[1:]: print (i)
实例中,通过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可以通过以上两种方式存储文件,第一种是指定起始地址和长度,第二种是指定其实和终止地址。