蛙蛙推荐: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()方法