海天一色001 发表于 2017-6-27 12:31

160个CrakeMe程序之014

本帖最后由 海天一色001 于 2017-8-19 19:01 编辑

经过第12、第13个两个CM程序,感觉心里已经有了阴影了,第14个可千万别这样说是一星,再出一个P-code出来!先运行看一下程序基本情况,只有序列号,还有一个“about”菜单,“about”菜单打开也就是一般的关于内容,对Crack没有什么帮助。

输入“1234567890”,点击“Check it”按钮,弹出错误信息框!嗯,这下可能不会很难了!

先查壳,结果是VB程序,没加壳:

第一步,爆破:导入OD,看这一次的按钮事件断点,是否管用:在反汇编窗口中右键查找二进制字串或快捷键“Ctrl+B”,输入“816C24”,确定,

马上找到了3个:

在这三个按钮事件的下一句的跳转上分别下断点后,F9运行程序,输入“1234567890”,再点击“Check it”按钮,程序中断于00401F55处:

F8单步一下,来到检验注册码的代码段首,这次的代码比较熟悉了,心中不是那么紧张了:先向下拉,很快在注释栏中看到了错误信息框的标题和内容:

再向下,就是成功信息框的标题和内容了!那么爆破就应该从成功信息开始向上找跳过成功的指令,再找让其失效的其他跳转指令:

00403AA2处跳过成功,下一地址00403AA4处则是从00403787跳来的,那么转到00403787处,“jg bjanes_1.00403AA4”是条件跳转,改成无条件跳转jmp命令试一试:

F9运行程序,还是没有成功,说明在这个跳转前还有其他跳转跳过了本指令,还要向上查找:在00403731处的跳转是跳到了00403745处,在跳向成功的指令之前,不用理会,继续向上查找:在00403704处的跳转是跳到了00403A24处,跳到了失败,nop掉试一下:

F9运行程序,成功了!

将修改后的程序存为bjanes.1_nop.exe,打开bjanes.1_nop.exe,不输入或随意输入字符,点击“Check it”按钮均弹出成功信息框。爆破完成。接下来,第二步,追码:换工具,VBDecompiler来了!

从VB Decompiler左侧窗口看到有两个窗体,点击CrackmeV20a窗体和Form1,在右侧的信息栏中看到了相关的信息,知道了Form1是关于窗口,CrackmeV20a是主窗体,Command1_Click是“Check it”按钮。再选择Code -> CrackmeV20a ->Command1_Click_403620,右侧出现按钮事件的代码,这次与OD对照,能够很好地对上了!



