聚星亭

吾笨笨且懒散兮 急须改之而奋进

  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  2 随笔 :: 3 文章 :: 3 评论 :: 0 Trackbacks
不知道CM的分析应该发到哪个版块,本来以为是CM和RM的那个版块,可是上面写的是活动版块,不敢乱发,就发到这个我比较熟悉的版块吧,如果发错位置了,就麻烦斑斑大哥代劳转移一下!谢谢!

首先感谢PPT同学给我了这个CM,很有意思,它的具体要求如下:

这里是引用了它原先的文字
Hi! There!..It's my first keygenme (crackme). Here are some tasks you should do:
-------------------------------------------------------------------------
1. To start searching a key for your name, you need to patch something to enter 
   more than 1 symbol, (Patch it to 80 symbols) (no jne, je, & etc jump patching.)

2. Find key generator solution, and write a keygen

3. Patch it, to stop closing after the registration procedure
   (not allowed to patch jne, je, & etc "jump patching". (e.g: "jne" -> "je")
-------------------------------------------------------------------------
Exe file is not protected, and it is very easy to find key & to write a 
keygen. But no built-in keygens (injections). As u can see I made it for newbies...

__________________
P.s: Don't forget what i said: "no jump patching". :) 
Have fun!!! ;) THanx to crackmes.de

好了,不多说了,进入正题,应该说这个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个小时,希望这个能对大家有所帮助!

附件在这里下
点击这里下载我的附件


posted on 2008-11-01 12:22 美丽の破船 阅读(139) 评论(0)  编辑 收藏 引用 所属分类: 软件安全类
只有注册用户登录后才能发表评论。