首页
社区
课程
招聘
[原创]菜鸟挑战VB程序 - 跟踪经验和实例(之二)
2005-11-13 15:56 7897

[原创]菜鸟挑战VB程序 - 跟踪经验和实例(之二)

hud 活跃值
2
2005-11-13 15:56
7897
  经过上一次破解sunson’s crackme No.1的成功,对VB程序的信心增强了一些,也多少积累了一些经验:

1、        要熟悉VB经常调用的函数,一般是以__vba和rtc前缀开头的,像__vbaStrCmp, rtcMsgbox, rtcMidCharVar等;
2、        重点要放在我们所分析的程序代码上,比如我们调试的exe文件名为:crackme.exe,那么在OD中就要注意Call crackme.xxxxxx一类的调用,而对于Call &MSVBVM60.xxxxxx、Call User32.xxxxxx、OLEAUT32. xxxxxx一类的系统函数一般步过就行了;
3、        VB程序的For、While、Do…Loop循环结尾常常用jo跳转来判断是否要继续循环还是结束循环;
4、        SmartCheck是分析VB程序的一大利器,配合ollyDbg使用,常常能赶到事半功倍的效果。

一些别的程序语言也适合的经验:

1、        碰到WndProc、ProcClass这类窗口和消息函数调用,一般不要步入,否则很难退出来(其它程序也适用);
2、        对于分段验证的程序:正确- ABCDE,试练-12345,如果A错了,根本就不会运行到B。在跟踪分析出A的要求后,重启,试练改为A2345,再跟踪分析。用这种方法就能一步步地走到目标;
3、        这点不是技术问题,也不只是适用于VB程序,但可能重要过很多技术因素:耐心!

前面成功分析过happytown的crackme #06、#07,比较喜欢他的作品(因为适合我这样的初学者啊!),看了看本站他发表的Crackme #1,也是VB程序,好像现在还没有人分析过算法,那就把它作为我的第二个VB程序练习吧。

【软件名称】:happytown CrackMe ###1.exe
【原贴参考】:http://bbs.pediy.com/showthread.php?s=&threadid=15354
【软件下载】:因为原贴中下载有时候有问题,我就传上一个附件:happytown-crackme-01.zip
【软件信息】: VB 6.0,无壳,64 KB,用户名-注册码方式,无错误提示
【破解工具】:OllyDbg 1.10聆风听雨汉化第二版, SmartCheck 6.20

启动后运行一下,随便输入个用户和试练码,没有任何提示,用SmartCheck打开,F5运行,输入:

Name: hud
Serial: 123123

点击Check按钮,回到SmartCheck中,察看Events。

Events中有:FormCreate,Form_Load,txtName和txtSerial的GotFocus/LostFocus事件,都没有什么和注册码验证相关的内容,那么所有的验证都在按钮Check的Click事件中完成了。

点击cmdCheck_Click左边+号展开,发现的动作有:
1.        取得Name的字符和长度
2.        取得试练码的字符和长度

然后就结束了。说明输入的用户名或者试练码不符合要求!

现在轮到OD上场了,用OD打开并按F9运行,在Crackme中输入上述Name及试练码,回到OD中,先试试下断点在__vbaStrCmp上,断不下来;再试__vbaStrCopy,断下了:

