本破解练习来自MSJ2009 Challenge#2,下载地址如下:https://reverse.put.as/wp-content/uploads/2010/05/MSJ20092.zip。
难度系数Level 2,所以破解起来比较麻烦,主要是计算Keygen的流程比较繁琐。
打开运行,如下。输入正确的名称、邮箱及Serial才能注册。
0x1 代码分析
Hopper中找到验证输入的关键函数[Level2 validateSerial:forName:forEmail:]。如下。
-[Level2 validateSerial:forName:forEmail:]:
0000292c push ebp ; Objective C Implementation defined at 0x4120 (instance method)
0000292d mov ebp, esp
0000292f push edi
00002930 push esi
00002931 push ebx
00002932 sub esp, 0x4c
00002935 mov eax, dword [objc_msg_length] ; @selector(length)
0000293a mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
0000293e mov eax, dword [ebp+arg_8]
00002941 mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002944 call imp___jump_table__objc_msgSend
00002949 cmp eax, 0xe
0000294c jne loc_2bf3
00002952 mov eax, dword [objc_msg_length] ; @selector(length)
00002957 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
0000295b mov eax, dword [ebp+arg_10]
0000295e mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002961 call imp___jump_table__objc_msgSend
00002966 cmp eax, 0x3
00002969 jbe loc_2bf3
0000296f mov eax, dword [objc_msg_lossyCString] ; @selector(lossyCString)
00002974 mov esi, 0x4
00002979 xor ebx, ebx
0000297b mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
0000297f mov eax, dword [ebp+arg_C]
00002982 mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002985 call imp___jump_table__objc_msgSend
0000298a mov dword [esp+0x58+var_50], 0x0
00002992 mov edi, eax
00002994 mov eax, dword [objc_msg_characterAtIndex_] ; @selector(characterAtIndex:)
00002999 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
0000299d mov eax, dword [ebp+arg_10]
000029a0 mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
000029a3 call imp___jump_table__objc_msgSend
000029a8 mov dword [esp+0x58+var_50], 0x4
000029b0 movzx eax, ax
000029b3 mov dword [ebp+var_30], eax
000029b6 mov eax, dword [objc_msg_characterAtIndex_] ; @selector(characterAtIndex:)
000029bb mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
000029bf mov eax, dword [ebp+arg_10]
000029c2 mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
000029c5 call imp___jump_table__objc_msgSend
000029ca mov dword [esp+0x58+var_58], edi ; argument #1 for method imp___jump_table__strlen
000029cd movzx eax, ax
000029d0 mov dword [ebp+var_2C], eax
000029d3 call imp___jump_table__strlen
000029d8 xor ecx, ecx
000029da mov dword [ebp+var_40], eax
000029dd jmp loc_2a16
loc_29df:
000029df movsx eax, byte [edi+ebx] ; CODE XREF=-[Level2 validateSerial:forName:forEmail:]+237
000029e3 inc ebx
000029e4 imul eax, esi
000029e7 add esi, 0x4
000029ea mov edx, eax
000029ec shl edx, 0x6
000029ef lea eax, dword [edx+eax*2+0x4e]
000029f3 add eax, dword [ebp+var_30]
000029f6 add ecx, eax
000029f8 mov eax, 0x68db8bad
000029fd imul ecx
000029ff mov eax, ecx
00002a01 sar eax, 0x1f
00002a04 sar edx, 0xc
00002a07 sub edx, eax
00002a09 mov eax, ecx
00002a0b imul edx, edx, 0x2710
00002a11 sub eax, edx
00002a13 mov dword [ebp+var_28], eax
loc_2a16:
00002a16 cmp dword [ebp+var_40], ebx ; CODE XREF=-[Level2 validateSerial:forName:forEmail:]+177
00002a19 ja loc_29df
00002a1b mov eax, dword [ebp+var_28]
00002a1e mov esi, 0x4
00002a23 xor ebx, ebx
00002a25 mov dword [esp+0x58+var_50], 0x3088 ; @"%i"
00002a2d mov dword [esp+0x58+var_4C], eax
00002a31 mov eax, dword [objc_msg_stringWithFormat_] ; @selector(stringWithFormat:)
00002a36 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002a3a mov eax, dword [cls_NSString] ; cls_NSString
00002a3f mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002a42 call imp___jump_table__objc_msgSend
00002a47 mov dword [esp+0x58+var_58], edi ; argument #1 for method imp___jump_table__strlen
00002a4a mov dword [ebp+var_24], eax
00002a4d call imp___jump_table__strlen
00002a52 xor ecx, ecx
00002a54 mov dword [ebp+var_3C], eax
00002a57 jmp loc_2a8b
loc_2a59:
00002a59 movsx eax, byte [edi+ebx] ; CODE XREF=-[Level2 validateSerial:forName:forEmail:]+354
00002a5d inc ebx
00002a5e imul eax, esi
00002a61 add esi, 0x8
00002a64 lea eax, dword [eax+eax*4+0x4d]
00002a68 add eax, dword [ebp+var_2C]
00002a6b add ecx, eax
00002a6d mov eax, 0x68db8bad
00002a72 imul ecx
00002a74 mov eax, ecx
00002a76 sar eax, 0x1f
00002a79 sar edx, 0xc
00002a7c sub edx, eax
00002a7e mov eax, ecx
00002a80 imul edx, edx, 0x2710
00002a86 sub eax, edx
00002a88 mov dword [ebp+var_20], eax
loc_2a8b:
00002a8b cmp ebx, dword [ebp+var_3C] ; CODE XREF=-[Level2 validateSerial:forName:forEmail:]+299
00002a8e jb loc_2a59
00002a90 mov eax, dword [ebp+var_20]
00002a93 xor ebx, ebx
00002a95 mov esi, 0x4
00002a9a mov dword [esp+0x58+var_50], 0x3088 ; @"%i"
00002aa2 mov edi, 0x4
00002aa7 mov dword [esp+0x58+var_4C], eax
00002aab mov eax, dword [objc_msg_stringWithFormat_] ; @selector(stringWithFormat:)
00002ab0 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002ab4 mov eax, dword [cls_NSString] ; cls_NSString
00002ab9 mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002abc call imp___jump_table__objc_msgSend
00002ac1 mov edx, 0x68db8bad
00002ac6 mov dword [esp+0x58+var_50], 0x3088 ; @"%i"
00002ace mov dword [ebp+var_38], eax
00002ad1 mov eax, dword [ebp+var_30]
00002ad4 imul eax, dword [ebp+var_2C]
00002ad8 mov ecx, eax
00002ada add ecx, 0x4d2
00002ae0 mov eax, ecx
00002ae2 imul edx
00002ae4 mov eax, ecx
00002ae6 sar eax, 0x1f
00002ae9 sar edx, 0xc
00002aec sub edx, eax
00002aee mov eax, dword [objc_msg_stringWithFormat_] ; @selector(stringWithFormat:)
00002af3 imul edx, edx, 0x2710
00002af9 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002afd mov eax, dword [cls_NSString] ; cls_NSString
00002b02 sub ecx, edx
00002b04 mov dword [esp+0x58+var_4C], ecx
00002b08 mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002b0b call imp___jump_table__objc_msgSend
00002b10 mov dword [esp+0x58+var_50], ebx
00002b14 mov dword [esp+0x58+var_4C], esi
00002b18 mov si, 0x5
00002b1c mov dword [ebp+var_34], eax
00002b1f mov eax, dword [objc_msg_substringWithRange_] ; @selector(substringWithRange:)
00002b24 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002b28 mov eax, dword [ebp+arg_8]
00002b2b mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002b2e call imp___jump_table__objc_msgSend
00002b33 mov dword [esp+0x58+var_50], esi
00002b37 mov si, 0xa
00002b3b mov dword [esp+0x58+var_4C], edi
00002b3f mov ebx, eax
00002b41 mov eax, dword [objc_msg_substringWithRange_] ; @selector(substringWithRange:)
00002b46 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002b4a mov eax, dword [ebp+arg_8]
00002b4d mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002b50 call imp___jump_table__objc_msgSend
00002b55 mov dword [esp+0x58+var_50], esi
00002b59 mov dword [esp+0x58+var_4C], edi
00002b5d mov dword [ebp+var_1C], eax
00002b60 mov eax, dword [objc_msg_substringWithRange_] ; @selector(substringWithRange:)
00002b65 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002b69 mov eax, dword [ebp+arg_8]
00002b6c mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002b6f call imp___jump_table__objc_msgSend
00002b74 mov dword [esp+0x58+var_58], 0x3098 ; @"Serial Number: %@-%@-%@", argument #1 for method imp___jump_table__NSLog
00002b7b mov esi, eax
00002b7d mov eax, dword [ebp+var_34]
00002b80 mov dword [esp+0x58+var_4C], eax
00002b84 mov eax, dword [ebp+var_38]
00002b87 mov dword [esp+0x58+var_50], eax
00002b8b mov eax, dword [ebp+var_24]
00002b8e mov dword [esp+0x58+var_54], eax
00002b92 call imp___jump_table__NSLog
00002b97 mov eax, dword [ebp+var_24]
00002b9a mov dword [esp+0x58+var_58], ebx ; argument #1 for method imp___jump_table__objc_msgSend
00002b9d mov dword [esp+0x58+var_50], eax
00002ba1 mov eax, dword [objc_msg_isEqual_] ; @selector(isEqual:)
00002ba6 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002baa call imp___jump_table__objc_msgSend
00002baf test al, al
00002bb1 je loc_2bf3
00002bb3 mov eax, dword [ebp+var_38]
00002bb6 mov dword [esp+0x58+var_50], eax
00002bba mov eax, dword [objc_msg_isEqual_] ; @selector(isEqual:)
00002bbf mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002bc3 mov eax, dword [ebp+var_1C]
00002bc6 mov dword [esp+0x58+var_58], eax ; argument #1 for method imp___jump_table__objc_msgSend
00002bc9 call imp___jump_table__objc_msgSend
00002bce test al, al
00002bd0 je loc_2bf3
00002bd2 mov eax, dword [ebp+var_34]
00002bd5 mov dword [esp+0x58+var_58], esi ; argument #1 for method imp___jump_table__objc_msgSend
00002bd8 mov dword [esp+0x58+var_50], eax
00002bdc mov eax, dword [objc_msg_isEqual_] ; @selector(isEqual:)
00002be1 mov dword [esp+0x58+var_54], eax ; argument #2 for method imp___jump_table__objc_msgSend
00002be5 call imp___jump_table__objc_msgSend
00002bea mov edx, 0x1
00002bef test al, al
00002bf1 jne loc_2bf5
loc_2bf3:
00002bf3 xor edx, edx ; CODE XREF=-[Level2 validateSerial:forName:forEmail:]+32, -[Level2 validateSerial:forName:forEmail:]+61, -[Level2 validateSerial:forName:forEmail:]+645, -[Level2 validateSerial:forName:forEmail:]+676
loc_2bf5:
00002bf5 add esp, 0x4c ; CODE XREF=-[Level2 validateSerial:forName:forEmail:]+709
00002bf8 mov eax, edx
00002bfa pop ebx
00002bfb pop esi
00002bfc pop edi
00002bfd leave
00002bfe ret
; endp
这个函数包含两个循环,第一个循环生成第一部分的Serial,part1,第二个循环生成第二部分的Serial,part2 ,最后计算第三部分的Serial,part3。然后通过“-”连接起来。所以,Serial的格式为 part1-part2-part3。
其中,具体分析可得到:
part1:见代码段【 loc_29df】循环取输入的Name和Email的第一位字符ASCII码值进行一系列的计算,取最后的结果。
part2:见代码段【 loc_2a59】循环取输入的Name和Email的第五位字符ASCII码值进行一系列的计算,取最后的结果。
part3:见代码段【 00002ad1-00002b0b 】取Email的第一和五位字符ASCII码值进行一系列的计算,取最后的结果。
最后截取输入的Serial,是否和计算得到的Serial每一部分都相等。
0x2 Keygen算法
如何写keygen呢?这里直接复制了汇编的计算过程,没有深究算法的原理,用Objective C重新写了一遍汇编。关键代码如下。
- (NSString*)part1ByName:(NSString *)name email:(NSString *) email {
signed long esi = 0x4;
signed long ecx = 0;
signed long edx = 0;
signed long eax = 0;
for (int i = 0; i<name.length;i++) {
eax = [name characterAtIndex:i];
eax *= esi;
esi += 0x4;
edx = eax<<0x6;
eax = edx + eax *2 + 0x4e;
eax += [email characterAtIndex:0];
ecx += eax;
eax = ecx;
eax = ((ecx * 0x68db8bad) & 0x00000000ffffffff)>>32>>0x1f;
edx =((ecx * 0x68db8bad) & 0xffffffff00000000)>>32>>(0xc);
edx = edx - eax;
eax = ecx;
edx *= 0x2710;
eax = eax-edx;
}
return [NSString stringWithFormat:@"%d",eax];
}
- (NSString*)part2ByName:(NSString *)name email:(NSString *) email {
signed long esi = 0x4;
signed long ecx = 0;
signed long edx = 0;
signed long eax = 0;
for (int i = 0; i<name.length;i++) {
eax = [name characterAtIndex:i];
eax *= esi;
esi += 0x8;
eax = eax + eax *4 + 0x4d;
eax += [email characterAtIndex:4];
ecx += eax;
eax = ecx;
eax = ((ecx * 0x68db8bad) & 0x00000000ffffffff)>>32>>0x1f;
edx =((ecx * 0x68db8bad) & 0xffffffff00000000)>>32>>(0xc);
edx = edx - eax;
eax = ecx;
edx *= 0x2710;
eax = eax - edx;
}
return [NSString stringWithFormat:@"%d",eax];
}
- (NSString*)part3ByName:(NSString *)name email:(NSString *) email {
signed long ecx = 0;
signed long eax = [email characterAtIndex:0];
eax *= [email characterAtIndex:4];
ecx = eax;
ecx+=0x4d2;
eax = ecx;
long edx = 0x68db8bad;
signed long tem = edx * eax ;
eax = (tem & 0x00000000ffffffff)>>32>>0x1f;
edx =(tem & 0xffffffff00000000)>>32>>(0xc);
edx *= 0x2710;
ecx -= edx;
return [NSString stringWithFormat:@"%d",ecx];
}
- (NSString*)keyGen {
NSString *name = @"qwer";
NSString *email = @"o@p.com";
NSString *serial = [NSString stringWithFormat:@"%@-%@-%@",
[self part1ByName:name email:email ],
[self part2ByName:name email:email ],
[self part3ByName:name email:email ]];
return serial;
}
0x3 验证
设Name为qwer ,邮箱为o@p.com,根据Keygen程序得到序列号3796-6164-2223,输入程序,验证Success。:)!