将VB Decompiler中的注释粘贴到OD对应地址的注释栏中,从“Check it”按钮事件段首下断,F9运行,输入“1234567890”,点击“Check it”按钮,程序中断,F8单步运行至004036D9地址处,此时得到了假码;继续向下,注册码长度与9进行比较,说明注册码要么不大于9位或者是不小于9位,要么就是只有9位,看下面运行情况如何了。我刚才爆破时就是在跳转指令上进行了nop,那么注册码长度就可以不限定了。
004036D9> \8B45 E4       mov eax,dwordptr ss:                   ;得到假码
004036DC.50            push eax                                           ;/String = NULL004036DD.FF15
08104000 call dword ptrds:[<&MSVBVM60.__vbaLenBstr>]      ; \得到假码长度,存入eax中
004036E3.33C9          xor ecx,ecx
004036E5.83F8 09       cmp eax,0x9                                        ;注册码长度与9比较
004036E8.0f95c1      setne cl                                           ;if eax=9 then cl=0;if eax<>9 then cl=1
004036EB.F7D9          neg ecx                                          ;ecx求补后存入ecx中:cl=0,求补后还为0;cl=1,求补为-1,用FFFFFFFF表示
004036ED.8BF1          mov esi,ecx                                        ;esi=ecx
004036EF.8D4D E4       lea ecx,dword ptr ss:
004036F2.FF15 C0104000 call dword ptrds:[<&MSVBVM60.__vbaFreeStr>]      ;msvbvm60.__vbaFreeStr
004036F8.8D4D D4       lea ecx,dword ptr ss:
004036FB.FF15 C4104000 call dword ptrds:[<&MSVBVM60.__vbaFreeObj>]      ;msvbvm60.__vbaFreeObj
00403701.66:3BF3       cmp si,bx                                          ;si来源于ecx
00403704      0F85 1A030000 jnz bjanes_1.00403A24                              ;If ecx <> 0 Then 跳到失败:
可知注册码必须为9位继续向下到00403701处,si与bx进行比较,前面bx=0一直不变,si又在004036ED处被ecx赋值,所以ecx在上一条指令中应该为0,继续逆推到004036E5地址,eax是注册码长度,所以注册码必须是9位的:此时我输入的假码长度为10,超过了9,所以向下一步,跳转实现了,程序失败;将按钮事件段首断点禁用,在004036D9处下断,F9运行,程序弹出错误信息框,点掉,将注册码文本框中的字符删掉第一位,变成“234567890”,再点击“Check it”按钮,程序再次中断,继续单步至00403704处,信息栏中显示跳转未实现,继续向下进行到下列代码处:
00403745> \8B45 E4       mov eax,dwordptr ss:                   ;得到假码
00403748.50            push eax                                           ;/String = NULL
00403749.FF15 08104000 call dword ptrds:[<&MSVBVM60.__vbaLenBstr>]      ; \__vbaLenBstr
0040374F.8BC8          mov ecx,eax
00403751.FF15 50104000 call dword ptrds:[<&MSVBVM60.__vbaI2I4>]         ;把ecx从4字节整数转换成2字节整数
00403757.8D4D E4       lea ecx,dword ptr ss:
0040375A.8985 14FFFFFF mov dword ptrss:,eax                   ;var_EC = Len(var_1C)
00403760.C745 E8 01000>mov dword ptrss:,0x1                   ;ss:=1
00403767.FF15 C0104000 call dword ptrds:[<&MSVBVM60.__vbaFreeStr>]      ;msvbvm60.__vbaFreeStr
0040376D.8D4D D4       lea ecx,dword ptr ss:
00403770.FF15 C4104000 call dword ptrds:[<&MSVBVM60.__vbaFreeObj>]      ;var_eax = %fobj
00403776.8B35 AC104000 mov esi,dword ptrds:[<&MSVBVM60.__vbaStrMove>]   ;msvbvm60.__vbaStrMove
0040377C>66:8B8D 14FFF>mov cx,wordptr ss:
00403783. |66:394D E8    cmp word ptrss:,cx                        ;此处比较就有点不正常:上面已经确定长度必须为9,1>9不成立,所以此处不可能跳转
00403787    |0F8F 17030000 jg bjanes_1.00403AA4                                    ;(If var_18 <= 0 Then)跳往成功,改成无条件跳转jmp或者是jl即爆破
结合上一段代码,注册码只能为9位,现在到00403783处和1进行比较也没什么,问题是比较的结果:9不可能小于1,所以这里也不可能跳往成功处,改成无条件跳转指令就爆破了,要查找注册算法就不能改它,继续向下:从VB Decompiler中粘贴来的注释中看出:从00403831处开始到0040386B处取假码的第一位字符与“9”和“0”比较看是否为数字,结果存入bl寄存器中,然后对bl求补;来到004038AA处对bx进行检测,如果不为0,则注册码错误,程序失败;

