【文章标题】: KCR CM2的简单分析
【文章作者】: samisgod
【下载地址】: http://bbs.pediy.com/showthread.php?t=79864
【编写语言】: VC6
【使用工具】: OD
【操作平台】: Windows XP x64 SP3
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
[更新下]
今天没事干来到CM版转转,无意间看到这个CM,还没人分析,遂自己下下来看看...
这个CM算法的2个关键点并不难定位GetWindowText直接可到了
下面进行简单分析
打开后的第一个框内数值这里将其称为MCode
第一部分:
00401EC0 . 53 push ebx
00401EC1 . 56 push esi
00401EC2 . 57 push edi
00401EC3 . 8BF1 mov esi, ecx
00401EC5 . 6A 01 push 1
00401EC7 . E8 1A030000 call <CWnd::UpdateData(int)> ; jmp 到 MFC42.#6334
00401ECC . 8B46 60 mov eax, dword ptr [esi+60]
00401ECF . 8D5E 64 lea ebx, dword ptr [esi+64]
00401ED2 . 53 push ebx
00401ED3 . 68 E9030000 push 3E9
00401ED8 . 8B78 F8 mov edi, dword ptr [eax-8]
00401EDB . 8BCE mov ecx, esi
00401EDD . E8 D4020000 call <CWnd::GetDlgItem(int)> ; jmp 到 MFC42.#3092
00401EE2 . 8BC8 mov ecx, eax
00401EE4 . E8 F1020000 call <CWnd::GetWindowTextA(CString &)> ; jmp 到 MFC42.#3874
00401EE9 . 33C0 xor eax, eax
00401EEB . 85FF test edi, edi
00401EED . 7E 12 jle short <loc_401F01>
00401EEF > > 8B4E 60 mov ecx, dword ptr [esi+60] ; SN
00401EF2 . 40 inc eax
00401EF3 . 3BC7 cmp eax, edi
00401EF5 . 8A5408 FF mov dl, byte ptr [eax+ecx-1]
00401EF9 . 8890 7B414000 mov byte ptr [eax+40417B], dl
00401EFF .^ 7C EE jl short <loc_401EEF>
00401F01 > > 83FF 0A cmp edi, 0A ; loc_401F01
00401F04 . 7C 45 jl short <loc_401F4B>
00401F06 . 8B0D 9C414000 mov ecx, dword ptr [40419C]
00401F0C . 8B15 A0414000 mov edx, dword ptr [4041A0]
00401F12 . 33C0 xor eax, eax ; eax初始化
00401F14 > > 8B3B mov edi, dword ptr [ebx] ; loc_401F14
00401F16 . 40 inc eax
00401F17 . 83F8 0A cmp eax, 0A ; 10?
00401F1A . 0FBE7C07 FF movsx edi, byte ptr [edi+eax-1] ; 逐位取前10位
00401F1F . 8D4C39 D0 lea ecx, dword ptr [ecx+edi-30] ; ecx=ecx+edi-0x30
00401F23 . 890D 9C414000 mov dword ptr [40419C], ecx ; (前10位ASC-0x30累加)放入40419C
00401F29 . 8B7E 60 mov edi, dword ptr [esi+60] ; SN
00401F2C . 0FBE7C38 FF movsx edi, byte ptr [eax+edi-1] ; 逐位取SN
00401F31 . 8D543A D0 lea edx, dword ptr [edx+edi-30] ; ASC - 0x30累加
00401F35 . 8915 A0414000 mov dword ptr [4041A0], edx ; 存入4041A0
00401F3B .^ 7C D7 jl short <loc_401F14>
00401F3D . 8BCE mov ecx, esi
00401F3F . C605 60414000>mov byte ptr [404160], 1
00401F46 . E8 87010000 call <CDialog::OnCancel(void)> ; jmp 到 MFC42.#4376
00401F4B > > 5F pop edi ; loc_401F4B
00401F4C . 5E pop esi
00401F4D . 5B pop ebx
00401F4E . C3 retn
这一部分有3个全局变量用在算法部分
40419C
4041A0
作用上面已经说明
404160
注册码达10位后会置1
用来简单看了下会用作流程判断,为1时会开启注册流程2
下面开始第2部分
这里说明下,为了方便,我们的注册码直接填写一个简单分析后获取并经过简单修改的值 -_-bb
00A0000000033333333399
另外,为了分析方便,我的MCode被我锁定为324207125552-2111
00401600 |. 83EC 10 sub esp, 10
00401603 |. 53 push ebx
00401604 |. 55 push ebp
00401605 |. 8BE9 mov ebp, ecx
00401607 |. 57 push edi
00401608 |. C64424 0F 00 mov byte ptr [esp+F], 0
0040160D |. C64424 10 00 mov byte ptr [esp+10], 0
00401612 |. 8D7D 60 lea edi, [arg.23]
00401615 |. 66:C74424 11 >mov word ptr [esp+11], 0
0040161C |. 57 push edi
0040161D |. 68 E8030000 push 3E8
00401622 |. E8 8F0B0000 call <CWnd::GetDlgItem(int)> ; jmp 到 MFC42.#3092
00401627 |. 8BC8 mov ecx, eax
00401629 |. E8 AC0B0000 call <CWnd::GetWindowTextA(CString &)> ; jmp 到 MFC42.#3874
0040162E |. 8B07 mov eax, dword ptr [edi]
00401630 |. 8378 F8 16 cmp dword ptr [eax-8], 16 ; 注册码不到22位就挂
00401634 |. 74 07 je short <loc_40163D>
00401636 |. 6A 00 push 0
00401638 |. E9 25010000 jmp <loc_401762>
0040163D >|> 56 push esi ; loc_40163D
0040163E |. FF15 84314000 call dword ptr [<&MSVCRT.clock>] ; msvcrt.clock
00401644 |. 8D75 64 lea esi, [arg.24]
00401647 |. 8BCD mov ecx, ebp
00401649 |. 56 push esi
0040164A |. 68 E9030000 push 3E9
0040164F |. 894424 24 mov dword ptr [esp+24], eax
00401653 |. E8 5E0B0000 call <CWnd::GetDlgItem(int)> ; jmp 到 MFC42.#3092
00401658 |. 8BC8 mov ecx, eax
0040165A E8 7B0B0000 call <CWnd::GetWindowTextA(CString &)> ; 324207125552-2111
0040165F |. 8B06 mov eax, dword ptr [esi] ; MCode
00401661 |. 8A48 0F mov cl, byte ptr [eax+F] ; 16位(1)
00401664 |. 884C24 14 mov byte ptr [esp+14], cl
00401668 |. 8A50 10 mov dl, byte ptr [eax+10] ; 17位(1)
0040166B |. 8D4424 14 lea eax, dword ptr [esp+14]
0040166F |. 885424 15 mov byte ptr [esp+15], dl ; 末2位转数字
00401673 |. 50 push eax ; /s
00401674 |. C64424 1A 00 mov byte ptr [esp+1A], 0 ; |
00401679 |. FF15 E4314000 call dword ptr [<&MSVCRT.atoi>] ; \atoi
0040167F |. 8BD8 mov ebx, eax ; 11 -> B 放 ebx
00401681 |. 8B06 mov eax, dword ptr [esi] ; MCode
00401683 |. 8A48 0D mov cl, byte ptr [eax+D] ; 14位(2)
00401686 |. 884C24 18 mov byte ptr [esp+18], cl
0040168A |. 8A50 0E mov dl, byte ptr [eax+E] ; 15位(1)
0040168D |. 8D4424 18 lea eax, dword ptr [esp+18]
00401691 |. 885424 19 mov byte ptr [esp+19], dl ; 14.15位连接转数字
00401695 |. 50 push eax ; /s
00401696 |. C64424 1E 00 mov byte ptr [esp+1E], 0 ; |
0040169B |. FF15 E4314000 call dword ptr [<&MSVCRT.atoi>] ; \atoi
004016A1 |. 8B0E mov ecx, dword ptr [esi] ; 21 -> 0x15
004016A3 |. 894424 20 mov dword ptr [esp+20], eax ; eax(15)保存
004016A7 |. 8B07 mov eax, dword ptr [edi] ; SN
004016A9 |. 0FBE1419 movsx edx, byte ptr [ecx+ebx] ; MCode取ebx+1(B->12)位 (2->ASC=0x32)
004016AD |. 0FBE4C02 D0 movsx ecx, byte ptr [edx+eax-30] ; SN取上面计算出的0x32+1-0x30位 (3) = 0
004016B2 |. 51 push ecx ; /c
004016B3 |. FF15 D0314000 call dword ptr [<&MSVCRT.isupper>] ; \isupper
004016B9 |. 83C4 0C add esp, 0C ; 判断是否大写,是则返回非0值
004016BC |. 85C0 test eax, eax
004016BE |. 74 20 je short <off_4036E0> ; 0则跳
004016C0 |. 8B16 mov edx, dword ptr [esi] ; MCode
004016C2 |. 8B0F mov ecx, dword ptr [edi] ; SN
004016C4 |. 0FBE041A movsx eax, byte ptr [edx+ebx] ; MCode取第ebx+1(C->12)位 = 2 -> ASC=0x32
004016C8 |. 8B5424 18 mov edx, dword ptr [esp+18] ; 上面计算出的15
004016CC |. 8A5C08 D0 mov bl, byte ptr [eax+ecx-30] ; SN取eax(0x32)-0x30+1位 (A -> 0x41)
004016D0 |. 8A1495 204040>mov dl, byte ptr [edx*4+404020] ; 查表取值 edx=0x15 时得值1,直接Ctrl+G到404020可看到
004016D7 |. 80C2 41 add dl, 41 ; 1+0x41 = 0x42
004016DA |. 3ADA cmp bl, dl
004016DC |. B3 01 mov bl, 1 ; 成功标识1
004016DE |. 74 04 je short <loc_4016E4> ; 根据0x42,修改第3位为B,并需要恢复全局变量值
004016E0 >|> 8A5C24 13 mov bl, byte ptr [esp+13] ; off_4036E0
004016E4 >|> 8B0D A0414000 mov ecx, dword ptr [4041A0] ; loc_4016E4
004016EA |. 33C0 xor eax, eax ; 初始化eax
004016EC >|> 8B17 /mov edx, dword ptr [edi] ; loc_4016EC
004016EE |. 40 |inc eax ; eax++
004016EF |. 83F8 0B |cmp eax, 0B ; 11?
004016F2 |. 0FBE5410 0A |movsx edx, byte ptr [eax+edx+A] ; SN取eax+0xA+1位(61) -> SN从12位开始向后取值
004016F7 |. 8D4C11 D0 |lea ecx, dword ptr [ecx+edx-30]
004016FB |. 890D A0414000 |mov dword ptr [4041A0], ecx
00401701 |.^ 7C E9 \jl short <loc_4016EC> ; [4041A0] + 12位向后各位与0x30的差 -> 第一个终值
00401703 |. 8B06 mov eax, dword ptr [esi] ; MCode
00401705 |. 8B15 9C414000 mov edx, dword ptr [40419C] ; 1F
0040170B |. 0FBE48 0A movsx ecx, byte ptr [eax+A] ; MCode取11位 (5)
0040170F |. 8D440A 2A lea eax, dword ptr [edx+ecx+2A] ; 0x1F+11位ASC+0x2A=7E
00401713 |. A3 9C414000 mov dword ptr [40419C], eax ; 7E
00401718 |. 8B0E mov ecx, dword ptr [esi] ; MCode
0040171A |. 99 cdq
0040171B |. 0FBE49 0B movsx ecx, byte ptr [ecx+B] ; MCode取12位 (2 -> ASC = 32)
0040171F |. 83E9 30 sub ecx, 30 ; -0x30 = 2
00401722 |. F7F9 idiv ecx ; 7E/2
00401724 |. 8BF0 mov esi, eax ; 3F -> 第二个终值
00401726 |. FF15 84314000 call dword ptr [<&MSVCRT.clock>] ; msvcrt.clock
0040172C |. 8B0D A0414000 mov ecx, dword ptr [4041A0]
00401732 |. 3BCE cmp ecx, esi ; 终值1,2比较
00401734 |. 5E pop esi
00401735 |. 75 3B jnz short <loc_401772>
00401737 |. 80FB 01 cmp bl, 1
0040173A |. 75 36 jnz short <loc_401772>
0040173C |. 8B7C24 18 mov edi, dword ptr [esp+18]
00401740 |. 6A 01 push 1
00401742 |. 2BC7 sub eax, edi
00401744 |. 8BC8 mov ecx, eax
00401746 |. B8 D34D6210 mov eax, 10624DD3
0040174B |. F7E9 imul ecx
0040174D C1FA 06 sar edx, 6
00401750 8BC2 mov eax, edx
00401752 C1E8 1F shr eax, 1F
00401755 03D0 add edx, eax
00401757 F7DA neg edx
00401759 1BD2 sbb edx, edx
0040175B 42 inc edx
0040175C |. 8915 78414000 mov dword ptr [404178], edx
00401762 >|> 6A 01 push 1 ; loc_401762
00401764 |. 8BCD mov ecx, ebp
00401766 |. E8 4B0A0000 call <CWnd::GetDlgItem(int)> ; jmp 到 MFC42.#3092
0040176B |. 8BC8 mov ecx, eax
0040176D |. E8 380A0000 call <CWnd::EnableWindow(int)> ; jmp 到 MFC42.#2642
00401772 >|> 5F pop edi ; loc_401772
00401773 |. 5D pop ebp
00401774 |. 5B pop ebx
00401775 |. 83C4 10 add esp, 10
00401778 \. C3 retn
附,由于MCode不固定,这里可以将程序补丁使其产生固定值,另一方面,那两个全局变量在经过注册流程后会发生改变
这里我们同样将其手动初始化
我的方法很简陋,大家可自行解决
0040165A /E9 6F0F0000 jmp 004025CE
004025CE E8 07FCFFFF call <CWnd::GetWindowTextA(CString &)> ; jmp 到 MFC42.#3874
004025D3 C701 33323432 mov dword ptr [ecx], 32343233
004025D9 C741 04 30373>mov dword ptr [ecx+4], 32313730
004025E0 C741 08 35353>mov dword ptr [ecx+8], 32353535
004025E7 C741 0C 2D323>mov dword ptr [ecx+C], 3131322D
004025EE C741 10 31000>mov dword ptr [ecx+10], 31
004025F5 C705 9C414000>mov dword ptr [40419C], 1F
004025FF C705 A0414000>mov dword ptr [4041A0], 12
00402609 ^ E9 51F0FFFF jmp 0040165F
要得到一个注册码
1. 0x3F-0x12= 0x2D
2. 使11位向后各位-0x30值累加得0x2D
这里的33333333399即符合条件
拼合前值得到
00B0000000033333333399
问题
最后,我们尝试填写注册码进去,发现在OD中,程序成功走到了注册流程最后
mov dword ptr [404178], edx
这里404178为成功标示,并于
0040176B |. 8BC8 mov ecx, eax
0040176D |. E8 380A0000 call <CWnd::EnableWindow(int)> ; jmp 到 MFC42.#2642
这里激活了OK按钮,但是程序却不能最终激活
这里看下发现某Clock函数在检测执行时间...
这里下断EnableWindow,很快来到
004017A0 6A 00 push 0
004017A2 . 6A 01 push 1
004017A4 . E8 0D0A0000 call <CWnd::GetDlgItem(int)> ; jmp 到 MFC42.#3092
004017A9 . 8BC8 mov ecx, eax
004017AB . E8 FA090000 call <CWnd::EnableWindow(int)> ; jmp 到 MFC42.#2642
004017B0 . C3 retn
直接在函数头C3
至此,OK激活完成,功能正常
如果你把断点全部取消也可解决此问题
这里提示下
程序在接受注册码10位后才会激活流程2,直接复制入注册码的话会需要再复制一遍
也可复制前21位再手动输入1位即可
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!