【目 标】:Diablo 2oo2’s CrackMe 2
【工 具】:IDA 4.7
【任 务】:算法分析
【操作平台】:Windows 2003 server
【作 者】: LOVEBOOM[DFCG][FCG][US]
【相关链接】: 见附件
【简要说明】: 用IDA再分析一篇简单的算法。
【详细过程】:
因为CRACKME是用masm写的,所以非常方便分析的。这次目标用yoda加了壳,怎么脱壳我就不说了,很简单的。脱壳后,用IDA分析一下结果就出来了:
code:00401028 DialogFunc: ; DATA XREF: start+Eo
code:00401028 push ebp
code:00401029 mov ebp, esp
code:0040102B cmp dword ptr [ebp+0Ch], 111h
code:00401032 jnz loc_401245
code:00401038 mov eax, [ebp+10h] ; CASE EAX==WM_COMMAND
code:0040103B cmp ax, 65h
code:0040103F jnz loc_40125D
code:00401045 pusha ; CASE AX==IDC_BTN_CHECKREG
code:00401046 mov byte ptr ds:UCASE_Buffer, 53h ; "SJKAZBVTECGIDFNG"
code:0040104D mov byte ptr ds:UCASE_Buffer+1, 4Ah
code:00401054 mov byte ptr ds:UCASE_Buffer+2, 4Bh
code:0040105B mov byte ptr ds:UCASE_Buffer+3, 41h
code:00401062 mov byte ptr ds:UCASE_Buffer+4, 5Ah
code:00401069 mov byte ptr ds:UCASE_Buffer+5, 42h
code:00401070 mov byte ptr ds:UCASE_Buffer+6, 56h
code:00401077 mov byte ptr ds:UCASE_Buffer+7, 54h
code:0040107E mov byte ptr ds:UCASE_Buffer+8, 45h
code:00401085 mov byte ptr ds:UCASE_Buffer+9, 43h
code:0040108C mov byte ptr ds:UCASE_Buffer+0Ah, 47h
code:00401093 mov byte ptr ds:UCASE_Buffer+0Bh, 49h
code:0040109A mov byte ptr ds:UCASE_Buffer+0Ch, 44h
code:004010A1 mov byte ptr ds:UCASE_Buffer+0Dh, 46h
code:004010A8 mov byte ptr ds:UCASE_Buffer+0Eh, 4Eh
code:004010AF mov byte ptr ds:UCASE_Buffer+0Fh, 47h ; 准备获取注册码
code:004010B6 push 28h ; nMaxCount
code:004010B8 push offset SN_Buffer ; lpString
code:004010BD push 68h ; nIDDlgItem
code:004010BF push dword ptr [ebp+8] ; hDlg
code:004010C2 call GetDlgItemTextA ; 获取注册码
code:004010C7 cmp eax, 10h
code:004010CA jnz short Reg_Failed ; 比较注册码,如果注册码长度不是10h则over
code:004010CC push 28h ; nMaxCount
code:004010CE push offset SzName_Buffer ; lpString
code:004010D3 push 67h ; nIDDlgItem
code:004010D5 push dword ptr [ebp+8] ; hDlg
code:004010D8 call GetDlgItemTextA ; 获取用户名
code:004010DD test eax, eax
code:004010DF jz short loc_401101
code:004010E1 cmp eax, 8 ; 用户名长度不能大于8
code:004010E4 jg short loc_401115
code:004010E6 cmp eax, 1 ; 如果用户名小于1则提示,问题提示,后面的提示最少2位,这里判断却是不为空就算过关了
code:004010E9 jl short loc_4010ED
code:004010EB jmp short @UCASE ; 这里实际就是一个转为大写的函数。
code:004010EB ; 如果小于'A'则加20h,相加后值还是小于'A'则把字符转为'F'
code:004010EB ; 如果大于'Z'则减20h(就是转为大写),运算值大于'Z'则字符转为'G'
code:004010EB ; 运算值小于'A',则把字符转为'S'
code:004010ED ; ----------------------------------------------------------------------------
code:004010ED
code:004010ED loc_4010ED: ; CODE XREF: code:004010E9j
code:004010ED push offset aNameMustBeAtLe ; lpString
code:004010F2 push 68h ; nIDDlgItem
code:004010F4 push dword ptr [ebp+8] ; hDlg
code:004010F7 call SetDlgItemTextA ; 显示错误信息
code:004010FC jmp loc_401242
code:00401101 ; ----------------------------------------------------------------------------
code:00401101
code:00401101 loc_401101: ; CODE XREF: code:004010DFj
code:00401101 push offset aEnterAName ; lpString
code:00401106 push 68h ; nIDDlgItem
code:00401108 push dword ptr [ebp+8] ; hDlg
code:0040110B call SetDlgItemTextA
code:00401110 jmp loc_401242
code:00401115 ; ----------------------------------------------------------------------------
code:00401115
code:00401115 loc_401115: ; CODE XREF: code:004010E4j
code:00401115 push offset aNameIsTooLong ; lpString
code:0040111A push 68h ; nIDDlgItem
code:0040111C push dword ptr [ebp+8] ; hDlg
code:0040111F call SetDlgItemTextA
code:00401124 jmp loc_401242
code:00401129 ; ----------------------------------------------------------------------------
code:00401129
code:00401129 Reg_Failed: ; CODE XREF: code:004010CAj
code:00401129 ; code:0040120Fj ...
code:00401129 push offset String ; lpString
code:0040112E push 68h ; nIDDlgItem
code:00401130 push dword ptr [ebp+8] ; hDlg
code:00401133 call SetDlgItemTextA
code:00401138 jmp loc_401242
code:0040113D
code:0040113D ; ************** S U B R O U T I N E *****************************************
code:0040113D
code:0040113D ; 这里实际就是一个转为大写的函数。
code:0040113D ; 如果小于'A'则加20h,相加后值还是小于'A'则把字符转为'F'
code:0040113D ; 如果大于'Z'则减20h(就是转为大写),运算值大于'Z'则字符转为'G'
code:0040113D ; 运算值小于'A',则把字符转为'S'
code:0040113D
code:0040113D @UCASE proc near ; CODE XREF: code:004010EBj
code:0040113D xor ebx, ebx
code:0040113F xor ecx, ecx ; 初始化相关寄存器
code:00401141 xor edx, edx
code:00401143 xor edi, edi
code:00401145 xor esi, esi
code:00401147
code:00401147 loc_401147: ; CODE XREF: @UCASE+47j
code:00401147 mov bl, ds:SzName_Buffer[ecx]
code:0040114D cmp bl, 41h ; 如果用户名小于'A'则跳去加20h
code:00401150 jl short ADD_20h
code:00401152
code:00401152 loc_401152: ; CODE XREF: @UCASE:loc_401163j
code:00401152 cmp bl, 5Ah ; 如果用户名大于'Z'则跳去减20h,也就是uCASE
code:00401155 jg short UPCASE
code:00401157
code:00401157 loc_401157: ; CODE XREF: @UCASE:loc_401176j
code:00401157 jmp short loc_401178
code:00401159 ; ----------------------------------------------------------------------------
code:00401159
code:00401159 ADD_20h: ; CODE XREF: @UCASE+13j
code:00401159 add bl, 20h
code:0040115C cmp bl, 41h ; 如果+20后还是小于41则直接置BL为46H('F')
code:0040115F jge short loc_401163
code:00401161 mov bl, 46h
code:00401163
code:00401163 loc_401163: ; CODE XREF: @UCASE+22j
code:00401163 jmp short loc_401152 ; 如果用户名大于'Z'则跳去减20h,也就是uCASE
code:00401165 ; ----------------------------------------------------------------------------
code:00401165
code:00401165 UPCASE: ; CODE XREF: @UCASE+18j
code:00401165 sub bl, 20h
code:00401168 cmp bl, 5Ah ; 如果-20小于或等于则跳
code:0040116B jle short loc_40116F ; 如果减后小于'A'则改为'S'
code:0040116D mov bl, 47h ; 如果-20后还是大于'Z'则把BL改为'D'
code:0040116F
code:0040116F loc_40116F: ; CODE XREF: @UCASE+2Ej
code:0040116F cmp bl, 41h ; 如果减后小于'A'则改为'S'
code:00401172 jge short loc_401176
code:00401174 mov bl, 53h
code:00401176
code:00401176 loc_401176: ; CODE XREF: @UCASE+35j
code:00401176 jmp short loc_401157
code:00401178 ; ----------------------------------------------------------------------------
code:00401178
code:00401178 loc_401178: ; CODE XREF: @UCASE:loc_401157j
code:00401178 mov byte ptr ds:UCASE_Buffer[edx], bl ; "SJKAZBVTECGIDFNG"
code:0040117E add edx, 2 ; 每次加2,替换原有的数据,偶数替换
code:00401181 inc ecx
code:00401182 cmp ecx, eax
code:00401184 jnz short loc_401147
code:00401184 @UCASE endp
code:00401184
code:00401186 xor ecx, ecx ; 初始化相关寄存器
code:00401188 xor edx, edx
code:0040118A xor ebx, ebx
code:0040118C
code:0040118C Lp_Sum_value: ; CODE XREF: code:00401198j
code:0040118C mov bl, byte ptr ds:UCASE_Buffer[ecx] ; 取出转为大写后字符
code:00401192 add edx, ebx ; 计算大写替换后字符串的和sumValue
code:00401194 inc ecx
code:00401195 cmp ecx, 10h
code:00401198 jnz short Lp_Sum_value ; 取出转为大写后字符
code:0040119A imul eax, 0FFh ; 用户名长度乘以0FFh的值key1
code:004011A0 imul edx, eax ; 再用key1乘以sumValue,设为imulvalue
code:004011A3 xor edx, 0ACEBDFABh ; 用imulValue 异或常数0ACEBDFABH的值设为XorValue
code:004011A9 bswap edx ; 计算出的xorValue反转
code:004011AB push edx
code:004011AC push offset szLx ; "%lX"
code:004011B1 push offset sz_save_fmstr ; 转换后的十六进制值输出为字符串
code:004011B6 call wsprintfA
code:004011BB add esp, 0Ch
code:004011BE xor ebx, ebx
code:004011C0 xor ecx, ecx
code:004011C2
code:004011C2 loc_4011C2: ; CODE XREF: code:004011DCj
code:004011C2 mov bl, ds:sz_save_fmstr[ecx]
code:004011C8 cmp bl, 3Ah ; 比较值是否小于':'
code:004011CB jl short jl3a ; 如果值小于':'则加11h
code:004011CD jmp short loc_4011D8
code:004011CF ; ----------------------------------------------------------------------------
code:004011CF
code:004011CF jl3a: ; CODE XREF: code:004011CBj
code:004011CF add bl, 11h ; 如果值小于':'则加11h
code:004011D2 mov ds:sz_save_fmstr[ecx], bl
code:004011D8
code:004011D8 loc_4011D8: ; CODE XREF: code:004011CDj
code:004011D8 inc ecx
code:004011D9 cmp ecx, 8
code:004011DC jnz short loc_4011C2 ; 循环判断替换
code:004011DE xor ebx, ebx
code:004011E0 xor ecx, ecx
code:004011E2 xor edx, edx
code:004011E4
code:004011E4 loc_4011E4: ; CODE XREF: code:004011F7j
code:004011E4 mov bl, ds:sz_save_fmstr[ecx] ; 再次取出运算后的值
code:004011EA mov byte ptr ds:(UCASE_Buffer+1)[edx], bl ; 奇数替换字符
code:004011F0 add edx, 2
code:004011F3 inc ecx
code:004011F4 cmp edx, 10h
code:004011F7 jnz short loc_4011E4 ; 再次取出运算后的值
code:004011F9 xor ebx, ebx
code:004011FB xor ecx, ecx
code:004011FD xor edx, edx
code:004011FF xor eax, eax
code:00401201
code:00401201 Loop_Compare_Data: ; CODE XREF: code:00401231j
code:00401201 mov bl, ds:SN_Buffer[edx] ; 取出假码
code:00401207 mov al, byte ptr ds:UCASE_Buffer[edx] ; 取出真码
code:0040120D xor eax, ebx
code:0040120F jnz Reg_Failed ; 如果不相等则over
code:00401215 mov bl, ds:byte_4030C9[edx]
code:0040121B mov al, byte ptr ds:(UCASE_Buffer+1)[edx]
code:00401221 add al, 5 ; 比较真注册码的偶数位-5是否等于假码的偶数位
code:00401223 cmp bl, al
code:00401225 jnz Reg_Failed
code:0040122B add edx, 2
code:0040122E cmp edx, 10h
code:00401231 jnz short Loop_Compare_Data ; 取出假码
code:00401233 push offset aThankYouForYou ; lpString
code:00401238 push 68h ; nIDDlgItem
code:0040123A push dword ptr [ebp+8] ; hDlg
code:0040123D call SetDlgItemTextA ; 显示正确信息
code:00401242
code:00401242 loc_401242: ; CODE XREF: code:004010FCj
code:00401242 ; code:00401110j ...
code:00401242 popa
code:00401243 jmp short loc_401257
code:00401245 ; ----------------------------------------------------------------------------
算法总结:
又抓了个软杮子, 算法也是非常这简单的,先把注册名转为大写,然后替换固定字符串里奇数位的字符,s1,然后把s1的值累加s2,s2*0ff*用户名长度key1,key1再异或固定值0ACEBDFABh结果保存为key2,key2的每一位比较是否小于’:’,小于则加上11h,然后再加上5,结果替换固定字符串里偶数位的字符。
Greetz:
Fly.Jingulong,yock,tDasm.David.hexer,hmimys,ahao.UFO(brother).alan(sister).all of my friends and you!
By loveboom[DFCG][FCG][US]
Email:loveboom#163.com
Date:2005-6-13 14:32