如bx为0,则程序正常向下进行:一直到004038F1至0040391B处,取1 xor 2 = 3 ,再将数字变成Unicode字符“3”,存入edx中,再存入到ss:;
004038F1> \66:8B45 E8    mov ax,wordptr ss:                        ;ax=1
004038F5.8B1D 74104000 mov ebx,dword ptrds:[<&MSVBVM60.#rtcStrFromVar_536>];msvbvm60.rtcStrFromVar
004038FB.66:35 0200    xor ax,0x2                                              ;ax xor 2 =3 ,存入ax中,也就是说ax=3
004038FF.8D4D A0       lea ecx,dword ptr ss:
00403902.0F80 A4020000 jobjanes_1.00403BAC                                    ;溢出错误(If Err.Number <> 0 Then)
00403908. |51            push ecx
00403909. |66:8945 A8    mov word ptrss:,ax                        ;var_58 = var_18 xor 0002h
0040390D. |C745 A0 02000>mov dword ptr ss:,0x2
00403914. |FFD3          call ebx                                             ;msvbvm60.rtcStrFromVar;<&MSVBVM60.#rtcStrFromVar_536>
00403916. |8BD0          mov edx,eax
00403918. |8D4D D8       lea ecx,dword ptrss:
0040391B. |FFD6          call esi                                             ;var_28 = Str$()=Unicode “3”
继续向下单步走到00403939B6处,此处调用比较,如不等返回ax=-1,内存表示为“FFFFFFFF”;如两数相等则ax=0。看注释中有var18、var28作为—__vbaVarTstNe的参数进行比较,看到var18和var28的值明显是个内存地址形式,但这两个数值来自于“ebp-0xD0”和“ebp-0x80”,这两个数值肯定是不相等的,那么这个调用之后(到达00403A01处,检测edx,ZF不为0则跳到失败)就弹出错误信息了!实在是郁闷,如果按我这样的理解,就没有正确的注册码啊!

但是还不信邪,作者不可能写一个CM只让人爆破啊!
前面已分析出注册码有9位,而且全是数字,所以干脆在004039B7处先下断后,将第一个字符依次改成0-9中的数字试验着看看!
F9运行,弹出错误信息框,将第一个字符依次改成0-9中的数字,点击“Checkit”按钮,查看每一次调用后eax的值:0、1、2时eax=-1,到3时eax=0了!
此时再向下,那么到达00403A04处时就会不跳,再到00403A12处,没有溢出也不跳转;
继续向下,到00403A1D处,无条件跳转至0040377C,开始循环了,说明第一个字符是“3”:
继续单步走,这一次又失败了,同时第二个字符处也是“3”,看不出与第一个字符的区别,所以下一次重新运行程序时注册码要让每一个都不重复才行,输入“321456789”试试:
第一个字符是“3”,感觉程序中计算注册码不是取“3”进行计算,而是用1 xor 2得到数值3,再与取的字符“3”比较,不知对不对。
第一次运行到达了00403A1D处,无条件跳转回0040377C处。再次单步到达004038F1至0040391B处,004038F1处eax=ss:=2,取2 xor 2 = 0 ,再将数字变成Unicode字符“0”,存入edx中,再存入到ss:;继续走至0040391D处时,堆栈中情况如下:

堆栈SS:;ss:=UNICODE"321456789";ss:= UNICODE " 0";ss:= 0;ss:= 2;ss:= 2;
继续下去,程序又弹出错误信息;猜测第二个字符是2 xor 2 的结果0;F9运行,试一试将第二个字符改成“0”,这次第二次循环也过了,到了第三次循环,看到是3 xor 2 =1,正好我的第三个字符是“1”,所以到004039B7处时eax=0,可以到达第四个循环;F9运行,程序弹出错误信息,在OD中查看00403997地址处ss:= " 6",那么就将第4位数改为“6”;再运行,可以看到004038F1处,第一次ss:=1;第二次ss:=2;第三次ss:=3;第四次ss:=4,第五次为5,所以猜测是1-9共9次循环,每个字符是与2异或后的结果。先在计算器中将后面几个数字(5-9)与2异或的结果算出来,分别是7、4、5、10、11,但连起来变成了30167451011,多出了两位!再仔细观察程序中004039A5处:004039A5.FF15 B0104000 call dword ptrds:[<&MSVBVM60.#rtcRightCharVar_619>]    ; var_80 = Right(var_28, 1)取字符串右边一位;前几个都是空格连上一个数字组成了一个字符串,最后两个是两个数字连在一起组成的字符串,所以都取右边的字符,就等到了字符串“301674501”。将“301674501”填入文本框,再次试一下,成功!

注册机就比较简单了:
Private Sub Command1_Click()
   Label1.Visible = False
   Label2.Visible = True
   For i = 1 To 9
         a = i Xor 2
         a = Right(a, 1)
      code = code & a
   Next
   Text1.Visible = True
    Text1.Text = code
End Sub
本程序虽然比上一个容易分析一些,可是也很让人头痛,VB确实比其他编程语言难分析,特别是堆栈中存取数据,不知道该从哪里入手!
在练习过程中,肯定还有不到位及分析错误的地方,欢迎各位坛友讨论指导!
附件,含CM原程序、爆破后的程序及014注册机。百度链接是:http://pan.baidu.com/s/1skMkJY9密码: 86pm,160个CM、我已练习过的前14个crackme程序(不含012)都在里面。

海天一色001 发表于 2020-5-29 19:31

xiaomm250 发表于 2020-4-21 16:23
首先,为什么“816C24”?
还有标题中应该是crack,单词拼错了!

你好!谢谢你的提醒!单词确实是拼写错误!
816C24是VB中的按钮事件,你可以在本网站里搜索一下,也可以直接看这一篇:https://www.52pojie.cn/thread-802115-1-1.html,讲得非常详细。

海天一色001 发表于 2017-6-29 19:02

肥牛 发表于 2017-6-27 14:53
从这些帖子,逐渐看到了楼主的进步,加油!

谢谢肥牛大神的鼓励!你上次给我发的那个程序我也找到了序列号,可是下一步也是出现了你所说的不成功现象!我在OD中发现它算机器码时看到调用硬盘信息说用虚拟机,会不会因此而失败?

捷豹网络丶贱仔 发表于 2017-6-27 12:52

肥牛 发表于 2017-6-27 14:53

从这些帖子,逐渐看到了楼主的进步,加油!

小村村 发表于 2017-6-28 08:34

做一个测试 很好

ChHorizon 发表于 2017-6-28 15:25

谢谢楼主,正好练手

血荐轩辕 发表于 2017-6-28 21:40

小白表示,受教了,回去学习一个

小村村 发表于 2017-6-29 08:40

做一个测试 很好

longzan110 发表于 2017-6-29 21:41

看起来好晕了

fishinfire 发表于 2017-7-4 14:36

要不要这么拼命呀,追码追得头都大
页: [1] 2
查看完整版本: 160个CrakeMe程序之014