本来想每天一破的,发现我天真了。
目标: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;
}