【文章标题】: 下内存写入断点,快速到达算法核心
【文章作者】: bxm
【作者邮箱】: bxm78@163.com
【保护方式】: name,serial
【编写语言】: Borland Delphi 4.0 - 5.0
【使用工具】: OD,peid
【操作平台】: winxp
【作者声明】: 只是感兴趣,失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
用peid查壳,无壳,收信足够信息,用OD载入,通过出错字符串“try again !”向上查找,在地址[00458816]处下断点,输入
name:bxm78
serial:780328051
断在下面:
00458816 |. E8 45FFFFFF call 00458760 ; (initial cpu selection)
0045881B |. 8D55 FC lea edx, [ebp-4]
0045881E |. 8B83 D0020000 mov eax, [ebx+2D0]
00458824 |. E8 97CDFCFF call 004255C0
00458829 |. 8B45 FC mov eax, [ebp-4] ; serial入EAX
0045882C |. E8 43EFFAFF call 00407774 ; serial计算部分
00458831 |. 3B05 44B84500 cmp eax, [45B844] ; 比较EAX与[45B844]处的值,我的[45B844]处的值为3760
00458837 |. 75 1B jnz short 00458854 ; 关键跳,爆破点
00458839 |. B8 88884500 mov eax, 00458888 ; you cracked the ubc crackme#1 ! please send your solution to ubcrackers@hotmail.com !
0045883E |. E8 29C1FEFF call 0044496C
00458843 |. BA E8884500 mov edx, 004588E8 ; cracked
00458848 |. A1 3CB84500 mov eax, [45B83C]
0045884D |. E8 9ECDFCFF call 004255F0
00458852 |. EB 0A jmp short 0045885E
00458854 |> B8 F8884500 mov eax, 004588F8 ; try again !
00458859 |. E8 0EC1FEFF call 0044496C
可以看出,地址[45B844]处的值很重要,那我们重新运行程序,在地址[45B844]处四个字节部分下内存写入断点,运行后,先断在地址[00458816]处,F9继续运行,断在地址[004587A4]处,然后删除内存断点
004587A4 |. 8903 mov [ebx], eax ; [ebx]清0
004587A6 |. 8B07 mov eax, [edi] ; name入EAX
004587A8 |. E8 B7B2FAFF call 00403A64 ; 算出name长度,返回值在EAX中
004587AD |. 85C0 test eax, eax
004587AF |. 7E 19 jle short 004587CA
004587B1 |. C706 01000000 mov dword ptr [esi], 1 ; [esi]处写入1
004587B7 |> 8B17 /mov edx, [edi] ; name运算
004587B9 |. 8B0E |mov ecx, [esi] ; ECX用于寻址
004587BB |. 0FB6540A FF |movzx edx, byte ptr [edx+ecx-1] ; name的每个字符依次进入EDX
004587C0 |. C1E2 03 |shl edx, 3 ; EDX左移3位
004587C3 |. 0113 |add [ebx], edx ; 累加于[EBX]
004587C5 |. FF06 |inc dword ptr [esi]
004587C7 |. 48 |dec eax ; EAX用于控制循环
004587C8 |.^ 75 ED \jnz short 004587B7 ; 没读完,继续循环
004587CA |> 8B07 mov eax, [edi]
004587CC |. E8 93B2FAFF call 00403A64 ; EAX为name长度
004587D1 |. C1E0 03 shl eax, 3 ; eax左移3位
004587D4 |. 0103 add [ebx], eax ; 累加于[ebx]
004587D6 |. 8B03 mov eax, [ebx] ; [EBX]入EAX
004587D8 |. C1E0 02 shl eax, 2 ; eax左移2位
004587DB |. 8903 mov [ebx], eax ; EAX中就是我们上一步看到的数据3760
一直按F8运行到地址[0045882C]处的serial计算部分,F7跟入:
00407774 /$ 55 push ebp
00407775 |. 8BEC mov ebp, esp
00407777 |. 83C4 F0 add esp, -10
0040777A |. 53 push ebx
0040777B |. 56 push esi
0040777C |. 33D2 xor edx, edx
0040777E |. 8955 F8 mov [ebp-8], edx
00407781 |. 8BD8 mov ebx, eax
00407783 |. 33C0 xor eax, eax
00407785 |. 55 push ebp
00407786 |. 68 DC774000 push 004077DC
0040778B |. 64:FF30 push dword ptr fs:[eax]
0040778E |. 64:8920 mov fs:[eax], esp
00407791 |. 8D55 FC lea edx, [ebp-4]
00407794 |. 8BC3 mov eax, ebx
00407796 |. E8 D9B1FFFF call 00402974 ; 关键call,计算假注册码部分
到[00407796]处继续F7跟入:
00402974 /$ 53 push ebx
00402975 |. 56 push esi
00402976 |. 57 push edi
00402977 |. 89C6 mov esi, eax
00402979 |. 50 push eax
0040297A |. 85C0 test eax, eax
0040297C |. 74 73 je short 004029F1
0040297E |. 31C0 xor eax, eax
00402980 |. 31DB xor ebx, ebx
00402982 |. BF CCCCCC0C mov edi, 0CCCCCCC
00402987 |> 8A1E /mov bl, [esi]
00402989 |. 46 |inc esi
0040298A |. 80FB 20 |cmp bl, 20 ; 删除serial前导空格
0040298D |.^ 74 F8 \je short 00402987
0040298F |. B5 00 mov ch, 0
00402991 |. 80FB 2D cmp bl, 2D ; Switch (cases 24..78)
00402994 |. 74 69 je short 004029FF ; 检查serial有无非法字符
00402996 |. 80FB 2B cmp bl, 2B
00402999 |. 74 66 je short 00402A01
0040299B |. 80FB 24 cmp bl, 24
0040299E |. 74 66 je short 00402A06
004029A0 |. 80FB 78 cmp bl, 78
004029A3 |. 74 61 je short 00402A06
004029A5 |. 80FB 58 cmp bl, 58
004029A8 |. 74 5C je short 00402A06
004029AA |. 80FB 30 cmp bl, 30
004029AD |. 75 13 jnz short 004029C2
004029AF |. 8A1E mov bl, [esi] ; Case 30 ('0') of switch 00402991
004029B1 |. 46 inc esi
004029B2 |. 80FB 78 cmp bl, 78
004029B5 |. 74 4F je short 00402A06
004029B7 |. 80FB 58 cmp bl, 58
004029BA |. 74 4A je short 00402A06
004029BC |. 84DB test bl, bl
004029BE |. 74 20 je short 004029E0
004029C0 |. EB 04 jmp short 004029C6
004029C2 |> 84DB test bl, bl ; Default case of switch 00402991
004029C4 |. 74 34 je short 004029FA
004029C6 |> 80EB 30 /sub bl, 30 ; bl-30
004029C9 |. 80FB 09 |cmp bl, 9 ; bl>9 ?
004029CC |. 77 2C |ja short 004029FA ; 是,跳出
004029CE |. 39F8 |cmp eax, edi ; EAX>0CCCCCCC ?
004029D0 |. 77 28 |ja short 004029FA ; 是,跳出
004029D2 |. 8D0480 |lea eax, [eax+eax*4] ; EAX*5
004029D5 |. 01C0 |add eax, eax ; EAX*2
004029D7 |. 01D8 |add eax, ebx ; 累加于EBX
004029D9 |. 8A1E |mov bl, [esi] ; 循环读入serial中的每个字符
004029DB |. 46 |inc esi
004029DC |. 84DB |test bl, bl ; 读完没?
004029DE |.^ 75 E6 \jnz short 004029C6 ; 没有,继续读
最终计算结果放入EAX中返回,我的为2E82DC73,这个值就是要和name计算值相比较的。通过分析不难发现,serial计算部分就是把十进制的字符串转换成十六进制数,反过来说,只要我们把name计算结果转换成十进制数即成serial.
算法小结:
1、name的每个字符左移3位并累加,结果记为A。
2、name长度左移3位并与A相加,结果记为B。
3、把B左移2位,然后转换成十进制即成注册码。
附注册机源码:
#include<string.h>
main()
{
char name[64];
unsigned long serial;
int i,len,temp;
scanf("%s",&name);
len=strlen(name);
serial=0;
for(i=0;i<len;i++)
{
serial+=(unsigned long)name[i]<<3;
}
serial+=len<<3;
serial<<=2;
if(serial>0x0ccccccc)return;
printf("%u",serial);
}
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2006年07月15日 下午 10:28:07
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!