crackmes.de上下载的 能搞出来纯属运气
相关文件见附件
Difficulty: 2 - Needs a little brain (or luck)
Platform: Windows
Language: Assembler
分析如下:
004021EA 6A 20 PUSH 20
004021EC 68 E2114000 PUSH KeygenMe.004011E2
004021F1 68 2E010000 PUSH 12E
004021F6 FF75 08 PUSH DWORD PTR SS:[EBP+8]
004021F9 FF15 60024100 CALL DWORD PTR DS:[<&USER32.GetDlgItemTextA>] ; USER32.GetDlgItemTextA
004021FF 83F8 1B CMP EAX,1B ;取得serial 长度小于等于0x1B
00402202 0F87 69010000 JA KeygenMe.00402371
00402208 6A 29 PUSH 29
0040220A 68 04104000 PUSH KeygenMe.00401004
0040220F 68 2D010000 PUSH 12D
00402214 FF75 08 PUSH DWORD PTR SS:[EBP+8]
00402217 FF15 60024100 CALL DWORD PTR DS:[<&USER32.GetDlgItemTextA>] ; USER32.GetDlgItemTextA
0040221D 83F8 01 CMP EAX,1 ;取得name 长度大于等于1
00402220 72 74 JB SHORT KeygenMe.00402296
00402222 83F8 1E CMP EAX,1E
00402225 77 6F JA SHORT KeygenMe.00402296 ;name长度小于等于0x1e
00402227 A0 04104000 MOV AL,BYTE PTR DS:[401004]
0040222C 3C 20 CMP AL,20 ;name[0]不能为'-'
0040222E 74 38 JE SHORT KeygenMe.00402268
00402230 E9 F5000000 JMP KeygenMe.0040232A ;这里跳走
================================================================================================================
0040232A 90 NOP
0040232B 90 NOP
0040232C 90 NOP
0040232D 90 NOP
0040232E 90 NOP
0040232F 55 PUSH EBP
00402330 81EC 00100000 SUB ESP,1000
00402336 50 PUSH EAX
00402337 51 PUSH ECX
00402338 52 PUSH EDX
00402339 B8 04104000 MOV EAX,KeygenMe.00401004 ; ASCII "dalixux"
0040233E B9 5E104000 MOV ECX,KeygenMe.0040105E
00402343 8A10 MOV DL,BYTE PTR DS:[EAX]
00402345 84D2 TEST DL,DL
00402347 74 06 JE SHORT KeygenMe.0040234F
00402349 8811 MOV BYTE PTR DS:[ECX],DL
0040234B 40 INC EAX
0040234C 41 INC ECX
0040234D ^ EB F4 JMP SHORT KeygenMe.00402343 ;这个循环复制name到40105E
0040234F 5A POP EDX
00402350 59 POP ECX
00402351 58 POP EAX
00402352 BB 5E104000 MOV EBX,KeygenMe.0040105E
00402357 BD 55104000 MOV EBP,KeygenMe.00401055 ; ASCII "12345678"
0040235C E8 85000000 CALL KeygenMe.004023E6 ;关键CALL
00402361 81C4 00100000 ADD ESP,1000
00402367 5D POP EBP
00402368 803D 01124000 F>CMP BYTE PTR DS:[401201],0FF
0040236F E7 CA OUT 0CA,EAX ; I/O 命令
注意40326f的指令 在执行完关键call后 会变成 jb short 4023A5 这里就是爆破点了
==============================================================================================================
004023E6 68 04104000 PUSH KeygenMe.00401004 ; ASCII "dalixux"
004023EB E8 A0030000 CALL KeygenMe.00402790 ; 把name中的小写字母变大写 存放地址不变
004023F0 A0 04104000 MOV AL,BYTE PTR DS:[401004]
004023F5 84C0 TEST AL,AL
004023F7 8D35 04104000 LEA ESI,DWORD PTR DS:[401004]
004023FD 8D3D 04104000 LEA EDI,DWORD PTR DS:[401004]
00402403 74 29 JE SHORT KeygenMe.0040242E
00402405 C70424 00000000 MOV DWORD PTR SS:[ESP],0 ;返回地址清0
==============================================================================================================
0040240C 0FBE0E MOVSX ECX,BYTE PTR DS:[ESI]
0040240F 51 PUSH ECX
00402410 68 2D104000 PUSH KeygenMe.0040102D ; ASCII "KYPZAXSFCSNGRQTNWD8592VQWRKH"
;常量串const_string出现
00402415 E8 87010000 CALL KeygenMe.004025A1 ;这个call是查找字符是否在const_string出现
如出现则返回地址 未出现则返回0 功能近似于 strchr
0040241A 83C4 08 ADD ESP,8 ;平衡堆栈
0040241D 85C0 TEST EAX,EAX
0040241F 74 05 JE SHORT KeygenMe.00402426
00402421 8A16 MOV DL,BYTE PTR DS:[ESI]
00402423 8817 MOV BYTE PTR DS:[EDI],DL
00402425 47 INC EDI
00402426 8A46 01 MOV AL,BYTE PTR DS:[ESI+1]
00402429 46 INC ESI
0040242A 84C0 TEST AL,AL
0040242C ^ 75 DE JNZ SHORT KeygenMe.0040240C
0040242E 8D05 04104000 LEA EAX,DWORD PTR DS:[401004]
00402434 C607 00 MOV BYTE PTR DS:[EDI],0 ;name变换后的字符串name2 存放的地址不变
这段代码 是把name中 不属于常量串的 字符删除 并用后面首个 属于常量串的字符覆盖
比如 我输入的用户名dalixux 大写后为DALIXUX 执行上面的代码后 为DAXX
==============================================================================================================
00402437 8D50 01 LEA EDX,DWORD PTR DS:[EAX+1] ;name2+1
0040243A 8D2424 LEA ESP,DWORD PTR SS:[ESP]
0040243D 8A08 MOV CL,BYTE PTR DS:[EAX] ;name2[i]
0040243F 40 INC EAX
00402440 84C9 TEST CL,CL
00402442 ^ 75 F9 JNZ SHORT KeygenMe.0040243D
00402444 29D0 SUB EAX,EDX ;计算出name2的长度
00402446 83F8 18 CMP EAX,18
00402449 7D 27 JGE SHORT KeygenMe.00402472 ;长度大于0x18跳走
0040244B B9 18000000 MOV ECX,18
00402450 29C1 SUB ECX,EAX ;计数器
00402452 8DB8 04104000 LEA EDI,DWORD PTR DS:[EAX+401004]
00402458 89C8 MOV EAX,ECX
0040245A C1E9 02 SHR ECX,2
0040245D BE 2D104000 MOV ESI,KeygenMe.0040102D ; ASCII "KYPZAXSFCSNGRQTNWD8592VQWRKH"
00402462 F3:A5 REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI] ;以双字的形式复制
00402464 89C1 MOV ECX,EAX
00402466 83E1 03 AND ECX,3
00402469 F3:A4 REP MOVS BYTE PTR ES:[EDI],BYTE PTR DS:[ESI] ;继续复制
0040246B C605 1C104000 C>MOV BYTE PTR DS:[40101C],0C0 ;填充问号 记为newname
这段代码的作用 检查name2的长度 如大于等于0x18则不变 小于0x18的部分 用const_string填充 直到长度为0x18
===============================================================================================================
00402472 B8 2D104000 MOV EAX,KeygenMe.0040102D ; ASCII "KYPZAXSFCSNGRQTNWD8592VQWRKH"
00402477 C64424 39 00 MOV BYTE PTR SS:[ESP+39],0
0040247C C68424 84000000>MOV BYTE PTR SS:[ESP+84],0
00402484 31ED XOR EBP,EBP
00402486 8D48 01 LEA ECX,DWORD PTR DS:[EAX+1]
00402489 8A10 MOV DL,BYTE PTR DS:[EAX]
0040248B 40 INC EAX
0040248C 84D2 TEST DL,DL
0040248E ^ 75 F9 JNZ SHORT KeygenMe.00402489
00402490 29C8 SUB EAX,ECX ;计算const_string的长度
00402492 894424 10 MOV DWORD PTR SS:[ESP+10],EAX
00402496 B8 01000000 MOV EAX,1
0040249B 2D 78F44800 SUB EAX,48F478 ;1-0x48f478
004024A0 894424 18 MOV DWORD PTR SS:[ESP+18],EAX
004024A4 31DB XOR EBX,EBX
004024A6 C74424 14 77F44>MOV DWORD PTR SS:[ESP+14],48F477
004024AE 8D05 04104000 LEA EAX,DWORD PTR DS:[401004]
004024B4 48 DEC EAX
004024B5 8DBC24 84000000 LEA EDI,DWORD PTR SS:[ESP+84]
004024BC 894424 1C MOV DWORD PTR SS:[ESP+1C],EAX ;eax为newname[-1]
004024C0 EB 04 JMP SHORT KeygenMe.004024C6
004024C2 8B4424 1C MOV EAX,DWORD PTR SS:[ESP+1C] ;newname[-1]
004024C6 0FBE4C18 01 MOVSX ECX,BYTE PTR DS:[EAX+EBX+1] ;ecx为newname[i] i从0-0x18
004024CB 8D73 01 LEA ESI,DWORD PTR DS:[EBX+1] ;esi为i+1
004024CE 51 PUSH ECX
004024CF 68 2D104000 PUSH KeygenMe.0040102D ; ASCII "KYPZAXSFCSNGRQTNWD8592VQWRKH"
004024D4 E8 C8000000 CALL KeygenMe.004025A1 ;类似strchr 肯定会返回一个地址&const_string[j]
004024D9 BA 890BB7FF MOV EDX,FFB70B89 ;1-0x48f478就是FFB70B89
004024DE 89C1 MOV ECX,EAX
004024E0 01D1 ADD ECX,EDX
004024E2 81C1 4BE40800 ADD ECX,8E44B ; ASCII ".4.42"
执行完这句 ECX的值为j+1,我们看下计算过程: &const_string[j] - 0x48f478 + 0x8E44B + 1
注意下const_string的首地址为0x40102d 计算下会发现0x40102d + 0x8E44B - 0x48f478 = 0 就是const_string首个字符的索引j
再加1 就变为 j+1。。。
004024E8 8D41 FF LEA EAX,DWORD PTR DS:[ECX-1] ;EAX为j
004024EB 0FAFC1 IMUL EAX,ECX ;此时EAX = j * (j + 1)
004024EE 01E8 ADD EAX,EBP ;EBP首次计算为0
004024F0 99 CDQ
004024F1 F77C24 18 IDIV DWORD PTR SS:[ESP+18] ;const_string.length
004024F5 83C4 08 ADD ESP,8
004024F8 B9 06000000 MOV ECX,6
004024FD 42 INC EDX
004024FE 89D5 MOV EBP,EDX ;EBP为(EAX % const_length.length) + 1
00402500 BA 2C104000 MOV EDX,KeygenMe.0040102C ;&const_string[-1]
00402505 8A042A MOV AL,BYTE PTR DS:[EDX+EBP] ;const_string[x]
00402508 8807 MOV BYTE PTR DS:[EDI],AL ;这里的AL的值已经是正确的serial了只需要每 六位添加一个'-'就行了 注意观察EDI
0040250A 51 PUSH ECX
0040250B 31C9 XOR ECX,ECX
0040250D 8A0D 01124000 MOV CL,BYTE PTR DS:[401201]
00402513 80B9 E2114000 2>CMP BYTE PTR DS:[ECX+4011E2],2D
0040251A 75 0C JNZ SHORT KeygenMe.00402528
0040251C FE05 01124000 INC BYTE PTR DS:[401201]
00402522 8A0D 01124000 MOV CL,BYTE PTR DS:[401201]
00402528 2A81 E2114000 SUB AL,BYTE PTR DS:[ECX+4011E2] ;与填入的伪码比较
0040252E 59 POP ECX
0040252F E8 A5FEFFFF CALL KeygenMe.004023D9 ;相等则[401201]不变 不等值为-2
00402534 FE05 01124000 INC BYTE PTR DS:[401201] ; [401201]++
0040253A 89F0 MOV EAX,ESI
0040253C 99 CDQ
0040253D F7F9 IDIV ECX
0040253F 47 INC EDI
00402540 85D2 TEST EDX,EDX ;检测 (i+1) %6 == 0
00402542 75 09 JNZ SHORT KeygenMe.0040254D
00402544 83FB 17 CMP EBX,17
00402547 7D 04 JGE SHORT KeygenMe.0040254D
00402549 C607 2D MOV BYTE PTR DS:[EDI],2D ;填充'-'
0040254C 47 INC EDI
0040254D 89F3 MOV EBX,ESI
0040254F 803D 01124000 F>CMP BYTE PTR DS:[401201],0FF
00402556 74 2B JE SHORT KeygenMe.00402583
00402558 83FB 18 CMP EBX,18
0040255B ^ 0F8C 61FFFFFF JL KeygenMe.004024C2
00402561 8B8424 F0000000 MOV EAX,DWORD PTR SS:[ESP+F0]
00402568 C607 00 MOV BYTE PTR DS:[EDI],0
0040256B 8DB424 84000000 LEA ESI,DWORD PTR SS:[ESP+84]
00402572 B8 80104000 MOV EAX,KeygenMe.00401080
00402577 8A16 MOV DL,BYTE PTR DS:[ESI]
00402579 84D2 TEST DL,DL
0040257B 74 06 JE SHORT KeygenMe.00402583
0040257D 8810 MOV BYTE PTR DS:[EAX],DL
0040257F 40 INC EAX
00402580 46 INC ESI
00402581 ^ EB F4 JMP SHORT KeygenMe.00402577
00402583 89F0 MOV EAX,ESI
00402585 56 PUSH ESI
00402586 E8 8C010000 CALL KeygenMe.00402717 ;这个CALL是个小ANTI
它会计算原来被清0的返回地址 如果40236c-40257c中被下了断点计算出的 返回地址就是错的 同时还检验serial中'-'位置
0040258B 812D 31124000 A>SUB DWORD PTR DS:[401231],75AB46AE
00402595 8B35 31124000 MOV ESI,DWORD PTR DS:[401231]
0040259B 897424 04 MOV DWORD PTR SS:[ESP+4],ESI
0040259F 5E POP ESI
004025A0 C3 RETN
=========================================================================================================================
注册机
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define SERIAL_LENGTH 0x18
#define MAX_NAMELENGTH 0x1e+10
void main(int argc, char **argv)
{
char serial[SERIAL_LENGTH] = {0};
char name[MAX_NAMELENGTH];
const char const_string[] = "KYPZAXSFCSNGRQTNWD8592VQWRKH";
int name_length;
int cosnt_string_length;
int i, j;
int sum = 0;
printf("please input your name: \n");
scanf("%s", name);
fflush(stdout);
name_length = strlen(name);
if(name_length > 0x1e)
{
printf(" name's length must be less then 0x1e\n");
goto end;
}
cosnt_string_length = strlen(const_string);
for(i = 0, j = 0; i < name_length; i++)
{
name[i] = toupper(name[i]);
if(NULL != strchr(const_string, name[i]))
{
serial[j++] = name[i];
}
}
memcpy(&serial[j], const_string, SERIAL_LENGTH - strlen(serial));
for(i = 0; i < SERIAL_LENGTH; i++)
{
j = strchr(const_string, serial[i]) - const_string;
j = (j * (j + 1) + sum)% cosnt_string_length ;
sum = j + 1;
serial[i] = const_string[j];
if(0 == i % 6 && 0 != i)
printf("-");
printf("%C", serial[i]);
}
printf("\n");
end:
getchar();
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课