不知道CM的分析应该发到哪个版块,本来以为是CM和RM的那个版块,可是上面写的是活动版块,不敢乱发,就发到这个我比较熟悉的版块吧,如果发错位置了,就麻烦斑斑大哥代劳转移一下!谢谢!
首先感谢PPT同学给我了这个CM,很有意思,它的具体要求如下:
好了,不多说了,进入正题,应该说这个CM确实很容易,完全的明码,根本没有隐藏!很适合象我这样的新人!而且它也确实很有意思!
刚拿到这个CM的时候,直接用OD打开,这个小程序基本上就一目了然了!顺手在GetDlgItemTextA上F2,F9,可是他居然断不下来!
基本上到了DialogBoxParamA这个函数就飞了……
想必没有人会不知道DialogBoxParamA这个函数是干什么的吧!
用资源编辑器找到两个文本框的ID:1001,1002,转换成HEX就是3E9,3EA
1.text:0040102E ; =============== S U B R O U T I N E =======================================
2.text:0040102E
3.text:0040102E ; Attributes: bp-based frame
4.text:0040102E
5.text:0040102E ; INT_PTR __stdcall DialogFunc(HWND, UINT, WPARAM, LPARAM)
6.text:0040102E DialogFunc proc near ; DATA XREF: start+13o
7.text:0040102E
8.text:0040102E hDlg = dword ptr 8
9.text:0040102E arg_4 = dword ptr 0Ch
10.text:0040102E arg_8 = dword ptr 10h
11.text:0040102E
12.text:0040102E push ebp
13.text:0040102F mov ebp, esp
14.text:00401031 mov eax, [ebp+arg_4]
15.text:00401034 cmp eax, 110h
16.text:00401039 jnz short loc_401089
17.text:0040103B mov eax, [ebp+hDlg]
18.text:0040103E mov hDlg, eax
19.text:00401043 push 3E9h ; nIDDlgItem
20.text:00401048 push [ebp+hDlg] ; hDlg
21.text:0040104B call GetDlgItem
22.text:00401050 mov hWnd, eax
23.text:00401055 xor eax, eax
24.text:00401057 push 3EAh ; nIDDlgItem
25.text:0040105C push [ebp+hDlg] ; hDlg
26.text:0040105F call GetDlgItem
27.text:00401064 mov dword_403210, eax
28.text:00401069 xor eax, eax
29.text:0040106B call sub_40130D
30.text:00401070 push 13h ; uFlags
31.text:00401072 push 0 ; cy
32.text:00401074 push 0 ; cx
33.text:00401076 push 0 ; Y
34.text:00401078 push 0 ; X
35.text:0040107A push 0FFFFFFFFh ; hWndInsertAfter
36.text:0040107C push [ebp+hDlg] ; hWnd
37.text:0040107F call SetWindowPos
38.text:00401084 jmp loc_401271
39
GetDlgItem到两个文本框以后,都会跟进
.text:0040106B call sub_40130D 这个函数里面去
我们也进去看看吧~
1.text:0040130D ; =============== S U B R O U T I N E =======================================
2.text:0040130D
3.text:0040130D
4.text:0040130D sub_40130D proc near ; CODE XREF: DialogFunc+3Dp
5.text:0040130D push eax
6.text:0040130E xor eax, eax
7.text:00401310 mov eax, hDlg
8.text:00401315 push 0 ; lParam
9.text:00401317 push 1 ; wParam
10.text:00401319 push 0C5h ; Msg
11.text:0040131E push 3E9h ; nIDDlgItem
12.text:00401323 push eax ; hDlg
13.text:00401324 call SendDlgItemMessageA
14.text:00401329 xor eax, eax
15.text:0040132B mov eax, hDlg
16.text:00401330 push 0 ; lParam
17.text:00401332 push 1 ; wParam
18.text:00401334 push 0C5h ; Msg
19.text:00401339 push 3EAh ; nIDDlgItem
20.text:0040133E push eax ; hDlg
21.text:0040133F call SendDlgItemMessageA
22.text:00401344 pop eax
23.text:00401345 retn
24.text:00401345 sub_40130D endp
25
看到了吧,这里向两个文本框发送消息了做文本个数的限制了,要取消它,就把上面的两个PUSH 1改成PUSH 50就OK了!
这样输入字符字数的限制就取消了!
再看取消信息提示后失败的方法,找到MessageBoxA我们来看看(它有两个MessageBoxA,我想大家不会找错的!)
1.text:0040111B ; ---------------------------------------------------------------------------
2.text:0040111B
3.text:0040111B loc_40111B: ; CODE XREF: DialogFunc+A8j
4.text:0040111B ; DialogFunc+ADj
5.text:0040111B xor eax, eax
6.text:0040111D cmp ecx, 1
7.text:00401120 jnz short loc_401130
8.text:00401122 xor ecx, ecx
9.text:00401124 mov ecx, offset aCongratulation ; "Congratulations!!!"
10.text:00401129 mov eax, offset aWellDonePlease ; "Well, done, please, submit your solutio"
11.text:0040112E jmp short loc_40113C
12.text:00401130 ; ---------------------------------------------------------------------------
13.text:00401130
14.text:00401130 loc_401130: ; CODE XREF: DialogFunc+F2j
15.text:00401130 xor ecx, ecx
16.text:00401132 mov eax, offset aSomethingWrong ; "Something wrong with serial, or name."
17.text:00401137 mov ecx, offset aError__ ; "Error.."
18.text:0040113C
19.text:0040113C loc_40113C: ; CODE XREF: DialogFunc+100j
20.text:0040113C push 0 ; uType
21.text:0040113E push ecx ; lpCaption
22.text:0040113F push eax ; lpText
23.text:00401140 push [ebp+hDlg] ; hWnd
24.text:00401143 call MessageBoxA
25.text:00401148 mov eax, 0
26.text:0040114D cmp eax, 0
27.text:00401150 jnz loc_401255
28.text:00401156 jmp loc_exit
29
我想大家在看到这个函数后面的代码的时候,谁都不会没有感觉的:
1.text:00401148 mov eax, 0
2.text:0040114D cmp eax, 0
3.text:00401150 jnz loc_401255
4
这里的JNZ基本上就是被NOP掉了,怎么改才能让它正常也不用我说了吧,把赋值的0改成1就OK了~
好了,下面我们来分析一下他的这个程序的算法流程!
看这里:
1.text:004010F1 mov eax, offset aISaidItIsVeryE ; "=== I said it is very easy, for newbies"
2.text:004010F6 xor eax, eax
3.text:004010F8 xor ecx, ecx
4.text:004010FA xor ebx, ebx
5.text:004010FC xor edx, edx
6
7.text:004010FE
8.text:004010FE loc_4010FE: ; CODE XREF: DialogFunc+150j
9.text:004010FE inc ebx ;这里把EBX+1
10.text:004010FF push ebx
11.text:00401100 push hWnd ; hWnd
12.text:00401106 call GetWindowTextLengthA
13.text:0040110B xor ecx, ecx
14.text:0040110D mov ebx, eax
15.text:0040110F mov eax, offset Buffer
16.text:00401114 call sub_Name ;这里检测我们输入的用户名
17.text:00401119 jmp short loc_40115B
18
我们跟进这个sub_Name函数看看吧!
1{
2 .text:004012D1 ; =============== S U B R O U T I N E =======================================
3 .text:004012D1
4 .text:004012D1
5 .text:004012D1 sub_Name proc near ; CODE XREF: DialogFunc+E6p
6 .text:004012D1 ; sub_Name +17j
7 .text:004012D1 mov dl, [eax]
8 .text:004012D3 imul ecx, 48h
9 .text:004012D6 sub ecx, edx
10 .text:004012D8 sub ecx, 6Fh
11 .text:004012DB mov edx, ecx
12 .text:004012DD xor ecx, 0BACAFh
13 .text:004012E3 inc eax
14 .text:004012E4 dec ebx
15 .text:004012E5 cmp ebx, 0
16 .text:004012E8 jnz short sub_4012D1
17 .text:004012EA retn
18 .text:004012EA sub_Name endp
19}
继续,我们来到loc_40115B来看一下:
1.text:0040115B ; ---------------------------------------------------------------------------
2.text:0040115B
3.text:0040115B loc_40115B: ; CODE XREF: DialogFunc+EBj
4.text:0040115B pop ebx
5.text:0040115C cmp ebx, 2 ;看到没?如果处理用户名时这里是1,处理完了程序就再跳回loc_4010FE把EBX+1再就处理注册码了!
6.text:0040115F jz short loc_401183
7.text:00401161 xor edx, edx
8.text:00401163 mov dword_403218, ecx
9.text:00401169 xor eax, eax
10.text:0040116B push offset pcbBuffer ; pcbBuffer
11.text:00401170 push offset Buffer ; lpBuffer
12.text:00401175 call GetUserNameA
13.text:0040117A xor edx, edx
14.text:0040117C xor ecx, ecx
15.text:0040117E jmp loc_4010FE
16:
好我们到loc_401183看看:
1; ---------------------------------------------------------------------------
2.text:00401183
3.text:00401183 loc_401183: ; CODE XREF: DialogFunc+131j
4.text:00401183 xor edx, edx
5.text:00401185 mov dword_40321C, ecx
6.text:0040118B push dword_40321C
7.text:00401191 push dword_403218
8.text:00401197 call sub_40127A
9
来到sub_40127A,我不多注释了,大家可以边用OD跟这个CM边看我帖出来的代码,这里程序条理代码如下:
1{
2 .text:0040127A
3 .text:0040127A ; =============== S U B R O U T I N E =======================================
4 .text:0040127A
5 .text:0040127A ; Attributes: bp-based frame
6 .text:0040127A
7 .text:0040127A sub_40127A proc near ; CODE XREF: DialogFunc+169p
8 .text:0040127A
9 .text:0040127A arg_0 = dword ptr 8
10 .text:0040127A arg_4 = dword ptr 0Ch
11 .text:0040127A
12 .text:0040127A push ebp
13 .text:0040127B mov ebp, esp
14 .text:0040127D xor eax, eax
15 .text:0040127F xor ebx, ebx
16 .text:00401281 mov eax, [ebp+arg_0]
17 .text:00401284 mov ebx, [ebp+arg_4]
18 .text:00401287 mov edx, eax
19 .text:00401289 xor edx, ebx
20 .text:0040128B xor edx, 0FFACh
21 .text:00401291 xor ebx, 553h
22 .text:00401297 add eax, ebx
23 .text:00401299 add ebx, edx
24 .text:0040129B dec ebx
25 .text:0040129C add eax, ebx
26 .text:0040129E leave
27 .text:0040129F retn 8
28 .text:0040129F sub_40127A endp
29 .text:0040129F
30}
31.text:0040119C mov dword_403220, eax
32.text:004011A1 call sub_401346
33{
34 .text:00401346
35 .text:00401346 ; =============== S U B R O U T I N E =======================================
36 .text:00401346
37 .text:00401346
38 .text:00401346 sub_401346 proc near ; CODE XREF: DialogFunc+173p
39 .text:00401346 mov eax, dword_40321C
40 .text:0040134B mov ebx, dword_403218
41 .text:00401351 cmp eax, ebx
42 .text:00401353 jnz short locret_401363
43 .text:00401355 xor ebx, 8Eh
44 .text:0040135B add ebx, eax
45 .text:0040135D mov dword_403218, ebx
46 .text:00401363
47 .text:00401363 locret_401363: ; CODE XREF: sub_401346+Dj
48 .text:00401363 retn
49 .text:00401363 sub_401346 endp
50 .text:00401363
51
52}
53
54.text:004011A6 push dword_40321C
55.text:004011AC push offset unk_403224
56.text:004011B1 call sub_4012A2
57{
58 .text:004012A2
59 .text:004012A2 ; =============== S U B R O U T I N E =======================================
60 .text:004012A2
61 .text:004012A2 ; Attributes: bp-based frame
62 .text:004012A2
63 .text:004012A2 sub_4012A2 proc near ; CODE XREF: DialogFunc+183p
64 .text:004012A2 ; DialogFunc+199p
65 .text:004012A2
66 .text:004012A2 arg_0 = dword ptr 8
67 .text:004012A2 arg_4 = dword ptr 0Ch
68 .text:004012A2
69 .text:004012A2 push ebp
70 .text:004012A3 mov ebp, esp
71 .text:004012A5 mov esi, [ebp+arg_0]
72 .text:004012A8 add esi, 8
73 .text:004012AB mov eax, [ebp+arg_4]
74 .text:004012AE mov ecx, 10h
75 .text:004012B3 xor ebx, ebx
76 .text:004012B5
77 .text:004012B5 loc_4012B5: ; CODE XREF: sub_4012A2+29j
78 .text:004012B5 xor edx, edx
79 .text:004012B7 div ecx
80 .text:004012B9 dec esi
81 .text:004012BA add dl, 30h
82 .text:004012BD cmp dl, 3Ah
83 .text:004012C0 jb short loc_4012C5
84 .text:004012C2 add dl, 7
85 .text:004012C5
86 .text:004012C5 loc_4012C5: ; CODE XREF: sub_4012A2+1Ej
87 .text:004012C5 mov [esi], dl
88 .text:004012C7 inc ebx
89 .text:004012C8 cmp ebx, 8
90 .text:004012CB jnz short loc_4012B5
91 .text:004012CD leave
92 .text:004012CE retn 8
93 .text:004012CE sub_4012A2 endp
94 .text:004012CE
95}
96.text:004011A6 push dword_40321C
97.text:004011AC push offset unk_403224
98.text:004011B1 call sub_4012A2
99.text:004011B6 mov eax, offset unk_403224
100.text:004011BB add eax, 8
101.text:004011BE push dword_403220
102.text:004011C4 lea eax, [eax]
103.text:004011C6 push eax
104.text:004011C7 call sub_4012A2
105.text:004011CC mov eax, offset unk_403224
106.text:004011D1 add eax, 10h
107.text:004011D4 push dword_403218
108.text:004011DA lea eax, [eax]
109.text:004011DC push eax
110.text:004011DD call sub_4012A2
111.text:004011E2 mov eax, dword_403210
112
在这里反复的调用sub_4012A2函数,只要稍微用OD跟一下,我想即使不懂汇编也能明白,它这是在把我们在上面三个函数中得到的值连接起来!
下面的代码就很明显了,获取我们输入的注册码!
1.text:004011E7 push eax ; hWnd
2.text:004011E8 call GetWindowTextLengthA ;获取我们输入的注册码的长度,
3.text:004011ED mov ecx, 0
4.text:004011F2 cmp eax, 18h
5.text:004011F5 jnz loc_40111B ;如果小于24位,就直接提示失败了!
6.text:004011FB inc eax
7.text:004011FC push eax ; cchMax
8.text:004011FD push offset String ; lpString
9.text:00401202 push 3EAh ; nIDDlgItem
10.text:00401207 push [ebp+hDlg] ; hDlg
11.text:0040120A call GetDlgItemTextA ;获取我们输入的假码
12.text:0040120F mov eax, offset String
13.text:00401214 call sub_4012EB ;这里是转换得到真码了!我们跟进这个CALL看看去,双击sub_4012EB
14
15真正出现注册码的CALL在这里sub_4012EB:
16{
17 .text:004012EB
18 .text:004012EB ; =============== S U B R O U T I N E =======================================
19 .text:004012EB
20 .text:004012EB
21 .text:004012EB sub_4012EB proc near ; CODE XREF: DialogFunc+1E6p
22 .text:004012EB mov edx, offset unk_SN
23 .text:004012F0 add edx, 4
24 .text:004012F3 mov byte ptr [edx], 2Dh
25 .text:004012F6 add edx, 0Ah
26 .text:004012F9 mov byte ptr [edx], 2Dh
27 .text:004012FC mov edx, offset unk_SN
28 .text:00401301 mov byte ptr [edx], 4Bh
29 .text:00401304 inc edx
30 .text:00401305 mov byte ptr [edx], 4Fh
31 .text:00401308 inc edx
32 .text:00401309 mov byte ptr [edx], 53h
33 .text:0040130C retn
34 .text:0040130C sub_4012EB endp
35}
36
好了,知道了这个,下面就剩下写注册机了~
怎么给程序打补丁我就不说了,如果大家有不知道的可以看我的源程序!
这里我只列出我的KEYGEN的算法部分!(程序本来就是用MASM32写的,所以我也就不翻译成C了,直接用内联汇编来写了,代码直接用IDA考出来时候,省时省力,嘿嘿~!)
1DWORD CKeygenDlg::CLName(char *Name)
2{
3 DWORD result;
4 int len = strlen(Name);
5 _asm{
6 mov eax,Name
7 mov ebx,len
8 xor edx,edx
9 xor ecx,ecx
10 L000:
11 mov dl, byte ptr [eax]
12 imul ecx, ecx, 0x48
13 sub ecx, edx
14 sub ecx, 0x6F
15 mov edx, ecx
16 xor ecx, 0x0BACAF
17 inc eax
18 dec ebx
19 cmp ebx, 0
20 jnz L000
21 mov result,ecx
22 }
23 return result;
24}
25
26DWORD CKeygenDlg::CkSn1(DWORD code)
27{
28 DWORD result;
29 _asm{
30 xor eax, eax
31 xor ebx, ebx
32 mov eax, code
33 mov ebx, code
34 mov edx, eax
35 xor edx, ebx
36 xor edx, 0x0FFAC
37 xor ebx, 0x553
38 add eax, ebx
39 add ebx, edx
40 dec ebx
41 add eax, ebx
42 mov result,eax
43 }
44 return result;
45}
46
47DWORD CKeygenDlg::CkSn2(DWORD code)
48{
49 DWORD result;
50 _asm{
51 mov eax, code
52 mov ebx, code
53 xor ebx, 0x8E
54 add ebx, eax
55 mov result, ebx
56 }
57 return result;
58}
59
60void CKeygenDlg::CkSn3(char *_addr,DWORD _code)
61{
62 itoa(_code,_addr,16); //这个用汇编反而麻烦了,直接用C就OK了~
63}
64
65char * CKeygenDlg::GetSerial(DWORD _addr)
66{
67 char *Serial = NULL;
68 _asm{
69 mov edx, _addr
70 add edx, 4
71 mov byte ptr [edx], 0x2D
72 add edx, 0x0A
73 mov byte ptr [edx], 0x2D
74 mov edx, _addr
75 mov byte ptr [edx], 0x4B
76 inc edx
77 mov byte ptr [edx], 0x4F
78 inc edx
79 mov byte ptr [edx], 0x53
80 }
81 Serial = (char *)_addr;
82 return Serial;
83}
84
85
86
87void CKeygenDlg::OnKey()
88{
89 //查找CM的窗口,确定程序是否已经启动!
90
91……(省略,详见附件)
92 //先PATCH掉它对输入字符的个数限制
93
94……(省略,详见附件)
95
96 //再PATCH掉它提示后就退出
97
98……(省略,详见附件)
99
100 //再写一下它的算法了
101
102 const int nBufSize = 128;
103 TCHAR chBuf[nBufSize];
104 ZeroMemory(chBuf,nBufSize);
105 DWORD t_rst;
106 DWORD dwRet = nBufSize;
107 if (::GetUserName(chBuf,&dwRet))
108 {
109 DWORD tmpsn = 0;
110 char *tmpserial = new char[24];
111
112 m_Name = chBuf;
113 tmpsn = CLName(chBuf); //这里得到0x30A2E5B8
114 CkSn3(tmpserial,tmpsn);
115 tmpserial += 8;
116 t_rst = CkSn1(tmpsn); //得到0x91E9A739
117 CkSn3(tmpserial,t_rst);
118 tmpserial += 8;
119 t_rst = CkSn2(tmpsn); //得到0x6145CAEE
120 CkSn3(tmpserial,t_rst);
121 tmpserial -= 16;
122 m_Serial = GetSerial((DWORD )tmpserial);
123 }
124 m_Serial.MakeUpper();
125 UpdateData(FALSE);
126}
127
哈哈,第一次用IDA分析程序,真的很别扭,但是,不得不承认IDA功能的强大!
这个程序我从分析到写KEYGEN,一共用了将近4个小时,希望这个能对大家有所帮助!