好友
阅读权限 25
听众
最后登录 1970-1-1
Thend
发表于 2013-12-18 13:49
CM是什么?Crackme是什么?这是什么东西?楼主发的什么?
他们都是一些公开给别人尝试破解的小程序,制作 Crackme 的人可能是程序员,想测试一下自己的软件保护技术,也可能是一位 Cracker,想挑战一下其它 Cracker 的破解实力,也可能是一些正在学习破解的人,自己编一些小程序给自己破解,KeyGenMe是要求别人做出它的 keygen (序号产生器), ReverseMe 要求别人把它的算法做出逆向分析, UnpackMe 是要求别人把它成功脱壳,本版块禁止回复非技术无关水贴。
[文章标题]: 【吾爱2013CM大赛解答】-- White Decrypt & CrackMe -- White 算法详细分析+还原
[作者信息]: 0n1y3nd
[操作平台]: Win7 Sp1 & Windows XP Sp3
[使用工具]: OD
[软件名称]: White Decrypt & CrackMe -- White
[下载地址]: 【吾爱2013CM大赛题目】-- White Decrypt & CrackMe -- White http://www.52pojie.cn/thread-228419-1-1.html
正文:
查壳,无壳,MFC写的程序。
运行下,随意输入,提示不能为空,提示字符串长度必须为23.
载入OD,直接查找MFC的按钮事件特征码:FF 55 14 EB 7F FF 75 0C ,下好断点。
输入一组测试数据:12345678901234567890123和abcdefghijklmnopqrstuvw
断下,F7跟进:
[AppleScript] 纯文本查看 复制代码
00401460 /. 55 push ebp ; 按钮事件call
00401461 |. 8BEC mov ebp,esp
00401463 |. 83EC 10 sub esp,0x10
00401466 |. 53 push ebx
00401467 |. 56 push esi
00401468 |. 57 push edi
00401469 |. 8BF1 mov esi,ecx
0040146B |. 6A 01 push 0x1
0040146D |. E8 22B80000 call White_De.0040CC94 ; 取注册码
00401472 |. 68 C8000000 push 0xC8
00401477 |. E8 C28A0000 call White_De.00409F3E
0040147C |. 8BD8 mov ebx,eax
0040147E |. 68 C8000000 push 0xC8
00401483 |. 895D F8 mov [local.2],ebx
00401486 |. E8 B38A0000 call White_De.00409F3E ; 取用户名
0040148B |. 8B8E D4000000 mov ecx,dword ptr ds:[esi+0xD4]
00401491 |. 8BF8 mov edi,eax
00401493 |. 8B86 D8000000 mov eax,dword ptr ds:[esi+0xD8]
00401499 83C4 08 add esp,0x8 ; eax存注册码 ecx存用户名
0040149C |. 8B49 F8 mov ecx,dword ptr ds:[ecx-0x8] ; ecx是用户名长度
0040149F |. 33D2 xor edx,edx
004014A1 |. 8B40 F8 mov eax,dword ptr ds:[eax-0x8]
004014A4 |. 894D FC mov [local.1],ecx ; eax是注册码长度
004014A7 |. 85C9 test ecx,ecx ; 是否为空
004014A9 |. 0F94C2 sete dl
004014AC |. 33C9 xor ecx,ecx
004014AE |. 897D F0 mov [local.4],edi
004014B1 |. 85C0 test eax,eax ; 是否为空
004014B3 |. 0F94C1 sete cl
004014B6 |. 0BD1 or edx,ecx
004014B8 |. 74 1A je XWhite_De.004014D4
004014BA |. 6A 10 push 0x10
004014BC |. 68 28614100 push White_De.00416128 ; 错误
004014C1 |. 68 14614100 push White_De.00416114 ; 请输入用户名和密码
004014C6 |. 8BCE mov ecx,esi
004014C8 |. E8 6BB00000 call White_De.0040C538 ; 提示 不能为空
004014CD |. 5F pop edi
004014CE |. 5E pop esi
004014CF |. 5B pop ebx
004014D0 |. 8BE5 mov esp,ebp
004014D2 |. 5D pop ebp
004014D3 |. C3 retn
004014D4 |> 8B4D FC mov ecx,[local.1]
004014D7 |. 33D2 xor edx,edx
004014D9 |. 83F9 17 cmp ecx,0x17 ; 比较注册码长度
004014DC |. 0F9CC2 setl dl
004014DF |. 33C9 xor ecx,ecx
004014E1 |. 83F8 17 cmp eax,0x17 ; 比较用户名长度
004014E4 |. 0F9CC1 setl cl
004014E7 |. 0BD1 or edx,ecx
004014E9 |. 74 1A je XWhite_De.00401505
004014EB |. 6A 10 push 0x10
004014ED |. 68 28614100 push White_De.00416128 ; 错误
004014F2 |. 68 00614100 push White_De.00416100 ; 字符串长度等于23
004014F7 |. 8BCE mov ecx,esi
004014F9 |. E8 3AB00000 call White_De.0040C538 ; 提示长度必须是23位
004014FE |. 5F pop edi
004014FF |. 5E pop esi
00401500 |. 5B pop ebx
00401501 |. 8BE5 mov esp,ebp
00401503 |. 5D pop ebp
00401504 |. C3 retn
00401505 |> 8B86 D4000000 mov eax,dword ptr ds:[esi+0xD4] ; 用户名存入eax
0040150B |. 50 push eax
0040150C |. 57 push edi
0040150D |. E8 EC0D0000 call White_De.004022FE
00401512 |. 8B96 D8000000 mov edx,dword ptr ds:[esi+0xD8] ; 注册码存入edx
00401518 |. 52 push edx
00401519 |. 53 push ebx
0040151A |. E8 DF0D0000 call White_De.004022FE ; 返回注册码长度
0040151F |. 8B86 D4000000 mov eax,dword ptr ds:[esi+0xD4] ; 用户名存入eax
00401525 |. 83C4 10 add esp,0x10
00401528 |. 33C9 xor ecx,ecx
0040152A |. 8078 04 65 cmp byte ptr ds:[eax+0x4],0x65 ; 用户名第5位 和 e 比较 必须相等
0040152E |. 0F95C1 setne cl
00401531 |. 33D2 xor edx,edx
00401533 |. 8038 57 cmp byte ptr ds:[eax],0x57 ; 用户名第1位 和 W 比较 必须相等
00401536 |. 0F95C2 setne dl
00401539 |. 0BCA or ecx,edx
0040153B |. 74 1A je XWhite_De.00401557
0040153D |. 6A 10 push 0x10
0040153F |. 68 28614100 push White_De.00416128 ; 错误
00401544 |. 68 F4604100 push White_De.004160F4 ; 错误字符串
00401549 |. 8BCE mov ecx,esi
0040154B |. E8 E8AF0000 call White_De.0040C538
00401550 |. 5F pop edi
00401551 |. 5E pop esi
00401552 |. 5B pop ebx
00401553 |. 8BE5 mov esp,ebp
00401555 |. 5D pop ebp
00401556 |. C3 retn
00401557 |> 83C9 FF or ecx,0xFFFFFFFF
0040155A |. 33C0 xor eax,eax
0040155C |. F2:AE repne scas byte ptr es:[edi]
0040155E |. F7D1 not ecx
00401560 |. 83C1 FE add ecx,-0x2
00401563 |. 8BFB mov edi,ebx
00401565 |. 894D FC mov [local.1],ecx
00401568 |. 83C9 FF or ecx,0xFFFFFFFF
0040156B |. F2:AE repne scas byte ptr es:[edi]
0040156D |. F7D1 not ecx
0040156F |. 83C1 FE add ecx,-0x2
00401572 |. 894D F4 mov [local.3],ecx
00401575 |. 60 pushad
00401576 |. 61 popad ; 下面是第一次循环处理
00401577 |. 8B4D F4 mov ecx,[local.3] ; ecx 存注册码的长度 -1
0040157A |. 8B45 F8 mov eax,[local.2] ; eax存入注册码
0040157D |. 03C1 add eax,ecx ; 用eax + 长度减1 就是eax取注册码最后一位
0040157F |. 8D51 01 lea edx,dword ptr ds:[ecx+0x1]
00401582 |> 8A48 FF /mov cl,byte ptr ds:[eax-0x1] ; cl 中 存入 eax-1 也就是现在字符前一位的字符
00401585 |. 8A18 |mov bl,byte ptr ds:[eax] ; bl中存入 eax 也就是最后一个
00401587 |. 32D9 |xor bl,cl ; 也就是说 注册码的后一位与前一位亦或操作 结果放入bl
00401589 |. 8ACB |mov cl,bl ; 亦或后的值 传给cl
0040158B |. 8818 |mov byte ptr ds:[eax],bl ; 替换掉原始数据后面的那一位
0040158D |. 0FBE58 FF |movsx ebx,byte ptr ds:[eax-0x1] ; 取倒数第二位 放入EBX
00401591 |. 0FBEC9 |movsx ecx,cl
00401594 |. 03D9 |add ebx,ecx ; 倒数第二位 + 异或得到的值
00401596 |. 48 |dec eax
00401597 |. 4A |dec edx
00401598 |.^ 75 E8 \jnz XWhite_De.00401582
0040159A |. 8B7D F0 mov edi,[local.4] ; 用户名存入 edi
0040159D |. 8B55 FC mov edx,[local.1] ; 用户名长度存入 edx
004015A0 |. 33F6 xor esi,esi ; 循环计数器清零
004015A2 |. 8D043A lea eax,dword ptr ds:[edx+edi]
004015A5 |> 8A48 FF /mov cl,byte ptr ds:[eax-0x1] ; 倒数第二位存入 cl
004015A8 |. 8A10 |mov dl,byte ptr ds:[eax] ; 倒数第一位 存入 dl
004015AA |. 32D1 |xor dl,cl ; 倒数第一和第二位异或 存入dl
004015AC |. 8810 |mov byte ptr ds:[eax],dl ; 异或后的值 替换倒数第一位
004015AE |. 0FBE0C3E |movsx ecx,byte ptr ds:[esi+edi]
004015B2 |. 0FBED2 |movsx edx,dl
004015B5 |. 03CA |add ecx,edx
004015B7 |. 8B55 FC |mov edx,[local.1]
004015BA |. 46 |inc esi
004015BB |. 48 |dec eax
004015BC |. 3BF2 |cmp esi,edx
004015BE |.^ 76 E5 \jbe XWhite_De.004015A5
004015C0 |. 8B45 F8 mov eax,[local.2] ; 注册码替换完成之后新的注册码 存入 eax
004015C3 |. 23CB and ecx,ebx
004015C5 |. 51 push ecx ; push了 and ecx,ebx
004015C6 |. 57 push edi ; edi是新的用户名的地址
004015C7 |. 50 push eax ; eax是新的注册码的地址
004015C8 |. E8 13000000 call White_De.004015E0 ; 很重要的call
004015CD |. 83C4 0C add esp,0xC
004015D0 |. 5F pop edi
004015D1 |. 5E pop esi
004015D2 |. 5B pop ebx
004015D3 |. 8BE5 mov esp,ebp
004015D5 |. 5D pop ebp
004015D6 \. C3 retn
上面处理了输入的用户名和注册码。
从用户名的最后一位开始,与前一位异或,替换本身。第一位和0x08异或。
注册码做同样的处理。
跟进那个最重要的call里面去:004015C8 |. E8 13000000 call White_De.004015E0
[AppleScript] 纯文本查看 复制代码
004015E0 /$ 51 push ecx
004015E1 |. 53 push ebx ; ebx貌似是注册码的第一位
004015E2 |. 55 push ebp
004015E3 |. 56 push esi ; 注册码长度
004015E4 |. 57 push edi ; 新的用户名的地址
004015E5 |. 6A 32 push 0x32 ; push 0x32
004015E7 |. E8 52890000 call White_De.00409F3E
004015EC |. 6A 64 push 0x64
004015EE |. 8BE8 mov ebp,eax
004015F0 |. E8 49890000 call White_De.00409F3E
004015F5 |. 8BF8 mov edi,eax
004015F7 |. B9 19000000 mov ecx,0x19
004015FC |. 33C0 xor eax,eax
004015FE |. 897C24 18 mov dword ptr ss:[esp+0x18],edi
00401602 |. F3:AB rep stos dword ptr es:[edi]
00401604 |. B9 0C000000 mov ecx,0xC
00401609 |. 8BFD mov edi,ebp
0040160B |. F3:AB rep stos dword ptr es:[edi]
0040160D |. 66:AB stos word ptr es:[edi]
0040160F |. B9 08000000 mov ecx,0x8
00401614 |. BE B0604100 mov esi,White_De.004160B0
00401619 |. 8BFD mov edi,ebp
0040161B |. 33C0 xor eax,eax
0040161D |. F3:A5 rep movs dword ptr es:[edi],dword ptr>; 向上面申请的地址空间 填充数据
0040161F |. 8B7424 20 mov esi,dword ptr ss:[esp+0x20] ; esi存入新的注册码
00401623 |. 83C9 FF or ecx,0xFFFFFFFF
00401626 |. 8BFE mov edi,esi ; edi也是新的注册码
00401628 |. 83C4 08 add esp,0x8
0040162B |. F2:AE repne scas byte ptr es:[edi]
0040162D |. 8B5424 1C mov edx,dword ptr ss:[esp+0x1C] ; edx存入新的用户名
00401631 |. F7D1 not ecx
00401633 |. 49 dec ecx ; not ecx 然后 dec ecx ecx中得到长度
00401634 |. 8BFA mov edi,edx ; edi中存入新的用户名
00401636 |. 8BD9 mov ebx,ecx ; 长度 存入 ebx
00401638 |. 83C9 FF or ecx,0xFFFFFFFF
0040163B |. F2:AE repne scas byte ptr es:[edi] ; edi指向一个新的地址
0040163D |. F7D1 not ecx ; esi 存的 注册码的地址
0040163F |. 49 dec ecx ; ebp 存的 初始字符串的地址
00401640 |. 894C24 18 mov dword ptr ss:[esp+0x18],ecx ; edx 存的 用户名的地址
00401644 |> 8A0C30 /mov cl,byte ptr ds:[eax+esi] ; 取注册码的第一位 给cl
00401647 |. 300C28 |xor byte ptr ds:[eax+ebp],cl ; 注册码第一位和初始字符串第一位 xor 然后替换初始字符串对应位置
0040164A |. 83F8 0A |cmp eax,0xA ; 第一次解码 只解0xA次 解码到第十一个字符
0040164D |. 75 13 |jnz XWhite_De.00401662
0040164F |. 8D7B F6 |lea edi,dword ptr ds:[ebx-0xA]
00401652 |. 3BF8 |cmp edi,eax
00401654 |. 72 0C |jb XWhite_De.00401662
00401656 |> 8A0C06 |/mov cl,byte ptr ds:[esi+eax] ; 新注册码的第十一位 赋值 给cl
00401659 |. 304C06 01 ||xor byte ptr ds:[esi+eax+0x1],cl ; 注册码的第十二位 与 第十一位 异或 新值赋给 第十三位
0040165D |. 40 ||inc eax
0040165E |. 3BC7 ||cmp eax,edi
00401660 |.^ 76 F4 |\jbe XWhite_De.00401656 ; 循环处理更新 注册码的第十二位到第十四位 3位
00401662 |> 40 |inc eax
00401663 |. 83F8 0A |cmp eax,0xA
00401666 |.^ 76 DC \jbe XWhite_De.00401644
00401668 |. 8B4C24 18 mov ecx,dword ptr ss:[esp+0x18]
0040166C |. B8 0A000000 mov eax,0xA ; 从第十二位开始 解码 原始字符串
00401671 |> 8A1C10 /mov bl,byte ptr ds:[eax+edx] ; 新用户名的第十一位 赋值 给bl
00401674 |. 301C28 |xor byte ptr ds:[eax+ebp],bl ; 原始字符串第十一位和用户名第十一位 异或
00401677 |. 83F8 14 |cmp eax,0x14 ; 从第十一位解码到第二十一位 还剩下5位没有解码
0040167A |. 75 13 |jnz XWhite_De.0040168F
0040167C |. 8D79 EC |lea edi,dword ptr ds:[ecx-0x14]
0040167F |. 3BF8 |cmp edi,eax
00401681 |. 72 0C |jb XWhite_De.0040168F
00401683 |> 8A1C02 |/mov bl,byte ptr ds:[edx+eax]
00401686 |. 205C02 01 ||and byte ptr ds:[edx+eax+0x1],bl
0040168A |. 40 ||inc eax
0040168B |. 3BC7 ||cmp eax,edi
0040168D |.^ 76 F4 |\jbe XWhite_De.00401683
0040168F |> 40 |inc eax
00401690 |. 83F8 14 |cmp eax,0x14
00401693 |.^ 76 DC \jbe XWhite_De.00401671
00401695 |. 8BCE mov ecx,esi ; ecx 存入 注册码的地址
00401697 |. 8BC2 mov eax,edx ; eax 存入 用户名的地址
00401699 |. 2BCA sub ecx,edx ; 相 减 得到 28
0040169B |. BF 0B000000 mov edi,0xB
004016A0 |> 8A1C01 /mov bl,byte ptr ds:[ecx+eax] ; 注册码的第一位 赋值 给bl
004016A3 |. 3018 |xor byte ptr ds:[eax],bl ; 用户名的第一位 异或 注册码的第一位 然后更新用户名
004016A5 |. 40 |inc eax ; 移动向 下一位
004016A6 |. 4F |dec edi
004016A7 |.^ 75 F7 \jnz XWhite_De.004016A0 ; 一共更新了 十一位
004016A9 |. 8BFA mov edi,edx ; 更新之后的用户名 存入edi中 esi中是注册码的地址\
004016AB |. 8D46 0A lea eax,dword ptr ds:[esi+0xA] ; 注册码第十一位赋值 给eax
004016AE |. 2BFE sub edi,esi
004016B0 |. BE 0B000000 mov esi,0xB
004016B5 |> 8A1C07 /mov bl,byte ptr ds:[edi+eax] ; 新的用户名的第十一位 赋值 给bl
004016B8 |. 2018 |and byte ptr ds:[eax],bl ; 注册码的第十一位 and 用户名的第十一位 更新注册码
004016BA |. 40 |inc eax
004016BB |. 4E |dec esi
004016BC |.^ 75 F7 \jnz XWhite_De.004016B5 ; 一直更新到第二十一位
004016BE |. 8D42 14 lea eax,dword ptr ds:[edx+0x14] ; 用户名的第二十一位 赋值 给eax
004016C1 |. BE 06000000 mov esi,0x6
004016C6 |> 8A1C08 /mov bl,byte ptr ds:[eax+ecx] ; 注册码的第二十一位 赋值 给bl
004016C9 |. 2018 |and byte ptr ds:[eax],bl ; 用户名的第二十一位 and 注册码的第二十一位 更新用户名
004016CB |. 40 |inc eax
004016CC |. 4E |dec esi
004016CD |.^ 75 F7 \jnz XWhite_De.004016C6 ; 从第二十一位 更新到第二十六位
004016CF |. 8D45 14 lea eax,[arg.4] ; 初始字符串身下的十位 存入eax
004016D2 |. 2BD5 sub edx,ebp
004016D4 |. BE 06000000 mov esi,0x6
004016D9 |> 8A0C02 /mov cl,byte ptr ds:[edx+eax] ; 新的用户名的第二十一位 赋值 给cl
004016DC |. 8A18 |mov bl,byte ptr ds:[eax] ; 初始字符串的第二十一位 赋值 给bl
004016DE |. 32D9 |xor bl,cl ; 初始字符串第二十一位和用户名第二十一位 异或 更新字符串
004016E0 |. 8818 |mov byte ptr ds:[eax],bl
004016E2 |. 40 |inc eax
004016E3 |. 4E |dec esi
004016E4 |.^ 75 F3 \jnz XWhite_De.004016D9 ; 一直更新到第二十六位
004016E6 |. 8B7424 10 mov esi,dword ptr ss:[esp+0x10]
004016EA |. 55 push ebp ; 这儿就可以看到 把解码完成的字符串压栈了
004016EB |. 68 38614100 push White_De.00416138 ; %s
004016F0 |. 56 push esi
004016F1 |. E8 080C0000 call White_De.004022FE
算法不是很复杂,几个循环处理而已。
下面是我用C语言还原的算法部分的源代码:
[C] 纯文本查看 复制代码
#include <stdio.h>
#include <string.h>
void main()
{
char UserName[26] = "White_CrackMe_JUST_For_Fun";
char PassWord[26] = "Do_You_Like_It_Or_NOT__:)_";
char MsgText[30] = {0x1F, 0x44, 0x5D, 0x63, 0x42, 0x72, 0x43, 0x7D,
0x42, 0x22, 0x4F, 0x55, 0x08, 0x5B, 0x79, 0x68, 0x67,
0x7E, 0x78, 0x39, 0x63, 0x61, 0x61, 0x6F, 0x74, 0x7B,
0x6E, 0x67, 0x20, 0x21};
int i;
UserName[26] = '\0';
PassWord[26] = '\0';
printf("用户名:%s\n",UserName);
printf("注册码:%s\n", PassWord);
//第一次处理用户名和注册码
for (i=25; i>0; i--)
{
UserName[i] = UserName[i] ^ UserName[i-1];
PassWord[i] = PassWord[i] ^ PassWord[i-1];
}
UserName[0] = UserName[0] ^ 0x08;
PassWord[0] = PassWord[0] ^ 0x08;
//第一次解码 解到0xA处
//注册码的第n位 和 原始字符串的第n位 异或
for (i=0; i<11; i++)
{
MsgText[i] = MsgText[i] ^ PassWord[i]; //解码出 Something A
}
//更新注册码的第 12 13 14 位
//注册码从第12位开始、与前一位异或,更新自身。
for (i=11; i<14; i++)
{
PassWord[i] = PassWord[i] ^ PassWord[i-1]; //只更新了3个数据
}
//第二次解码 从第12位处解码到第21位
//用户名的第n位 和 原始字符串的第n位 异或
for (i=10; i<21; i++) //从第11位开始的 解码到第21位
{
MsgText[i] = MsgText[i] ^ UserName[i];
}
//更新用户名的第 1 到 11位
//用户名的第n位 和 注册码的第n位 异或 更新用户名
for (i=0; i<11;i++)
{
UserName[i] = UserName[i] ^ PassWord[i];
}
//更新注册码的第 11 到 22位
//注册码的 第n位 和 用户名的第n位 and操作 更新注册码
for (i=10; i<21; i++)
{
PassWord[i] = PassWord[i] & UserName[i];
}
//更新用户名的第 23到 26位
//用户名的 第n位 和 注册码的第n位 and操作 更新用户名
for (i=20; i<26; i++)
{
UserName[i] = UserName[i] & PassWord[i];
}
//第三次解码 从第21位 解码到第26位
//初始字符串第n位 和 用户名 第n位 异或
for (i=20; i<26; i++)
{
MsgText[i] = MsgText[i] ^ UserName[i];
}
MsgText[30] = '\0';
printf("解码完成:%s\n", MsgText);
}
上面是根据提供的字符串做的一个验证:
免费评分
查看全部评分