海天一色001 发表于 2019-7-14 08:07

160个Crackme之030学习笔记

本帖最后由 海天一色001 于 2019-7-14 16:34 编辑

第30个CM程序,这个程序有好几个窗体,先在File菜单上选择“password”命令进入主窗体,输入“1234567890”,点击“OK”按钮,弹出错误提示框,在About菜单上点击弹出关于信息,没什么用处:
      
第一步、查壳:

无壳,这个程序是VB5.0编程:
第二步、爆破
用OD载入cracking4all.1.exe,智能搜索字符串:

在004033A5这一行双击进入CPU窗口:

向上查看至00403370处,指令是“je cracking.0040345E”,跳过了成功提示,来到失败提示处,所以将这里nop掉试一下:

修改后的文件保存为cracking4all.1.nop.exe,运行,在password窗口中输入任何字符或者不输入字符,点击“OK”按钮时,均弹出成功提示框,说明破解成功:

第三步、追码:
将00403370处的nop指令撤消修改,观察代码:
向上查看至0040334E处,指令要调用MSVBVM50.__vbaVarTstEq函数,这就是关键比较了,=则失败,不等则成功;

继续向上看,__vbaVarTstEq函数的两个要比较的参数分别是= ss:,= ss:,实际参数地址应该是ss:【ebp-0x30】与ss:【ebp-0xC0】,从堆栈窗口中看到,ss:= “qBQSYdXUe_B\V”,也就是说输入的password经计算后等于“qBQSYdXUe_B\V”才行:
再向上查看,有点吃力了,还是用SmatrCheck/VB Decompiler这两个VB的专用反编译工具及监控工具SoftSnoop来配合OD使用吧:
先将VB Decompiler的解析导入OD中(VB Decompiler直接生成的map文件导入OD中没发现注释有什么改变,可能有什么地方不对;要先用VB Decompiler生成bas文件,再利用bas转map工具转换成map文件后导入OD才行),从SmatrCheck/VB Decompiler/SoftSnoop这三个工具中均可以看到“OK”按钮事件开始于004030F0处:OD中在此地址下断,然后F9运行程序,在File菜单上选择“password”命令进入主窗体,输入“1234567890”,点击“OK”按钮,程序中断于004030F0处:

F8向下,一直到004031A8处,得到password字符串存入中;
从004031D3至004031DA处,得到假码的长度,并存入ss:中,作为下一步循环的次数:
004031D3   .51               push ecx                                              ; /var18 =0012F4B8
004031D4   .52               push edx                                              ; |retBuffer8 =0012F488
004031D5   .BE 01000000      mov esi,0x1                                           ; |
004031DA > .FF15 18614000      call dword ptr ds:[<&MSVBVM50.__vbaLenVar>]         ; \var_58=Len(var_28)=Len(password.text)
004031E0   .50               push eax                                              ;=len(password.text)
004031E1   .FF15 74614000      call dword ptr ds:[<&MSVBVM50.__vbaI2Var>]            ; msvbvm50.__vbaI2Var
004031E7 > .8985 F8FEFFFF      mov dword ptr ss:,eax                      ;var_108=CInt(Me)
004031ED   .8BFE               mov edi,esi
从004031EF到0040332A是一个大循环。循环次数是假码的长度值:[其中004031FC、00403206、00403312、00403319等处由导入的注释有点小问题,不知道该怎么说好,前面两个是将标志位ZF用00000001h来表示了,后面两个地址处是将di、si用00000001h来表示,感觉不太合适,需要自己根据情况修改调整一下。]
004031EF   >66:3BBD F8FEFFFF   cmp di,word ptr ss:                        ;di与10比较:从1到len(password.text)循环
004031F6   .8B1D 6C614000      mov ebx,dword ptr ds:[<&MSVBVM50.__vbaStrVarVal>]   ; msvbvm50.__vbaStrVarVal
004031FC > .0F8F 2D010000      jg <cracking.End`If>                                  ; If`00000001h<=0`Then////if di-10<=0时转移
00403202   .66:83FE 04         cmp si,0x4
00403206 > .7E 05            jle short <cracking.End`If>                           ;If`00000001h`>`4`Then////if si-4>0时转移
00403208   .BE 01000000      mov esi,0x1
0040320D > >0FBFCF             movsx ecx,di                                          ;End`If
。。。。。。。。。
00403309 > .FF15 00614000      call dword ptr ds:[<&MSVBVM50.__vbaFreeVarList>]      ;call`undef`'Ignore`this`'__vbaFreeVarList(00000006,`2,`var_68,`2,`2,`var_98,`var_A8)
0040330F   .83C4 1C            add esp,0x1C
00403312 > .66:46            inc si                                                ;si=00000001h`+`1///si自加1 si=si+1
00403314   .B8 01000000      mov eax,0x1
00403319 > .66:03C7            add ax,di                                             ;00000001h=00000001h`+`di///ax=ax+di
0040331C > .0F80 44020000      jo cracking.00403566                                  ; If`Err.Number<>0`Then
00403322 > .0F80 3E020000      jo cracking.00403566                                  ;If`Err.Number<>0`Then`GoTo`loc_00403566
00403328   .8BF8               mov edi,eax
0040332A > .^ E9 C0FEFFFF      jmp cracking.004031EF                                 ; GoTo`loc_004031EF
到0040322B处,依次取假码的每一个字符,存入var_68即SS:中;
00403210   .8D45 A8            lea eax,dword ptr ss:
00403213   .8D55 D8            lea edx,dword ptr ss:
00403216   .50               push eax                                              ; /Length8 = 0x0
00403217   .51               push ecx                                              ; |Start = 0x12F4B8
00403218   .8D45 98            lea eax,dword ptr ss:                     ; |
0040321B   .52               push edx                                              ; |dString8 = 0012F488
0040321C   .50               push eax                                              ; |RetBUFFER = NULL
0040321D   .C745 B0 01000000   mov dword ptr ss:,0x1                     ; |
00403224   .C745 A8 02000000   mov dword ptr ss:,0x2                     ; |
0040322B > .FF15 38614000      call dword ptr ds:[<&MSVBVM50.#rtcMidCharVar_632>]    ; \var_68=Mid(var_28,`di,`1) /取假码的每一个字符
继续到0040325C处,将2000(0x7D0)存入ss:中,在00403263处循环取“2000”的每一个字符,存入var_98即SS:中;
00403231   .B8 02000000      mov eax,0x2
00403236   .8D8D 78FFFFFF      lea ecx,dword ptr ss:
0040323C   .0FBFD6             movsx edx,si
0040323F   .8985 78FFFFFF      mov dword ptr ss:,eax
00403245   .8945 88            mov dword ptr ss:,eax
00403248   .51               push ecx                                              ; /Length8 =0x12F4B8
00403249   .8D45 88            lea eax,dword ptr ss:                     ; |
0040324C   .52               push edx                                              ; |Start = 0x12F488
0040324D   .8D8D 68FFFFFF      lea ecx,dword ptr ss:                     ; |
00403253   .50               push eax                                              ; |dString8 =NULL
00403254   .51               push ecx                                              ; |RetBUFFER = 0012F4B8
00403255   .C745 80 01000000   mov dword ptr ss:,0x1                     ; |
0040325C   .C745 90 D0070000   mov dword ptr ss:,0x7D0                     ; |0x7D0的10进制数值为2000
00403263 > .FF15 38614000      call dword ptr ds:[<&MSVBVM50.#rtcMidCharVar_632>]    ; \var_98=Mid(2000,`si,`1) ///循环取“2000”的每一个字符
00403269处到00403288处将取得的假码字符转换成16进制数值,转存到ss:中;
00403269   .8D55 98            lea edx,dword ptr ss:
0040326C   .8D45 C0            lea eax,dword ptr ss:
0040326F   .52               push edx
00403270   .50               push eax
00403271 > .FFD3               call ebx                                              ;var_40=CStr(var_68)
00403273   .50               push eax                                              ; /String = NULL
00403274   .FF15 0C614000      call dword ptr ds:[<&MSVBVM50.#rtcAnsiValueBstr_516>] ; \rtcAnsiValueBstr
0040327A   .0FBFD0             movsx edx,ax
0040327D   .8D8D 68FFFFFF      lea ecx,dword ptr ss:
00403283   .8D45 BC            lea eax,dword ptr ss:
00403286   .51               push ecx
00403287   .50               push eax
00403288   .8995 E8FEFFFF      mov dword ptr ss:,edx
0040328E处到00403291处,将每一位假码字符对应的“2000”的字符转换成16进制数值,存入中;
0040328E > .FFD3               call ebx                                              ;var_44=CStr(var_98)
00403290   .50               push eax                                              ; /String = NULL
00403291   .FF15 0C614000      call dword ptr ds:[<&MSVBVM50.#rtcAnsiValueBstr_516>] ; \rtcAnsiValueBstr
00403297到004032AA处,假码与对应的“2000”的每一位字符的16进制数值进行异或运算,存入,并从ASCII码转为字符,存入var_A8即SS:中;
00403297   .8B95 E8FEFFFF      mov edx,dword ptr ss:
0040329D   .0FBFC8             movsx ecx,ax
004032A0   .33D1               xor edx,ecx                                           ;异或运算:
004032A2   .8D85 58FFFFFF      lea eax,dword ptr ss:
004032A8   .52               push edx
004032A9   .50               push eax
004032AA > .FF15 64614000      call dword ptr ds:[<&MSVBVM50.#rtcVarBstrFromAnsi_608>;var_A8=Chr(Asc(var_40)`xor`ecx) 【rtcVarBstrFromAnsi:ASCII码转为字符】
004032B0到004032 CD处,将异或运算后转换成的字符先连接起来,存入var_B8中,再复制回var_38中:
004032B0   .8D4D C8            lea ecx,dword ptr ss:
004032B3   .8D95 58FFFFFF      lea edx,dword ptr ss:
004032B9   .51               push ecx
004032BA   .8D85 48FFFFFF      lea eax,dword ptr ss:
004032C0   .52               push edx
004032C1   .50               push eax
004032C2 > .FF15 70614000      call dword ptr ds:[<&MSVBVM50.__vbaVarCat>]         ; var_B8=var_38`&`var_A8
004032C8   .8BD0               mov edx,eax
004032CA   .8D4D C8            lea ecx,dword ptr ss:
004032CD > .FF15 F8604000      call dword ptr ds:[<&MSVBVM50.__vbaVarMove>]          ;var_38=var_B8
0040332F到0040334E处,将var_38中的字符与“qBQSYdXUe_B\V”进行比较,相同则成功,不同则失败。
0040332F <> > \8D45 C8            lea eax,dword ptr ss:                           ;End`If
00403332    .8D8D 38FFFFFF      lea ecx,dword ptr ss:
00403338    .50               push eax                                                ; /var18 =0012F428
00403339    .51               push ecx                                                ; |var28 = 0012F4A8
0040333A    .C785 40FFFFFF C827>mov dword ptr ss:,cracking.004027C8             ; |qBQSYdXUe_B\V
00403344    .C785 38FFFFFF 0880>mov dword ptr ss:,0x8008                        ; |
0040334E    .FF15 44614000      call dword ptr ds:[<&MSVBVM50.__vbaVarTstEq>]             ; \关键比较:关系运算,if =,ax=-1;else ax=0
由异或运算的性质可反推出注册算法,即取“qBQSYdXUe_B\V”与“2000200020002”的每一对应字符的ASCII值进行异或运算,所得结果连接起来即是注册码了:用VB编写的主要代码段如下:
key = "qBQSYdXUe_B\V"
source = "2000200020002"
For i = 1 To 13
    p(i) = Asc(Mid(key, i, 1)) Xor Asc(Mid(source, i, 1))
    password = password & Chr(p(i))
Next
Text1.Text = Trim(password)
计算出的密码是“CrackTheWorld”,验证了一下,是正确的。
附件,含CM原程序、爆破后的程序、注册机、OD的调试文件等。百度链接是:http://pan.baidu.com/s/1skMkJY9,密码: 86pm,160个CM、我已练习过的前30个crackme程序(不含012)都在里面。

vethenc 发表于 2019-7-14 08:14

论坛有你更精彩!

izchoo 发表于 2019-7-14 08:41

哇支持大佬!

qingshanlushui 发表于 2019-7-14 09:30

好强大....

空白处、 发表于 2019-7-14 10:24

学习下!

yujie0880 发表于 2019-7-14 10:53

楼主幸苦了   谢谢分享~!!

LinKehat 发表于 2019-7-14 13:51

我的头本来就不小,看到你发的这一串数字。。。更大了

zuiedlh 发表于 2019-7-14 14:36

感谢分享纯支持 辛苦

王宇 发表于 2019-7-17 09:15

感谢分享,支持一下
页: [1]
查看完整版本: 160个Crackme之030学习笔记