首先要说明,这个Crackme No. 02是happytown没有在看雪发布过的。我在本站happytown的Crackme No.1的贴子里面看到了它的主页,于是到那里下载了下来。
Happytown,你好!一时没能和你联系上,请原谅我没征得你同意的情况下就将你的crackme No. 2 发布了,如果我这样做对你带来可能的不便,我将删除附件并向你致歉!
【软件名称】:happytown CrackMe ###2.exe
【软件下载】:
附件:happytown-crackme-02.zip
【软件信息】: VB 6.0,无壳,64 KB,用户名-注册码方式,无错误提示
【破解工具】:OllyDbg 1.10聆风听雨汉化第二版, SmartCheck 6.20
启动后运行一下,输入用户名hud,点击Check,没有任何提示。奇怪的是,注册码文本框不能输入任何字符。这个版本happytown没有发布过,不知是否是因为有这个问题,还是Name有什么要求,是没有达到要求而导致Serial框不能输入。
这时候有一个小技巧。在OD的插件中选择“窗口工具”,然后最小化OD,将鼠标移到Serial文本框上,同时按住Shift,这时Serial文本框的句柄就取到了,然后在OD窗口工具插件的标题设置文本框里输入123123,点击“设置”,Serial框中就有123123了,然后关闭窗口工具。
在OD中下断点于__vbaStrCopy,回到Crackme中点击Check按钮,OD中断了下来。
00407ACA . BA >mov edx,CrackMe_.004071D4 ; UNICODE "Congratulations"
00407ACF . 8D4>lea ecx,dword ptr ss:[ebp-34]
00407AD2 . 8B3>mov esi,dword ptr ds:[<&MSVBVM60>; MSVBVM60.__vbaStrCopy
断到了这里。
00407AD8 . FFD>call esi ; <&MSVBVM60.__vbaStrCopy>
00407ADA . BA >mov edx,CrackMe_.004071F8 ; UNICODE "Good Job!"
像上一个Crackme No. 1一样,先载入了提示字符。F8继续:
……
00407B1F > \8B5>mov edx,dword ptr ss:[ebp-48] ; Name: hud出来了
00407B22 . 895>mov dword ptr ss:[ebp-48],ebx
00407B25 . 8D4>lea ecx,dword ptr ss:[ebp-44]
00407B28 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaS>; MSVBVM60.__vbaStrMove
00407B2E . 8D4>lea ecx,dword ptr ss:[ebp-4C]
00407B31 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>; MSVBVM60.__vbaFreeObj
00407B37 . 8B4>mov eax,dword ptr ss:[ebp-44]
00407B3A . 50 push eax
00407B3B . FF1>call dword ptr ds:[<&MSVBVM60.__vbaL>; MSVBVM60.__vbaLenBstr
00407B41 . 8BC>mov ecx,eax ; 取得Name的长度
00407B43 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaI>; MSVBVM60.__vbaI2I4
00407B49 . 894>mov dword ptr ss:[ebp-28],eax
00407B4C . BA >mov edx,CrackMe_.00407220 ; 常数字串"8129-",像是前缀
……
00407B95 > \8B5>mov edx,dword ptr ss:[ebp-48] ; 试练码123123出来了
00407B98 . 52 push edx
00407B99 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaL>; MSVBVM60.__vbaLenBstr
00407B9F . 8BC>mov ecx,eax ; 取得长度
00407BA1 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaI>; MSVBVM60.__vbaI2I4
00407BA7 . 8BF>mov esi,eax
00407BA9 . 897>mov dword ptr ss:[ebp-2C],esi
00407BAC . 8D4>lea ecx,dword ptr ss:[ebp-48]
00407BAF . 8B1>mov ebx,dword ptr ds:[<&MSVBVM60.__v>; MSVBVM60.__vbaFreeStr
00407BB5 . FFD>call ebx ; <&MSVBVM60.__vbaFreeStr>
00407BB7 . 8D4>lea ecx,dword ptr ss:[ebp-4C]
00407BBA . FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>; MSVBVM60.__vbaFreeObj
00407BC0 . 66:>cmp word ptr ss:[ebp-28],5 ; 堆栈中是Name长度,和5比较,等于5
00407BC5 . 0F8>jl CrackMe_.00407E3E ; 跳就over了
00407BCB . 66:>cmp si,5 ; si=6, 是试练码长,也要是5位以上
返回去改一下Name和试练码,Name改成5位长,试练码改成前缀8129-加上5位12345 。
Name: hud01
Serial: 8129-12345
再跟踪到这里后继续,接下来就是最关键的地方了:
00407BCF . /0F8>jl CrackMe_.00407E3E
00407BD5 . |BE >mov esi,1
00407BDA > |66:>cmp si,word ptr ss:[ebp-28] ; 一个从1到Name位长5的循环
00407BDE . |0F8>jg CrackMe_.00407C9A
00407BE4 . |C74>mov dword ptr ss:[ebp-54],1
00407BEB . |C74>mov dword ptr ss:[ebp-5C],2
00407BF2 . |8D4>lea eax,dword ptr ss:[ebp-44]
00407BF5 . |894>mov dword ptr ss:[ebp-74],eax
00407BF8 . |C74>mov dword ptr ss:[ebp-7C],4008
00407BFF . |0FB>movsx eax,si
00407C02 . |898>mov dword ptr ss:[ebp-DC],eax
00407C08 . |8D4>lea ecx,dword ptr ss:[ebp-5C]
00407C0B . |51 push ecx ; /Arg4
00407C0C . |50 push eax ; |Arg3
00407C0D . |8D5>lea edx,dword ptr ss:[ebp-7C] ; |
00407C10 . |52 push edx ; |Arg2
00407C11 . |8D4>lea eax,dword ptr ss:[ebp-6C] ; |
00407C14 . |50 push eax ; |Arg1
00407C15 . |FF1>call dword ptr ds:[<&MSVBVM60.#632>] ; \rtcMidCharVar
00407C1B . |8D4>lea ecx,dword ptr ss:[ebp-6C]
00407C1E . |51 push ecx
00407C1F . |8D5>lea edx,dword ptr ss:[ebp-48]
00407C22 . |52 push edx
00407C23 . |FF1>call dword ptr ds:[<&MSVBVM60.__vbaS>; MSVBVM60.__vbaStrVarVal
00407C29 . |50 push eax ; /Arg1
00407C2A . |FF1>call dword ptr ds:[<&MSVBVM60.#516>] ; \rtcAnsiValueBstr
00407C30 . |0FB>movsx eax,ax ; 依次取Name各位ASCII值
00407C33 . |898>mov dword ptr ss:[ebp-E0],eax
00407C39 . |DB8>fild dword ptr ss:[ebp-E0]
00407C3F . |DD9>fstp qword ptr ss:[ebp-E8]
00407C45 . |DD8>fld qword ptr ss:[ebp-E8]
00407C4B . |DC4>fadd qword ptr ss:[ebp-3C] ; ASCII相加
00407C4E . |DB8>fild dword ptr ss:[ebp-DC]
00407C54 . |DD9>fstp qword ptr ss:[ebp-F0]
00407C5A . |DC8>fadd qword ptr ss:[ebp-F0] ; 再加循环变量值(1到Name位长)
00407C60 . |DD5>fstp qword ptr ss:[ebp-3C]
00407C63 . |DFE>fstsw ax
00407C65 . |A8 >test al,0D
00407C67 . |0F8>jnz CrackMe_.00407EB1
00407C6D . |8D4>lea ecx,dword ptr ss:[ebp-48]
00407C70 . |FFD>call ebx
00407C72 . |8D4>lea ecx,dword ptr ss:[ebp-6C]
00407C75 . |51 push ecx
00407C76 . |8D5>lea edx,dword ptr ss:[ebp-5C]
00407C79 . |52 push edx
00407C7A . |6A >push 2
00407C7C . |FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>; MSVBVM60.__vbaFreeVarList
00407C82 . |83C>add esp,0C
00407C85 . |B8 >mov eax,1
00407C8A . |66:>add ax,si
00407C8D . |0F8>jo CrackMe_.00407EB6
00407C93 . |8BF>mov esi,eax
00407C95 .^|E9 >jmp CrackMe_.00407BDA ; 循环回去
上面一段将Name各位相加,并从一加到位长,设这个值为Name_Sum。
00407C9A > |DD4>fld qword ptr ss:[ebp-3C]
00407C9D . |FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>; MSVBVM60.__vbaFpI4
00407CA3 . |0FB>movsx ecx,word ptr ss:[ebp-28]
00407CA7 . |99 cdq
00407CA8 . |F7F>idiv ecx ; ASC码和循环位相加后结果后除Name长度
00407CAA . |81C>add edx,4FEF177 ; 余数和4FEF177相加
Name_Sum除以Name位长,余数和常数4FEF177相加,后面会作为注册码比较的依据,设为Comp_Sum(重要!)。上面一段操作,其实只为了取一个余数!
……
00407D00 > \8B5>mov edx,dword ptr ss:[ebp-48] ; 载入试练码
00407D03 . C74>mov dword ptr ss:[ebp-48],0
00407D0A . 8D4>lea ecx,dword ptr ss:[ebp-40]
00407D0D . 8B1>mov ebx,dword ptr ds:[<&MSVBVM60.__v>; MSVBVM60.__vbaStrMove
00407D13 . FFD>call ebx ; <&MSVBVM60.__vbaStrMove>
00407D15 . 8D4>lea ecx,dword ptr ss:[ebp-4C]
00407D18 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>; MSVBVM60.__vbaFreeObj
00407D1E . 8D4>lea eax,dword ptr ss:[ebp-40]
00407D21 . 894>mov dword ptr ss:[ebp-74],eax
00407D24 . C74>mov dword ptr ss:[ebp-7C],4008
00407D2B . 6A >push 5 ; /Arg3 = 00000005
00407D2D . 8D4>lea ecx,dword ptr ss:[ebp-7C] ; |
00407D30 . 51 push ecx ; |Arg2
00407D31 . 8D5>lea edx,dword ptr ss:[ebp-5C] ; |
00407D34 . 52 push edx ; |Arg1
00407D35 . FF1>call dword ptr ds:[<&MSVBVM60.#617>] ; \rtcLeftCharVar
00407D3B . 8B4>mov eax,dword ptr ss:[ebp-24] ; 取试练码的前5位"8129-"
00407D3E . 898>mov dword ptr ss:[ebp-84],eax
00407D44 . C78>mov dword ptr ss:[ebp-8C],8008
00407D4E . 8D4>lea ecx,dword ptr ss:[ebp-5C]
00407D51 . 51 push ecx
00407D52 . 8D9>lea edx,dword ptr ss:[ebp-8C]
00407D58 . 52 push edx
00407D59 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaV>; MSVBVM60.__vbaVarTstNe
00407D5F . 8BF>mov esi,eax ; 上面判断试练码前5位是否是”8129-“
00407D61 . 8D4>lea ecx,dword ptr ss:[ebp-5C]
00407D64 . 8B3>mov edi,dword ptr ds:[<&MSVBVM60.__v>; MSVBVM60.__vbaFreeVar
00407D6A . FFD>call edi ; <&MSVBVM60.__vbaFreeVar>
00407D6C . 66:>test si,si
00407D6F . 0F8>jnz CrackMe_.00407E3E ; 这里不能跳
如果前5位不是”8129-”,那么就跳到game over了。
00407D75 . 8D4>lea eax,dword ptr ss:[ebp-40]
00407D78 . 894>mov dword ptr ss:[ebp-74],eax
00407D7B . BE >mov esi,4008
00407D80 . 897>mov dword ptr ss:[ebp-7C],esi
00407D83 . 8B4>mov eax,dword ptr ss:[ebp-2C]
00407D86 . 66:>sub ax,5 ; 试练码长度-5
00407D8A . 0F8>jo CrackMe_.00407EB6
00407D90 . 0FB>movsx ecx,ax
00407D93 . 51 push ecx ; /Arg3
00407D94 . 8D5>lea edx,dword ptr ss:[ebp-7C] ; |
00407D97 . 52 push edx ; |Arg2
00407D98 . 8D4>lea eax,dword ptr ss:[ebp-5C] ; |
00407D9B . 50 push eax ; |Arg1
00407D9C . FF1>call dword ptr ds:[<&MSVBVM60.#619>] ; \rtcRightCharVar
00407DA2 . 8D4>lea ecx,dword ptr ss:[ebp-5C] ; 上面取试练码第5位以后部分
00407DA5 . 51 push ecx
00407DA6 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaS>; MSVBVM60.__vbaStrVarMove
00407DAC . 8BD>mov edx,eax
00407DAE . 8D4>lea ecx,dword ptr ss:[ebp-40]
00407DB1 . FFD>call ebx
00407DB3 . 8D4>lea ecx,dword ptr ss:[ebp-5C]
00407DB6 . FFD>call edi
00407DB8 . 8B5>mov edx,dword ptr ss:[ebp-40]
00407DBB . 52 push edx ; /Arg1
00407DBC . FF1>call dword ptr ds:[<&MSVBVM60.#581>] ; \rtcR8ValFromBstr
将取到的除前缀部分的字符串转化成数值(可能是Cdble,没验证过),所以后半部分的注册码应该是数值。
00407DC2 . DC0>fadd qword ptr ds:[401110] ; 转化后的数值+951753
00407DC8 . DFE>fstsw ax
00407DCA . A8 >test al,0D
00407DCC . 0F8>jnz CrackMe_.00407EB1
00407DD2 . FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>; MSVBVM60.__vbaFpR8
00407DD8 . DC5>fcomp qword ptr ss:[ebp-3C] ; 再和上面的Comp_Sum比较
从上面这一段我们可以发现,注册码的后半部分应该等于:Comp_Sum ? 951753
所对应的字符,在这里直接修改寄存器使其相等。
00407DDB . DFE>fstsw ax
00407DDD . F6C>test ah,40
00407DE0 . 74 >je short CrackMe_.00407E3E ; 不能跳
如果不相等就跳到game over了。
00407DE2 . B9 >mov ecx,80020004
00407DE7 . 894>mov dword ptr ss:[ebp-64],ecx
00407DEA . B8 >mov eax,0A
00407DEF . 894>mov dword ptr ss:[ebp-6C],eax
00407DF2 . 894>mov dword ptr ss:[ebp-54],ecx
00407DF5 . 894>mov dword ptr ss:[ebp-5C],eax
00407DF8 . 8D4>lea eax,dword ptr ss:[ebp-34]
00407DFB . 898>mov dword ptr ss:[ebp-84],eax
00407E01 . 89B>mov dword ptr ss:[ebp-8C],esi
00407E07 . 8D4>lea ecx,dword ptr ss:[ebp-30]
00407E0A . 894>mov dword ptr ss:[ebp-74],ecx
00407E0D . 897>mov dword ptr ss:[ebp-7C],esi
00407E10 . 8D5>lea edx,dword ptr ss:[ebp-6C]
00407E13 . 52 push edx
00407E14 . 8D4>lea eax,dword ptr ss:[ebp-5C]
00407E17 . 50 push eax
00407E18 . 8D8>lea ecx,dword ptr ss:[ebp-8C]
00407E1E . 51 push ecx
00407E1F . 6A >push 40
00407E21 . 8D5>lea edx,dword ptr ss:[ebp-7C]
00407E24 . 52 push edx ; 到这里就成功了
00407E25 . FF1>call dword ptr ds:[<&MSVBVM60.#595>] ; MSVBVM60.rtcMsgBox
下面显示标题为”Congratulation的对话框:”Good Job!”
这个Crackme也不难,我个人主要在” 余数和常数4FEF177相加”和注册码后半部分比较这里反复了几次。
下面是算法总结和C语言注册机。
/********************************************************************
happytown crackme No.2 C 语言注册机(Win-TC)
By hud, November 13, 2005
-----------------------------
算法:
1. Name要在5位以上;
2. Name各位ASCII码相加,再加从1到位长的数字,得Sum1;
3. Sum1 除以Name位长,余数+常数0x4FEF177,得Comp_Sum;
4. 注册码前5位为固定字符串"8129-";
5. 注册码后半部分应该为整数值,加上常数951753应该等于Comp_Sum。
********************************************************************/
#include <stdio.h>
void main()
{
char name[80];
int i, len, sum = 0;
unsigned long x, base = 0x4FEF177, sub = 951753;
printf("Input name(at least 5) please:\n");
scanf("%s", name);
len = strlen(name);
if (len<5)
{
printf("Name at least 5!\n");
return;
}
for (i=0; i<len; ++i)
sum += name[i] + ( i + 1 );
x = (unsigned long)( sum % len ) + base - sub;
printf("The serial is: 8129-%lu\n", x);
getch();
}