004079A3    .  8B3D 80>mov edi,dword ptr ds:[<&MSVBVM60._>;  MSVBVM60.__vbaStrCopy
004079A9    .  33DB    xor ebx,ebx
004079AB    .  BA 5871>mov edx,CrackMe_.00407158          ;  UNICODE "Congratulations"
004079B0    .  8D4D D8 lea ecx,dword ptr ss:[ebp-28]
004079B3    .  895D E8 mov dword ptr ss:[ebp-18],ebx
004079B6    .  895D DC mov dword ptr ss:[ebp-24],ebx
004079B9    .  895D D8 mov dword ptr ss:[ebp-28],ebx
004079BC    .  895D D4 mov dword ptr ss:[ebp-2C],ebx
004079BF    .  895D D0 mov dword ptr ss:[ebp-30],ebx
004079C2    .  895D CC mov dword ptr ss:[ebp-34],ebx
004079C5    .  895D C8 mov dword ptr ss:[ebp-38],ebx
004079C8    .  895D B8 mov dword ptr ss:[ebp-48],ebx
004079CB    .  895D A8 mov dword ptr ss:[ebp-58],ebx
004079CE    .  895D 98 mov dword ptr ss:[ebp-68],ebx
004079D1    .  895D 88 mov dword ptr ss:[ebp-78],ebx
004079D4    .  899D 78>mov dword ptr ss:[ebp-88],ebx
004079DA    .  899D 68>mov dword ptr ss:[ebp-98],ebx
004079E0    .  899D 58>mov dword ptr ss:[ebp-A8],ebx
004079E6    .  FFD7    call edi                           ;  <&MSVBVM60.__vbaStrCopy>
004079E8    .  BA 7C71>mov edx,CrackMe_.0040717C          ;  UNICODE "Good Job!"
004079ED    .  8D4D DC lea ecx,dword ptr ss:[ebp-24]

很快看到下面有”Congratilations”和”Good Job!”,心中一阵狂喜!是SmartCheck错了吗?一路F8按下去:

……

00407A2D    > \8B5>mov edx,dword ptr ss:[ebp-30]        ;  这里出现了试练码hud
00407A30    .  8B3>mov edi,dword ptr ds:[<&MSVBVM60.__v>;  MSVBVM60.__vbaStrMove
00407A36    .  8D4>lea ecx,dword ptr ss:[ebp-2C]
00407A39    .  895>mov dword ptr ss:[ebp-30],ebx
00407A3C    .  FFD>call edi                             ;  <&MSVBVM60.__vbaStrMove>
00407A3E    .  8D4>lea ecx,dword ptr ss:[ebp-38]
00407A41    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>;  MSVBVM60.__vbaFreeObj
00407A47    .  8B4>mov eax,dword ptr ss:[ebp-2C]
00407A4A    .  50  push eax
00407A4B    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaL>;  MSVBVM60.__vbaLenBstr
00407A51    .  8BC>mov ecx,eax                          ;  得到的Name长度3放到ecx中

走到这里,发现不对啊,这不是和SmartCheck里“先取Name的字串和长度”的过程是一致的吗?

那么为什么有”Congratilations”和”Good Job!”字串呢?想了一下,可能是happytown为了避免破解者通过查找这两个字串很快定位,然后逆流而上,很快就能找到关键算法,所以提前在这里处理。这样看还没开始呢!但是断点应该下对了(这里有点运气成分,正好把这两个字串提前处理,调用了这个函数,在大部分VB程序中,用这个函数并不能断到关键处)!继续F8:
……

00407A97    > \8B5>mov edx,dword ptr ss:[ebp-30]        ;  试练码出现,预料之中
00407A9A    .  8D4>lea ecx,dword ptr ss:[ebp-18]
00407A9D    .  895>mov dword ptr ss:[ebp-30],ebx
00407AA0    .  FFD>call edi
00407AA2    .  8D4>lea ecx,dword ptr ss:[ebp-38]
00407AA5    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>;  MSVBVM60.__vbaFreeObj
00407AAB    .  8B5>mov edx,dword ptr ss:[ebp-18]
00407AAE    .  52  push edx
00407AAF    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaL>;  MSVBVM60.__vbaLenBstr
00407AB5    .  8BC>mov ecx,eax                          ;  试练码长度
00407AB7    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaI>;  MSVBVM60.__vbaI2I4
00407ABD    .  66:>cmp word ptr ss:[ebp-1C],5

哈哈,原来问题出在这里,Name要5位以上!按F9,将Name改为hud01,将前面的断点关闭,在这里下个断点,再按F9向下继续:

00407AC2    . /0F8>jl CrackMe_.004081C4                 ;  跳就over了
00407AC8    . |66:>cmp ax,0A

另一个问题出现了,注册码不小于10位长,如法炮制,试练码改为:1234567890,F9继续:

00407ACC    . /0F8>jl CrackMe_.004081C4                 ;  跳就over了
00407AD2    . |8B3>mov esi,dword ptr ds:[<&MSVBVM60.#63>;  MSVBVM60.rtcMidCharVar
00407AD8    . |8D4>lea eax,dword ptr ss:[ebp-18]
00407ADB    . |8D4>lea ecx,dword ptr ss:[ebp-48]
00407ADE    . |894>mov dword ptr ss:[ebp-80],eax
00407AE1    . |51  push ecx
00407AE2    . |8D9>lea edx,dword ptr ss:[ebp-88]
00407AE8    . |6A >push 1
00407AEA    . |8D4>lea eax,dword ptr ss:[ebp-58]
00407AED    . |52  push edx
00407AEE    . |50  push eax
00407AEF    . |C74>mov dword ptr ss:[ebp-40],1
00407AF6    . |C74>mov dword ptr ss:[ebp-48],2
00407AFD    . |C78>mov dword ptr ss:[ebp-88],4008
00407B07    . |FFD>call esi                             ;  <&MSVBVM60.#632>
00407B09    . |8B3>mov edi,dword ptr ds:[<&MSVBVM60.__v>;  MSVBVM60.__vbaStrVarVal
00407B0F    . |8D4>lea ecx,dword ptr ss:[ebp-58]
00407B12    . |8D5>lea edx,dword ptr ss:[ebp-30]
00407B15    . |51  push ecx
00407B16    . |52  push edx
00407B17    . |FFD>call edi                             ;  <&MSVBVM60.__vbaStrVarVal>
00407B19    . |50  push eax                             ; /Arg1
00407B1A    . |FF1>call dword ptr ds:[<&MSVBVM60.#516>] ; \rtcAnsiValueBstr
00407B20    . |33C>xor ecx,ecx
00407B22    . |66:>cmp ax,70

上面这一段将试练码第一位”1”取出来,将其值31放入ax中,与0x70(112., ‘p’)比较。

00407B26    .  0F9>setne cl                             ;  上面比较相等就为假,不相等就设为真
00407B29    .  F7D>neg ecx
00407B2B    .  898>mov dword ptr ss:[ebp-BC],ecx
00407B31    .  8D4>lea ecx,dword ptr ss:[ebp-30]
00407B34    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>;  MSVBVM60.__vbaFreeStr
00407B3A    .  8D5>lea edx,dword ptr ss:[ebp-58]
00407B3D    .  8D4>lea eax,dword ptr ss:[ebp-48]
00407B40    .  52  push edx
00407B41    .  50  push eax
00407B42    .  6A >push 2
00407B44    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>;  MSVBVM60.__vbaFreeVarList
00407B4A    .  83C>add esp,0C
00407B4D    .  66:>cmp word ptr ss:[ebp-BC],bx          ;  堆栈=FFFF,bx=0000
00407B54    .  0F8>jnz CrackMe_.004081C4                ;  不相等则跳,跳则over

将试练码第1位改为p:p234567890,再到这里后继续F8:
……

00407BCC    .  66:>mov bx,ax                            ;  将上面取到的Name第1位'h'值0x68放入bx
00407BCF    .  8D5>lea edx,dword ptr ss:[ebp-58]
00407BD2    .  8D4>lea eax,dword ptr ss:[ebp-30]
00407BD5    .  52  push edx
00407BD6    .  50  push eax
00407BD7    .  FFD>call edi
00407BD9    .  50  push eax                             ; /Arg1
00407BDA    .  FF1>call dword ptr ds:[<&MSVBVM60.#516>] ; \rtcAnsiValueBstr
00407BE0    .  33C>xor ecx,ecx                          ;  上面将试练码第2位'2'的值0x32放入ax
00407BE2    .  66:>cmp ax,bx                            ;  ax和bx比较

到这里大家应该很明白了吧,试练码第2位应该等于Name第1位,为了加快速度,我们不用再重复回去了,在寄存器窗口在eax上双击,将eax的值改为0x68,继续:

00407BE5    .  8D5>lea edx,dword ptr ss:[ebp-34]
00407BE8    .  8D4>lea eax,dword ptr ss:[ebp-30]
00407BEB    .  0F9>setne cl                             ;  根据比较结果设置bool变量
00407BEE    .  52  push edx
00407BEF    .  50  push eax
00407BF0    .  F7D>neg ecx
00407BF2    .  6A >push 2
00407BF4    .  898>mov dword ptr ss:[ebp-BC],ecx
00407BFA    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>;  MSVBVM60.__vbaFreeStrList
00407C00    .  8D4>lea ecx,dword ptr ss:[ebp-78]
00407C03    .  8D5>lea edx,dword ptr ss:[ebp-68]
00407C06    .  51  push ecx
00407C07    .  8D4>lea eax,dword ptr ss:[ebp-58]
00407C0A    .  52  push edx
00407C0B    .  8D4>lea ecx,dword ptr ss:[ebp-48]
00407C0E    .  50  push eax
00407C0F    .  51  push ecx
00407C10    .  6A >push 4
00407C12    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>;  MSVBVM60.__vbaFreeVarList
00407C18    .  33D>xor ebx,ebx
00407C1A    .  83C>add esp,20
00407C1D    .  66:>cmp word ptr ss:[ebp-BC],bx          ;  上面比较如果不相等这里就跳了(game over)
00407C24    .  0F8>jnz CrackMe_.004081C4

由于我们直接改了寄存器的值,这次没跳!

00407C2A    .  8D5>lea edx,dword ptr ss:[ebp-18]
00407C2D    .  8D4>lea eax,dword ptr ss:[ebp-48]
00407C30    .  895>mov dword ptr ss:[ebp-80],edx
00407C33    .  50  push eax
00407C34    .  8D8>lea ecx,dword ptr ss:[ebp-88]
00407C3A    .  6A >push 3
00407C3C    .  8D5>lea edx,dword ptr ss:[ebp-58]
00407C3F    .  51  push ecx
00407C40    .  52  push edx
00407C41    .  C74>mov dword ptr ss:[ebp-40],1
00407C48    .  C74>mov dword ptr ss:[ebp-48],2
00407C4F    .  C78>mov dword ptr ss:[ebp-88],4008
00407C59    .  FFD>call esi
00407C5B    .  8D4>lea eax,dword ptr ss:[ebp-58]
00407C5E    .  8D4>lea ecx,dword ptr ss:[ebp-30]
00407C61    .  50  push eax
00407C62    .  51  push ecx
00407C63    .  FFD>call edi
00407C65    .  50  push eax                             ; /Arg1
00407C66    .  FF1>call dword ptr ds:[<&MSVBVM60.#516>] ; \rtcAnsiValueBstr
00407C6C    .  33D>xor edx,edx
00407C6E    .  66:>cmp ax,65                            ;  试练码第3位要等于0x65('e')
00407C72    .  0F9>setne dl
00407C75    .  F7D>neg edx
00407C77    .  8D4>lea ecx,dword ptr ss:[ebp-30]
00407C7A    .  899>mov dword ptr ss:[ebp-BC],edx
00407C80    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>;  MSVBVM60.__vbaFreeStr
00407C86    .  8D4>lea eax,dword ptr ss:[ebp-58]
00407C89    .  8D4>lea ecx,dword ptr ss:[ebp-48]
00407C8C    .  50  push eax
00407C8D    .  51  push ecx
00407C8E    .  6A >push 2
00407C90    .  FF1>call dword ptr ds:[<&MSVBVM60.__vbaF>;  MSVBVM60.__vbaFreeVarList
00407C96    .  83C>add esp,0C
00407C99    .  66:>cmp word ptr ss:[ebp-BC],bx          ;  试练码第3位比较
00407CA0    .  0F8>jnz CrackMe_.004081C4                ;  试练码第3位不等于e就跳了

……

00407D19    .  66:>mov bx,ax                            ;  Name第2位'u'
00407D1C    .  8D4>lea eax,dword ptr ss:[ebp-58]
00407D1F    .  8D4>lea ecx,dword ptr ss:[ebp-30]
00407D22    .  50  push eax
00407D23    .  51  push ecx
00407D24    .  FFD>call edi
00407D26    .  50  push eax                             ; /Arg1
00407D27    .  FF1>call dword ptr ds:[<&MSVBVM60.#516>] ; \rtcAnsiValueBstr
00407D2D    .  33D>xor edx,edx
00407D2F    .  66:>cmp ax,bx                            ;  注册码第4位要等于Name第2位

到这里我们可以先推测算法:

1.        Name长度5位;
2.        注册码长度10位;
3.        注册码奇数位为固定字符;
4.        注册码偶数位是Name。

以前分析过happytown的crackme #7,它的注册码前面是HT-T: H(appy)T(own)-(crackme)7,这个固定字串可能也是个有意义的字串吧,前2位是pe,和happytown关系不上啊,哦,pediy,正好5位,就是它了!

输入一试,果然是它!上面的”Good Job!”出来了,看来我后部分都不需要验证了。

附C语言注册机:

/********************************************************************

happytown crackme #1 C语言注册机(Win-TC)

By hud, November 12, 2005

********************************************************************/

#include <stdio.h>

void main()
{
    char name[5], sn[11], fix[] = "pediy";
    int i;

    printf("Input 5-character name:\n");
    scanf("%s", name);

    if (strlen(name)!=5)
        return;

    for (i=0; i<10; ++i)
    {
        sn[i] = fix[i/2];
        sn[(i++)+1] = name[i/2];
    }
    sn[10]='\0';
    printf("Serial is: %s\n", sn);
    getch();
}

因为有了上次拆解sunson’s crackme No.1的经验,加上happytown crackme #1相比起来简单些,所以相当顺利,连F7都没用上,整个过程只用了10多分钟,反倒是写这篇破文花了我个把钟。

因为进度比想像的快,又是周末,我就继续着手happytown的crackme No. 02。

[培训]《安卓高级研修班(网课)》月薪三万计划,掌 握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法

收藏
点赞7
打赏
分享
最新回复 (10)
雪    币: 221
活跃值: (151)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hud 2 2005-11-13 16:05
2
0
首先要说明,这个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();
}
雪    币: 234
活跃值: (370)
能力值: ( LV9,RANK:530 )
在线值:
发帖
回帖
粉丝
lnn1123 13 2005-11-13 17:02
3
0
不错,学习了
雪    币: 214
活跃值: (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
ljy3282393 1 2005-11-14 00:53
4
0
最初由 lnn1123 发布
不错,学习了
雪    币: 50
活跃值: (145)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
zhaoocn 7 2005-11-14 12:04
5
0
学习学习我头疼Vb
雪    币: 443
活跃值: (200)
能力值: ( LV9,RANK:1140 )
在线值:
发帖
回帖
粉丝
冷血书生 28 2005-11-19 22:37
6
0
学习了!・
雪    币: 721
活跃值: (350)
能力值: ( LV9,RANK:1250 )
在线值:
发帖
回帖
粉丝
happytown 31 2005-11-22 08:50
7
0
CrackMe ###2的确因为我的疏忽,Serial框不能输入。而且,由于分析还原精灵导致机子硬盘所有文件丢失,所以也就无法得知起初的代码,也所以就没有上传这个CrackMe。

但今天看到你能把这个CrackMe也给破掉,真是高兴。

======================================

BTW:

我注意到你的注册机都是用tc做的,你为何不用VC,Delphi,VB,或者W32ASM写呢?

用这些会方便许多。
雪    币: 221
活跃值: (151)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
hud 2 2005-11-22 16:36
8
0
happytown, 你好!

谢谢你的点评!我其后不久把你的Crackme 03也解开了(14位长,6、12为'-',中间为余数对称,后面是3、5位余数后缀),但因为我对于VB程序暂时没有什么更深入的新的理解,其破文也就没发了。

你的crackme非常好,是我最好的入门练习。但是你的04、05是C#写的,而我现在只会Ollydbg(据说VS.Net版的有反编译器),且我现在准备多练练基础,等以后再学习其它程序破解。

至于写注册机的语言。Delphi和W32ASM我不会,VB在写很多位和逻辑运算时比较烦,VC编译出来的文件很大且带有一大串的附加文件。所以我个人偏爱用TC,加上C语言比较精练,用它写简单的注册机很方便,且文件短小,不需要附Project文件都很清楚。但如果牵涉到Window方面内容的注册机用TC和C语言写就比较麻烦(要有很好的SDK功力),比如你的crackme6,其中有GetVolumeInformation,而且(我自己写的注册机)后面还要用到int64,在TC中都较难实现,就要用VC了(这个注册机用VB也不方便,有好多位运算)。

以后我有时间还希望学习学习W32ASM,到时有问题还请多指教。
雪    币: 277
活跃值: (312)
能力值: ( LV9,RANK:330 )
在线值:
发帖
回帖
粉丝
wangshq397 8 2005-12-1 21:21
9
0
看看我这个http://bbs.pediy.com/showthread.php?s=&threadid=15766
雪    币: 191
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
玉面骄龙 2005-12-7 13:13
10
0
不错,受教了
雪    币: 210
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
突然厉害 2005-12-11 21:08
11
0
作者的帖子很好,很适合初学者,感谢。
游客
登录 | 注册 方可回帖
返回