└文章标题┐:eKH-CrackMe算法分析
└破文作者┐:-=>大菜一号<=-
└破解对象┐:CrackMe(附件)
└下载地址┐:附件
└对象大小┐:193k
└加壳方式┐:没有耶
└保护方式┐:普通算法
└编写语言┐:Delphi
└使用工具┐:OD
└破解平台┐:D版XP
└破解声明┐:无话可说!!!!!!!!
----------------------------------------------------------------------------------
└破解过程┐:
呃~~~这个CrackMe偶也是从附件上下载下来滴!不过破解者并没有分析算法,所以偶就拿来试试咧!
找字符串,很容易断下了:
"Wrong Serial number!"
00427B99 |. E8 82FEFFFF call 00427A20
00427B9E |. 3D 4E61BC00 cmp eax, 0BC614E
00427BA3 |. 7D 1E jge short 00427BC3
00427BA5 |> 6A 00 push 0
00427BA7 |. 68 087C4200 push 00427C08 ; error
00427BAC |. 68 107C4200 push 00427C10 ; wrong serial number !
向上看,00427b99处,一个call,一个cmp,一个jge可以跳过错误信息的跳转,呵,经典..
断在00427b99处了!
F7跟进去,来到这里:
00427A20 /$ 55 push ebp
00427A21 |. 8BEC mov ebp, esp
00427A23 |. 83C4 F0 add esp, -10
00427A26 |. 53 push ebx
00427A27 |. 56 push esi
00427A28 |. 33C9 xor ecx, ecx
00427A2A |. 894D F0 mov dword ptr [ebp-10], ecx
00427A2D |. 894D F4 mov dword ptr [ebp-C], ecx
00427A30 |. 8955 F8 mov dword ptr [ebp-8], edx
00427A33 |. 8945 FC mov dword ptr [ebp-4], eax
00427A36 |. 8B45 FC mov eax, dword ptr [ebp-4]
00427A39 |. E8 26BFFDFF call 00403964
00427A3E |. 8B45 F8 mov eax, dword ptr [ebp-8]
00427A41 |. E8 1EBFFDFF call 00403964
00427A46 |. 33C0 xor eax, eax
00427A48 |. 55 push ebp
00427A49 |. 68 2A7B4200 push 00427B2A
00427A4E |. 64:FF30 push dword ptr fs:[eax]
00427A51 |. 64:8920 mov dword ptr fs:[eax], esp
00427A54 |. 33DB xor ebx, ebx
00427A56 |. 8B45 FC mov eax, dword ptr [ebp-4]
00427A59 |. E8 52BDFDFF call 004037B0 ; 取name长度
00427A5E |. 8BF0 mov esi, eax
00427A60 |. 85F6 test esi, esi
00427A62 |. 7E 3C jle short 00427AA0 ; name长度为空就出错
00427A64 |. B8 01000000 mov eax, 1
00427A69 |> 8BD0 /mov edx, eax
00427A6B |. 8B4D FC |mov ecx, dword ptr [ebp-4] ; name传到ecx
00427A6E |. 0FB64C11 FF |movzx ecx, byte ptr [ecx+edx-1] ; 取name字符
00427A73 |. 03D9 |add ebx, ecx ; 累加上上一次循环结果
00427A75 |. 71 05 |jno short 00427A7C
00427A77 |. E8 B4AFFDFF |call 00402A30
00427A7C |> C1E3 08 |shl ebx, 8 ; 累加结果左移8位
00427A7F |. 8B0D 80884200 |mov ecx, dword ptr [428880] ; 字符串a("LANNYDIBANDINGINANAKEKHYANGNGENTOT")传到ecx
00427A85 |. 0FB65411 FF |movzx edx, byte ptr [ecx+edx-1] ; 每次循环取字符串a的字符
00427A8A |. 0BDA |or ebx, edx ; 每次循环取出的字符串a的字符与左移后的结果做“或”运算
00427A8C |. 85DB |test ebx, ebx
00427A8E |. 7D 0C |jge short 00427A9C ; 结果是否大于0
00427A90 |. 6BD3 FF |imul edx, ebx, -1 ; 结果小于0则*-1
00427A93 |. 71 05 |jno short 00427A9A
00427A95 |. E8 96AFFDFF |call 00402A30
00427A9A |> 8BDA |mov ebx, edx
00427A9C |> 40 |inc eax ; eax+1
00427A9D |. 4E |dec esi ; 计数减一
00427A9E |.^ 75 C9 \jnz short 00427A69 ; 没算法跳上去
00427AA0 |> 81F3 78563412 xor ebx, 12345678 ; 循环结果与0x12345678异或
00427AA6 |. 8D55 F0 lea edx, dword ptr [ebp-10]
00427AA9 |. 8BC3 mov eax, ebx
00427AAB |. E8 44E9FDFF call 004063F4 ; 把最后结果转换成十进制并格式化为字符串->
00427AB0 |. 8B45 F0 mov eax, dword ptr [ebp-10] ; 结果字符串到eax
00427AB3 |. E8 F8BCFDFF call 004037B0 ; 取结果字符串长度
00427AB8 |. 8BF0 mov esi, eax ; 长度到esi
00427ABA |. 85F6 test esi, esi
00427ABC |. 7E 38 jle short 00427AF6 ; 长度为空就出错
00427ABE |> 8BC3 /mov eax, ebx
00427AC0 |. B9 0A000000 |mov ecx, 0A ; 0xa传到ecx
00427AC5 |. 99 |cdq ; 双字扩展
00427AC6 |. F7F9 |idiv ecx ; 这个循环共用了两个idiv,这个主要是取余->取余到edx;
00427AC8 |. 6215 3C7B4200 |bound edx, qword ptr [427B3C]
00427ACE |. 8A92 84884200 |mov dl, byte ptr [edx+428884] ; 根据余数从"LANNY5646521"里取相应的字符
00427AD4 |. 8D45 F0 |lea eax, dword ptr [ebp-10]
00427AD7 |. E8 FCBBFDFF |call 004036D8
00427ADC |. 8B55 F0 |mov edx, dword ptr [ebp-10]
00427ADF |. 8D45 F4 |lea eax, dword ptr [ebp-C]
00427AE2 |. E8 D1BCFDFF |call 004037B8
00427AE7 |. 8BC3 |mov eax, ebx
00427AE9 |. B9 0A000000 |mov ecx, 0A ; 0xa到ecx
00427AEE |. 99 |cdq ; 双字扩展(根据上一次循环idiv的商的符号填充edx)
00427AEF |. F7F9 |idiv ecx ; 有符号除
00427AF1 |. 8BD8 |mov ebx, eax ; 商传到ebx
00427AF3 |. 4E |dec esi ; 计数器减一
00427AF4 |.^ 75 C8 \jnz short 00427ABE
00427AF6 |> 8B45 F4 mov eax, dword ptr [ebp-C] ;ebp-c里是真码
00427AF9 |. 8B55 F8 mov edx, dword ptr [ebp-8] ;ebp-8里是假码
00427AFC |. E8 BFBDFDFF call 004038C0 ;对比的call,里面跳转太多,偶就不跟了!有兴趣可以进去看一下
00427B01 |. 75 07 jnz short 00427B0A ;对比的call出来后,这里如果跳就错了
00427B03 |. BB 4E61BC00 mov ebx, 0BC614E ;把0xbc614e传到ebx->0xbc614e是个注册成功的标记,算法call出去以后,会根据这个判断是否注册成功,当然,上面跳了之后这个标记就不在ebx里了,所以要爆破的话把427b01处的jnz,nop掉或改为je就行,当然也可以手动给ebx赋一个0x0bc614e
00427B08 |. EB 05 jmp short 00427B0F
00427B0A |> BB 91D61200 mov ebx, 12D691
00427B0F |> 33C0 xor eax, eax
00427B11 |. 5A pop edx
00427B12 |. 59 pop ecx
00427B13 |. 59 pop ecx
00427B14 |. 64:8910 mov dword ptr fs:[eax], edx
00427B17 |. 68 317B4200 push 00427B31
00427B1C |> 8D45 F0 lea eax, dword ptr [ebp-10]
00427B1F |. BA 04000000 mov edx, 4
00427B24 |. E8 2FBAFDFF call 00403558
00427B29 \. C3 retn
算法call出来就到这:
00427B99 |. E8 82FEFFFF call 00427A20 ;算法call
00427B9E |. 3D 4E61BC00 cmp eax, 0BC614E ;这里就判断eax地址里的内容是否为0xbc614e
00427BA3 |. 7D 1E jge short 00427BC3 ;爆破点
00427BA5 |> 6A 00 push 0
00427BA7 |. 68 087C4200 push 00427C08 ; error
00427BAC |. 68 107C4200 push 00427C10 ; wrong serial number !
00427BB1 |. A1 44974200 mov eax, dword ptr [429744]
00427BB6 |. E8 411EFFFF call 004199FC
00427BBB |. 50 push eax ; |hOwner
00427BBC |. E8 4FD9FDFF call <jmp.&user32.MessageBoxA> ; \MessageBoxA
00427BC1 |. EB 1C jmp short 00427BDF
00427BC3 |> 6A 00 push 0
00427BC5 |. 68 287C4200 push 00427C28 ; success
00427BCA |. 68 307C4200 push 00427C30 ; congratulation ! you've did it.\nmail us : ekhmail@egroups.com
算法总结:
1、依次取name字符循环,累加(加上上次的循环结果),也依次"LANNYDIBANDINGINANAKEKHYANGNGENTOT"
里取出与循环计数器相应位置的字符,将其与累加后的结果相"或",或后的结果如果小于0,结果就乘以-1!大于0啥也不做;
然后,把最后的结果转换成十进制并格式化成新的字符串;
2、根据新的字符串长度开始循环,将上面循环的结果(十六进制整数)先与0xA取余,根据余数从"LANNY5646521"里取相应的字符,再用上面循环结果除以0xA,得出商(向后面几次循环提供取余的被除数)
之后得出的字符串就是注册码了;
下面是c++的注册机:
#include <iostream.h>
#include <stdio.h>
#include <string.h>
#include <windows.h>
void main()
{
char name[100],lscode[100];
char lpChar1[]="LANNYDIBANDINGINANAKEKHYANGNGENTOT",
lpChar2[]="LANNY5646521";
int i,yu,len;
unsigned long ls1=0,ls2=0;
cout<<"Your name:";
cin>>name;
len=strlen(name);
for(i=0;i<len;i++)
{
ls1=ls1+name[i];
ls2=ls1<<8;
ls1=abs(ls2 | lpChar1[i]);
}
ls1^=0x12345678;
len=sprintf(lscode,"%i",ls1);
for(i=0;i<len;i++)
{
yu=ls1 % 0xA;
name[i]=lpChar2[yu];
ls1/=0xA;
}
name[i]='\0';
cout<<"Your code:"<<name<<endl;
}
很简单,不加注释了!
----------------------------------------------------------------------------------
└经验总结┐:
这个CrackMe难度不高,适合新手!
呵呵,其实注册码就在"LANNY5646521"这串里面!!
----------------------------------------------------------------------------------
└版权声明┐ 本文原创于看雪软件安全论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年4月7日 11:59:5
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)