首页
社区
课程
招聘
[原创]逆向分析RE-Trace Crackme by Crudd^RET 对抗狡猾的SMC及其注册机编写
2013-2-23 19:56 7457

[原创]逆向分析RE-Trace Crackme by Crudd^RET 对抗狡猾的SMC及其注册机编写

fob 活跃值
5
2013-2-23 19:56
7457
【文章标题】: 逆向分析RE-Trace Crackme by Crudd^RET 对抗狡猾的SMC及其注册机编写
【文章作者】: 返璞归真
【软件大小】: 9.50kb
【下载地址】: Reverse RE-Trace.rar
【加壳方式】: UPolyX v0.5
【编写语言】: MASM32 / TASM32
【操作平台】: WinALL
【软件介绍】: ReTeam的一个cm
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
引言.
本文主要是分析这个cm的Serial前8位为什么是0C030400的具体过程,以及算法分析。大家可以下载分析下,非常有意思,当然大牛可以直接无视

【详细过程】
  

  
  加了压缩壳。怎么搞都可以,直接来到OEP
  00401031 >/$  6A 00         push    0x0                                                         ; /pModule = NULL
  00401033  |.  E8 94040000   call    <jmp.&KERNEL32.GetModuleHandleA>                            ; \GetModuleHandleA
  00401038  |.  A3 A8304000   mov     dword ptr [0x4030A8], eax
  0040103D  |.  6A 00         push    0x0                                                         ; /lParam = NULL
  0040103F  |.  68 5C104000   push    0040105C                                                    ; |DlgProc = RE-Trace.0040105C
  00401044  |.  6A 00         push    0x0                                                         ; |hOwner = NULL
  00401046  |.  68 A1304000   push    004030A1                                                    ; |pTemplate = "RETWIN"
  0040104B  |.  FF35 A8304000 push    dword ptr [0x4030A8]                                        ; |hInst = NULL
  00401051  |.  E8 4C040000   call    <jmp.&USER32.DialogBoxParamA>                               ; \DialogBoxParamA
  00401056  |.  50            push    eax                                                         ; /ExitCode
  00401057  \.  E8 6A040000   call    <jmp.&KERNEL32.ExitProcess>                                 ; \ExitProcess

  
  
  --------------------------------------窗体过程函数----------------------------------------------------
  0040105C  /.  55            push    ebp
  0040105D  |.  8BEC          mov     ebp, esp
  0040105F  |.  817D 0C 10010>cmp     dword ptr [ebp+0xC], 0x110
  ;WM_InitDialog
  00401066  |.  75 13         jnz     short 0040107B
 

  -------------------------------------InitDialog消息处理----------------------------------------------
  00401068  |.  FF35 A8304000 push    dword ptr [0x4030A8]
  0040106E  |.  FF75 08       push    dword ptr [ebp+0x8]
  00401071  |.  E8 77020000   call    004012ED
 

  
  来看下004012ED里做了些什么
  
  		004012ED  /$  55            push    ebp
  		004012EE  |.  8BEC          mov     ebp, esp
  		004012F0  |.  60            pushad
  		004012F1  |.  8D35 08324000 lea     esi, dword ptr [0x403208]
  		004012F7  |.  8D3D 95134000 lea     edi, dword ptr [0x401395]
  		004012FD  |.  B9 20000000   mov     ecx, 0x20
  		00401302  |.  F3:A4         rep     movs byte ptr es:[edi], byte ptr [esi]
  		;进行0x20字节的拷贝,SMC?看下,0040130A  call    00401395,显然隐藏着巨大的阴谋
  			;我们去看下0x403208和0x401395
  			----------------------0x403208处代码-----------------------------
  			00403208    90              nop
  			00403209    60              pushad
  			0040320A    8D3D E6134000   lea     edi, dword ptr [0x4013E6]
  			00403210    B9 70000000     mov     ecx, 0x70
  			00403215    F3:A4           rep     movs byte ptr es:[edi], byte ptr>
  			00403217    61              popad
  			00403218    C3              retn
  			----------------------0x401395处代码-----------------------------
  			00401395  /$  60            pushad
  			00401396  |.  6A 21         push    0x21
  			00401398  |.  6A 00         push    0x0                              ; /Count = 0x0
  			0040139A  |.  A0 C0304000   mov     al, byte ptr [0x4030C0]          ; |
  			0040139F  |.  66:0FB6C0     movzx   ax, al                           ; |
  			004013A3  |.  66:50         push    ax                               ; |Buffer
  			004013A5  |.  FF35 13314000 push    dword ptr [0x403113]             ; |hWnd = NULL
  			004013AB  |.  E8 04010000   call    <jmp.&USER32.GetWindowTextA>     ; \GetWindowTextA
  			004013B0  |.  6A 21         push    0x21
  			004013B2  |.  6A 00         push    0x0                              ; /Count = 0x0
  			004013B4  |.  A0 EA304000   mov     al, byte ptr [0x4030EA]          ; |
  			004013B9  |.  66:0FB6C0     movzx   ax, al                           ; |
  			004013BD  |.  66:50         push    ax                               ; |Buffer
  			004013BF  |.  FF35 17314000 push    dword ptr [0x403117]             ; |hWnd = NULL
  			004013C5  |.  E8 EA000000   call    <jmp.&USER32.GetWindowTextA>     ; \GetWindowTextA
  			004013CA  |.  6A 21         push    0x21
  			004013CC  |.  6A 00         push    0x0                              ; /Count = 0x0
  			004013CE  |.  A0 D5304000   mov     al, byte ptr [0x4030D5]          ; |
  			004013D3  |.  66:0FB6C0     movzx   ax, al                           ; |
  			004013D7  |.  66:50         push    ax                               ; |Buffer
  			004013D9  |.  FF35 1B314000 push    dword ptr [0x40311B]             ; |hWnd = NULL
  			004013DF  |.  E8 D0000000   call    <jmp.&USER32.GetWindowTextA>     ; \GetWindowTextA
  			004013E4  |.  61            popad
  			004013E5  \.  C3            retn
  			----------------------------------------------------------------
  			0x403208代码正好是0x20 ,功能是对0x4013E6处代码进行替换。然而0x401395可以看出是获取用户输入信息的,把这里覆盖了?后面怎么获取.
  			后来发现压根就没用到这些代码,而是作者耍调皮了。
  		00401304  |.  8D35 23314000 lea     esi, dword ptr [0x403123]
  		0040130A  |.  E8 86000000   call    00401395
  		;似乎看到了什么,此时00401395代码已经变成了
  			    nop
  			    pushad
  			    lea     edi, dword ptr [0x4013E6]
  			    mov     ecx, 0x70
  			    rep     movs byte ptr es:[edi], byte ptr [esi]
  			    popad
  			    retn
  	    进行一次SMC将0x403123代码填入到0x4013E6中,看下0x403123
  				00403123    90              nop
  				00403124    58              pop     eax
  				00403125    5B              pop     ebx
  				00403126    891D AC304000   mov     dword ptr [0x4030AC], ebx
  				0040312C    50              push    eax
  				0040312D    68 C0304000     push    004030C0
  				00403132    6A 14           push    0x14
  				00403134    6A 0D           push    0xD
  				00403136    FF35 13314000   push    dword ptr [0x403113]
  				0040313C    FF15 9D304000   call    dword ptr [0x40309D]            
  				00403142    A3 FF304000     mov     dword ptr [0x4030FF], eax
  				00403147    68 D5304000     push    004030D5
  				0040314C    6A 14           push    0x14
  				0040314E    6A 0D           push    0xD
  				00403150    FF35 17314000   push    dword ptr [0x403117]
  				00403156    FF15 9D304000   call    dword ptr [0x40309D]             
  				0040315C    A3 03314000     mov     dword ptr [0x403103], eax
  				00403161    68 EA304000     push    004030EA
  				00403166    6A 14           push    0x14
  				00403168    6A 0D           push    0xD
  				0040316A    FF35 1B314000   push    dword ptr [0x40311B]
  				00403170    FF15 9D304000   call    dword ptr [0x40309D]             
  				00403176    A3 07314000     mov     dword ptr [0x403107], eax
  				0040317B    C3              retn
  				0x40309D应该是SendMessageA指针
  				0xD正好是WM_GETTEXT,这里就是获取用户输入信息的正真的地方了。显然0x4030C0,0x4030D5,0x4030EA为存储用户输入信息的地址
  				0x403113,0x403117,0x40311B是存放窗体上三个Edit 句柄的地址,然后获取的最大长度均为0x14,那么根据常理可以推出
  				004030C0存放用户名.004030D5为Group.004030EA为Serial,0x4030FF,0x403103,0x403107存放实际获取长度
  
  -----------------------备忘
  代码SMC部分 0x403123 功能为获取用户输入信息
  用户名存储位置0x4030C0
  
  
  		0040130F  |.  6A 64         push    0x64                             ; /ControlID = 64 (100.)
  		00401311  |.  FF75 08       push    dword ptr [ebp+0x8]              ; |hWnd
  		00401314  |.  E8 95010000   call    <jmp.&USER32.GetDlgItem>         ; \GetDlgItem
  		00401319  |.  A3 13314000   mov     dword ptr [0x403113], eax
  		;获取ID为0x64的控件句柄并且存到0x403113中.正式上面推断的用户名edit。
  		0040131E  |.  6A 65         push    0x65                             ; /ControlID = 65 (101.)
  		00401320  |.  FF75 08       push    dword ptr [ebp+0x8]              ; |hWnd
  		00401323  |.  E8 86010000   call    <jmp.&USER32.GetDlgItem>         ; \GetDlgItem
  		00401328  |.  A3 17314000   mov     dword ptr [0x403117], eax
  
  		0040132D  |.  6A 66         push    0x66                             ; /ControlID = 66 (102.)
  		0040132F  |.  FF75 08       push    dword ptr [ebp+0x8]              ; |hWnd
  		00401332  |.  E8 77010000   call    <jmp.&USER32.GetDlgItem>         ; \GetDlgItem
  		00401337  |.  A3 1B314000   mov     dword ptr [0x40311B], eax
  
  		0040133C  |.  68 81304000   push    00403081                         ; /FileName = "User32.dll"
  		00401341  |.  E8 9E010000   call    <jmp.&KERNEL32.LoadLibraryA>     ; \LoadLibraryA
  		00401346  |.  A3 99304000   mov     dword ptr [0x403099], eax
  		0040134B  |.  68 8C304000   push    0040308C                         ; /ProcNameOrOrdinal = "SendMessageA"
  		00401350  |.  FF35 99304000 push    dword ptr [0x403099]             ; |hModule = NULL
  		00401356  |.  E8 77010000   call    <jmp.&KERNEL32.GetProcAddress>   ; \GetProcAddress
  		0040135B  |.  A3 9D304000   mov     dword ptr [0x40309D], eax
  		;获取函数入口,存储,和我们之前上面看到的地址一样,验证了我的想法。
  
  		00401360  |.  68 0C304000   push    0040300C                         ; /lParam = 0x40300C
  		00401365  |.  6A 00         push    0x0                              ; |wParam = 0x0
  		00401367  |.  6A 0C         push    0xC                              ; |Message = WM_SETTEXT
  		00401369  |.  FF75 08       push    dword ptr [ebp+0x8]              ; |hWnd
  		0040136C  |.  FF15 9D304000 call    dword ptr [0x40309D]             ; \SendMessageA
  		00401372  |.  68 C8000000   push    0xC8                             ; /RsrcName = 200.
  		00401377  |.  FF75 0C       push    dword ptr [ebp+0xC]              ; |hInst
  		0040137A  |.  E8 3B010000   call    <jmp.&USER32.LoadIconA>          ; \LoadIconA
  		0040137F  |.  50            push    eax                              ; /lParam
  		00401380  |.  6A 01         push    0x1                              ; |wParam = 0x1
  		00401382  |.  68 80000000   push    0x80                             ; |Message = WM_SETICON
  		00401387  |.  FF75 08       push    dword ptr [ebp+0x8]              ; |hWnd
  		0040138A  |.  FF15 9D304000 call    dword ptr [0x40309D]             ; \SendMessageA
  		00401390  |.  61            popad
  		00401391  |.  C9            leave
  		00401392  \.  C2 0800       retn    0x8
    


  -------------------------------------InitDialog消息处理结束----------------------------------------------
  大致做了下面几件事情
  1.获取3个Edit的句柄并且保存下来。
  2.进行了2层SMC,对00401395代码进行了SMC,修改为另一个SMC功能
  使用方法如下
                  lea     esi, dword ptr [xxxxxxx]
                  call    00401395
  将会把xxxxxxxxx处的0x70字节的代码复制到0x4013E6处,那么下面调用Call 0x4013E6实际上调用的是call xxxxxxx处的功能.
  3.获取了User32.dll下的SendMessageA入口地址存在0x40309D处,以备后面的调用
  
  ----------------------------------------------------------------------------------------------------------
  
  00401076  |.  E9 96000000   jmp     00401111
  0040107B  |>  817D 0C 11010>cmp     dword ptr [ebp+0xC], 0x111
  00401082  |.  75 7D         jnz     short 00401101
  ------------------------------------WM_COMMAND消息处理----------------------------------------------------
  00401084  |.  817D 10 E8030>cmp     dword ptr [ebp+0x10], 0x3E8
  ;按下了check按钮
  0040108B  |.  75 5A         jnz     short 004010E7
  0040108D  |.  60            pushad
  0040108E  |.  FF75 08       push    dword ptr [ebp+0x8]
  00401091  |.  E8 50030000   call    004013E6
  ;又看到了熟悉的0x4013E6,不过根据程序流程,目前的功能应该是0x403123的功能(获取用户输入信息,窗体句柄和SendMessageA函数入口已经在InitDialog中
  获取过了,所以不用担心出错)
  ;获取用户信息完毕了,那些变量就被填入的具体的数据。

  00401096  |.  8D35 7C314000 lea     esi, dword ptr [0x40317C]
  0040109C  |.  E8 F4020000   call    00401395

  ;看到邪恶的GNV组合了!这次是要让 0x4013E6变成为0x40317C啊,我们来看下0x40317C
   
  	-----------------------0x40317C---------------------------------
  	0040317C    90              nop
  	0040317D    A1 03314000     mov     eax, dword ptr [0x403103]
  	;Group的长度0x403103
  	00403182    BB 04000000     mov     ebx, 0x4
  	00403187    33D2            xor     edx, edx
  	00403189    F7F3            div     ebx
  
  	0040318B    8D05 D8314000   lea     eax, dword ptr [0x4031D8]
  	00403191    40              inc     eax
  	00403192    40              inc     eax
  	;对 Group % 4的进行讨论
  	00403193    83FA 00         cmp     edx, 0x0
  	00403196    74 11           je      short 004031A9
  	00403198    83FA 01         cmp     edx, 0x1
  	0040319B    74 13           je      short 004031B0
  	0040319D    83FA 02         cmp     edx, 0x2
  	004031A0    74 15           je      short 004031B7
  	004031A2    C700 1754A70E   mov     dword ptr [eax], 0xEA75417
  	004031A8    C3              retn
  	004031A9    C700 52455400   mov     dword ptr [eax], 0x544552
  	004031AF    C3              retn
  	004031B0    C700 32303034   mov     dword ptr [eax], 0x34303032
  	004031B6    C3              retn
  	004031B7    C700 53757A79   mov     dword ptr [eax], 0x797A7553
  	004031BD    C3              retn
  		;我们看下0x4031D8
  		004031D8    90              nop
  		004031D9    B8 EFBEADDE     mov     eax, 0xDEADBEEF
  		004031DE    8B0D 0B314000   mov     ecx, dword ptr [0x40310B]
  		004031E4    33C8            xor     ecx, eax
  		;0x4031D8+2处正好是常数0xDEADBEEF的地址,那么个call所做的事情就很清楚了.
  		int mod = strlen( group );
  		if ( mod == 0 ) 
  			mov     dword ptr [0x4031DA], 0x544552
  		else if ( mod == 1 )
  			mov     dword ptr [0x4031DA], 0x34303032
  		else if ( mod == 2  )
  			mov     dword ptr [0x4031DA], 0x797A7553
  		else
  			mov     dword ptr [0x4031DA], 0xEA75417
  		;但是我们发现这个常量也是在代码中的,,作者又调皮了。
  	-----------------------0x40317C----------------------------------
  


  004010A1  |.  E8 40030000   call    004013E6
  ;0x4013E6被上面的GNV组合XX之后实际功能是0x40317C,根据strlen(group)%4来确定0x4031DA的值.
  
  004010A6  |.  E8 6C000000   call    00401117

  
  	-----------------------------Call 0x401117分析-------------------
  	;看到下面提示信息,似乎处理用户名的地方。分析之后并不单单如此。
  	00401117  /$  60            pushad
  	00401118  |.  C705 0F314000>mov     dword ptr [0x40310F], 0x0
  	;标志位清0
  	00401122  |.  8D05 EA304000 lea     eax, dword ptr [0x4030EA]
  	;eax -> &serial[0]
  	00401128  |.  E8 8F000000   call    004011BC
  

                  我们看下0x4011BC这个Call干了些什么
      
  		-----------------------------Call 0x4011BC分析---------------------
  		004011BC  /$  60            pushad
  		004011BD  |.  8BF0          mov     esi, eax
  		004011BF  |.  33C9          xor     ecx, ecx
  		004011C1  |.  33D2          xor     edx, edx
  		004011C3  |>  83F9 06       /cmp     ecx, 0x6
  		004011C6  |.  7F 41         |jg      short 00401209
  		004011C8  |.  8A06          |mov     al, byte ptr [esi]
  		004011CA  |.  3C 30         |cmp     al, 0x30                        
  		004011CC  |.  0F8C 84000000 |jl      00401256
  		004011D2  |.  3C 3A         |cmp     al, 0x3A
  		004011D4  |.  7E 12         |jle     short 004011E8
  		004011D6  |.  3C 41         |cmp     al, 0x41
  		004011D8  |.  7C 7C         |jl      short 00401256
  		004011DA  |.  3C 46         |cmp     al, 0x46
  		004011DC  |.  7E 15         |jle     short 004011F3
  		004011DE  |.  3C 61         |cmp     al, 0x61
  		004011E0  |.  7C 74         |jl      short 00401256
  		004011E2  |.  3C 66         |cmp     al, 0x66
  		004011E4  |.  7E 18         |jle     short 004011FE
  		004011E6  |.  EB 6E         |jmp     short 00401256
  		004011E8  |>  2C 30         |sub     al, 0x30                        
  		004011EA  |.  8AD0          |mov     dl, al
  		004011EC  |.  46            |inc     esi
  		004011ED  |.  C1CA 04       |ror     edx, 0x4
  		004011F0  |.  41            |inc     ecx
  		004011F1  |.^ EB D0         |jmp     short 004011C3
  		004011F3  |>  2C 37         |sub     al, 0x37                        
  		004011F5  |.  8AD0          |mov     dl, al
  		004011F7  |.  46            |inc     esi
  		004011F8  |.  C1CA 04       |ror     edx, 0x4
  		004011FB  |.  41            |inc     ecx
  		004011FC  |.^ EB C5         |jmp     short 004011C3
  		004011FE  |>  2C 57         |sub     al, 0x57                       
  		00401200  |.  8AD0          |mov     dl, al
  		00401202  |.  46            |inc     esi
  		00401203  |.  C1CA 04       |ror     edx, 0x4
  		00401206  |.  41            |inc     ecx
  		00401207  |.^ EB BA         \jmp     short 004011C3
  		;以上是对 byte ptr [esi] ~  byte ptr [esi + 0x6 ]进行处理,将原先的Ascii转换成16进制,并且保存在edx中
  		uint edx;
  		for (int i = 0; i <= 0x6 ; ++i)
  		{
  			if ( str[ i ] >= 0x3A && str[i ] < 0x41 )
  			{
  				str[ i ] -0x30;
  			}
  			else if ( str[ i ] >= 0x41 && str[ i ] < 0x46 )
  			{
  				str[ i ] - 0x41;
  			}
  			else if ( str[ i ] >= 0x61 && str[i ] < 0x66 )
  			{
  				str[ i ] - 0x61;
  			}
  		}
  
  
  		00401209  |>  8A06          mov     al, byte ptr [esi]
  		0040120B  |.  8ACA          mov     cl, dl
  		0040120D  |.  66:C1E1 04    shl     cx, 0x4
  		00401211  |.  3C 30         cmp     al, 0x30                        
  		00401213  |.  7C 41         jl      short 00401256
  		00401215  |.  3C 3A         cmp     al, 0x3A
  		00401217  |.  7E 12         jle     short 0040122B
  		00401219  |.  3C 41         cmp     al, 0x41
  		0040121B  |.  7C 39         jl      short 00401256
  		0040121D  |.  3C 46         cmp     al, 0x46
  		0040121F  |.  7E 19         jle     short 0040123A
  		00401221  |.  3C 61         cmp     al, 0x61
  		00401223  |.  7C 31         jl      short 00401256
  		00401225  |.  3C 66         cmp     al, 0x66
  		00401227  |.  7E 20         jle     short 00401249
  		00401229  |.  EB 2B         jmp     short 00401256
  		0040122B  |>  2C 30         sub     al, 0x30                         
  		0040122D  |.  8AC8          mov     cl, al
  		0040122F  |.  C0E1 04       shl     cl, 0x4
  		00401232  |.  66:C1E9 04    shr     cx, 0x4
  		00401236  |.  8AD1          mov     dl, cl
  		00401238  |.  EB 1C         jmp     short 00401256
  		0040123A  |>  2C 37         sub     al, 0x37                         
  		0040123C  |.  8AC8          mov     cl, al
  		0040123E  |.  C0E1 04       shl     cl, 0x4
  		00401241  |.  66:C1E9 04    shr     cx, 0x4
  		00401245  |.  8AD1          mov     dl, cl
  		00401247  |.  EB 0D         jmp     short 00401256
  		00401249  |>  2C 57         sub     al, 0x57                        
  		0040124B  |.  8AC8          mov     cl, al
  		0040124D  |.  C0E1 04       shl     cl, 0x4
  		00401250  |.  66:C1E9 04    shr     cx, 0x4
  		00401254  |.  8AD1          mov     dl, cl
  		;对str[0x7]进行处理
  		if ( str[ 0x7 ] >=0x30 && str[ 0x7 ] <= 0x3A )
  		{
  			str[ 0x7 ] - 0x30;
  		}
  		else if ( str[ 0x7 ] >=0x41 && str[ 0x7 ] <= 0x46 )
  		{
  			 str[ 0x7 ] - 0x41;
  		}
  		else if ( str[ 0x7 ] >=0x61 && str[ 0x7 ] <= 0x66 )
  		{
  			str[ 0x7 ] - 0x61;
  		}
  		00401256  |>  C1CA 04       ror     edx, 0x4                         
  		00401259  |.  8915 0B314000 mov     dword ptr [0x40310B], edx
  		;将最后的的hex值存入0x40310B中
  		;本函数功能将字符串中的前8个字符(0~9,a~f,A~F)转换成hex,但是转换之后的顺序是颠倒的例如 字符串为 "Ffabcd12345",则转换成 21dcbaff
  		0040125F  |.  61            popad
  		00401260  \.  C3            retn
  		-----------------------------Call 0x4011BC分析结束-------------------
      

  
  
  	0040112D  |.  833D FF304000>cmp     dword ptr [0x4030FF], 0x4
  	;用户名长度是否小于4?小于4的话则弹出提示框
  	00401134  |.  7C 43         jl      short 00401179
  	00401136  |.  833D 07314000>cmp     dword ptr [0x403107], 0x0
  	;输入的Serial是否为空?
  	0040113D  |.  74 71         je      short 004011B0 
  	;上面两个条件都不满足
  	0040113F  |.  8B35 0B314000 mov     esi, dword ptr [0x40310B]
  	;取出Serial转换过的hex值
  	00401145  |.  8D3D 95124000 lea     edi, dword ptr [0x401295]
  	0040114B  |.  83C7 02       add     edi, 0x2
  	0040114E  |.  8937          mov     dword ptr [edi], esi
  	; mov dword ptr[ 0x401297 ],esi 

  	;过去看下,
    

