[转].NET Reflector 7.0 License 机制分析
.NET Reflector免费版只能升级到6.7.0.3. 可下载(http://reflector.red-gate.com/download.aspx?TreatAsUpdate=1)的最新版本为7.0. 运行时会要求Activate。
点击Active 按钮,弹出Activate 对话框
如果选择继续执行, 通过菜单也可以呼出Activate对话框
祭出WinDbg, F6, Attached到Reflector的进程上.
根据WinDbg的输出,得知Reflector是基于.NET2.0的,
*** wait with pending attach
WARNING: Inaccessible path: ‘d:\mypdb’
Symbol search path is: srv*d:\MsSymbols*http://msdl.microsoft.com/download/symbols;
Executable search path is:
ModLoad: 00400000 00848000 D:\_Personal\_DevTools\Reflector7\Reflector.exe
…
ModLoad: 79e70000 7a400000 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
…
因此执行 .loadby sos mscorwks 加载当前.NET版本对应的sos , 如果debug .NET 4.0, 就要使用命令.load sos clr 来加载sos.!
执行!clrstack查看callstack, 不巧的是当前线程不是Managed Thread.
执行!thread 列出所有Manged线程
0:015> !threads
ThreadCount: 8
UnstartedThread: 0
BackgroundThread: 7
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
PreEmptive GC Alloc Lock
ID OSID ThreadOBJ State GC Context Domain Count APT Exception
0 1 13dc 0015a2a8 6020 Enabled 09c3ae48:09c3c1b4 00164470 1 STA
2 2 1548 0015d0f0 b220 Enabled 00000000:00000000 00164470 0 MTA (Finalizer)
4 3 e98 001e9bd0 880b220 Enabled 00000000:00000000 00164470 0 MTA (Threadpool Completion Port)
6 4 1f84 0021f638 80a220 Enabled 00000000:00000000 00164470 0 MTA (Threadpool Completion Port)
8 5 1718 002223f8 220 Enabled 00000000:00000000 00164470 0 Ukn
11 8 1870 095a8728 80a220 Enabled 00000000:00000000 00164470 0 MTA (Threadpool Completion Port)
13 7 1a4c 095a8340 200b220 Enabled 00000000:00000000 00164470 0 MTA
14 6 179c 095a8b10 200b220 Enabled 00000000:00000000 00164470 0 MTA
执行~0s切换到0号线程
执行!clrstack
0:000> !clrstack
OS Thread Id: 0×1098 (0)
ESP EIP
0012e98c 7c90e514 [InlinedCallFrame: 0012e98c] System.Windows.Forms.UnsafeNativeMethods.WaitMessage()
0012e988 7b1d8ea8 System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
0012ea24 7b1d8997 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
0012ea78 7b1d87e1 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
0012eaa8 7b6ede2b System.Windows.Forms.Application.RunDialog(System.Windows.Forms.Form)
0012eabc 7b7225ab System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window)
0012eb48 05ddd3d4 RedGate.Licensing.Client.Licence.’œ (System.Windows.Forms.IWin32Window, Œ.™, System.Object, System.Drawing.Icon)
0012ec00 05ddd167 RedGate.Licensing.Client.Licence.™(System.Windows.Forms.IWin32Window, System.Drawing.Icon)
0012ec74 05ddd040 €..œ–(System.Windows.Forms.IWin32Window)
0012ecc8 05ddcf73 ‘.ž†.Activate()
0012ed04 05ddce17 ‘.ž†.Execute(System.String)
0012edac 05ddc906 ‘.–.Execute(System.String)
0012ee08 05ddc7e6 ‘.ž†.Š(System.Object, System.EventArgs)
0012ee78 01263ab3 DynamicClass.(System.Object, System.Object, System.EventArgs)
0012ee8c 05ddc681 ‘.+..OnClick(System.EventArgs)
0012eec4 05ddc5f2 ‘.+..PerformClick()
0012eef8 05ddc55d ‘.+.+..OnClick(System.EventArgs)
0012ef38 7b88f8f9 System.Windows.Forms.MenuItem+MenuItemData.Execute()
0012ef44 7b7933a8 System.Windows.Forms.Command.Invoke()
0012ef50 7ba195df System.Windows.Forms.Command.DispatchID(Int32)
….
以上调用栈表明,点击Menu后,RedGate.Licensing.Client.Licence搞了一些事情,然后弹出了Activate Dialog. 我把目标所定在两个class上:
1. RedGate.Licensing.Client.Licence 这个class好像是用来管理License的
2. Activate Dialog 看看怎么能让Activate button可用,从而断到License严证的代码。
从RedGate.Licensing.Client.Licence开刀
0:000> !dumpheap -type RedGate.Licensing.Client.Licence
Address MT Size
0000000005d0e9c8 000007ff00d33990 176
0000000005d0ea78 000007ff00eb2da0 88
0000000005d0f1c0 000007ff00eb4c18 40
total 0 objects
Statistics:
MT Count TotalSize Class Name
000007ff00eb4c18 1 40 System.Collections.Generic.List`1[[RedGate.Licensing.Client.Licence+.–, Reflector]]
000007ff00eb2da0 1 88 RedGate.Licensing.Client.Licence+.–
000007ff00d33990 1 176 RedGate.Licensing.Client.Licence
Total 3 objects
从上面的执行结果得出RedGate.Licensing.Client.Licence的Method Table 000007ff00d33990
进一步得到它的地址
0:000> !dumpheap -mt 000007ff00d33990
Address MT Size
000000000592a640 000007ff00d53990 176
total 0 objects
Statistics:
MT Count TotalSize Class Name
000007ff00d53990 1 176 RedGate.Licensing.Client.Licence
Total 1 objects
再来看看 RedGate.Licensing.Client.Licence的内容:
0:000> !do 000000000592a640
Name: RedGate.Licensing.Client.Licence
MethodTable: 000007ff00d53990
EEClass: 000007ff00d3d718
Size: 176(0xb0) bytes
File: D:\_HHuang\_DevTools\Reflector7\Reflector.exe
Fields:
MT Field Offset Type VT Attr Value Name
000007fee84b9748 40002a7 88 System.DateTime 1 instance 000000000592a6c8
000007fee84b9748 40002a8 90 System.DateTime 1 instance 000000000592a6d0
000007fee84b9748 40002a9 98 System.DateTime 1 instance 000000000592a6d8
000007ff00d536d8 40002aa 70 System.Int32 1 instance 1
000007fee8496970 40002ab 8 System.String 0 instance 000000000592af18
000007fee8496970 40002ac 10 System.String 0 instance 0000000005a64c98
000007fee849c858 40002ad 74 System.Int32 1 instance 24
000007fee8496970 40002ae 18 System.String 0 instance 000000000592ae80
000007fee8496970 40002af 20 System.String 0 instance 000000000592aeb0
000007fee84b9748 40002b0 a0 System.DateTime 1 instance 000000000592a6e0
000007fee8496970 40002b1 28 System.String 0 instance 0000000002631420
000007fee8496970 40002b2 30 System.String 0 instance 0000000000000000
000007fee849d688 40002b3 84 System.Boolean 1 instance 0
000007fee849d688 40002b4 85 System.Boolean 1 instance 0
000007fee8496970 40002b5 38 System.String 0 instance 000000000591cee0
000007fee849c858 40002b6 78 System.Int32 1 instance 7
000007fee849c858 40002b7 7c System.Int32 1 instance 0
000007fee8496970 40002b8 40 System.String 0 instance 0000000000000000
000007fee8496970 40002b9 48 System.String 0 instance 0000000000000000
000007ff00d53830 40002ba 80 System.Int32 1 instance 0
000007fee8496970 40002bb 50 System.String 0 instance 00000000059334a0
000007fee8496970 40002bc 58 System.String 0 instance 0000000002631420
000007fee849d688 40002bd 86 System.Boolean 1 instance 0
000007ff00ed2da0 40002be 60 …ent.Licence+.– 0 instance 000000000592a6f0
000007fee3e7d488 40002bf 68 …ent.SqlConnection 0 instance 0000000000000000
000007ff001a70c8 40002a6 478 ˆœ.ˆ 0 static 000000000591e498
System.DateTime无非是用来看是否过期,我只关心字符串,用!do 一个一个看:
000000000592af18 C:\Users\HHuang\AppData\Local\Red Gate\Licenses
0000000005a64c98 5410d7dc-1bec-4a91-94b5-4e63ee1a9e4c
000000000592ae80 evaluation
000000000592aeb0 {17c157ee-b2d1-4bd5-aeae-870f28654c42}
0000000002631420 空串
000000000591cee0 .NET Reflector
00000000059334a0 92A2-B24D-A33C-6B93
0000000002631420 空串
由此看见,RedGate.Licensing.Client.Licence只是一个数据包,并不包含验证机制。
尝试把5410d7dc-1bec-4a91-94b5-4e63ee1a9e4c和92A2-B24D-A33C-6B93 输入到Activate 对话框,没有任何反应
HKEY_CURRENT_USER\Software\Thingummy Software\Licensing\.NET Reflector\7.0下的键值{17c157ee-b2d1-4bd5-aeae-870f28654c42} 记录了Reflector 的License信息,Reflector第一次执行时会生成这个键值,如果Reflector过了14天的试用期,就删除这个键(注意,不是仅仅删除它的值),Reflector就不再提示过期
如果用C#代码调用
RedGate.Licensing.Client.Licence c = new RedGate.Licensing.Client.Licence();
c.get_SerialNumber(); 返回null
c.ToString(); 返回
Activated : False
DaysLeftInTrial : 0
Edition : evaluation
SerialNumber :
TrialStatus :
License Mode : LOCAL_MACHINE
下面把注意力移到Activate Dialog上。程序会读取Activate Dialog上TextBox的值进行验证,因此对TextBox.get_Text()方法加断点。
执行!dumpheap -type TextBox得到TextBox的Method Table 000007fee6d19100
执行!dumpmt -md MethodTable 列出TextBox上所有的方法,包括它们的MD
0:000> !dumpmt -md 000007fee6d19100
EEClass: 000007fee6939738
Module: 000007fee6921000
Name: System.Windows.Forms.TextBox
mdToken: 000000000200010c
File: C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Windows.Forms\v4.0_4.0.0.0__b77a5c561934e089\System.Windows.Forms.dll
BaseSize: 0xe8
ComponentSize: 0×0
Slots in VTable: 387
Number of IFaces in IFaceMap: 14
————————————–
MethodDesc Table
Entry MethodDesc JIT Name
000007fee6b8c470 000007fee6a2d530 PreJIT Windows.Forms.TextBox.get_Text()
在TextBox.get_Text()上下断点:!bpmd -md 000007fee6a2d530 (对于.NET 上的程序而言bp GetWindowTextW 已经是老黄历了)
然后继续执行g
果然,每次向TextBox中输入,都会中断,调用栈为:
0:000> !clrstack
OS Thread Id: 0x1aa0 (0)
Child SP IP Call Site
000000000012b698 000007fee6c6d7b0 System.Windows.Forms.TextBox.get_Text()
000000000012b6a0 000007ff010f540f ™ .™ .’š (System.Object, System.EventArgs)
….
0:000> !ip2md 000007ff010f540f
MethodDesc: 000007ff01113ea0
Method Name: ™ .™ .’š (System.Object, System.EventArgs)
Class: 000007ff01121468
MethodTable: 000007ff01113f50
mdToken: 0000000006000548
Module: 000007ff000530d8
IsJitted: yes
CodeAddr: 000007ff010f52c0
反汇编这个函数
0:000> !u 000007ff01113ea0
可以得知这个函数的主要逻辑是(此处引用的代码为32位机代码):
07db8772 ff9064010000 call dword ptr <Unloaded_sspc.dll>+0×163 (00000164)[eax]
调用Text.getText() , 得到SN
07db878c e88f919871 call mscorlib_ni+0×681920 (79741920) (System.String.ToUpper(), mdToken: 060001b0)
把SN转成大写07db86ea e891919871 call mscorlib_ni+0×681880 (79741880) (System.String.Trim(), mdToken: 060001b6)
Trim(SN)
07db86fb ff15b8077f05 call dword ptr [<Unloaded_sspc.dll>+0x57f07b7 (057f07b8)] (Œ .†–[1].š[1](System.String), mdToken: 06000486)
调用函数( md=057f07b0 )对SN进行处理, 姑且称之为IsSNValid(string SN)
……
// 重要, [ebp-24h]中记录SN是否合法
07db8714 8b55dc mov edx,dword ptr [ebp-24h]
07db8717 3909 cmp dword ptr [ecx],ecx
// !do ecx 得到PictureBox
//设置绿色对号PictrueBox是否可见,由此可以推断函数调用1用于判断SN是否合法07db8719 e8ca2e3973 call System_Windows_Forms_ni+0x17b5e8 (7b14b5e8) (System.Windows.Forms.Control.set_Visible(Boolean), mdToken: 06001455)
……
07db873f 837ddc00 cmp dword ptr [ebp-24h],0
// 验证失败,跳入失败的分支
07db8743 7416 je <Unloaded_sspc.dll>+0x7db875a (07db875b)
函数IsSNValid(string SN)的逻辑是
如果SN=”I NEED MORE TIME”, 退出, 返回1, 也就是说”I NEED MORE TIME”算是一个有效的SN
否则调用CheckSN(string SN)
07db8859 ff15c4077f05 call dword ptr [<Unloaded_l32.dll>+0x322dbdf (0322dbe0)] (Œ .†–.š(System.String), mdToken: 06000487) 04b393af 8945d0 mov dword ptr [ebp-30h],eax
04b393b2 0fb645d0 movzx eax,byte ptr [ebp-30h]
//把比较结果存入[ebp-24h]
04b393b6 8945dc mov dword ptr [ebp-24h],eax
//退出
04b393ba eb52 jmp <Unloaded_l32.dll>+0x4b3940d (04b3940e)
CheckSN(string SN)的逻辑是
把SN转大写,Trim,
if(SN 匹配 ^[A-Z]{2}-[0-9A-Z]{1}-[0-9A-Z]{1}-\d{5}-[0-9A-F]{4}$)
{
//捏造SN : HH-A-0-12345-abcd
调用string.Substring截取前4个部分,SN变为HH-A-0-12345
调用函数CreateMegicNumber(短SN)生成一个随机数,如00007ed9, 再把这个数字format({0:X4} )成string
然后return SN.EndWith(“7ed9”)
为此捏造SN HH-A-0-12345-7ED9
}
else
{
if(SN 匹配 ^\d{3}-\d{3}-\d{6}-[0-9A-F]{4}$)
{
捏造SN:123-123-111111-abcd
}
else
{
调用函数CheckSNWithRegex(string SN)判断SN是否合法
{
此函数算出一个字符集, 2346789ABCDEFGHJKMNPRTWXYZ
构造正则表达式^A3[2346789ABCDEFGHJKMNPRTWXYZ]{2}(-([2346789ABCDEFGHJKMNPRTWXYZ]{4})){5}$
为此捏造SN A3HH-ABCD-ABCD-ABCD-ABCD-ABCD
}
调用函数CheckChars(string SN, char c1, char c2)判断SN是否合法
{
检查SN的第2个和第三个字符是否合乎要求
把上面的SN修改为 A3KE-ABCD-ABCD-ABCD-ABCD-ABCD
}
}
}
目前的成果
1. 删除HKEY_CURRENT_USER\Software\Thingummy Software\Licensing\.NET Reflector\7.0下的键值{17c157ee-b2d1-4bd5-aeae-870f28654c42},重新获得14天的试用期
2. 输入序列号”I NEED MORE TIME”激活Reflector,每次输入都重新获得14天的使用期
3. 得到两个SN
但是点击Activate按钮, 出错
要到http://www.red-gate.com/webactivation/activate进行手动验证. Activation Server上的逻辑就无从知晓了.
Reflector 7.0 的License机制暂时分析到这里.
来自:.NET Reflector 7.0 License 机制分析 http://blog.adminzc.info/post-388.html