蛙蛙推荐:windbg里查看DateTime值

蛙蛙推荐:windbg里查看DateTime值
我们都知道在windbg里可以用!do命令查看一个引用对象的详细信息,但像DateTime,Guid,IpAddress等并不能直接用windbg命令打印出来。
我们一个一个说,先创建一个console程序叫DateTimeTest,在属性页里启用非托管代码调试,代码如下
using System;
namespace DateTimeTest
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime dt = DateTime.Now;
            Console.WriteLine(dt);
            Console.Read();
        }
    }
}

并在Console.Read();行上加入断点,F5启动调试程序,断点断住后,在即使窗口里输入如下命令
.load sos
已加载扩展 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\sos.dll
!Name2EE *!System.DateTime
PDB symbol for mscorwks.dll not loaded
Module: 790c2000 (mscorlib.dll)
Token: 0x02000032
MethodTable:
79104b50
EEClass: 79104aec
Name: System.DateTime
--------------------------------------
Module: 00a9205c (sorttbls.nlp)
--------------------------------------
Module: 00a923cc (prcp.nlp)
--------------------------------------
Module: 00a927cc (mscorlib.resources.dll)
--------------------------------------
Module: 00a72c24 (DateTimeTest.exe)

!clrstack -a
OS Thread Id: 0xcd4 (3284)
ESP       EIP    
0012f434 011300d5 DateTimeTest.Program.Main(System.String[])
    PARAMETERS:
        args = 0x013e1b20
    LOCALS:
        0x0012f43c = 0x88f0476c

0012f69c 79e7be1b [GCFrame: 0012f69c]

!DumpVC  79104b50 0x0012f43c
Name: System.DateTime
MethodTable 79104b50
EEClass: 79104aec
Size: 16(0x10) bytes
 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
791042d4  40000f4        0        System.UInt64  0 instance 9856781253186963308 dateData
79122414  40000f0       30       System.Int32[]  0   shared   static DaysToMonth365
    >> Domain:Value  0014d3b0:013e1c78 <<
79122414  40000f1       34       System.Int32[]  0   shared   static DaysToMonth366
    >> Domain:Value  0014d3b0:013e1cb8 <<
79104b50  40000f2       28      System.DateTime  1   shared   static MinValue
    >> Domain:Value  0014d3b0:013e1c58 <<
79104b50  40000f3       2c      System.DateTime  1   shared   static MaxValue
    >> Domain:Value  0014d3b0:013e1c68 <<

9856781253186963308这个值是一个ULong类型的,DateTime的构造函数不支持这个类型的重载,Convert.ToDateTime对这个参数的重载版本也是始终返回异常,然后看MSDN里对DateTime的说明
在 .NET Framework 2.0 版以前,DateTime 结构包含一个 64 位字段,该字段由一个未使用的 2 位字段和一个私有字段 Ticks 串联组成,Ticks 字段是一个 62 位无符号字段,其中包含表示日期和时间的刻度数。Ticks 字段的值可通过 Ticks 属性获取。

从 .NET Framework 2.0 开始,DateTime 结构包含一个由私有字段 Kind 和 Ticks 字段串联组成的 64 位字段。Kind 字段是一个 2 位字段,它指示 DateTime 结构是表示本地时间、协调通用时间 (UTC) 还是 UTC 和本地时间都未指定。Kind 字段用于处理本地时间和 UTC 时间之间的转换,但不用于时间的比较或算术运算。Kind 字段的值可通过 Kind 属性获取。

所以我们要把9856781253186963308这个值转换成2进制,然后把高位的2位换成零,然后在传入DateTime的构造函数里,具体代码如下
using System;
using System.IO;

namespace DateTimeTest
{
    class Program
    {
        static void Main(string[] args)
        {
            MemoryStream ms = new MemoryStream();
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write(9856781253186963308UL);
            byte[] bs = ms.ToArray();
            bs[7] = (byte)(bs[7] & 63);
            ms = new MemoryStream(bs);
            BinaryReader br = new BinaryReader(ms);
            Int64 i = br.ReadInt64();
            Console.WriteLine(new DateTime(i));
            Console.Read();
        }
    }
}
其中把第8个字节按位于上63就是把高位2位置0,因为63的二进制是00111111。
后来ReflectorDateTime的代码,发现.net里有一个类似的函数,只用以下代码就OK了
Console.WriteLine(new DateTime((long)(9856781253186963308UL & 0x3fffffffffffffffL)));
同理,IPAddress的代码如下
IPAddress ip = IPAddress.Parse("192.168.1.1");
windbg分析如下
!clrstack -a
OS Thread Id: 0x338 (824)
ESP       EIP    
0012f438 011300aa DateTimeTest.Program.Main(System.String[])
    PARAMETERS:
        args = 0x013e1b20
    LOCALS:
        0x0012f440 = 0x013e1d40

0012f69c 79e7be1b [GCFrame: 0012f69c]


!do 0x013e1d40
Name: System.Net.IPAddress
MethodTable: 7a77d078
EEClass: 7a7dc4f8
Size: 40(0x28) bytes
 (C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
790fb9bc  400209c        4         System.Int64  0 instance 16885952 m_Address
790f9244  400209d       14        System.String  0 instance 013fd0e4 m_ToString
7a787ec0  40020a1       1c         System.Int32  0 instance        2 m_Family
7912a84c  40020a2       18      System.UInt16[]  0 instance 013e1d68 m_Numbers
790fb9bc  40020a3        c         System.Int64  0 instance 0 m_ScopeId
790fdb60  40020a4       20         System.Int32  0 instance        0 m_HashCode
7a77d078  4002098      7b4 System.Net.IPAddress  0   static 013fcef8 Any
7a77d078  4002099      7b8 System.Net.IPAddress  0   static 013fcf3c Loopback
7a77d078  400209a      7bc System.Net.IPAddress  0   static 013fcf80 Broadcast
7a77d078  400209b      7c0 System.Net.IPAddress  0   static 013fcf80 None
7a77d078  400209e      7c4 System.Net.IPAddress  0   static 013fcfe0 IPv6Any
7a77d078  400209f      7c8 System.Net.IPAddress  0   static 013fd040 IPv6Loopback
7a77d078  40020a0      7cc System.Net.IPAddress  0   static 013fd0a0 IPv6None


最终可用如下函数得到IP
private static string IntToIP(long ip_Int)
{
    long num = ((ip_Int & 0xff000000L) >> 0x18);
    if (num < 0L)
    {
        num += 0x100L;
    }
    long num2 = (ip_Int & 0xff0000L) >> 0x10;
    if (num2 < 0L)
    {
        num2 += 0x100L;
    }
    long num3 = (ip_Int & 0xff00L) >> 8;
    if (num3 < 0L)
    {
        num3 += 0x100L;
    }
    long num4 = ip_Int & 0xffL;
    if (num4 < 0L)
    {
        num4 += 0x100L;
    }
    return (num4 + "." + num3 + "." + num2 + "." + num);
}
或者用以下语句(支持IPV6啥的)
Console.WriteLine(new IPAddress(16885952));
GUID类型dumpvc后是a到k的一串值,有int,short,byte的都有,你要一步一步的把值查出来,然后写一个程序传给System.Guid的构造函数,然后ToString()方法后才能看到,比较麻烦,如果能在windbg里动态执行某个对象的方法就好了,比如ToString()方法

posted @ 2008-03-12 13:48  蛙蛙王子  Views(2878)  Comments(15Edit  收藏  举报