本来想每天一破的,发现我天真了。
目标:crackme.rar
先检查有没有壳: crackme6.exe:ASPack 2.x (without poly) -> Alexey Solodovnikov [Overlay] 用AspackDie1.41脱壳后: unpacked.ExE:LCC Win32 1.x -> Jacob Navia [Overlay] 用w32dasm打开,发现了:GetDlgItemTextA 很好,接下来用OD打开。 用Ctrl+N 下API断点:GetDlgItemTextA F9运行下 00401539 |. E8 FA010000 CALL <JMP.&USER32.GetDlgItemTextA> ; \GetDlgItemTextA 0040153E |. 89C3 MOV EBX,EAX ; EAX是返回的长度,EBX = EAX 00401540 |. 09DB OR EBX,EBX ; if (len(name) != 0 ) 00401542 |. 75 04 JNZ SHORT unpacked.00401548 00401544 |. 31C0 XOR EAX,EAX 00401546 |. EB 50 JMP SHORT unpacked.00401598 00401548 |> BF BC020000 MOV EDI,2BC ; 2BC 是十进制 700 0040154D |. BE 30000000 MOV ESI,30 ; 30 是十进制 48 也就是 '9' 00401552 |. B8 48000000 MOV EAX,48 ; 48 是十进制 72 00401557 |. 99 CDQ ; Convert Double to Quad,EDX拓展为EAX的高位 00401558 |. F7FB IDIV EBX ; 0040155A |. 29C6 SUB ESI,EAX 0040155C |. 8D34B6 LEA ESI,DWORD PTR DS:[ESI+ESI*4] 0040155F |. 29F7 SUB EDI,ESI 00401561 |. 6BFF 6B IMUL EDI,EDI,6B 00401564 |. 81EF 6CCF0000 SUB EDI,0CF6C 0040156A |. 81FF 00230000 CMP EDI,2300 00401570 |. 7F 08 JG SHORT unpacked.0040157A 00401572 |. 81FF 90010000 CMP EDI,190 00401578 |. 7D 04 JGE SHORT unpacked.0040157E 0040157A |> 31C0 XOR EAX,EAX 0040157C |. EB 1A JMP SHORT unpacked.00401598 0040157E |> 8D85 00FFFFFF LEA EAX,DWORD PTR SS:[EBP-100] 分析过程: a = 30 - (48/len(name)) b = 2BC - ptr[a+4a] c = b * b * 6B d = c - 0CF6C 可能是个负数。。 if d > 2300 跳到 0040157A 然后就完蛋了 if d >= 190 跳到 0040157E 有戏 EDI与0CF6C想减后为e, 400 <= e <=8960 往上看,发现EDI - ESI,然后一开始的EDI赋值为2BC,关键在ESI ESI 赋值为30,30 - (48/len(name)),余数放在EAX中,然后ESI - EAX 减去这个余数 然后取地址。。这个地址怎么办?DWORD PTR DS:[ESI+ESI*4]? 在这里做不下去了,看了下答案,发现2点很可怕的地方: (1)DWORD PTR DS:[ESI+ESI*4] 是取ESI * 5 ,据大神说,lea是专业计算这类公式的 ,这里有中括号,就当成特殊处理吧 (2)IMUL EDI,EDI,6B 是将 第二个操作数 * 第三个操作数 然后结果放在第一个操作数 纠错后,总结下: EDI = [ 2bc - (30 - 48/namelen)*5 ]*6b- CF6C 然后结果要: 190 <= EDI <= 2300 那么经过一番运算后:namelen 要在 [3,9] 之间。。 F9重新运行下,输入长度为6的 xihuan 序列号输入:woaini 接下来进行序列号的猜解: 004013B4 |. 09C0 OR EAX,EAX ;if namelen == 0 跳走00401504 挂了 004013B6 |. 0F84 48010000 JE unpacked.00401504 004013BC |. B8 CF110000 MOV EAX,11CF 004013C1 |. 0FB68D E1FCFF>MOVZX ECX,BYTE PTR SS:[EBP-31F] ;这里是序列号的第一位'w' 004013C8 |. 99 CDQ 004013C9 |. F7F9 IDIV ECX 004013CB |. 83FA 17 CMP EDX,17 ;if (EDX == 17) 004013CE |. 74 07 JE SHORT unpacked.004013D7 ; 跳到004013D7 不挂 004013D0 |. 31C0 XOR EAX,EAX 004013D2 |. E9 2D010000 JMP unpacked.00401504 ; 不跳走就挂掉了, 004013D7 |> 31DB XOR EBX,EBX 004013D9 |. EB 0B JMP SHORT unpacked.004013E6 004013DB |> 8B45 10 /MOV EAX,DWORD PTR SS:[EBP+10] ; name = "xihuan" 004013DE |. 0FBE0418 |MOVSX EAX,BYTE PTR DS:[EAX+EBX] ; name的第一个字符'x' 004013E2 |. 0145 FC |ADD DWORD PTR SS:[EBP-4],EAX ; ?! 004013E5 |. 43 |INC EBX ; 自增 004013E6 |> 3B5D 0C CMP EBX,DWORD PTR SS:[EBP+C] ; name 的 长度 6 004013E9 |.^ 7C F0 \JL SHORT unpacked.004013DB ; 递增至长度6则结束 004013EB |. 31DB XOR EBX,EBX 004013ED |. E9 83000000 JMP unpacked.00401475 分析过程: EAX = 11CF ECX = 'w' EAX/ECX 商放在EAX,余数放在EDX if (EDX == 17) 就不会挂 ,那么这个ECX应该是 23(10) = 17(h): 36 * 126 + 23 42 * 108 + 23 54 * 84 + 23 56 * 81 + 23 63 * 72 + 23 72 * 63 + 23 81 * 56 + 23 84 * 54 + 23 这里我去108,也就是'l',重新开始,F9 序列号输入为lwoaini,判定成功,避免挂了 004013DB |> 8B45 10 /MOV EAX,DWORD PTR SS:[EBP+10] ; name = "xihuan" 004013DE |. 0FBE0418 |MOVSX EAX,BYTE PTR DS:[EAX+EBX] ; name的第一个字符'x' 004013E2 |. 0145 FC |ADD DWORD PTR SS:[EBP-4],EAX ; 不懂! 004013E5 |. 43 |INC EBX ; 自增 004013E6 |> 3B5D 0C CMP EBX,DWORD PTR SS:[EBP+C] ; 004013E9 |.^ 7C F0 \JL SHORT unpacked.004013DB 这段就是把用户名 "xihuan"的每一个字符都加到 SS:[EBP-4]中。 那么SS:[EBP-4]到底是什么? 找到0D中的: 0012F8F0 0000021F <- 这个地方就是EBP-4。 0012F8F4 /0012FA14 0012F8F8 |0040158E RETURN to unpacked.0040158E from unpacked.00401305 0012F8FC |00490332 0012F900 |00000006 <- 这里就是 EBP+C 也就是存在着长度 0012F904 |0012F914 ASCII "xihuan" 0012F908 |0012FA3B ASCII "SHiT ... you entered the correct serial!" 0012F90C |00402593 ASCII "You have to make an own working keygen! 这里我懂了,把name的每一个字符都加到[EBP-4]中,最后加完 “xihuan”总和为28D. 加完之后又会跳入一个循环,这个循环是计算用: 004013F2 |> 8B55 10 /MOV EDX,DWORD PTR SS:[EBP+10] ;这是“xihuan”的地址 004013F5 |. 0FBE3C1A |MOVSX EDI,BYTE PTR DS:[EDX+EBX] ;这里循环不断去xihuan的单字符,第一个为x 004013F9 |. 8B75 FC |MOV ESI,DWORD PTR SS:[EBP-4] ; 刚刚的 xihuan 字符和 :28D 004013FC |. 89D9 |MOV ECX,EBX ; 004013FE |. C1E1 02 |SHL ECX,2 ; ECX 左移2为,第一次中为000即为 0 00401401 |. 89DA |MOV EDX,EBX ; 00401403 |. 42 |INC EDX ; 第一次中,EDX 增1 为 1 00401404 |. 29D1 |SUB ECX,EDX ; 0 - 1 = FFFFFFFF 00401406 |. 0FB68C0D E1FE>|MOVZX ECX,BYTE PTR SS:[EBP+ECX-11F] ; 查看了地址发现是 ECX = 0 0040140E |. 89FA |MOV EDX,EDI ; EDX = 'x' 00401410 |. 31CA |XOR EDX,ECX ; EDX = name[i] ^SS:[EBP+(3*i-1)-11F] 00401412 |. 89F1 |MOV ECX,ESI ; ECX = 28D ..字符和 00401414 |. 0FAFCB |IMUL ECX,EBX ; 00401417 |. 29F1 |SUB ECX,ESI 00401419 |. 89CE |MOV ESI,ECX 0040141B |. 83F6 FF |XOR ESI,FFFFFFFF ; ESI = (sum*i-sum)^FFFFFFFF 0040141E |. 8DB432 4D0100>|LEA ESI,DWORD PTR DS:[EDX+ESI+14D] ; ESI = DS:[EDX + ESI + 14D] 00401425 |. 8B4D 0C |MOV ECX,DWORD PTR SS:[EBP+C] ; 00401428 |. 89DA |MOV EDX,EBX 0040142A |. 83C2 03 |ADD EDX,3 0040142D |. 0FAFCA |IMUL ECX,EDX 00401430 |. 0FAFCF |IMUL ECX,EDI 00401433 |. 89F0 |MOV EAX,ESI 00401435 |. 01C8 |ADD EAX,ECX 00401437 |. B9 0A000000 |MOV ECX,0A 0040143C |. 31D2 |XOR EDX,EDX 0040143E |. F7F1 |DIV ECX 00401440 |. 83C2 30 |ADD EDX,30 00401443 |. 88941D FCFEFF>|MOV BYTE PTR SS:[EBP+EBX-104],DL 0040144A |. 0FB6BC1D FCFE>|MOVZX EDI,BYTE PTR SS:[EBP+EBX-104] 00401452 |. 81F7 ACAD0000 |XOR EDI,0ADAC 00401458 |. 89DE |MOV ESI,EBX 0040145A |. 83C6 02 |ADD ESI,2 0040145D |. 89F8 |MOV EAX,EDI 0040145F |. 0FAFC6 |IMUL EAX,ESI 00401462 |. B9 0A000000 |MOV ECX,0A 00401467 |. 99 |CDQ 00401468 |. F7F9 |IDIV ECX 0040146A |. 83C2 30 |ADD EDX,30 0040146D |. 88941D FCFEFF>|MOV BYTE PTR SS:[EBP+EBX-104],DL 00401474 |. 43 |INC EBX 00401475 |> 3B5D 0C CMP EBX,DWORD PTR SS:[EBP+C] 00401478 |.^ 0F8C 74FFFFFF \JL unpacked.004013F2 分析过程: 这一段好长。 其中涉及到 是一段字母表 CBA0 GFED ...: 0012F7D4 43424100 0012F7D8 47464544 0012F7DC 4B4A4948 0012F7E0 4F4E4D4C 0012F7E4 53525150 0012F7E8 57565554 0012F7EC 005A5958 (((((name[i]^helpStr[i*3-1])+((sum*i-sum)^0xffffffff)+0x14d+(i+3)*name_len*name[i])%10+0x30)^0xadac)*(i+2))%10+0x30; 其中helpStr就是26字母表 把这计算结果存放到 SS:[EBP+EBX-104] Ps:贫道做完这个计算过程分析后,深感蛋疼。 0040147E |. 8D85 FCFEFFFF LEA EAX,DWORD PTR SS:[EBP-104] ;这里存在着计算完的序列号 204069 00401484 |. 50 PUSH EAX 00401485 |. 6A 54 PUSH 54 00401487 |. 8D85 DCFBFFFF LEA EAX,DWORD PTR SS:[EBP-424] 0040148D |. 50 PUSH EAX ; |Format 0040148E |. 8D85 E1FBFFFF LEA EAX,DWORD PTR SS:[EBP-41F] ; | 00401494 |. 50 PUSH EAX ; |s 00401495 |. E8 CE020000 CALL <JMP.&USER32.wsprintfA> ; \wsprintfA <- 这里把结算结果改为T204069 0040149A |. 8B7D 0C MOV EDI,DWORD PTR SS:[EBP+C] ; namelen = 6 0040149D |. 89F8 MOV EAX,EDI ; 6 0040149F |. 0FAF45 FC IMUL EAX,DWORD PTR SS:[EBP-4] ; 6 * 2BD (sum(name)) 004014A3 |. B9 64000000 MOV ECX,64 ; 64 004014A8 |. 99 CDQ 004014A9 |. F7F9 IDIV ECX ; 6 * 2BD (sum(name)) /64 004014AB |. 89D7 MOV EDI,EDX ; 6 * 2BD (sum(name)) mod 64 004014AD |. 83C7 30 ADD EDI,30 ; 6 * 2BD (sum(name)) mod 64 + 30 004014B0 |. 57 PUSH EDI 004014B1 |. 8DBD E1FBFFFF LEA EDI,DWORD PTR SS:[EBP-41F] 004014B7 |. 57 PUSH EDI 004014B8 |. 8DBD D6FBFFFF LEA EDI,DWORD PTR SS:[EBP-42A] 004014BE |. 57 PUSH EDI ; |Format 004014BF |. 8DBD E1FDFFFF LEA EDI,DWORD PTR SS:[EBP-21F] ; | format("%s-%d","T204069",42) 004014C5 |. 57 PUSH EDI ; |s 42的十进制是66 004014C6 |. E8 9D020000 CALL <JMP.&USER32.wsprintfA> ; \wsprintfA <- 到这里计算结果为T204069-66 004014CB |. 83C4 20 ADD ESP,20 004014CE |. 8D8D E1FDFFFF LEA ECX,DWORD PTR SS:[EBP-21F] 004014D4 |. 83C8 FF OR EAX,FFFFFFFF 004014CB |. 83C4 20 ADD ESP,20 004014CE |. 8D8D E1FDFFFF LEA ECX,DWORD PTR SS:[EBP-21F] ; 这里要注意。。应该遍历字符串 004014D4 |. 83C8 FF OR EAX,FFFFFFFF 004014D7 |> 40 /INC EAX 004014D8 |. 803C01 00 |CMP BYTE PTR DS:[ECX+EAX],0 ; 直到取到了字符‘\0’也就是结尾 004014DC |.^ 75 F9 \JNZ SHORT unpacked.004014D7 004014DE |. 50 PUSH EAX ; /Arg3 004014DF |. 8D85 E1FCFFFF LEA EAX,DWORD PTR SS:[EBP-31F] ; | T204069-TT 004014E5 |. 50 PUSH EAX ; |Arg2 004014E6 |. 8D85 E1FDFFFF LEA EAX,DWORD PTR SS:[EBP-21F] ; | lwoaini 004014EC |. 50 PUSH EAX ; |Arg1 004014ED |. E8 D0FDFFFF CALL unpacked.004012C2 ; \unpacked.004012C2 这里进去看看 004014F2 |. 83C4 0C ADD ESP,0C 004014F5 |. 83F8 00 CMP EAX,0 004014F8 |. 75 07 JNZ SHORT unpacked.00401501 004014FA |. B8 00000000 MOV EAX,0 004014FF |. EB 03 JMP SHORT unpacked.00401504 00401501 |> 31C0 XOR EAX,EAX 00401503 |. 40 INC EAX 00401504 |> 5F POP EDI 00401505 |. 5E POP ESI 00401506 |. 5B POP EBX 00401507 |. C9 LEAVE 00401508 \. C3 RETN 参数是T204069-66 和 lwoaini ,进来call 看看: 004012C2 /$ 55 PUSH EBP ; 004012C3 |. 89E5 MOV EBP,ESP 004012C5 |. 53 PUSH EBX 004012C6 |. 56 PUSH ESI 004012C7 |. 57 PUSH EDI 004012C8 |. 8B5D 10 MOV EBX,DWORD PTR SS:[EBP+10] ; len=10 004012CB |. 31F6 XOR ESI,ESI 004012CD |. 46 INC ESI ; <- 这一步导致'T'被忽略从'2'开始 004012CE |. EB 29 JMP SHORT unpacked.004012F9 ; 循环开始 004012D0 |> 8B55 08 /MOV EDX,DWORD PTR SS:[EBP+8] ; 204069-66 004012D3 |. 0FBE3C32 |MOVSX EDI,BYTE PTR DS:[EDX+ESI] ; 2 004012D7 |. 89F8 |MOV EAX,EDI 004012D9 |. 83F0 20 |XOR EAX,20 ; 2 XOR 20 004012DC |. B9 0A000000 |MOV ECX,0A 004012E1 |. 99 |CDQ 004012E2 |. F7F9 |IDIV ECX ; (2 XOR 20)/0A 004012E4 |. 89D7 |MOV EDI,EDX ; (2 XOR 20) mod 0A 004012E6 |. 83C7 30 |ADD EDI,30 ; EDI = (2 XOR 20) mod 0A + 30 004012E9 |. 8B55 0C |MOV EDX,DWORD PTR SS:[EBP+C] ; lwoaini 004012EC |. 0FBE1432 |MOVSX EDX,BYTE PTR DS:[EDX+ESI] ; EDX = l 004012F0 |. 39D7 |CMP EDI,EDX ; 比较 EDI 和 EDX <- 注意这里是关键!! 004012F2 |. 74 04 |JE SHORT unpacked.004012F8 004012F4 |. 31C0 |XOR EAX,EAX 004012F6 |. EB 08 |JMP SHORT unpacked.00401300 004012F8 |> 46 |INC ESI 004012F9 |> 39DE CMP ESI,EBX 004012FB |.^ 7C D3 \JL SHORT unpacked.004012D0 总结: 1. 用户名“xihuan”经过(((((name[i]^helpStr[i*3-1])+((sum*i-sum)^0xffffffff)+0x14d+(i+3)*name_len*name[i])%10+0x30)^0xadac)*(i+2))%10+0x30; 变成了“204069”,然后+'T'变成'T204069',加'-',然后加尾巴'66','66'是这么来的 (sum * length) % 0x64 +0x30;(Ps:'66'的分析较简单,于是没写出来) 2. 每个字符 EDI = (T XOR 20) mod 0A + 30 合起来就是“xihuan”的序列号了 if __name__ == "__main__": str = "204069-66"; res = "" for i in str : lrc = (ord(i) ^ 32) %10 +48 print "%c %d",i,ord(i),lrc res = res + chr(lrc) print 'l'+res 结果:l860625322 至此:用户名是xihuan 序列号是:l860625322
// getSerial.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include "string.h" #include "stdlib.h" #include <stdio.h> int main(int argc, char* argv[]) { unsigned int i,sum,length,length2,esi,ecx,edx,edi; char name[] = "xihuan"; char helpstr[]={'\0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; while (true) { printf("Please enter username(finished with '#' , name's length in [3,9]) :"); scanf("%s",name) ; if(strcmp(name,"#") == 0) break; length = strlen(name); char *tmpStr = (char*)malloc( sizeof(char)*length); char *tmpStr2 = (char*)malloc(sizeof(char)*length+4); char *resStr = (char*)malloc(sizeof(char)*length+4); sum = 0; for(i = 0 ; i < length ; i++) sum += (unsigned int)name[i]; for(i = 0 ; i < length ; i++) { if (i == 0) edx = 0 ^ (unsigned int)name[i]; else edx = (unsigned int)helpstr[3*i] ^ (unsigned int)name[i]; esi = (0xFFFFFFFF ^ sum*(i-1)) +edx +0x14d; ecx =(length*(i+3)*(unsigned int)name[i]+esi)%0xA+0x30; ecx =( (ecx ^ 0xADAC) *(2+i))%0xA+0x30; tmpStr[i]=ecx; } tmpStr[i] = '\0'; edi = (sum * length) % 0x64 +0x30; sprintf(tmpStr2,"%s-%d",tmpStr,edi); length2 = strlen(tmpStr2); for(i = 0 ; i < length2 ; i++) { tmpStr2[i] = (tmpStr2[i] ^ 0x20) % 0xA +0x30; } sprintf(resStr,"%c%s",'l',tmpStr2); printf("Result is: %s\n",resStr); } return 0; }