能力值:
( LV4,RANK:50 )
|
-
-
2 楼
刚才漏讲了该程序的反调试,这里补上(使用看雪ollyice的可以无视)。
作者一开始就给初学者一个下马威:
00402137 > $ 6A 00 push 0
00402139 . 68 42214000 push 00402142 ; ASCII "OLLYDBG"
0040214A . B8 90304000 mov eax, 00403090
0040214F . 83E8 04 sub eax, 4
0040216C . FFD0 call eax ; <jmp.&user32.FindWindowA>
0040216E . 83F8 00 cmp eax, 0
00402171 . 75 6B jnz short 004021DE
兜头一棒,进来就检测od。这还不算完,
00402EAF . 6A 00 push 0 ; /Timerproc = NULL
00402EB1 . 68 E8030000 push 3E8 ; |Timeout = 1000. ms
00402EB6 . 68 05040000 push 405 ; |TimerID = 405 (1029.)
00402EBB . FF75 08 push dword ptr ss:[ebp+8] ; |hWnd
00402EBE . E8 41020000 call <jmp.&user32.SetTimer> ; \SetTimer
创建完窗口后顺手建立一个定时器。进去看看
00402887 . FF75 08 push dword ptr ss:[ebp+8] ; Case 113 (WM_TIMER) of switch 004022ED
0040288A . E8 59F8FFFF call 004020E8
又是反od,
004020E8 $ 55 push ebp
004020E9 . 8BEC mov ebp, esp
004020EB . 6A 00 push 0
004020ED . 68 F6204000 push 004020F6 ; ASCII "OLLYDBG"
004020FE . B8 90304000 mov eax, 00403090
00402103 . 83E8 04 sub eax, 4
0040210C > \FFD0 call eax ; <jmp.&user32.FindWindowA>
所以要想不受干扰,要么使用ollyice,要么就爆掉这两处反调试。
|
能力值:
( LV4,RANK:50 )
|
-
-
3 楼
Level 002 :
一、破
作者在防简单爆破上下了功夫,故意打乱代码顺序。但只要掌握两点仍然随意爆破。
1、确保验证标志变量赋值为2
0040157E . C705 04504000>mov dword ptr ds:[405004], 2
2、确保eax返回时为2
004015AB . A1 04504000 mov eax, dword ptr ds:[405004]
二、解
算法描述:
1、序列号长度要超过8个字符
00401545 . 83F8 08 cmp eax, 8
00401548 . 7E 68 jle short 004015B2
2、第一个子符 + 1 = 0x32
0040154D . 8003 01 add byte ptr ds:[ebx], 1
00401588 . 803B 32 cmp byte ptr ds:[ebx], 32
0040158B . 75 25 jnz short 004015B2
2、第二个字符 + 2 = 任意 (作者本意估计要 sn[1] + 2 = 0x6c,可能疏忽写掉了一条指令)
00401550 . 8043 01 02 add byte ptr ds:[ebx+1], 2
00401554 . 807B 01 6C cmp byte ptr ds:[ebx+1], 6C
3、第三个字符 + 0x20 = 0x6a
00401558 . 8043 02 20 add byte ptr ds:[ebx+2], 20
0040158D . 807B 02 6A cmp byte ptr ds:[ebx+2], 6A
00401591 . 75 1F jnz short 004015B2
4、第四个字符 or 0x20 = 0x69
0040155C . 804B 03 20 or byte ptr ds:[ebx+3], 20
00401593 . 807B 03 69 cmp byte ptr ds:[ebx+3], 69
00401597 . 75 19 jnz short 004015B2
5、第五个字符 xor 0x20 = 0x50
00401560 . 8073 04 20 xor byte ptr ds:[ebx+4], 20
00401564 . 807B 04 50 cmp byte ptr ds:[ebx+4], 50
00401568 . 75 48 jnz short 004015B2
6、第六个字符 or 0x20 = 0x76
0040156A . 804B 05 20 or byte ptr ds:[ebx+5], 20
00401599 . 807B 05 4C cmp byte ptr ds:[ebx+5], 4C
0040159D . 74 13 je short 004015B2
7、第七个字符 + 0x3b = 0x6c
0040156E . 8043 06 3B add byte ptr ds:[ebx+6], 3B
004015A5 . 807B 06 6C cmp byte ptr ds:[ebx+6], 6C
004015A9 . 75 07 jnz short 004015B2
8、第八个字符 = 0x47
00401572 . 807B 07 47 cmp byte ptr ds:[ebx+7], 47
00401576 . 75 3A jnz short 004015B2
9、第九个字符 = 0x43
00401578 . 807B 08 43 cmp byte ptr ds:[ebx+8], 43
0040157C . 75 34 jnz short 004015B2
Level 002 keygen:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
char sn[10];
sn[0] = 0x32 -1;
sn[1] = '*';
sn[2] = 0x6a - 0x20;
sn[3] = 0x69 ^ 0x20;
sn[4] = 0x50 ^ 0x20;
sn[5] = 0x76 ^ 0x20;
sn[6] = 0x6c - 0x3b;
sn[7] = 0x47;
sn[8] = 0x43;
sn[9] = 0;
printf("Level 001 注册码:%s",sn);
getchar();
return 0;
}
|
能力值:
( LV4,RANK:50 )
|
-
-
4 楼
Level 002 :
一、破
作者在防简单爆破上下了功夫,故意打乱代码顺序。但只要掌握两点仍然随意爆破。
1、确保验证标志变量赋值为2
0040157E . C705 04504000>mov dword ptr ds:[405004], 2
2、确保eax返回时为2
004015AB . A1 04504000 mov eax, dword ptr ds:[405004]
二、解
算法描述:
1、序列号长度要超过8个字符
00401545 . 83F8 08 cmp eax, 8
00401548 . 7E 68 jle short 004015B2
2、第一个子符 + 1 = 0x32
0040154D . 8003 01 add byte ptr ds:[ebx], 1
00401588 . 803B 32 cmp byte ptr ds:[ebx], 32
0040158B . 75 25 jnz short 004015B2
2、第二个字符 + 2 = 任意 (作者本意估计要 sn[1] + 2 = 0x6c,可能疏忽写掉了一条指令)
00401550 . 8043 01 02 add byte ptr ds:[ebx+1], 2
00401554 . 807B 01 6C cmp byte ptr ds:[ebx+1], 6C
3、第三个字符 + 0x20 = 0x6a
00401558 . 8043 02 20 add byte ptr ds:[ebx+2], 20
0040158D . 807B 02 6A cmp byte ptr ds:[ebx+2], 6A
00401591 . 75 1F jnz short 004015B2
4、第四个字符 or 0x20 = 0x69
0040155C . 804B 03 20 or byte ptr ds:[ebx+3], 20
00401593 . 807B 03 69 cmp byte ptr ds:[ebx+3], 69
00401597 . 75 19 jnz short 004015B2
5、第五个字符 xor 0x20 = 0x50
00401560 . 8073 04 20 xor byte ptr ds:[ebx+4], 20
00401564 . 807B 04 50 cmp byte ptr ds:[ebx+4], 50
00401568 . 75 48 jnz short 004015B2
6、第六个字符 or 0x20 = 0x76
0040156A . 804B 05 20 or byte ptr ds:[ebx+5], 20
00401599 . 807B 05 4C cmp byte ptr ds:[ebx+5], 4C
0040159D . 74 13 je short 004015B2
7、第七个字符 + 0x3b = 0x6c
0040156E . 8043 06 3B add byte ptr ds:[ebx+6], 3B
004015A5 . 807B 06 6C cmp byte ptr ds:[ebx+6], 6C
004015A9 . 75 07 jnz short 004015B2
8、第八个字符 = 0x47
00401572 . 807B 07 47 cmp byte ptr ds:[ebx+7], 47
00401576 . 75 3A jnz short 004015B2
9、第九个字符 = 0x43
00401578 . 807B 08 43 cmp byte ptr ds:[ebx+8], 43
0040157C . 75 34 jnz short 004015B2
Level 002 keygen:
#include "stdafx.h"
#include "stdLib.h"
#include "time.h"
int _tmain(int argc, _TCHAR* argv[])
{
char sn[10];
sn[0] = 0x32 -1;
srand((unsigned int)time(NULL));
sn[1] = rand() % 90 + 0x21;
sn[2] = 0x6a - 0x20;
sn[3] = 0x69 ^ 0x20;
sn[4] = 0x50 ^ 0x20;
sn[5] = 0x76 ^ 0x20;
sn[6] = 0x6c - 0x3b;
sn[7] = 0x47;
sn[8] = 0x43;
sn[9] = 0;
printf("Level 001 注册码:%s",sn);
getchar();
return 0;
}
|
能力值:
( LV4,RANK:50 )
|
-
-
5 楼
Level 003 :
一、破
作者在防简单爆破上下了功夫,故意打乱代码顺序。但只要掌握两点仍然随意爆破。
1、确保验证标志变量赋值为3
00401632 . C705 04504000>mov dword ptr ds:[405004], 3
2、确保eax返回时为3
00401659 . A1 04504000 mov eax, dword ptr ds:[405004]
二、解
算法描述:
1、5 <= 用户名长度 <= 0x14
004015E1 . FFD0 call eax ; GetUserName
004015E3 . 83F8 05 cmp eax, 5
004015E6 . 72 78 jb short 00401660
004015E8 . 83F8 14 cmp eax, 14
004015EB . 7F 73 jg short 00401660
2、把用户名字符串中的小写字母转换为大写
00401621 > /803C19 61 cmp byte ptr ds:[ecx+ebx], 61
00401625 . |72 04 jb short 0040162B
00401627 . |802C19 20 sub byte ptr ds:[ecx+ebx], 20
3、查字符表得到序列号
00401618 . BF 08504000 mov edi, 00405008 ; ASCII "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| "
00401647 > /2C 41 sub al, 41
00401649 . |8A0438 mov al, byte ptr ds:[eax+edi]
keygen:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
char csUserName[21],*pUserName,*pKey;
char csTable[] = "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| ";
int nTable;
do
{
printf("请输入用户名(5-20个字符):");
gets_s(csUserName,21);
pUserName = csUserName;
nTable = 0;
while(*pUserName != '\0')
{
nTable ++;
if(*pUserName >= 0x61)
{
*pUserName -= 0x20;
}
pUserName ++;
}
}while(nTable < 5);
pKey = csUserName;
while(*pKey != '\0')
{
nTable = *pKey - 0x41;
*pKey = csTable[nTable];
pKey ++;
}
pKey = csUserName;
printf("注册码:%s",pKey);
getchar();
return 0;
}
三、评论
该函数仅演示一种思路,作者随手而写,未认真处理输入,所以该函数存在数组越界问题。比如:用户名中包含数字或者汉字。
|
能力值:
( LV4,RANK:50 )
|
-
-
6 楼
Level 004 :
一、破
作者在防简单爆破上下了功夫,故意打乱代码顺序。但只要掌握两点仍然随意爆破。
1、确保验证标志变量赋值为4
0040171F . C705 04504000>mov dword ptr ds:[405004], 4 ; Case 0 of switch 0040171B
2、确保eax返回时为4
0040175F . A1 04504000 mov eax, dword ptr ds:[405004] ; Case 0 of switch 0040175B
二、解
算法描述:
1、5 <= 用户名字符串长度 <= 0x14
00401695 . 83F8 05 cmp eax, 5
00401698 . 0F82 C8000000 jb 00401766
0040169E . 83F8 14 cmp eax, 14
004016A1 . 0F8F BF000000 jg 00401766
2、修正了Level 003 中没有检查输入的问题,限定输入必须是大小写字母
004016ED > /3C 61 cmp al, 61
004016EF . |72 10 jb short 00401701
004016F1 . |3C 7A cmp al, 7A
004016F3 . |77 0C ja short 00401701
00401701 > \3C 41 cmp al, 41 ; Default case of switch 0040171B
00401703 . 72 10 jb short 00401715
00401705 . 3C 5A cmp al, 5A
00401707 . 77 0C ja short 00401715
3、根据大小写分别查表得到注册码前半部分
004016D8 . BE 22504000 mov esi, 00405022 ; ASCII "qwertyuioplkjhgfdsazxcvbnm1357908642| "
(1)大写
00401709 . 2C 41 sub al, 41
0040170B . 8A0438 mov al, byte ptr ds:[eax+edi]
(2)小写
004016F5 . 2C 61 sub al, 61
004016F7 . 8A0430 mov al, byte ptr ds:[eax+esi]
4、再根据大小写分别查表得到注册码后半部分
004016DD . BF 08504000 mov edi, 00405008 ; ASCII
"PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| "
(1)大写
00401749 . 2C 41 sub al, 41
0040174B . 8A0430 mov al, byte ptr ds:[eax+esi]
(2)小写
00401735 . 2C 61 sub al, 61
00401737 . 8A0438 mov al, byte ptr ds:[eax+edi]
keygen:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
char csUserName[21],*pUserName,csKey[41],*pKey;
char csTable1[] = "qwertyuioplkjhgfdsazxcvbnm1357908642| ";
char csTable2[] = "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| ";
int nCount,nTable;
do
{
printf("请输入用户名(5-20个字符,只能是大小写字母):");
gets_s(csUserName,21);
pKey = csKey;
pUserName = csUserName;
nCount = 0;
while(*pUserName != '\0')
{
nCount ++;
if(*pUserName >= 0x61 && *pUserName <= 0x7a)
{
nTable = *pUserName - 0x61;
}
else
{
if(*pUserName >= 0x41 && *pUserName <= 0x5a)
{
nTable = *pUserName - 0x41;
}
else
{
printf("用户名不符合要求,请重新输入\r\n\r\n");
nCount = 0;
break;
}
}
*pKey = csTable1[nTable];
pUserName ++;
pKey ++;
}
}while(nCount < 5);
nCount = 0;
while(csUserName[nCount] != '\0')
{
if(csUserName[nCount] >= 0x61)
{
nTable = csUserName[nCount] - 0x61;
}
else
{
nTable = csUserName[nCount] - 0x41;
}
*pKey = csTable2[nTable];
nCount ++;
pKey ++;
}
*pKey = '\0';
printf("注册码:%s",csKey);
getchar();
return 0;
}
|
能力值:
( LV4,RANK:50 )
|
-
-
7 楼
Level 005 :
一、破
作者在防简单爆破上下了功夫,故意打乱代码顺序。但只要掌握两点仍然随意爆破。
1、确保验证标志变量赋值为5
004017E3 . C705 04504000>mov dword ptr ds:[405004], 5
2、确保eax返回时为5
0040182E . A1 04504000 mov eax, dword ptr ds:[405004]
二、解
算法描述:
1、5 <= 用户名字符串长度 <= 0x14
00401695 . 83F8 05 cmp eax, 5
00401698 . 0F82 C8000000 jb 00401766
0040169E . 83F8 14 cmp eax, 14
004016A1 . 0F8F BF000000 jg 00401766
2、转换字符值大于0x61的字符(又未考虑输入汉字等非预期情况)
004017F1 > /803C19 61 cmp byte ptr ds:[ecx+ebx], 61
004017F5 . |72 04 jb short 004017FB
004017F7 . |803419 20 xor byte ptr ds:[ecx+ebx], 20
3、根据转换完毕的字符查表取索引值
004017D9 . BE 08504000 mov esi, 00405008 ; ASCII "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| "
00401810 > /3A0431 cmp al, byte ptr ds:[ecx+esi]
00401813 . |74 07 je short 0040181C
4、查表得到注册码
004017DE . BF 22504000 mov edi, 00405022 ; ASCII "qwertyuioplkjhgfdsazxcvbnm1357908642| "
0040181C > \8A4439 F3 mov al, byte ptr ds:[ecx+edi-D]
keygen:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
char csUserName[21],*pUserName,csKey[41],*pTempTable;
char csTable1[] = "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| ";
char *pTable2 = &csTable1[26];
int nCount,nTable;
do
{
printf("请输入用户名(5-20个字符):");
gets_s(csUserName,21);
pUserName = csUserName;
nCount = 0;
while(*pUserName != '\0')
{
nCount ++;
if(*pUserName >= 0x61)
{
*pUserName ^= 0x20;
}
pUserName ++;
}
if(nCount < 5)
{
printf("用户名不符合要求,请重新输入\r\n\r\n");
}
}while(nCount < 5);
nCount = 0;
pTable2 -= 0xd;
while(csUserName[nCount] != '\0')
{
pTempTable = pTable2;
nTable = 0;
while(csTable1[nTable] != '\0')
{
if(csUserName[nCount] == csTable1[nTable])
{
pTempTable += nTable;
csKey[nCount] = *pTempTable;
break;
}
nTable ++;
}
nCount ++;
}
csKey[nCount] = '\0';
printf("注册码:%s",csKey);
getchar();
return 0;
}
|
能力值:
( LV4,RANK:50 )
|
-
-
8 楼
Level 006 :
一、破
作者在防简单爆破上下了功夫,故意打乱代码顺序。但只要掌握两点仍然随意爆破。
1、确保验证标志变量赋值为6
00401952 . C705 04504000>mov dword ptr ds:[405004], 6
2、确保eax返回时为5
0040182E . A1 04504000 mov eax, dword ptr ds:[405004]
二、解
算法描述:
1、用户名字符串长度 >= 5
00401865 . FFD0 call eax
00401867 . 83F8 05 cmp eax, 5
0040186A . 0F82 14010000 jb 00401984
2、公司名字符串长度 >= 1
00401890 . FFD0 call eax
00401892 . 83F8 01 cmp eax, 1
00401895 . 0F82 E9000000 jb 00401984
3、注册码字符串长度 >= 0xa
004018BB . FFD0 call eax
004018BD . 83F8 0A cmp eax, 0A
004018C0 . 0F82 BE000000 jb 00401984
4、注册码分析:
(1)第一个子符 = 0x4d - 3
004018C6 . 8D5D A0 lea ebx, dword ptr ss:[ebp-60]
004018C9 . 8A03 mov al, byte ptr ds:[ebx]
004018CB . 04 03 add al, 3
004018CD . 3C 4D cmp al, 4D
004018CF . 74 0A je short 004018DB
(2)第二个字符 = 0x69
004018DB > \8A43 01 mov al, byte ptr ds:[ebx+1]
004018DE . 34 69 xor al, 69
004018E0 . 74 0D je short 004018EF
(3)第三个字符 = 0x4d + 3
004018EF > \8A43 02 mov al, byte ptr ds:[ebx+2]
004018F2 . 2C 03 sub al, 3
004018F4 . 3C 4D cmp al, 4D
004018F6 . 74 0D je short 00401905
(4)第四个字符 = (company[0] & 6) + username[0]
00401905 > \8D75 E0 lea esi, dword ptr ss:[ebp-20]
00401908 . 8D7D C0 lea edi, dword ptr ss:[ebp-40]
0040190B . 8A27 mov ah, byte ptr ds:[edi]
0040190D . 80E4 06 and ah, 6
00401910 . 8A06 mov al, byte ptr ds:[esi]
00401912 . 02C4 add al, ah
00401914 . 2A43 03 sub al, byte ptr ds:[ebx+3]
00401917 . 75 6B jnz short 00401984
(5)第五个字符 = (username[0] & 9) + company[0]
00401919 . 8A26 mov ah, byte ptr ds:[esi]
0040191B . 80E4 09 and ah, 9
0040191E . 8A07 mov al, byte ptr ds:[edi]
00401920 . 02C4 add al, ah
00401922 . 2A43 04 sub al, byte ptr ds:[ebx+4]
00401925 . 75 5D jnz short 00401984
(6)第六、七、八、九个字符 = 任意字符,
第十、十一、十二、十三个字符 = (dword(username0123) ^ dword(sn6789) & 0x9070503) + dword(username0123)
00401927 . 8B43 05 mov eax, dword ptr ds:[ebx+5]
0040192A . 8B16 mov edx, dword ptr ds:[esi]
0040192C . 33D0 xor edx, eax
0040192E . 81E2 03050709 and edx, 9070503
00401934 . 0316 add edx, dword ptr ds:[esi]
00401936 . 8B43 09 mov eax, dword ptr ds:[ebx+9]
00401939 . 2BC2 sub eax, edx
0040193B .^ 75 C6 jnz short 00401903
5、转换用户名字符串中大于等于0x61的字符,username[x] &= 0xdf
00401941 > /803C31 61 cmp byte ptr ds:[ecx+esi], 61
00401945 . |72 04 jb short 0040194B
00401947 . |802431 DF and byte ptr ds:[ecx+esi], 0DF
6、查表得到后面的注册码
0040195C . BF 11504000 mov edi, 00405011 ; ASCII "HUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| "
00401969 > /2C 3D sub al, 3D
0040196B . |8A0438 mov al, byte ptr ds:[eax+edi]
0040196E . |3A4419 0D cmp al, byte ptr ds:[ecx+ebx+D]
00401972 . |75 10 jnz short 00401984
kengen:
#include "stdafx.h"
#include "stdLib.h"
#include "time.h"
int _tmain(int argc, _TCHAR* argv[])
{
char csUserName[21],*pUserName,csKey[41],csUserName1[21],csCompany[16];
char csTable[] = "HUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| ";
char *pKey;
int nCount,nTable;
do
{
printf("请输入用户名(5个字符以上):");
gets_s(csUserName,21);
pUserName = csUserName;
nCount = 0;
while(*pUserName != '\0')
{
if(*pUserName >= 0x61)
{
csUserName1[nCount] = *pUserName & 0xdf;
}
nCount ++;
pUserName ++;
}
csUserName1[nCount] = '\0';
if(nCount < 5)
{
printf("用户名不符合要求,请重新输入\r\n\r\n");
}
}while(nCount < 5);
csKey[0] = 0x4d - 3;
csKey[1] = 0x69;
csKey[2] = 0x4d + 3;
do
{
printf("请输入公司名称:");
gets_s(csCompany,16);
if(csCompany[0] != '\0')
{
csKey[3] = (csCompany[0] & 6) + csUserName[0];
csKey[4] = (csUserName[0] & 9) + csCompany[0];
break;
}
else
{
printf("公司名称不符合要求,请重新输入\r\n\r\n");
}
}while(nCount);
srand((unsigned int)time(NULL));
csKey[5] = rand() % 90 + 0x21;
csKey[6] = rand() % 90 + 0x21;
csKey[7] = rand() % 90 + 0x21;
csKey[8] = rand() % 90 + 0x21;
_asm
{
lea esi,csUserName
lea ebx,csKey
mov eax,[ebx+5]
mov edx,[esi]
xor edx,eax
and edx,0x9070503
add edx,[esi]
mov [ebx+9],edx
}
nCount = 0;
while(csUserName1[nCount] != '\0')
{
nTable = csUserName1[nCount] - 0x3d;
csKey[nCount+0xd] = csTable[nTable];
nCount ++;
}
csKey[nCount+0xd] = '\0';
printf("注册码:%s",csKey);
getchar();
return 0;
}
|
能力值:
(RANK:350 )
|
-
-
9 楼
水平不错,欢迎加入看雪论坛
|
能力值:
( LV4,RANK:50 )
|
-
-
10 楼
过奖啦!谢谢!
|
能力值:
( LV4,RANK:50 )
|
-
-
11 楼
Level 007 :
一、破
作者在防简单爆破上下了功夫,故意打乱代码顺序。但只要掌握两点仍然随意爆破。
1、确保验证标志变量赋值为7
00401A14 . C705 04504000>mov dword ptr ds:[405004], 7
2、确保eax返回时为7
00401A3D . A1 04504000 mov eax, dword ptr ds:[405004]
二、解
算法描述:
1、序列号字符串长度 >= 0x10
004019B0 . 83F8 10 cmp eax, 10
004019B3 . 0F82 8B000000 jb 00401A44
2、公司名字符串长度 >= 5
004019E8 . 83F8 05 cmp eax, 5
004019EB . 72 57 jb short 00401A44
3、用户名字符串长度 >= 5
00401A0F . 83F8 05 cmp eax, 5
00401A12 . 72 30 jb short 00401A44
4、加密序列号
004019B9 . 8D45 AD lea eax, dword ptr ss:[ebp-53]
004019BC . 50 push eax
004019BD . 8D45 DF lea eax, dword ptr ss:[ebp-21] ; sn
004019C0 . 50 push eax
004019C1 . E8 57F9FFFF call 0040131D
5、合成的序列号
00401A1E . 8D45 CE lea eax, dword ptr ss:[ebp-32] ; company
00401A21 . 50 push eax
00401A22 . 8D45 DF lea eax, dword ptr ss:[ebp-21] ; username
00401A25 . 50 push eax
00401A26 . E8 83F7FFFF call 004011AE ; strcat
6、验证序列号
00401A2B . 8D45 AD lea eax, dword ptr ss:[ebp-53]
00401A2E . 50 push eax
00401A2F . 8D45 DF lea eax, dword ptr ss:[ebp-21]
00401A32 . 50 push eax
00401A33 . E8 0EF7FFFF call 00401146 ; strcmp
7、关键加密函数CR-Game0.83.0040131D解析
(1)每四个字符一组
(2)每个字符用CR-Game0.83.00401210函数进行加密转换
0040134A > \8A17 mov dl, byte ptr ds:[edi]
0040134C . 52 push edx
0040134D . E8 BEFEFFFF call 00401210
(3)遇字符0x3d忽略后面字符结束加密序列号
00401388 . 807F 02 3D cmp byte ptr ds:[edi+2], 3D
(4)保存结果
00401357 . 8BC8 mov ecx, eax
00401364 > \C1E1 06 shl ecx, 6
004013A1 . 03C8 add ecx, eax
8、加密函数CR-Game0.83.00401210解析
查表获得索引值
00401215 . 8D05 08504000 lea eax, dword ptr ds:[405008]
Address=00405008, (ASCII "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| ")
0040121B . 8BD8 mov ebx, eax
0040121D . 8B4D 08 mov ecx, dword ptr ss:[ebp+8]
00401220 > 803B 00 cmp byte ptr ds:[ebx], 0
00401223 . 75 0D jnz short 00401232
00401232 > \380B cmp byte ptr ds:[ebx], cl
00401234 . 75 0A jnz short 00401240
keygen:
#include "stdafx.h"
#include "stdLib.h"
#include "time.h"
#include "string.h"
int _tmain(int argc, _TCHAR* argv[])
{
char csUserName[21],csKey[256],csTemp[256],csCompany[48];
char csTable[] = "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| ";
char *pKey,*pKeyTemp;
unsigned long ltemp;
int nCount,nTable;
do
{
printf("请输入用户名(5个字符以上):");
gets_s(csUserName,21);
nCount = strlen(csUserName);
if(nCount >= 5)
{
break;
}
printf("用户名不符合要求,请重新输入\r\n\r\n");
}while(true);
do
{
printf("请输入公司名称(5个字符以上):");
gets_s(csCompany,48);
nCount = strlen(csCompany);
if(nCount >= 5)
{
break;
}
printf("公司名称不符合要求,请重新输入\r\n\r\n");
}while(true);
strcpy(csTemp,csUserName);
strcat(csTemp,csCompany);
pKey = csKey;
pKeyTemp = csTemp;
do
{
ltemp = 0;
for(int i = 0; i < 3; i++)
{
if(*pKeyTemp == '\0')
{
do
{
ltemp = ltemp << 8;
i ++;
}while(i < 3);
break;
}
ltemp += *pKeyTemp;
ltemp = ltemp << 8;
pKeyTemp ++;
}
ltemp = ltemp >> 8;
nTable = (ltemp & 0xfc0000) >> 18;
*pKey = csTable[nTable];
pKey ++;
nTable = (ltemp & 0x3f000) >> 12;
*pKey = csTable[nTable];
pKey ++;
nTable = (ltemp & 0xfc0) >> 6;
*pKey = csTable[nTable];
pKey ++;
nTable = ltemp & 0x3f;
*pKey = csTable[nTable];
pKey ++;
}while(*pKeyTemp != '\0');
*pKey = '\0';
printf("注册码:%s",csKey);
getchar();
return 0;
}
|
能力值:
( LV4,RANK:50 )
|
-
-
12 楼
请管理员帮忙把我注册用的邮箱改为:wenbuxiu@139.com。原邮箱丢失,本站登陆密码忘了,无法自己更改。谢谢!
Level 008 :
一、破
又见反调试:
00402522 . 68 2B254000 push 0040252B ; ASCII "OLLYDBG"
00402541 . FFD0 call eax ; <jmp.&user32.FindWindowA>
00402543 . 83F8 00 cmp eax, 0
00402546 .^ 0F85 92FCFFFF jnz 004021DE ;建议爆破点
作者在防简单爆破上下了功夫,加了简单的干扰字节,故意打乱代码顺序。但只要掌握两点仍然随意爆破。
1、确保验证标志变量赋值为8
00401BDB > \C705 04504000>mov dword ptr ds:[405004], 8
2、确保eax返回时为8
00401C5A . A1 04504000 mov eax, dword ptr ds:[405004]
二、解
算法描述:
1、公司名字符串长度 >= 5
00401A7F . 83F8 05 cmp eax, 5
00401A82 . 0F82 D9010000 jb 00401C61
2、系统当前用户名
00401AA8 . FFD0 call eax ; GetSystemUserName
2、用户名字符串长度 >= 5
00401ADC . 83F8 05 cmp eax, 5
00401ADF . 0F82 7C010000 jb 00401C61
3、系统当前用户名、用户输入用户名合成新用户名1
00401AE5 . 8D45 80 lea eax, dword ptr ss:[ebp-80]
00401AE8 . 50 push eax
00401AE9 . 8D85 00FFFFFF lea eax, dword ptr ss:[ebp-100]
00401AEF . 50 push eax
00401AF0 . E8 B9F6FFFF call 004011AE ; strcat
4、新用户名查表转换得到新用户名2
Address=00405008, (ASCII "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| ")
00401AF5 . 8DB5 00FFFFFF lea esi, dword ptr ss:[ebp-100]
00401AFB . 8D3D 08504000 lea edi, dword ptr ds:[405008]
00401B01 . 33C0 xor eax, eax
00401B03 . 33C9 xor ecx, ecx
00401B05 . 8A06 mov al, byte ptr ds:[esi]
00401B11 . 8A2439 mov ah, byte ptr ds:[ecx+edi]
00401B14 > 38E0 cmp al, ah
00401B16 . 74 04 je short 00401B1C
以索引0x1a为界
00401B1C > \83F9 1A cmp ecx, 1A
00401B1F . 77 06 ja short 00401B27
00401B21 . 8A4439 1A mov al, byte ptr ds:[ecx+edi+1A]
00401B25 . /EB 04 jmp short 00401B2B
00401B27 > |8A4439 E6 mov al, byte ptr ds:[ecx+edi-1A]
5、新用户名2、程序作者网名合成新用户名3
00401B4C . 4A 69 50 00 ascii "JiP",0
00401B50 > 68 4C1B4000 push 00401B4C ; ASCII "JiP"
00401B55 . 8D85 00FFFFFF lea eax, dword ptr ss:[ebp-100]
00401B5B . 50 push eax
00401B5C . E8 29F6FFFF call 0040118A ; strcpy
00401B61 . 8D85 00FEFFFF lea eax, dword ptr ss:[ebp-200]
00401B67 . 50 push eax
00401B68 . 8D85 00FFFFFF lea eax, dword ptr ss:[ebp-100]
00401B6E . 50 push eax
00401B6F . E8 3AF6FFFF call 004011AE ; strcat
6、新用户名3限长0x20,不足取用户输入用户名补充,超出截断。
7、要求输入的序列号长度 >= 0x10
00401C08 . FFD0 call eax ; getsn
00401C0A . 83F8 10 cmp eax, 10
00401C0D . 72 52 jb short 00401C61
8、改动转换表
00401C20 . 6A 20 push 20 ; /Arg2 = 00000020
00401C22 . 6A 0C push 0C ; |Arg1 = 0000000C
00401C24 . E8 B2F5FFFF call 004011DB ; \CR-Game0.004011DB
Address=00405008, (ASCII "PLMKOIJNBHUYTRDXGVCFQAqwZSEWuiopertylkjhgfdsazxcvbnm1357908642| ")
9、转换序列号
00401C29 . 8D85 00FEFFFF lea eax, dword ptr ss:[ebp-200]
00401C2F . 50 push eax
00401C30 . 8D45 80 lea eax, dword ptr ss:[ebp-80]
00401C33 . 50 push eax
00401C34 . E8 E4F6FFFF call 0040131D ;该函数在上关已经解析过,本次不在赘述
10、还原转换表(掩耳盗铃)
00401C39 . 6A 20 push 20 ; /Arg2 = 00000020
00401C3B . 6A 0C push 0C ; |Arg1 = 0000000C
00401C3D . E8 99F5FFFF call 004011DB ; \CR-Game0.004011DB
11、比较转换序列号和新用户名3
00401C42 . 8D85 00FEFFFF lea eax, dword ptr ss:[ebp-200]
00401C48 . 50 push eax
00401C49 . 8D85 00FFFFFF lea eax, dword ptr ss:[ebp-100]
00401C4F . 50 push eax
00401C50 . E8 F1F4FFFF call 00401146 ; strcmp
keygen:
#include "stdafx.h"
#include "stdLib.h"
#include "time.h"
#include "string.h"
#include "windows.h"
int _tmain(int argc, _TCHAR* argv[])
{
char csUserName[21],csKey[256],csTemp[256],csCompany[48];
char csTable[] = "PLMKOIJNBHUYGVCFTRDXZSEWQAqwertyuioplkjhgfdsazxcvbnm1357908642| ";
char csTable1[] = "PLMKOIJNBHUYTRDXGVCFQAqwZSEWuiopertylkjhgfdsazxcvbnm1357908642| ";
char *pKey,*pKeyTemp;
unsigned long ltemp;
int nCount,nTable;
DWORD dwsize;
do
{
printf("请输入用户名(5个字符以上):");
gets_s(csUserName,21);
nCount = strlen(csUserName);
if(nCount >= 5)
{
break;
}
printf("用户名不符合要求,请重新输入\r\n\r\n");
}while(true);
do
{
printf("请输入公司名称(5个字符以上):");
gets_s(csCompany,48);
nCount = strlen(csCompany);
if(nCount >= 5)
{
break;
}
printf("公司名称不符合要求,请重新输入\r\n\r\n");
}while(true);
dwsize = 48;
GetUserNameA((char*)csCompany,&dwsize);
strcat(csCompany,csUserName);
nCount = 0;
while(csCompany[nCount] != '\0')
{
nTable = 0;
while(csTable[nTable] != '\0')
{
if(csCompany[nCount] == csTable[nTable])
{
if(nTable > 0x1a)
{
csCompany[nCount] = csTable[nTable - 0x1a];
}
else
{
csCompany[nCount] = csTable[nTable + 0x1a];
}
break;
}
nTable ++;
}
nCount ++;
}
strcpy(csTemp,"JiP");
strcat(csTemp,csCompany);
dwsize = strlen(csTemp);
if(dwsize < 0x20)
{
strcat(csTemp,csUserName);
}
csTemp[0x20] = '\0';
pKey = csKey;
pKeyTemp = csTemp;
do
{
ltemp = 0;
for(int i = 0; i < 3; i++)
{
if(*pKeyTemp == '\0')
{
do
{
ltemp = ltemp << 8;
i ++;
}while(i < 3);
break;
}
ltemp += *pKeyTemp;
ltemp = ltemp << 8;
pKeyTemp ++;
}
ltemp = ltemp >> 8;
nTable = (ltemp & 0xfc0000) >> 18;
*pKey = csTable1[nTable];
pKey ++;
nTable = (ltemp & 0x3f000) >> 12;
*pKey = csTable1[nTable];
pKey ++;
nTable = (ltemp & 0xfc0) >> 6;
*pKey = csTable1[nTable];
pKey ++;
nTable = ltemp & 0x3f;
*pKey = csTable1[nTable];
pKey ++;
}while(*pKeyTemp != '\0');
*pKey = '\0';
printf("注册码:%s",csKey);
getchar();
return 0;
}
|
能力值:
( LV4,RANK:50 )
|
-
-
13 楼
本程序尚有疑问求解:
作者为增加难度,特意使用地址调用如下:
0040214A > \B8 90304000 mov eax, 00403090
0040214F . 83E8 04 sub eax, 4
0040216C > \FFD0 call eax
我的问题是:作者怎么能在程序一开始就能确定该地址处是期望的调用呢?
|
|
|