【文章标题】: Adler32CrackMe破文
【文章作者】: dttom
【作者邮箱】: dttom2006@126.com
【下载地址】: http://bbs.pediy.com/attachment.php?attachmentid=6637&d=1183881215
【保护方式】: 无
【使用工具】: ollydbg,IDA,peid
【软件介绍】: adler32算法的crackme
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
春节在家休息没事,看了看windrand发布密码学系列crackme,看了一下只有crc32的破文,出于兴趣我也来试试adler32算法crackme的破解。首先在网
上查了一下adler32算法,查到RFC1950文档有adler32算法,大概看了一下C代码,下面开始查看crackMe程序。
peid 检查为delphi编译,ollydbg打开F9,输入用户名,注册码,bp GetDlgItemTextA 下断,下面见代码:
.....
0040886E > \68 FF000000 push 0FF ; /Count = FF (255.); Case 3EA of switch 00408854
00408873 . 68 AC924000 push 004092AC ; |Buffer = Adler32C.004092AC
00408878 . 68 F2030000 push 3F2 ; |ControlID = 3F2 (1010.)
0040887D . 8B45 08 mov eax, dword ptr [ebp+8] ; |
00408880 . 50 push eax ; |hWnd
00408881 . E8 B6BEFFFF call <jmp.&user32.GetDlgItemTextA> ; \GetDlgItemTextA 下断后在这个函数里,即在系统函数领空
00408886 . 8D45 B4 lea eax, dword ptr [ebp-4C] ; Alt+F9来到这里
00408889 . BA AC924000 mov edx, 004092AC ; ASCII "dttom"
0040888E . B9 FF000000 mov ecx, 0FF
00408893 . E8 C0AFFFFF call 00403858
00408898 . 837D B4 00 cmp dword ptr [ebp-4C], 0
0040889C . 75 1C jnz short 004088BA
0040889E . 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004088A0 . 68 DC8A4000 push 00408ADC ; |Title = ""D7,"",A2,"",B2,"崽崾?
004088A5 . 68 E88A4000 push 00408AE8 ; |Text = "用",BB,"?,B2,"",BB,"能为空请输入?,A1,""
004088AA . 8B45 08 mov eax, dword ptr [ebp+8] ; |
004088AD . 50 push eax ; |hOwner
004088AE . E8 C1BEFFFF call <jmp.&user32.MessageBoxA> ; \MessageBoxA
004088B3 . 33DB xor ebx, ebx
004088B5 . E9 A2010000 jmp 00408A5C
004088BA > 68 FF000000 push 0FF ; /Count = FF (255.)
004088BF . 68 AC934000 push 004093AC ; |Buffer = Adler32C.004093AC
004088C4 . 68 F3030000 push 3F3 ; |ControlID = 3F3 (1011.)
004088C9 . 8B45 08 mov eax, dword ptr [ebp+8] ; |
004088CC . 50 push eax ; |hWnd
004088CD . E8 6ABEFFFF call <jmp.&user32.GetDlgItemTextA> ; \GetDlgItemTextA
004088D2 . 8D45 B0 lea eax, dword ptr [ebp-50]
004088D5 . BA AC934000 mov edx, 004093AC ; ASCII "55556666"
004088DA . B9 FF000000 mov ecx, 0FF
004088DF . E8 74AFFFFF call 00403858 ; 计算假注册码长度
004088E4 . 837D B0 00 cmp dword ptr [ebp-50], 0 ; 检测假注册码是否为空
004088E8 . 75 1C jnz short 00408906
004088EA . 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
004088EC . 68 DC8A4000 push 00408ADC ; |Title = ""D7,"",A2,"",B2,"崽崾?
004088F1 . 68 008B4000 push 00408B00 ; |Text = ""D7,"",A2,"",B2,"崧?,B2,"",BB,"能为空请输入?,A1,""
004088F6 . 8B45 08 mov eax, dword ptr [ebp+8] ; |
004088F9 . 50 push eax ; |hOwner
004088FA . E8 75BEFFFF call <jmp.&user32.MessageBoxA> ; \MessageBoxA
004088FF . 33DB xor ebx, ebx
00408901 . E9 56010000 jmp 00408A5C
00408906 > 33C0 xor eax, eax
00408908 . 55 push ebp
00408909 . 68 88894000 push 00408988
0040890E . 64:FF30 push dword ptr fs:[eax]
00408911 . 64:8920 mov dword ptr fs:[eax], esp
00408914 . 8D45 A8 lea eax, dword ptr [ebp-58]
00408917 . BA AC924000 mov edx, 004092AC ; ASCII "dttom"
0040891C . B9 FF000000 mov ecx, 0FF
00408921 . E8 32AFFFFF call 00403858
00408926 . 8B45 A8 mov eax, dword ptr [ebp-58]
00408929 . 8D55 AC lea edx, dword ptr [ebp-54]
0040892C . E8 EBFCFFFF call 0040861C ; F8后出现注册码,我们用F7跟进分析之
00408931 . 8B45 AC mov eax, dword ptr [ebp-54]
00408934 . 50 push eax
00408935 . 8D45 A4 lea eax, dword ptr [ebp-5C]
00408938 . BA AC934000 mov edx, 004093AC ; ASCII "55556666"
0040893D . B9 FF000000 mov ecx, 0FF
00408942 . E8 11AFFFFF call 00403858
00408947 . 8B55 A4 mov edx, dword ptr [ebp-5C]
0040894A . 58 pop eax
0040894B . E8 80B0FFFF call 004039D0 ; 真假注册码比较函数
00408950 . 75 17 jnz short 00408969
00408952 . 6A 40 push 40 ; /Style = MB_OK|MB_ICONASTERISK|MB_APPLMODAL
00408954 . 68 DC8A4000 push 00408ADC ; |Title = ""D7,"",A2,"",B2,"崽崾?
00408959 . 68 188B4000 push 00408B18 ; |Text = "恭?,B2,"您?,AC,"",D7,"",A2,"",B2,"崧胝",B7,"?,A1,""
0040895E . 8B45 08 mov eax, dword ptr [ebp+8] ; |
00408961 . 50 push eax ; |hOwner
00408962 . E8 0DBEFFFF call <jmp.&user32.MessageBoxA> ; \MessageBoxA
......
F7跟进40892C后,来到下面一段,下面要过两次子函数调用,省略了一些准备过程代码见下面的代码:
......
0040869A . 8BD3 mov edx, ebx
0040869C . E8 03FBFFFF call 004081A4 ; 注册算法子函数,F7跟进
004086A1 . 8B55 F8 mov edx, dword ptr [ebp-8]
004086A4 . 8B45 F4 mov eax, dword ptr [ebp-C]
004086A7 . E8 8CCEFFFF call 00405538 ; 对真注册码进行检查计算F7跟进(见最下面)
004086AC . 8BD6 mov edx, esi
......
004081C0 |. 8BCE mov ecx, esi
004081C2 |. 8BD3 mov edx, ebx
004081C4 |. E8 23FFFFFF call 004080EC ; 第二个子函数F7跟进
......
00408114 |. 8BC7 mov eax, edi
00408116 |. E8 F9FEFFFF call 00408014 ; Adler32算法核心 F7跟进
........
00408014 /$ 53 PUSH EBX
00408015 |. 56 PUSH ESI
00408016 |. 50 PUSH EAX
00408017 |. 31DB XOR EBX,EBX ;置s2=0;
00408019 |. 66:8B58 02 MOV BX,WORD PTR DS:[EAX+2]
0040801D |. 8120 FFFF0000 AND DWORD PTR DS:[EAX],0FFFF ;adler & 0xffff;
00408023 |. 8B00 MOV EAX,DWORD PTR DS:[EAX] ;置adler初值1,s1中间结果存在EAX
00408025 |. 89D6 MOV ESI,EDX
00408027 |. 09C9 OR ECX,ECX
00408029 |. 74 25 JE SHORT Adler32C.00408050
0040802B |> 0FB616 /MOVZX EDX,BYTE PTR DS:[ESI]
0040802E |. 01D0 |ADD EAX,EDX
00408030 |. 3D F1FF0000 |CMP EAX,0FFF1 ;65521=0x0fff1
00408035 |. 7C 05 |JL SHORT Adler32C.0040803C
00408037 |. 2D F1FF0000 |SUB EAX,0FFF1
0040803C |> 01C3 |ADD EBX,EAX
0040803E |. 81FB F1FF0000 |CMP EBX,0FFF1
00408044 |. 7C 06 |JL SHORT Adler32C.0040804C
00408046 |. 81EB F1FF0000 |SUB EBX,0FFF1
0040804C |> 46 |INC ESI
0040804D |. 49 |DEC ECX
0040804E |.^ 75 DB \JNZ SHORT Adler32C.0040802B
00408050 |> C1E3 10 SHL EBX,10 ;(s2 << 16)
00408053 |. 01C3 ADD EBX,EAX ;+ s1
00408055 |. 58 POP EAX
00408056 |. 8918 MOV DWORD PTR DS:[EAX],EBX
00408058 |. 5E POP ESI
00408059 |. 5B POP EBX
0040805A \. C3 RETN
......
00405538 /$ 53 push ebx
00405539 |. 56 push esi
0040553A |. 57 push edi
0040553B |. 8BFA mov edi, edx
0040553D |. 8BF0 mov esi, eax
0040553F |. 8BC6 mov eax, esi
00405541 |. E8 3EE3FFFF call 00403884 ; 计算真注册码长度
00405546 |. 8BD8 mov ebx, eax
00405548 |. 8BC7 mov eax, edi
0040554A |. 8BD3 mov edx, ebx
0040554C |. E8 7FE5FFFF call 00403AD0
00405551 |. 8BD6 mov edx, esi
00405553 |. 8B37 mov esi, dword ptr [edi]
00405555 |. 85DB test ebx, ebx
00405557 |. 74 15 je short 0040556E
00405559 |> 8A02 /mov al, byte ptr [edx] ; 比较注册码每个字节,若大于0x61小于0x7A,则减0x20
0040555B |. 3C 61 |cmp al, 61
0040555D |. 72 06 |jb short 00405565
0040555F |. 3C 7A |cmp al, 7A
00405561 |. 77 02 |ja short 00405565
00405563 |. 2C 20 |sub al, 20
00405565 |> 8806 |mov byte ptr [esi], al
00405567 |. 42 |inc edx
00405568 |. 46 |inc esi
00405569 |. 4B |dec ebx
0040556A |. 85DB |test ebx, ebx
0040556C |.^ 75 EB \jnz short 00405559
0040556E |> 5F pop edi
0040556F |. 5E pop esi
00405570 |. 5B pop ebx
00405571 \. C3 retn
.....
核心算法汇编代码大概对应如下的C代码:
#define BASE 65521
unsigned long update_adler32(unsigned long adler,
unsigned char *buf, int len)
{
unsigned long s1 = adler & 0xffff;
unsigned long s2 = (adler >> 16) & 0xffff;
int n;
for (n = 0; n < len; n++) {
s1 = (s1 + buf[n]) % BASE;
s2 = (s2 + s1) % BASE;
}
return (s2 << 16) + s1;
}
注册算法分析出来,下面写出注册代码,这一块我的基础比较差,写的不完善,算是抛砖引玉吧
#include <stdio.h>
#include <string>
#define BASE 65521 /* largest prime smaller than 65536 */
unsigned long update_adler32(unsigned long adler,unsigned char *buf, int len)
{
unsigned long s1 = adler & 0xffff;
unsigned long s2 = (adler >> 16) & 0xffff;
int n;
for (n = 0; n < len; n++) {
s1 = (s1 + buf[n]) % BASE;
s2 = (s2 + s1) % BASE;
}
return (s2 << 16) + s1;
}
unsigned long adler32(unsigned char *buf, int len)
{
return update_adler32(1L, buf, len);
}
void main()
{
unsigned long Tmp=0;
int len;
unsigned char *str;
str = (unsigned char *) malloc(512);
printf("请输入用户名:");
scanf("%s",str);
len=strlen((const char*)str);
Tmp=adler32(str,len);
printf("\n注册码:%p \n",Tmp);
}
--------------------------------------------------------------------------------
【经验总结】
最好先了解算法原理,再跟踪,这样难度就小多了。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2008年02月21日 下午 01:51:01
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)