壹只老虎是PEDIY CrackMe 2007里面的一个crackme了 虽然已经有破解文章了 但是下面是自己写的 主要想叫大家帮我看看 思维上有什么可以注意或改进的 这样让我这个小菜成长得更快 用PEiD查出Borland Delphi 6.0 - 7.0 Delphi和BCB的可以用DEDE找按钮事件地址 所以用DEDE加载壹只老虎 找到Button1Click事件地址0048C6D4
用OD加载壹只老虎 Ctrl+g 找到0048C6D4地址断点 然后F9运行输入注册名 whatdayitis 注册码 111111111111111111 后 点击注册 就来到了刚才的断点处 说明断点正确了的 接下来开始分析代码 0048C6D4 /. 55 push ebp
0048C6D5 |. 8BEC mov ebp, esp
0048C6D7 |. 83C4 84 add esp, -7C
0048C6DA |. 53 push ebx
0048C6DB |. 56 push esi
0048C6DC |. 57 push edi
0048C6DD |. 33C9 xor ecx, ecx
0048C6DF |. 894D 84 mov dword ptr ss:[ebp-7C], ecx
0048C6E2 |. 894D FC mov dword ptr ss:[ebp-4], ecx
0048C6E5 |. 894D F8 mov dword ptr ss:[ebp-8], ecx
0048C6E8 |. 894D F4 mov dword ptr ss:[ebp-C], ecx
0048C6EB |. 894D F0 mov dword ptr ss:[ebp-10], ecx
0048C6EE |. 894D EC mov dword ptr ss:[ebp-14], ecx
0048C6F1 |. 8BD8 mov ebx, eax
0048C6F3 |. 33C0 xor eax, eax
0048C6F5 |. 55 push ebp
0048C6F6 |. 68 67C84800 push 4nil_壹?0048C867
0048C6FB |. 64:FF30 push dword ptr fs:[eax]
0048C6FE |. 64:8920 mov dword ptr fs:[eax], esp
0048C701 |. 8D55 FC lea edx, dword ptr ss:[ebp-4]
0048C704 |. 8B83 04030000 mov eax, dword ptr ds:[ebx+304]
0048C70A |. E8 E57EFAFF call 4nil_壹?004345F4 ; get name
0048C70F |. 8D55 F8 lea edx, dword ptr ss:[ebp-8]
0048C712 |. 8B83 08030000 mov eax, dword ptr ds:[ebx+308]
0048C718 |. E8 D77EFAFF call 4nil_壹?004345F4 ; get pwd
0048C71D |. 8D45 F4 lea eax, dword ptr ss:[ebp-C]
0048C720 |. BA 80C84800 mov edx, 4nil_壹?0048C880 ; ASCII "i am Bin Laden"
0048C725 |. E8 CA77F7FF call 4nil_壹?00403EF4
0048C72A |. 8D45 F0 lea eax, dword ptr ss:[ebp-10]
0048C72D |. BA 98C84800 mov edx, 4nil_壹?0048C898 ; ASCII "i am yi zhi lao hu"
0048C732 |. E8 BD77F7FF call 4nil_壹?00403EF4
0048C737 |. 8B45 FC mov eax, dword ptr ss:[ebp-4]
0048C73A |. E8 DD79F7FF call 4nil_壹?0040411C ; get name length
0048C73F |. 83F8 0A cmp eax, 0A
0048C742 |. 0F8C FC000000 jl 4nil_壹?0048C844 ; length of name <10 game over
0048C748 |. 8B45 FC mov eax, dword ptr ss:[ebp-4]
0048C74B |. E8 CC79F7FF call 4nil_壹?0040411C ; get name length
0048C750 |. 83F8 10 cmp eax, 10
0048C753 |. 0F8F EB000000 jg 4nil_壹?0048C844 ; length of name >16 game over
0048C759 |. 8B45 F8 mov eax, dword ptr ss:[ebp-8]
0048C75C |. E8 BB79F7FF call 4nil_壹?0040411C ; get pwd length
0048C761 |. 83F8 11 cmp eax, 11
0048C764 |. 0F8C DA000000 jl 4nil_壹?0048C844 ; length of pwd<17 game over
0048C76A |. 8B45 F8 mov eax, dword ptr ss:[ebp-8]
0048C76D |. E8 AA79F7FF call 4nil_壹?0040411C ; get pwd length
0048C772 |. 83F8 16 cmp eax, 16
0048C775 |. 0F8F C9000000 jg 4nil_壹?0048C844 ; length of pwd >22 game over
0048C77B |. 8D45 FC lea eax, dword ptr ss:[ebp-4]
0048C77E |. 8B55 F4 mov edx, dword ptr ss:[ebp-C]
0048C781 |. E8 9E79F7FF call 4nil_壹?00404124 ; str1=name+"i am Bin Laden"
{
00404124 $ 85D2 test edx, edx
00404126 . 74 3F je short 4nil_壹?00404167
00404128 . 8B08 mov ecx, dword ptr ds:[eax]
0040412A . 85C9 test ecx, ecx
0040412C .^ 0F84 7EFDFFFF je 4nil_壹?00403EB0
00404132 . 53 push ebx
00404133 . 56 push esi
00404134 . 57 push edi
00404135 . 89C3 mov ebx, eax
00404137 . 89D6 mov esi, edx ; get "i am Bin Laden"
00404139 . 8B79 FC mov edi, dword ptr ds:[ecx-4] ; get length of name
0040413C . 8B56 FC mov edx, dword ptr ds:[esi-4] ; get length of "i am Bin Laden"
0040413F . 01FA add edx, edi ; 两个长度相加的和
00404141 . 39CE cmp esi, ecx ; 比较用户名和"i am Bin Laden"
00404143 . 74 17 je short 4nil_壹?0040415C ;相等则返回
00404145 . E8 5E030000 call 4nil_壹?004044A8 ; get name
0040414A . 89F0 mov eax, esi ; str="i am Bin Laden"
0040414C . 8B4E FC mov ecx, dword ptr ds:[esi-4] ; length(str)
0040414F > 8B13 mov edx, dword ptr ds:[ebx] ; name
00404151 . 01FA add edx, edi ; name后的第一个地址
00404153 . E8 70E7FFFF call 4nil_壹?004028C8 ; name+str
{
004028C5 8D40 00 lea eax, dword ptr ds:[eax]
004028C8 /$ 56 push esi
004028C9 |. 57 push edi
004028CA |. 89C6 mov esi, eax
004028CC |. 89D7 mov edi, edx
004028CE |. 89C8 mov eax, ecx
004028D0 |. 39F7 cmp edi, esi
004028D2 |. 77 13 ja short 4nil_壹?004028E7 ;这个地方始终要跳到004028E7 所以004028D4-004028E6是做什么用的呢?
004028D4 |. 74 2F je short 4nil_壹?00402905 ;这个应该是检查是否已经拷贝了 拷贝了就不执行以下的了 但是前面一句已经跳了 这句话有用吗
004028D6 |. C1F9 02 sar ecx, 2
004028D9 |. 78 2A js short 4nil_壹?00402905
004028DB |. F3:A5 rep movs dword ptr es:[edi], dword ptr ds:[esi]
004028DD |. 89C1 mov ecx, eax
004028DF |. 83E1 03 and ecx, 3
004028E2 |. F3:A4 rep movs byte ptr es:[edi], byte ptr ds:[esi]
004028E4 |. 5F pop edi
004028E5 |. 5E pop esi
004028E6 |. C3 retn
004028E7 |> 8D7431 FC lea esi, dword ptr ds:[ecx+esi-4] ; &str(length-4)
004028EB |. 8D7C39 FC lea edi, dword ptr ds:[ecx+edi-4] ; 目标地址
004028EF |. C1F9 02 sar ecx, 2 ; length/4=N个双字
004028F2 |. 78 11 js short 4nil_壹?00402905
004028F4 |. FD std ; 窜拷贝反向
004028F5 |. F3:A5 rep movs dword ptr es:[edi], dword ptr ds:[esi] ; 复制N个双字
004028F7 |. 89C1 mov ecx, eax
004028F9 |. 83E1 03 and ecx, 3 ; length mod 4=复制双字后剩下的字节数
004028FC |. 83C6 03 add esi, 3
004028FF |. 83C7 03 add edi, 3 ; 定位地址
00402902 |. F3:A4 rep movs byte ptr es:[edi], byte ptr ds:[esi] ; 复制剩下字节
00402904 |. FC cld ; 恢复窜拷贝正向
00402905 |> 5F pop edi
00402906 |. 5E pop esi
00402907 \. C3 retn
}
00404158 . 5F pop edi
00404159 . 5E pop esi
0040415A . 5B pop ebx
0040415B . C3 retn
}
0048C786 |. BB 64000000 mov ebx, 64
0048C78B |. 8D45 88 lea eax, dword ptr ss:[ebp-78]
0048C78E |> C600 2E /mov byte ptr ds:[eax], 2E
0048C791 |. 40 |inc eax
0048C792 |. 4B |dec ebx
0048C793 |.^ 75 F9 \jnz short 4nil_壹?0048C78E
0048C795 |. 8B45 FC mov eax, dword ptr ss:[ebp-4]
0048C798 |. E8 7F79F7FF call 4nil_壹?0040411C ; get length of str1
0048C79D |. 8BF8 mov edi, eax ; for(m=0; m<length(str1); m++)
0048C79F |. 85FF test edi, edi
0048C7A1 |. 7E 47 jle short 4nil_壹?0048C7EA
0048C7A3 |. BB 01000000 mov ebx, 1
0048C7A8 |> 8B45 F0 /mov eax, dword ptr ss:[ebp-10] ; str2="i am yi zhi lao hu"
0048C7AB |. E8 6C79F7FF |call 4nil_壹?0040411C ; get length of str2
0048C7B0 |. 8BF0 |mov esi, eax
0048C7B2 |. 85F6 |test esi, esi
0048C7B4 |. 7E 30 |jle short 4nil_壹?0048C7E6
0048C7B6 |. B9 01000000 |mov ecx, 1
0048C7BB |> 8B45 FC |/mov eax, dword ptr ss:[ebp-4] ; for(n=0; n<length(str2); n++)
0048C7BE |. 0FB64418 FF ||movzx eax, byte ptr ds:[eax+ebx-1] ; str1[0]
0048C7C3 |. 8B55 F8 ||mov edx, dword ptr ss:[ebp-8]
0048C7C6 |. 0FB6540A FF ||movzx edx, byte ptr ds:[edx+ecx-1] ; pwd[n]
0048C7CB |. F7EA ||imul edx ; str1[m]*pwd[n]
0048C7CD |. 51 ||push ecx
0048C7CE |. B9 1A000000 ||mov ecx, 1A
0048C7D3 |. 33D2 ||xor edx, edx
0048C7D5 |. F7F1 ||div ecx ; str1[m]*pwd[n]/1a
0048C7D7 |. 59 ||pop ecx
0048C7D8 |. 83C2 41 ||add edx, 41 ; str1[m]*pwd[n]mod26+41
0048C7DB |. 8D0419 ||lea eax, dword ptr ds:[ecx+ebx]
0048C7DE |. 885405 87 ||mov byte ptr ss:[ebp+eax-79], dl ; 把结果存到内存里面
0048C7E2 |. 41 ||inc ecx
0048C7E3 |. 4E ||dec esi
0048C7E4 |.^ 75 D5 |\jnz short 4nil_壹?0048C7BB
0048C7E6 |> 43 |inc ebx
0048C7E7 |. 4F |dec edi
0048C7E8 |.^ 75 BE \jnz short 4nil_壹?0048C7A8
0048C7EA |> 8D45 EC lea eax, dword ptr ss:[ebp-14]
0048C7ED |. E8 6A76F7FF call 4nil_壹?00403E5C
0048C7F2 |. 8B45 F8 mov eax, dword ptr ss:[ebp-8]
0048C7F5 |. E8 2279F7FF call 4nil_壹?0040411C ; get pwd length
0048C7FA |. 8BF8 mov edi, eax
0048C7FC |. 85FF test edi, edi
0048C7FE |. 7E 1F jle short 4nil_壹?0048C81F
0048C800 |. 8D5D 8E lea ebx, dword ptr ss:[ebp-72]
0048C803 |> 8D45 84 /lea eax, dword ptr ss:[ebp-7C] ; 从str2第6位开始 反向复制每个字符 复制长度为输入的注册码长度(这个地方我没有跟进去 是观察结果得到的)
0048C806 |. 8A13 |mov dl, byte ptr ds:[ebx]
0048C808 |. E8 3778F7FF |call 4nil_壹?00404044
0048C80D |. 8B55 84 |mov edx, dword ptr ss:[ebp-7C]
0048C810 |. 8D45 EC |lea eax, dword ptr ss:[ebp-14]
0048C813 |. 8B4D EC |mov ecx, dword ptr ss:[ebp-14]
0048C816 |. E8 4D79F7FF |call 4nil_壹?00404168
0048C81B |. 43 |inc ebx
0048C81C |. 4F |dec edi
0048C81D |.^ 75 E4 \jnz short 4nil_壹?0048C803
0048C81F |> 8B45 EC mov eax, dword ptr ss:[ebp-14]
0048C822 |. 8B55 F8 mov edx, dword ptr ss:[ebp-8]
0048C825 |. E8 3E7AF7FF call 4nil_壹?00404268 ; 比较生成的注册码和输入的注册码
0048C82A |. 75 18 jnz short 4nil_壹?0048C844
0048C82C |. 6A 40 push 40
0048C82E |. B9 ACC84800 mov ecx, 4nil_壹?0048C8AC ; 恭喜你
0048C833 |. BA B4C84800 mov edx, 4nil_壹?0048C8B4 ; 注册成功!请联系我!qq:609841314
0048C838 |. A1 D0EB4800 mov eax, dword ptr ds:[48EBD0]
0048C83D |. 8B00 mov eax, dword ptr ds:[eax]
0048C83F |. E8 F478FCFF call 4nil_壹?00454138
0048C844 |> 33C0 xor eax, eax
0048C846 |. 5A pop edx
0048C847 |. 59 pop ecx
0048C848 |. 59 pop ecx
0048C849 |. 64:8910 mov dword ptr fs:[eax], edx
0048C84C |. 68 6EC84800 push 4nil_壹?0048C86E
0048C851 |> 8D45 84 lea eax, dword ptr ss:[ebp-7C]
0048C854 |. E8 0376F7FF call 4nil_壹?00403E5C
0048C859 |. 8D45 EC lea eax, dword ptr ss:[ebp-14]
0048C85C |. BA 05000000 mov edx, 5
0048C861 |. E8 1A76F7FF call 4nil_壹?00403E80
0048C866 \. C3 retn 以下是还原的C版本的算法
在XP环境下 VC6调试通过
#include<stdio.h>
#include<string.h>
int main(){
char name[50];
char pwd[50];
char tmp[50];
char tmp1[]="i am yi zhi lao hu";
int m, n, pwdLen, tmpLen, tmp1Len;
char tmp2[50];
char result[50];
printf("输入用户名:(长度10-16)");
scanf("%s", name);
printf("输入注册码(长度17-22):");
scanf("%s", pwd);
strcpy(tmp,name);
strcat(tmp,"i am Bin Laden");
tmp1Len=strlen(tmp1); //这个长度是个定值
pwdLen=strlen(pwd);
tmpLen=strlen(tmp);
if(pwdLen<tmp1Len){ //当输入的注册码小于18 第18位用'A'补上
pwd[pwdLen]='A';
pwd[pwdLen+1]='\0';
}
for(m=0; m<tmpLen; m++)
for(n=0; n<tmp1Len; n++) //这里可以看出 注册码是17位或者18位 因为"i am yi zhi lao hu"这个长度为18 大于18位的注册码也不纳入计算中
tmp2[n+m]=tmp[m]*pwd[n]%26+65;
for(m=0; m<pwdLen; m++) //从第六位开始颠倒复制
result[m]=tmp2[pwdLen-1-m+5];
result[m]='\0';
printf("计算后的注册码:\n%s\n", result);
getch();
return 0;
} 以下是写的注册机
在XP环境下 VC6调试通过
#include<stdio.h>
#include<string.h>
/*
经过算法分析得出
当注册码为18位时:
pwd[17]=name[5]*pwd[0]%26+65
pwd[16]=name[6]*pwd[0]%26+65
pwd[15]=name[7]*pwd[0]%26+65
pwd[14]=name[8]*pwd[0]%26+65
pwd[13]=name[9]*pwd[0]%26+65
pwd[12]=name[10]*pwd[0]%26+65
pwd[11]=name[11]*pwd[0]%26+65
pwd[10]=name[12]*pwd[0]%26+65
pwd[9]=name[13]*pwd[0]%26+65
pwd[8]=name[14]*pwd[0]%26+65
pwd[7]=name[15]*pwd[0]%26+65
pwd[6]=name[16]*pwd[0]%26+65
pwd[5]=name[17]*pwd[0]%26+65
pwd[4]=name[18]*pwd[0]%26+65
pwd[3]=name[19]*pwd[0]%26+65
pwd[2]=name[20]*pwd[0]%26+65
pwd[1]=name[21]*pwd[0]%26+65
pwd[0]=name[22]*pwd[0]%26+65
当注册码为17位时:
pwd[16]=name[5]*pwd[0]%26+65
pwd[15]=name[6]*pwd[0]%26+65
pwd[14]=name[7]*pwd[0]%26+65
pwd[13]=name[8]*pwd[0]%26+65
pwd[12]=name[9]*pwd[0]%26+65
pwd[11]=name[10]*pwd[0]%26+65
pwd[10]=name[11]*pwd[0]%26+65
pwd[9]=name[12]*pwd[0]%26+65
pwd[8]=name[13]*pwd[0]%26+65
pwd[7]=name[14]*pwd[0]%26+65
pwd[6]=name[15]*pwd[0]%26+65
pwd[5]=name[16]*pwd[0]%26+65
pwd[4]=name[17]*pwd[0]%26+65
pwd[3]=name[18]*pwd[0]%26+65
pwd[2]=name[19]*pwd[0]%26+65
pwd[1]=name[20]*pwd[0]%26+65
pwd[0]=name[21]*pwd[0]%26+65
*/
void yizhilaohu(char * tmp, char * name, int len){
int n,m;
for(m=65; m<91; m++)
if(m==name[22]*m%26+65) //算出pwd[0] 如果这里不马上跳出 还可以算出更多注册码
break;
printf("注册码:%c", m);
for(n=1; n<len; n++)
printf("%c", tmp[len+4-n]*m%26+65); //根据上面推导算出其他位的注册码
printf("\n");
}
int main(){
char name[50];
char tmp[50];
//char tmp1[]="i am yi zhi lao hu";
int m, n, pwdLen, tmpLen, tmp1Len;
printf("输入用户名:(长度10-16)");
scanf("%s", name);
strcpy(tmp,name);
strcat(tmp,"i am Bin Laden");
yizhilaohu(tmp, name, 18); //当注册码为18位时
yizhilaohu(tmp, name, 17); //当注册码为17位时
getch();
return 0;
}
到此完毕 这个crackme的注册码不唯一 算法虽然看得懂 写相应的破解算法想好好一阵
最后我还有个疑问 为什么算出的2个注册码 有时候第一个正确 有时候第二个正确 有时候都正确的(都不正确的情况还没发现哈) 这是为什么呢
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: