天清地宁 发表于 2015-8-21 20:11

160个CrackMe – 002

1. 爆破

2. 找算法

一:爆破程序
    这个程序是一个VB的程序,以前并没有摸过除C++之外的程序。程序载入时,下BP MessageBoxA和MessageBoxW都无法断下弹窗。
    临时看下《加密解密三》VB程序得知VB的显示对话框函数为:rtcMsgBox。吾爱的OD插件中有VB函数断点,点击下即可下rtcMsgBox断点。然后输入账户tqdn密码1234点击控件OK让程序跑起来。

.   程序跑起来后断在了MSVBVM50的动态链接库中。这里应该就是rtcMsgBox函数范围内。直接F8走出这个函数。F8往下的过程中会弹出消息框显示“You Get Wrong   Try Again”估摸着就是错误的消息吧。
.   走出函数后就返回到下面


004025E1   .51            push ecx
004025E2   .52            push edx
004025E3   .EB 56         jmp XAfkayas_.0040263B                           ;跳过了错误的显示
004025E5   >68 C81B4000   push Afkayas_.00401BC8                           ;UNICODE "You Get Wrong"
004025EA   .68 9C1B4000   push Afkayas_.00401B9C                           ;ASCII "\r"
004025EF   .FFD7          call edi
004025F1   .8BD0          mov edx,eax
004025F3   .8D4D E8       lea ecx,dword ptr ss:
004025F6   .FFD3          call ebx
004025F8   .50            push eax
004025F9   .68 E81B4000   push Afkayas_.00401BE8                           ;UNICODE "Try Again"
004025FE   .FFD7          call edi
00402600   .8945 CC       mov dword ptr ss:,eax
00402603   .8D45 94       lea eax,dword ptr ss:
00402606   .8D4D A4       lea ecx,dword ptr ss:
00402609   .50            push eax
0040260A   .8D55 B4       lea edx,dword ptr ss:
0040260D   .51            push ecx
0040260E   .52            push edx
0040260F   .8D45 C4       lea eax,dword ptr ss:
00402612   .6A 00         push 0x0
00402614   .50            push eax
00402615   .C745 C4 08000>mov dword ptr ss:,0x8
0040261C   .FF15 10414000 call dword ptr ds:[<&MSVBVM50.#595>]               ;显示错误信息弹框的函数
00402622   .8D4D E8       lea ecx,dword ptr ss:                  ;当前EIP的位置

.   在当前EIP处往上看,离最近的是一个JMP指令,这条指令在OD上点上去是直接跳过了这个显示错误信息的函数。那么在往上面找找。有没有什么跳转指令。

00402569   .83C4 0C       add esp,0xC
0040256C   .B9 04000280   mov ecx,0x80020004
00402571   .B8 0A000000   mov eax,0xA
00402576   .894D 9C       mov dword ptr ss:,ecx
00402579   .66:85F6       test si,si                        ;比较SI是否为0
0040257C   .8945 94       mov dword ptr ss:,eax
0040257F   .894D AC       mov dword ptr ss:,ecx
00402582   .8945 A4       mov dword ptr ss:,eax
00402585   .894D BC       mov dword ptr ss:,ecx
00402588   .8945 B4       mov dword ptr ss:,eax
0040258B   .74 58         je XAfkayas_.004025E5               ;如果SI等于0那么跳转到错误的显示
0040258D   .68 801B4000   push Afkayas_.00401B80            ;UNICODE "You Get It"
00402592   .68 9C1B4000   push Afkayas_.00401B9C            ;ASCII "\r"
00402597   .FFD7          call edi
00402599   .8BD0          mov edx,eax
0040259B   .8D4D E8       lea ecx,dword ptr ss:
0040259E   .FFD3          call ebx
004025A0   .50            push eax
004025A1   .68 A81B4000   push Afkayas_.00401BA8            ;UNICODE "KeyGen It Now"
004025A6   .FFD7          call edi
004025A8   .8D4D 94       lea ecx,dword ptr ss:
004025AB   .8945 CC       mov dword ptr ss:,eax
004025AE   .8D55 A4       lea edx,dword ptr ss:
004025B1   .51            push ecx
004025B2   .8D45 B4       lea eax,dword ptr ss:
004025B5   .52            push edx
004025B6   .50            push eax
004025B7   .8D4D C4       lea ecx,dword ptr ss:
004025BA   .6A 00         push 0x0
004025BC   .51            push ecx
004025BD   .C745 C4 08000>mov dword ptr ss:,0x8
004025C4   .FF15 10414000 call dword ptr ds:[<&MSVBVM50.#595>>;msvbvm50.rtcMsgBox
004025CA   .8D4D E8       lea ecx,dword ptr ss:
004025CD   .FF15 80414000 call dword ptr ds:[<&MSVBVM50.__vba>;msvbvm50.__vbaFreeStr
004025D3   .8D55 94       lea edx,dword ptr ss:
004025D6   .8D45 A4       lea eax,dword ptr ss:
004025D9   .52            push edx
004025DA   .8D4D B4       lea ecx,dword ptr ss:
004025DD   .50            push eax
004025DE   .8D55 C4       lea edx,dword ptr ss:
004025E1   .51            push ecx
004025E2   .52            push edx
004025E3   .EB 56         jmp XAfkayas_.0040263B            ;跳过了错误的显示
004025E5   >68 C81B4000   push Afkayas_.00401BC8            ;UNICODE "You Get Wrong"
004025EA   .68 9C1B4000   push Afkayas_.00401B9C            ;ASCII "\r"
004025EF   .FFD7          call edi
004025F1   .8BD0          mov edx,eax
004025F3   .8D4D E8       lea ecx,dword ptr ss:
.   往上找找到了一个靠谱的跳转点:
.   0040258Bje XAfkayas_.004025E5;如果SI等于0那么跳转到错误的显示
.   尝试把此处的JE修改成nop。然后跑程序试试~~ 爆破成功!


二:找出算法
.   首先想找算法那么先应该在爆破点下断点,并且跑到这里来。
00402561   .6A 02         push 0x2
00402563   .FF15 F4404000 call dword ptr ds:[<&MSVBVM50.__vba>;msvbvm50.__vbaFreeObjList
00402569   .83C4 0C       add esp,0xC
0040256C   .B9 04000280   mov ecx,0x80020004
00402571   .B8 0A000000   mov eax,0xA
00402576   .894D 9C       mov dword ptr ss:,ecx
00402579   .66:85F6       test si,si                        ;比较SI是否为0
0040257C   .8945 94       mov dword ptr ss:,eax
0040257F   .894D AC       mov dword ptr ss:,ecx
00402582   .8945 A4       mov dword ptr ss:,eax
00402585   .894D BC       mov dword ptr ss:,ecx
00402588   .8945 B4       mov dword ptr ss:,eax
0040258B   .74 58         je XAfkayas_.004025E5               ;如果SI等于0那么跳转到错误的显示
0040258D   .68 801B4000   push Afkayas_.00401B80            ;UNICODE "You Get It"
00402592   .68 9C1B4000   push Afkayas_.00401B9C            ;ASCII "\r"
00402597   .FFD7          call edi
.   JE的跳转是由TEST SI, SI来控制,所以我们应当找到那里给SI赋值的指令。
0040252D   .8D4D E0       lea ecx,dword ptr ss:
00402530   .FFD3          call ebx                            ;<&MSVBVM50.__vbaStrMove>
00402532   .50            push eax
00402533   .FF15 28414000 call dword ptr ds:[<&MSVBVM50.__vba>;msvbvm50.__vbaStrCmp
00402539   .8BF0          mov esi,eax                         ;vbaStrCmp 字符串比较函数的返回值给了ESI
0040253B   .8D55 E0       lea edx,dword ptr ss:
0040253E   .F7DE          neg esi
00402540   .8D45 E8       lea eax,dword ptr ss:
00402543   .52            push edx
00402544   .1BF6          sbb esi,esi
00402546   .8D4D E4       lea ecx,dword ptr ss:
00402549   .50            push eax
0040254A   .46            inc esi
0040254B   .51            push ecx
0040254C   .6A 03         push 0x3
0040254E   .F7DE          neg esi
00402550   .FF15 5C414000 call dword ptr ds:[<&MSVBVM50.__vba>;msvbvm50.__vbaFreeStrList
00402556   .83C4 10       add esp,0x10
00402559   .8D55 D8       lea edx,dword ptr ss:
0040255C   .8D45 DC       lea eax,dword ptr ss:
0040255F   .52            push edx
00402560   .50            push eax
00402561   .6A 02         push 0x2
00402563   .FF15 F4404000 call dword ptr ds:[<&MSVBVM50.__vba>;msvbvm50.__vbaFreeObjList
00402569   .83C4 0C       add esp,0xC
0040256C   .B9 04000280   mov ecx,0x80020004
00402571   .B8 0A000000   mov eax,0xA
00402576   .894D 9C       mov dword ptr ss:,ecx
00402579   .66:85F6       test si,si                        ;比较SI是否为0
0040257C   .8945 94       mov dword ptr ss:,eax
0040257F   .894D AC       mov dword ptr ss:,ecx
.   从 TEST SI, SI 处往上找,在很近的地方vbaStrCmp 字符串比较函数的返回值给了ESI。我们在vbaStrCmp 处下断点,OD跑过来看看比较的是什么内容。观察栈中可以看到函数直接是以明文方式作比较,我输入的密码1234和程序计算出来的KEY值。

.   我们往上看看反汇编代码.   我们往上看看反汇编代码
004024E5   .8D45 D8       lea eax,dword ptr ss:
004024E8   .50            push eax
004024E9   .FFD3          call ebx
004024EB   .8BF0          mov esi,eax
004024ED   .8D55 E4       lea edx,dword ptr ss:
004024F0   .52            push edx
004024F1   .56            push esi
004024F2   .8B0E          mov ecx,dword ptr ds:
004024F4   .FF91 A0000000 call dword ptr ds:
004024FA   .85C0          test eax,eax
004024FC   .7D 12         jge XAfkayas_.00402510
004024FE   .68 A0000000   push 0xA0
00402503   .68 5C1B4000   push Afkayas_.00401B5C
00402508   .56            push esi
00402509   .50            push eax
0040250A   .FF15 04414000 call dword ptr ds:[<&MSVBVM50.__vbaHresu>;msvbvm50.__vbaHresultCheckObj
00402510   >8B45 E8       mov eax,dword ptr ss:
00402513   .8B4D E4       mov ecx,dword ptr ss:
00402516   .8B3D 00414000 mov edi,dword ptr ds:[<&MSVBVM50.__vbaSt>;msvbvm50.__vbaStrCat
0040251C   .50            push eax
0040251D   .68 701B4000   push Afkayas_.00401B70                   ;UNICODE "AKA-"
00402522   .51            push ecx                                 ; /String
00402523   .FFD7          call edi                                 ; \__vbaStrCat
00402525   .8B1D 70414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaSt>;msvbvm50.__vbaStrMove
0040252B   .8BD0          mov edx,eax
0040252D   .8D4D E0       lea ecx,dword ptr ss:
00402530   .FFD3          call ebx                                 ;<&MSVBVM50.__vbaStrMove>
00402532   .50            push eax
00402533   .FF15 28414000 call dword ptr ds:[<&MSVBVM50.__vbaStrCm>;msvbvm50.__vbaStrCmp
00402539   .8BF0          mov esi,eax                              ;vbaStrCmp 字符串比较函数的返回值给了ESI

.   vbaStrCmp的第一个参数是由vbaStrMove的返回值给的。观察反汇编
00402525   .8B1D 70414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaSt>;msvbvm50.__vbaStrMove
0040252B   .8BD0          mov edx,eax
0040252D   .8D4D E0       lea ecx,dword ptr ss:
00402530   .FFD3          call ebx                                 ;<&MSVBVM50.__vbaStrMove>
00402532   .50            push eax
00402533   .FF15 28414000 call dword ptr ds:[<&MSVBVM50.__vbaStrCm>;msvbvm50.__vbaStrCmp
00402539   .8BF0          mov esi,eax                              ;vbaStrCmp 字符串比较函数的返回值给了ESI
. 并没有看到vbaStrMove存在PUSH参数的指令。我们在这里下断点进去看看vbaStrMove的实现是什么样子的。
vbaStrMove的实现
7403F8DA >56            push esi
7403F8DB    57            push edi
7403F8DC    8B01            mov eax,dword ptr ds:               ; ECX去一个DWORD给EAX
7403F8DE    8BFA            mov edi,edx                              ; EDX的内容给EDI
7403F8E0    8BF1            mov esi,ecx                              ; ECX的内容给ESI
7403F8E2    85C0            test eax,eax                           ; 判断ECX 去内容是否为NULL
7403F8E4    75 07         jnz Xmsvbvm50.7403F8ED
7403F8E6    8BC7            mov eax,edi
7403F8E8    893E            mov dword ptr ds:,edi               ; ECX取内容不等于NULL就将EDI存放至ECX中
7403F8EA    5F            pop edi
7403F8EB    5E            pop esi
7403F8EC    C3            retn
7403F8ED    50            push eax
7403F8EE    FF15 88190274   call dword ptr ds:[<&OLEAUT32.#6>]       ; oleaut32.SysFreeString
7403F8F4^ EB F0         jmp Xmsvbvm50.7403F8E6                   ; 否则就直接返回了
.   通过解释反汇编,可以知道vbaStrMove不是使用栈来传参数而是使用了两个寄存器EDX和ECX。结合反汇编,EDX是由vbaStrCat的返回值给与的。ECX由ebp-0x20来的。

.   vbaStrCat的两个参数是直接push一个字符串”AKA-”和push了一个ECX,ECX指向了一个字符串“390240”。最开始在爆破点下断点得出来的KEY位“AKA-390240”理算法很近了。我们接下来需要就是找到ECX是从哪来的。但是失败了。我对VB不熟悉,函数这里给出的结果让我很莫名其妙。

.   所以我决定在用最挫的方式重新在爆破点的函数头下断点,然后单步跟一次流程。并且关注函数的返回值和传出参数(lea EXX, ebp-XX,遇见这种考虑是传出参数,直接在十六进制窗口查看当前地址是什么内容,函数走完后修改成了什么数据!)

004023ED   .FF90 A0000000 call dword ptr ds:                   ;这里获得了账户
004023F3   .3BC7          cmp eax,edi
004023F5   .7D 12         jge XAfkayas_.00402409
004023F7   .68 A0000000   push 0xA0                                    ;如果返回值小于0就走这里
004023FC   .68 5C1B4000   push Afkayas_.00401B5C
00402401   .53            push ebx
00402402   .50            push eax
00402403   .FF15 04414000 call dword ptr ds:[<&MSVBVM50.__vbaHresultChec>;msvbvm50.__vbaHresultCheckObj
00402409   >8B95 50FFFFFF mov edx,dword ptr ss:
0040240F   .8B45 E4       mov eax,dword ptr ss:                ;vbaLenBstr 获取 账户的长度,eax返回长度
00402412   .50            push eax                                       ; /String
00402413   .8B1A          mov ebx,dword ptr ds:                     ; |
00402415   .FF15 E4404000 call dword ptr ds:[<&MSVBVM50.__vbaLenBstr>]   ; \__vbaLenBstr
0040241B   .8BF8          mov edi,eax                                    ;账户长度存储在EDI中
0040241D   .8B4D E8       mov ecx,dword ptr ss:
00402420   .69FF FB7C0100 imul edi,edi,0x17CFB                           ;将账户长度 * 0x17CFB
00402426   .51            push ecx                                       ; /String
00402427   .0F80 91020000 jo Afkayas_.004026BE                           ; |计算出来的结果>=0x80000000 就异常
0040242D   .FF15 F8404000 call dword ptr ds:[<&MSVBVM50.#516>]         ; \rtcAnsiValueBstr
00402433   .0FBFD0      movsx edx,ax                                 ;返回账户的第一个字符代码
00402436   .03FA          add edi,edx                                    ;返回的字符代码与账户长度 * 0x17CFB相加
00402438   .0F80 80020000 jo Afkayas_.004026BE                           ;结果大于0x80000000就异常
0040243E   .57            push edi                                       ;这个函数是将I4转换成STR
0040243F   .FF15 E0404000 call dword ptr ds:[<&MSVBVM50.__vbaStrI4>]   ;msvbvm50.__vbaStrI4
00402445   .8BD0          mov edx,eax                                    ;返回值为390240字符串

.    这里得到了字符串为390240,通过第一次失败的跟踪。那么可以知道这个地方是算出后面整数字符串的地方,对于KEY只需要在字符串前拼接一个”AKA-”就好了

.    这个算法很简单,也是和001一样只取了账户的第一个字节。不过这个账户有取账户长度做计算得出的结果。所以一个账户算出来的KEY只能在首字母和账户长度都相等的情况才能正常得出正确的结果!


void Fun(char *ZhangHu)
{
    char szBuff;
    unsigned long data = strlen(ZhangHu) * 0x17CFB + (unsigned long)ZhangHu;
    sprintf(szBuff, "AKA-%d", data);
    printf("%s \r\n", szBuff);
}


Cizel 发表于 2015-8-21 20:16

会分析算法,很厉害~

苏紫方璇 发表于 2015-8-21 20:59

膜拜会分析算法的大神,希望楼主有毅力把160的cm都做完(我是没这毅力{:301_971:})

panjb 发表于 2016-5-9 00:37

妖精的旋律 发表于 2016-5-9 02:50

厉害厉害{:1_927:}
页: [1]
查看完整版本: 160个CrackMe – 002