【文章标题】: ty123 Crackme 5的分析
【文章作者】: atomy
【作者主页】: http://2lin.net
--------------------------------------------------------------------------------
【详细过程】
首先感谢作者写出这么好的Creakme给我们这些小菜鸟们练手。
之前那个〈ty123的实用crackme- CPN Augur (新手飘过~~) 〉搞的偶晕头转向 确实不是新手练的。
先来分析一下代码吧。
新手拿到Crackme时可能不知道怎么下断点 如何找到代码 这个CrackMe代码比较小 可以手动查找
也可以输入命令 bp GetDlgItemTextA
有一处断点
004011C6 .- FF25 20204000 jmp [<&user32.GetDlgItemTextA>] ; user32.GetDlgItemTextA
其实
edi = 004011C6
004010CD > \83EF 08 sub edi, 8
004010D0 . FFD7 call edi ;
call edi 就是 call user32.GetDlgItemTextA 了
好了可以从这里根下去了
分析如下
004010CD > \83EF 08 sub edi, 8
004010D0 . FFD7 call edi ;
004010D2 . 85C0 test eax, eax
004010D4 . 0F84 92000000 je 0040116C
004010DA . C1E0 08 shl eax, 8 ; Count shl 8
004010DD . 66:3D 0020 cmp ax, 2000
004010E1 . 0F8F 85000000 jg 0040116C ; ax > 2000 跳走 注册码最大32位
004010E7 . 8D35 F9304000 lea esi, [4030F9] ; 输入序列号
004010ED . C1E8 08 shr eax, 8 ; EAX = 序列号个数
004010F0 . 91 xchg eax, ecx ; 放入 ECX 循环次数
004010F1 . 33C0 xor eax, eax
004010F3 . 33D2 xor edx, edx
004010F5 > AC lods byte ptr [esi]
004010F6 . 03D0 add edx, eax ; edx += eax 将序列号的 ascii 码相加
004010F8 .^ E2 FB loopd short 004010F5
004010FA . 3315 B4314000 xor edx, [4031B4] ; xor C:\序号 GetVolumeInformation
[4031B4] 哪里来的呢? 先在这个内存处下个硬件写断点
重新启动程序 发现 该内存 原来是用 GetVolumeInformation 获取 C:\ 的序号
00401100 . 52 push edx ; 保存 edx s
00401101 . 8D3D A6114000 lea edi, [4011A6]
00401107 . 68 2B314000 push 0040312B
0040110C . 68 80000000 push 80
00401111 . EB 05 jmp short 00401118
00401113 . 44 46 43 47 0>ascii "DFCG",0
00401118 > 83EF 04 sub edi, 4
0040111B . FFD7 call edi ; 获取当前目录
0040111D . 83E8 08 sub eax, 8 ; 目录值 - 8
00401120 . 8D90 2B314000 lea edx, [eax+40312B] ; 取当前目录的最后面8个字符
00401126 . 52 push edx
00401127 . E8 AC000000 call 004011D8 ; 将字符计算得到一个数字
0040112C . 5A pop edx
0040112D . 33C2 xor eax, edx ; 将值 xor s
0040112F 75 3B jnz short 0040116C ; 爆破点 s != 算出值 出错
这里不能单改成jz暴破需要动态修改 dx的值才行
再看看 00401127 . E8 AC000000 call 004011D8 是如何计算的
004011DE |. 8B7D 08 mov edi, [ebp+8] ; 后面八个字符
004011E1 |. 8B75 08 mov esi, [ebp+8]
004011E4 |> 8A07 /mov al, [edi]
004011E6 |. 47 |inc edi
004011E7 |. 0AC0 |or al, al
004011E9 |.^ 75 F9 \jnz short 004011E4 ; 有可能少于八个字符
004011EB |. 2BF7 sub esi, edi ; esi -= edi 取长度
004011ED |. 33DB xor ebx, ebx
004011EF |. 03FE add edi, esi ; edi += esi 还原edi重新指向字符串头
004011F1 |. 33D2 xor edx, edx
004011F3 |. F7D6 not esi ; not esi (esi 实际长度)
004011F5 |. EB 23 jmp short 0040121A
004011F7 |> 8A07 /mov al, [edi]
004011F9 |. 3C 41 |cmp al, 41 ; al < 41(A)
004011FB |. 72 0C |jb short 00401209
004011FD |. 2C 57 |sub al, 57 ; al - 57(W)
004011FF |. 80D2 00 |adc dl, 0
00401202 |. C0E2 05 |shl dl, 5
00401205 |. 02C2 |add al, dl ; al += dl(dl=0)
00401207 |. EB 02 |jmp short 0040120B
00401209 |> 2C 30 |sub al, 30
0040120B |> 8D4E FF |lea ecx, [esi-1]
0040120E |. 83E0 0F |and eax, 0F ; and 0F 取字节
00401211 |. C1E1 02 |shl ecx, 2
00401214 |. D3E0 |shl eax, cl
00401216 |. 03D8 |add ebx, eax
00401218 |. 47 |inc edi
00401219 |. 4E |dec esi
0040121A |> 0BF6 or esi, esi
0040121C |.^ 75 D9 \jnz short 004011F7
0040121E |. 8BC3 mov eax, ebx
--------------------------------------------------------------------------------
【经验总结】
其实一开始我以为放在什么文件夹下都可以。
如果按照我的想法的话 用户名输到天上去也不够
后来看到论坛上别的兄弟写出的注册机才发现
原来 Crackme输入的地方是用户名,而文件夹名称就是注册码了。
这才恍然大悟.原来可以这样变通的...
1.将输入序列号的ascii码相加 再xor磁盘序号 得到 D1
2.获取软件目录的后八位字符 s 算出一个数 D2
D1 != D2 序列号无效
以文件夹做注册码的话只要根据d2算出文件夹的名称就可以了
再看下获取软件目录的后八位字符 s 算出一个数 D2 的算法
写成passcal代码如下
function Calc(Value: string) : DWORD;
var
i,k : Integer;
p : DWORD;
begin
Result := 0;
for i := 1 to Length(Value) do
begin
if Value[i] < 'A' then
begin
p := Ord(Value[i]) - Ord('0');
end
else
begin
p := Ord(Value[i]) - Ord('W');
end;
k := Length(Value) - (i-1) - 1;
k := k shl 2;
p := p and $0F;
p := p shl k;
Result := Result + p;
end;
end;
这个算法其实就是把字符串转换成等量的数字
所以只要 把ascii码相加 再xor磁盘序号
得到的数值转换成字符就是注册码了
引用会员“yugung”的注册机代码如下
#include <stdio.h>
#include <string.h>
#include <windows.h>
int main(int argc, char* argv[])
{
char Name[33],SN[9]={0};
int NameLen;
long sum=0;
unsigned long CdiskVolSN;
printf("Input your Name:");
scanf("%s",Name);
NameLen=strlen(Name);
if(NameLen>32)
{
printf("\nName Tooooooo Long\n" );
return 1;
}
for(int i=0;i<NameLen;i++)
{
sum+=Name[i];
}
GetVolumeInformationA(
"c:\\",
0,0,
&CdiskVolSN,
0,0,0,0);
sum^=CdiskVolSN;
sprintf(SN,"%X",sum);
printf("\nIn order to Pass the check,\nChange your Dir Name to: %s",SN);
return 0;
}
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2007年02月05日 18:42:44
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课