Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.4k views
in Technique[技术] by (71.8m points)

debugging - how to dump string using Windbg poi function

Debugging .Net String value in windbg and WinDbg and SoS, how do I print/dump a large string? show a script that dump the string to a local file:

$$ Dumps the managed strings to a file
$$ Platform x86
$$ Usage $$>a<"c:empdumpstringtofolder.txt" 6544f9ac 5000 c:empstringtest
$$ First argument is the string method table pointer
$$ Second argument is the Min size of the string that needs to be used filter the strings
$$ Third is the path of the file
.foreach ($string {!dumpheap -short -mt ${$arg1}  -min ${$arg2}})
{ 

  $$ MT        Field      Offset               Type  VT     Attr    Value Name
  $$ 65452978  40000ed        4         System.Int32  1 instance    71117 m_stringLength
  $$ 65451dc8  40000ee        8          System.Char  1 instance       3c m_firstChar
  $$ 6544f9ac  40000ef        8        System.String  0   shared   static Empty

  $$ start of string is stored in the 8th offset, which can be inferred from above
  $$ Size of the string which is stored in the 4th offset
  r@$t0=  poi(${$string}+4)*2
  .writemem ${$arg3}${$string}.txt ${$string}+8 ${$string}+8+@$t0
}

this script is on x86. I modify the code and try on .net 4.0, x64 system.

the only difference is that the offset is different. for example:

    $$ .net 4.0 , the offset is different
$$                     MT    Field   Offset                 Type VT     Attr            Value Name
$$      000007fee4abc7e8  4000103        8         System.Int32  1 instance              460 m_stringLength
$$      000007fee4abb328  4000104        c          System.Char  1 instance               26 m_firstChar
$$      000007fee4ab6900  4000105       10        System.String  0   shared           static Empty

So, I change my code to:

  r@$t0=  poi(${$string}+8)*2
  .writemem ${$arg3}${$string}.txt ${$string}+c ${$string}+c+@$t0

Here, I wonder the function poi,
1. why here need '*2'?
2. I find a string address, run !do, like this:

0:000> !do 0x00000000ffad0de0
Name:        System.String
MethodTable: 000007fef5da6738
EEClass:     000007fef592ed68
Size:        794(0x31a) bytes
File:        C:WindowsMicrosoft.NetassemblyGAC_64mscorlibv4.0_4.0.0.0__b77a5c561934e089mscorlib.dll
String:      jv15Rr2HXPn3....
Fields:
              MT    Field   Offset                 Type VT     Attr            Value Name
000007fef5dac620  4000103        8         System.Int32  1 instance              384 m_stringLength
000007fef5dab160  4000104        c          System.Char  1 instance               6a m_firstChar
000007fef5da6738  4000105       10        System.String  0   shared           static Empty

I run

0:000> ? poi(0x00000000ffad0de0)+8
Evaluate expression: 8791627818816 = 000007fe`f5da6740

to get the length value of 384, but the output value is wrong(displayed is 8791627818816). What is wrong?

Thank you for helping me!

updated 1): I tried:

0:000> r@$t0= poi(0x00000000ffad0de0+8)
0:000> r@$t0
$t0=0076006a00000180

the result seems not correct.

Update 2): I tried to debug the script:

 .echo ${$str}
  r@$t0=  poi(${$str}+8)*2
  .printf "@$t0 is %d
", @$t0
  .echo ${$arg3}${$str}.txt
  .printf "${$str}+c: %p
", ${$str}+c
  .printf "${$str}+c+@$t0: %p
", ${$str}+c+@$t0
  $$.writemem ${$arg3}${$str}.txt ${$str}+c ${$str}+c+@$t0

then I got the output:

0x00000000ffad4550
@$t0 is 640
c:stringtestx00000000ffad4550.txt
0x00000000ffad4550+c: 00000000ffad455c
0x00000000ffad4550+c+@$t0: 00ec00d4ffad47dc

then I run the .writemem for the output address:

0:000> .writemem c:stringtestss.txt 00000000ffad455c L0n640
Writing 280 bytes.

I got the correct string, it's like this:

/txrqcf...........j7ULyzqxSmB3bpu

I run the command:

0:000> .writemem c:stringtestss.txt 00000000ffad455c 00ec00d4ffad47dc
                                                                      ^ Range error

I got the error Range error, I check the link to find out the result, but I have no idea.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

poi(${$string}+8) is the string length in characters.

*2 is needed because Strings in C# are Unicode and for writing memory, we need the bytes, not characters.

+c is the offset of the char[] on 64 bit. That's the start address to write from.

? poi(0x00000000ffad0de0)+8

This is incorrect, because poi(0x00000000ffad0de0) gives you the value of the method table of the .NET object, which is 000007fef5da6738 and then you add 8, which is 7FEF5DA6740.

What you want to do is

? poi(0x00000000ffad0de0+8) 

inside the braces.

To bypass the range error, use the L? syntax instead range start and range end:

.writemem ${$arg3}${$str}.txt ${$str}+c L? @$t0

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...