先跑一下
直接使用这个字符串去check,发现提示信息有关键字符串
CODE:0042FB80 00000021 C Sorry , The serial is incorect !
找到这个字符串的引用,有两个
跟下去发现这两个字符串都在一个函数中,最下面的3个框中左右都是错误,中间是对的,所以核心就在最上层和中间的这段代码
下面看看这段代码,直接在ollydbg中暂停,查看参数和返回值等信息
CODE:0042F998 push ebp CODE:0042F999 mov ebp, esp CODE:0042F99B xor ecx, ecx CODE:0042F99D push ecx CODE:0042F99E push ecx CODE:0042F99F push ecx CODE:0042F9A0 push ecx CODE:0042F9A1 push ecx CODE:0042F9A2 push ecx CODE:0042F9A3 push ebx CODE:0042F9A4 push esi CODE:0042F9A5 mov ebx, eax CODE:0042F9A7 xor eax, eax CODE:0042F9A9 push ebp CODE:0042F9AA push offset loc_42FB67 CODE:0042F9AF push dword ptr fs:[eax] CODE:0042F9B2 mov fs:[eax], esp CODE:0042F9B5 mov ds:dword_431750, 29h CODE:0042F9BF lea edx, [ebp+var_10] CODE:0042F9C2 mov eax, [ebx+1DCh] CODE:0042F9C8 call sub_41AA58 ;这个函数返回18 CODE:0042F9CD mov eax, [ebp+var_10] ;这里取得了用户名字符串 CODE:0042F9D0 call sub_403AB0 ;以用户名作为参数,调用sub_403AB0,这是一个判断用户名是不是空的函数 CODE:0042F9D5 mov ds:dword_43176C, eax ;将结果存放在固定位置,后面的第一个关键判断使用这个字符串 CODE:0042F9DA lea edx, [ebp+var_10] CODE:0042F9DD mov eax, [ebx+1DCh] CODE:0042F9E3 call sub_41AA58 CODE:0042F9E8 mov eax, [ebp+var_10] CODE:0042F9EB movzx eax, byte ptr [eax] CODE:0042F9EE mov esi, eax CODE:0042F9F0 shl esi, 3 CODE:0042F9F3 sub esi, eax CODE:0042F9F5 lea edx, [ebp+var_14] CODE:0042F9F8 mov eax, [ebx+1DCh] CODE:0042F9FE call sub_41AA58 CODE:0042FA03 mov eax, [ebp+var_14] CODE:0042FA06 movzx eax, byte ptr [eax+1] CODE:0042FA0A shl eax, 4 CODE:0042FA0D add esi, eax CODE:0042FA0F mov ds:dword_431754, esi CODE:0042FA15 lea edx, [ebp+var_10] CODE:0042FA18 mov eax, [ebx+1DCh] CODE:0042FA1E call sub_41AA58 CODE:0042FA23 mov eax, [ebp+var_10] CODE:0042FA26 movzx eax, byte ptr [eax+3] CODE:0042FA2A imul esi, eax, 0Bh CODE:0042FA2D lea edx, [ebp+var_14] CODE:0042FA30 mov eax, [ebx+1DCh] CODE:0042FA36 call sub_41AA58 CODE:0042FA3B mov eax, [ebp+var_14] CODE:0042FA3E movzx eax, byte ptr [eax+2] CODE:0042FA42 imul eax, 0Eh CODE:0042FA45 add esi, eax CODE:0042FA47 mov ds:dword_431758, esi CODE:0042FA4D mov eax, ds:dword_43176C CODE:0042FA52 call sub_406930 ;以用户名作为参数调用 CODE:0042FA57 cmp eax, 4 CODE:0042FA5A jge short loc_42FA79 ;第一个关键判断 CODE:0042FA5C push 0 ; uType CODE:0042FA5E mov ecx, offset aTryAgain_0 ; "Try Again!" CODE:0042FA63 mov edx, offset aSorryTheSerial ; "Sorry , The serial is incorect !" CODE:0042FA68 mov eax, ds:off_430A48 CODE:0042FA6D mov eax, [eax] ; int CODE:0042FA6F call sub_42A170 CODE:0042FA74 jmp loc_42FB37 CODE:0042FA79 ; --------------------------------------------------------------------------- CODE:0042FA79 CODE:0042FA79 loc_42FA79: ; CODE XREF: _TNS_BitBtn1Click+C2↑j CODE:0042FA79 lea edx, [ebp+var_10] CODE:0042FA7C mov eax, [ebx+1DCh] CODE:0042FA82 call sub_41AA58 CODE:0042FA87 mov eax, [ebp+var_10] ;取字符串 CODE:0042FA8A movzx eax, byte ptr [eax] ;取出字符串的第一个地址 CODE:0042FA8D imul ds:dword_431750 ;前面将这个位置赋值成了0x29 CODE:0042FA93 mov ds:dword_431750, eax ;将第一个字符乘以0x29 CODE:0042FA98 mov eax, ds:dword_431750 CODE:0042FA9D add ds:dword_431750, eax ;这里应该相当于乘以2了 CODE:0042FAA3 lea eax, [ebp+var_4] ;将这个字符串的地址放到局部变量中 CODE:0042FAA6 mov edx, offset _str_CW.Text CODE:0042FAAB call sub_403708 ;以字符串CW作为第二参数 CODE:0042FAB0 lea eax, [ebp+var_8] ;同上,将字符串地址放入局部变量 CODE:0042FAB3 mov edx, offset _str_CRACKED.Text CODE:0042FAB8 call sub_403708 ;以字符串CRACKED作为第二参数 CODE:0042FABD push [ebp+var_4] ;push了CW CODE:0042FAC0 push offset _str___5.Text ;push了又一个字符串 CODE:0042FAC5 lea edx, [ebp+var_18] ;这里是局部变量 CODE:0042FAC8 mov eax, ds:dword_431750 ;这里是用户名第一个字符串经过运算之后的结果 CODE:0042FACD call sub_406718 ;这里又对第一个字符串的运行结果再次进行一个运算 CODE:0042FAD2 push [ebp+var_18] ;将第二次运算结果放入var_18中,这里入栈了 CODE:0042FAD5 push offset _str___5.Text ;应该也是参数 CODE:0042FADA push [ebp+var_8] CODE:0042FADD lea eax, [ebp+var_C] CODE:0042FAE0 mov edx, 5 CODE:0042FAE5 call sub_4039AC ;关键函数了,第一个参数是var_C,第二个是5,后面3个参数依次是前面push的内容 CODE:0042FAEA lea edx, [ebp+var_10] CODE:0042FAED mov eax, [ebx+1E0h] CODE:0042FAF3 call sub_41AA58 ;这个函数读取了序列码的地址,然后返给var_10中作为下一个函数的参数 CODE:0042FAF8 mov edx, [ebp+var_10] ;第二个参数是序列码字符串 CODE:0042FAFB mov eax, [ebp+var_C] ;第一个参数是var_C,也是字符串 CODE:0042FAFE call sub_4039FC ;要求这个函数返回0 CODE:0042FB03 jnz short loc_42FB1F CODE:0042FB05 push 0 ; uType CODE:0042FB07 mov ecx, offset aCongratz_0 ; "Congratz !!" CODE:0042FB0C mov edx, offset aGoodJobDude ; "Good job dude =)" CODE:0042FB11 mov eax, ds:off_430A48 CODE:0042FB16 mov eax, [eax] ; int CODE:0042FB18 call sub_42A170 CODE:0042FB1D jmp short loc_42FB37 CODE:0042FB1F ; --------------------------------------------------------------------------- CODE:0042FB1F CODE:0042FB1F loc_42FB1F: ; CODE XREF: _TNS_BitBtn1Click+16B↑j CODE:0042FB1F push 0 ; uType CODE:0042FB21 mov ecx, offset aTryAgain_0 ; "Try Again!" CODE:0042FB26 mov edx, offset aSorryTheSerial ; "Sorry , The serial is incorect !" CODE:0042FB2B mov eax, ds:off_430A48 CODE:0042FB30 mov eax, [eax] ; int CODE:0042FB32 call sub_42A170
直接以默认的方式去运行,在ollydbg中看各个函数调用的参数和返回情况
在sub_406930处,传入用户名字符串,然后返回-2-(-1-length),也就是length-1,这里的length包括了'\0'字符,也就是说,最后这个函数的返回位用户名的字符串长度,最后结果为0x19,所以第一个条件判断为字符串长度大于4。这里已经符合了
然后是loc_42FA79处的函数,这个函数最后的跳转步骤在sub_4039FC处,要求这个函数返回0,而这个函数参数有两个,第一个参数是CW-6560-CRACKED,第二参数为序列码。所以这里猜测应该是根据用户名生成了6560这个字符串,和CW和CRACKED进行拼接,然后在这里进行最后一步的判断
从0042FA79开始,对汇编码进行了简要分析,这段可以直接在ollydbg中看各个函数的参数,结果以及栈的变化,可以大致猜出sub_4039AC应该是字符串拼接函数,而关键点的函数应该是一个字符串相对的判断函数。然后直接在序列码中输入CW-6560-CRACKED,发现果然正确,而6560这个值就是根据用户名字符串第一个字符乘以0x29再成2得到的,上文中没有分析的函数就是用来做字符串拼接(6560这个值在跟踪函数的过程中也会被放入到栈上,所以只需要用ollydbg跟踪调试每一步的变化就很容易得出结果了)
最后就OK了