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);
}
会分析算法,很厉害~ 膜拜会分析算法的大神,希望楼主有毅力把160的cm都做完(我是没这毅力{:301_971:}) 厉害厉害{:1_927:}
页:
[1]