00401295 |. 8D0D 17114000 lea ecx, dword ptr [0x401117]
;老把戏又上演了,0x401297是lea ecx, dword ptr []的取指地址,又进行了SMC。而且SMC的内容和用户输入相关
;那么可以得知,用户输入的内容必须包含一个地址(转成hex后是地址),作者好狡猾~-~。
0040129B |. 33C0 xor eax, eax
00401150 |. E8 0C010000 call 00401261

          ;上面mov     dword ptr [edi], esi 修改的内容恰巧在 00401261函数中。
      
  		---------------------------------0x0401261分析----------------------------
  		00401261  /$  60            pushad
  		00401262  |.  C705 1F314000>mov     dword ptr [0x40311F], 0x0
  		0040126C  |.  C705 21324000>mov     dword ptr [0x403221], 004012E1
  		00401276  |.  892D 1D324000 mov     dword ptr [0x40321D], ebp
  		0040127C  |.  68 00104000   push    00401000
       

00401000 /. 55 push ebp
00401001 |. 8BEC mov ebp, esp
00401003 |. 8B45 10 mov eax, dword ptr [ebp 0x10]
00401006 |. FF35 21324000 push dword ptr [0x403221]
0040100C |. 8F80 B8000000 pop dword ptr [eax 0xB8]
00401012 |. FF35 19324000 push dword ptr [0x403219]
00401018 |. 8F80 C4000000 pop dword ptr [eax 0xC4]
0040101E |. FF35 1D324000 push dword ptr [0x40321D]
00401024 |. 8F80 B4000000 pop dword ptr [eax 0xB4]
0040102A |. B8 00000000 mov eax, 0x0
0040102F |. C9 leave
00401030 \. C3 retn
00401281 |. 64:FF35 00000>push dword ptr fs:[0] 00401288 |. 8925 19324000 mov dword ptr [0x403219], esp 0040128E |. 64:8925 00000>mov dword ptr fs:[0], esp ;设置SEH异常,异常处理跳转的最终地址是0x4012E1,对异常处理不太了解,就一句带过啦。 004012E1 |. 64:8F05 00000>pop dword ptr fs:[0] 004012E8 |. 83C4 04 add esp, 0x4 ;难怪在序列号不满足条件的情况下,程序不会报错。 00401295 |. 8D0D 17114000 lea ecx, dword ptr [0x401117] ;用户输入不同的Serial lea ecx, dword ptr [xxxxx] 寻的地址是不同的,肯定有一些是非法的地址, ;有了上面的异常处理就不怕了,作者这招用的实在巧妙啊。 0040129B |. 33C0 xor eax, eax 0040129D |. 33D2 xor edx, edx 0040129F |. 8A01 mov al, byte ptr [ecx] 004012A1 |. C601 00 mov byte ptr [ecx], 0x0 004012A4 |. 8801 mov byte ptr [ecx], al ;用户输入不合法可能会引发异常哦 int cnt = 0; int temp = 0; for (int i = 0; i < count; ++i) { if ( str[ i ] !=0 ) { if ( str[ i +1 ] !=0 ) { temp = str[i] * str[i+1]; if ( str[ i + 2 ] != 0 ) { temp = temp * str[ i + 2 ]; temp +=str[ i + 3]; cnt+=temp; i +=4; } else { break; } } else { break; } } else { break; } } cnt+=temp; 004012A6 |> 3C 00 /cmp al, 0x0 004012A8 |. 74 25 |je short 004012CF 004012AA |. 8A59 01 |mov bl, byte ptr [ecx+0x1] 004012AD |. 80FB 00 |cmp bl, 0x0 004012B0 |. 74 1D |je short 004012CF 004012B2 |. F6E3 |mul bl ;ax = al * bl 004012B4 |. 0FB659 02 |movzx ebx, byte ptr [ecx+0x2] 004012B8 |. 66:83FB 00 |cmp bx, 0x0 004012BC |. 74 11 |je short 004012CF 004012BE |. 52 |push edx 004012BF |. F7E3 |mul ebx ; eax =eax * ebx 004012C1 |. 5A |pop edx 004012C2 |. 0241 03 |add al, byte ptr [ecx+0x3] 004012C5 |. 83C1 04 |add ecx, 0x4 004012C8 |. 03D0 |add edx, eax 004012CA |. 0FB601 |movzx eax, byte ptr [ecx] 004012CD |.^ EB D7 \jmp short 004012A6 004012CF |> 03D0 add edx, eax 004012D1 |. 0115 0F314000 add dword ptr [0x40310F], edx 004012D7 |. C705 1F314000>mov dword ptr [0x40311F], 0x1 ;标志位0x40311F 设置为1 004012E1 |. 64:8F05 00000>pop dword ptr fs:[0] 004012E8 |. 83C4 04 add esp, 0x4 004012EB |. 61 popad 004012EC \. C3 retn ---------------------------------0x0401261分析结束----------------------------

   
  	00401155  |.  833D 03314000>cmp     dword ptr [0x403103], 0x0
  	;Serial长度为0 ?
  	0040115C  |.  74 19         je      short 00401177
  	;Serial长度不为0
  	0040115E  |.  8B35 0B314000 mov     esi, dword ptr [0x40310B]
  	;再次取出转换过的hex值
  	00401164  |.  83C6 15       add     esi, 0x15
  
  	00401167  |.  8D3D 95124000 lea     edi, dword ptr [0x401295]
  	0040116D  |.  83C7 02       add     edi, 0x2
  	00401170  |.  8937          mov     dword ptr [edi], esi
  	;又出现SMC了,这次是把 00401297 的值改为 (hex值 + 0x15) ,
  	;用户输入的值转换成地址要满足访问两个连续的内存块,而且间隔是0x15?
  	00401172  |.  E8 EA000000   call    00401261
  	;再一次求值
  	00401177  |>  EB 15         jmp     short 0040118E
  	00401179  |>  6A 00         push    0x0                              ; /Style = MB_OK|MB_APPLMODAL
  	0040117B  |.  68 0C304000   push    0040300C                         ; |Title = "RE-Trace Crackme by Crudd [RET]"
  	00401180  |.  68 2C304000   push    0040302C                         ; |Text = "Enter atleast 4 characters for your name."
  	00401185  |.  6A 00         push    0x0                              ; |hOwner = NULL
  	00401187  |.  E8 34030000   call    <jmp.&USER32.MessageBoxA>        ; \MessageBoxA
  	0040118C  |.  EB 20         jmp     short 004011AE
  	0040118E  |>  8D05 EA304000 lea     eax, dword ptr [0x4030EA]
  	00401194  |.  83C0 09       add     eax, 0x9
  	; eax -> &serial[ 0x9 ]
  	00401197  |.  E8 20000000   call    004011BC
  	; 将Serial转换的 0x9 ~ 0xF 转换成 hex值 ?
  	0040119C  |.  8D35 BE314000 lea     esi, dword ptr [0x4031BE]
  	004011A2  |.  E8 EE010000   call    00401395
  	;再次发现 GNV组合,0x401395再次被XX
    

   
  		---------------------------0x4031BE分析----------------------
  		004031BE    90              nop
  		004031BF    60              pushad
  		004031C0    8D1D EA304000   lea     ebx, dword ptr [0x4030EA]
  		; ptr[ ebx ] -> Serial
  		004031C6    83C3 08         add     ebx, 0x8
  		004031C9    B8 47000000     mov     eax, 0x47
  		004031CE    0305 03314000   add     eax, dword ptr [0x403103]
  		004031D4    3803            cmp     byte ptr [ebx], al
  		;条件1. Serial[ 0x8 ] 要和 strlen( Group ) + 0x47 相同
  		004031D6    75 24           jnz     short 004031FC
  		004031D8    90              nop
  		004031D9    B8 EFBEADDE     mov     eax, 0xDEADBEEF
  		;这个值应该是有 strlen( Gruop ) % 4所确定了,之前的0x40317C中
  		004031DE    8B0D 0B314000   mov     ecx, dword ptr [0x40310B]
  		004031E4    33C8            xor     ecx, eax
  		004031E6    890D 0B314000   mov     dword ptr [0x40310B], ecx
  		Serial转换的地址 
  
  		004031EC    8B1D 0F314000   mov     ebx, dword ptr [0x40310F]
  		004031F2    33D8            xor     ebx, eax
  		004031F4    891D 0F314000   mov     dword ptr [0x40310F], ebx
  		004031FA    61              popad
  		004031FB    C3              retn
  		;上面不同的话,则设置标志位为0 
  		004031FC    C705 1F314000 0>mov     dword ptr [0x40311F], 0x0
  		00403206  ^ EB D0           jmp     short 004031D8
  
  		---------------------------0x4031BE分析结束----------------------
  		 hex( Serial  0x9 ~ 0xF ) xor getval(strlen(group%4)) == (hash( xxx ) ) xor getval( strlen(group%4))
   

  
  	004011A7  |.  60            pushad
  	004011A8  |.  E8 39020000   call    004013E6
  	;调用0x4031BE的功能,将
  	004011AD  |.  61            popad
  	004011AE  |>  61            popad
  	004011AF  |.  C3            retn
  	004011B0  |>  C705 0F314000>mov     dword ptr [0x40310F], 0x1
  	004011BA  \.^ EB F2         jmp     short 004011AE
  

  
  004010AB  |.  8D35 23314000 lea     esi, dword ptr [0x403123]
  004010B1  |.  E8 DF020000   call    00401395
  ;再次遇到gnv。。。0x4013E6替换为0x403123(获取用户输入信息的功能 )
  004010B6  |.  61            popad
  004010B7  |.  833D 1F314000>cmp     dword ptr [0x40311F], 0x1
  ;标志为不为1则失败,上面第一个条件Serial[ 0x8 ] 要和 strlen( Group ) + 0x47 相同
  004010BE  |.  75 25         jnz     short 004010E5
  004010C0  |.  A1 0F314000   mov     eax, dword ptr [0x40310F]
  004010C5  |.  83F8 00       cmp     eax, 0x0
  004010C8  |.  74 1B         je      short 004010E5
  ;标志0x40310F为0则失败
  004010CA  |.  3B05 0B314000 cmp     eax, dword ptr [0x40310B]
  ;条件dword ptr [0x40310B]要和dword ptr [0x40310F]相等
  004010D0  |.  75 13         jnz     short 004010E5
  004010D2  |.  6A 00         push    0x0                                                         ; /Style = MB_OK|MB_APPLMODAL
  004010D4  |.  68 0C304000   push    0040300C                                                    ; |Title = "RE-Trace Crackme by Crudd [RET]"
  004010D9  |.  68 56304000   push    00403056                                                    ; |Text = "Congratulations, now code a keygen for it."
  004010DE  |.  6A 00         push    0x0                                                         ; |hOwner = NULL
  004010E0  |.  E8 DB030000   call    <jmp.&USER32.MessageBoxA>                                   ; \MessageBoxA
  004010E5  |>  EB 2A         jmp     short 00401111
  004010E7  |>  817D 10 E9030>cmp     dword ptr [ebp+0x10], 0x3E9
  004010EE  |.  75 21         jnz     short 00401111
  004010F0  |.  6A 00         push    0x0
  004010F2  |.  6A 00         push    0x0
  004010F4  |.  6A 10         push    0x10
  004010F6  |.  FF75 08       push    dword ptr [ebp+0x8]
  004010F9  |.  FF15 9D304000 call    dword ptr [0x40309D]
  004010FF  |.  EB 10         jmp     short 00401111
  00401101  |>  837D 0C 10    cmp     dword ptr [ebp+0xC], 0x10
  00401105  |.  75 0A         jnz     short 00401111
  00401107  |.  6A 00         push    0x0                                                         ; /Result = 0x0
  00401109  |.  FF75 08       push    dword ptr [ebp+0x8]                                         ; |hWnd
  0040110C  |.  E8 97030000   call    <jmp.&USER32.EndDialog>                                     ; \EndDialog
  00401111  |>  33C0          xor     eax, eax
  00401113  |.  C9            leave
  00401114  \.  C2 1000       retn    0x10
  -------------------------------------------------窗体过程函数结束-------------------------------------------
  



  ----------------------------------------------构造满足条件的注册信息----------------------------------------
  这个cm大致的程序我们已经了解了。
  用户输入 name Gruop 和 serial
  serial前8位其实转换成了程序内部的地址,参与校验码的计算,通过group的长度来计算内部验证 getcheckval()。
  设内部地址转换函数为 conhex(),校验码计算函数为 getval()
  A = getval( conhex( serial[0x0]~serial[ 0x7 ] )
  B = getval( conhex( serial[0x0]~serial[ 0x7 ] ) + 0x15 )
  C = ( A + B )^ getcheckval( strlen( group ) )
  D = conhex( serial[0x9]~serial[ 0xF ] ) ^ getcheckval( strlen( group ) )
  E = ascii ( 0x47 + strlen(group) )
  
  km验证通过的条件就是
  C == D 且 E == serial[ 0x8 ] 且 strlen( name ) >= 4
  
  再来看下 A和B,C,D都是基于用户输入的serial和 group的,
  那么我们只要满足conhex( serial[0x9]~serial[ 0xF ] ) == A + B 即可满足 C == D
  而那么我们只要满足serial[0x9]~serial[ 0xF ] ==  ascii ( A + B ) 即可满足 C == D
  显然只要计算出 A + B 那么serial的 0x9位~0xF位(后8位)就可以确定下来
  
  注册码分为三部分
  8位ASC+1位ASC+8位ASC
  
  下面来构造一个可用的注册信息
  就把oep-0x401031选作计算校验码的取址的起始地址吧
  那么serial前8位则为13010400,第9位为acsii( strlen( group ) + 47h )
  计算出来的校验码为000C442A
  
  下面给出一个可用的注册信息
  
  name:返璞归真
  group:hello
  serial:13010400LA244C000

  ---------------------------------------------------------------------------------------------------------------
   理理思路,虽然构造出了一个可用的注册信息,但似乎偏移了这个km的初衷,把指令数据也当作了参与注册运算的一部分,
   大量用户输入信息没有参与运算。
   显然有点投机取巧。
   回想上面的一些常量、取址范围之间的联系。
   A和B在0x401261中计算时候获取的数据 有 0x15h的偏移.
  

0040113F |. 8B35 0B314000 mov esi, dword ptr [0x40310B]
;取出Serial转换过的hex值
00401145 |. 8D3D 95124000 lea edi, dword ptr [0x401295]
0040114B |. 83C7 02 add edi, 0x2
0040114E |. 8937 mov dword ptr [edi], esi

0040115E |. 8B35 0B314000 mov esi, dword ptr [0x40310B]
;再次取出转换过的hex值
00401164 |. 83C6 15 add esi, 0x15 ;有0x15的偏移
00401167 |. 8D3D 95124000 lea edi, dword ptr [0x401295]
0040116D |. 83C7 02 add edi, 0x2
00401170 |. 8937 mov dword ptr [edi], esi

   且0x401261计算过程中每次处理 0x4长度的数据,也就是4个为一组。
  
   再来看下,我们存储用户输入信息的地方
   项目        存储位置        长度存储地址        控件ID        HWND存储位置
  user    0x4030C0        0x4030FF        0x64        0x403113
  group        0x4030D5        0x403103        0x65        0x403117
  serial        0x4030EA        0x403107        0x66        0x40311B
  0x4030D5 - 0x4030D5 = 0x15 正好是0x15h!
  而且user小于 0x4 长度时会提示错误!
  瞬间理解了作者这个km的思路!
  serial包含指向user的存储地址,让user和group参与信息的校验!,这样就可以做到
  不同user和group不同 serial。当然要发现serial包含指向user的存储地址需要上面的分析过程(ps:我等菜鸟才需要)
  
  那么serial的结构可以变成
  0C030400+ ascii(strlen(group) + 47h)+ ascii( getval(user)+getval(group) )
  总共17位,其中前8位为固定项,第9位还是和之前一样,后八位通过上面的推论得出是 user和group 校验码之和。
  
  
  注册机代码下:
  
  #include "stdafx.h"
  #include <windows.h>
  #include <stdio.h>
  #include <string.h>
  
  
  DWORD fun( char *p ,int len )
  {
  	DWORD t = 0;
  	for (int i = 0 ; p[ i ] != 0 && i<len ; i+=4 )
  	{
  		if ( p[ i ] != 0 )
  		{
  			DWORD temp = p[ i ];
  			if ( p[ i + 1 ] != 0 )
  			{
  				temp = p[ i ] * p[ i + 1 ];
  				if ( p[ i + 2 ] != 0 )
  				{
  					temp = temp * p[ i + 2 ];
  					if ( p[ i + 3 ] != 0 )
  					{
  						BYTE t = p[ i + 3 ];
  						__asm
  						{
  							push eax
  							mov eax,temp
  							add al,t
  							mov temp,eax
  							pop eax
  						}
  
  					}
  				}
  			}
  			t += temp;
  		}
  	}
  
  	return t;
  }
  int _tmain(int argc, _TCHAR* argv[])
  {
  	while (true)
  	{
  		DWORD temp = 0 ;
  		char szBuffer[ 255 ];
  		printf("Input Yourname:");
  		gets(szBuffer);
  		printf("%dwqdwq",strlen( szBuffer ));
  		temp = fun( szBuffer,strlen( szBuffer ));
  		printf("Input YouGroup:");
  		gets(szBuffer);
  		temp += fun( szBuffer,strlen( szBuffer ));
  		printf("Your Serial: 0C030400%c", strlen( szBuffer ) + 0x47 );
  		sprintf( szBuffer,"%.8X\n",temp );
  		for (int i = 7 ; i>=0 ;i--)
  		{
  			printf("%c",szBuffer[i]);
  		}
  		puts("");
  	}
  	return 0;
  }
  

  
  


给出几组正确的注册信息
name:pediy
group:pediy
srial: 0C030400L44582200

name:fobnn
group:pediy
serial: 0C030400L2B132200

name:FiGHT2013
group:FiGHT2013
serial: 0C030400PC4516100

  
                 
  
  
  
  
--------------------------------------------------------------------------------
【经验总结】
  KM的算法十分简单,关键是分析其过程以及推出Serial的格式等信息。
  
  这个KM设计的思想十分有新意。充分利用了汇编语言的特点,程序内部有多次SMC。
  还有异常处理的应用等,
  其中有一点一点:
  通过用户输入的数据来计算取地范围,从而获得有效数据进行计算这点做的非常好。(用户输入的Serial中包含了计算校验码用的地址,个人觉得本文分析的这个地址指向
  用户user的缓冲空间应该是作者原本的意思)
  
  
  
  
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                       2013年02月22日 23:54:40

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

上传的附件:
收藏
点赞3
打赏
分享
最新回复 (2)
雪    币: 114
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jimdlf 2013-2-23 23:40
2
0
好深厚的功力啊
雪    币: 45
活跃值: (55)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
shenger 2013-4-25 18:09
3
0
不懂SMC,收藏先。
游客
登录 | 注册 方可回帖
返回