[原创]一个Cracker代码分析及注册机编写,可以申请邀请码吗?
这个crack早在几年前就被CCDebuger的一篇文章提到过,不过他只是讲解了一些爆破的方法。今天刚好有空,捡起来分析了一下。如果有什么分析不对的地方还请大家指出。第一次发贴,希望可以起来抛砖引玉的效果。还请个位高手多多指点。先谢谢了!!
工具:OD+editplus+UltraEdit
1. 程序运行界面

2.用OD载入程序

3.程序是用汇编语言编写的,无壳。查壳的过程就省略了。查看当前模块中的名称后,可以在bp GetDlgItemTextA下断
4.F9运行程序,输入用户名和注册码后断下

断下后,注意右下角。Call GetDlgItemTextA到这一行,按回车键到反汇编窗口。到反汇编窗口后,往上翻,0040109C /$ C705 82214000>mov dword ptr ds:[0x402182],0xFEDCBA98
在这一行下断,ctrl+F2重新运行程序。记住这个参数,程序中的算法要用到这个参数的。

5.重新运行程序,输入用户名注册码后在上面我们下断的地方断下

看到这里大家应该很熟悉了,读出用户名和注册码返回字节数。按F8单步运行程序,注册堆栈窗口,找到用户名和注册码在内存中的位置。

可以很清楚的在内存区看到输入的注册码和用户名了,0x402182就是上面提到的那个数据,往下看,一会就会用到了。
004010D2 |. 0BC0 or eax,eax ;输入的用户名不能为空
004010D4 |. 74 49 je short cycle.0040111F
004010D6 |. B9 10000000 mov ecx,0x10
004010DB |. 2BC8 sub ecx,eax
004010DD |. BE 60214000 mov esi,cycle.00402160 ; ASCII "obaby"
004010E2 |. 8BFE mov edi,esi ; cycle.00401029
004010E4 |. 03F8 add edi,eax
004010E6 |. FC cld
004010E7 |. F3:A4 rep movs byte ptr es:[edi],byte ptr ds:[>
这几句其实就是把我们输入的用户名填充成一个16字节的用户名,如:我输入的是obaby,填充成16字节的用户名后为obabyobabyobabyo,就是用我们输入的用户名来填充空的字节,要求用户名为16位,这个跟后面算法有关系的,一会就可以看到了。

004010E9 |. 33C9 xor ecx,ecx
004010EB |. BE 71214000 mov esi,cycle.00402171 ; ASCII "0000000000000000"
004010F0 |> 41 /inc ecx
004010F1 |. AC |lods byte ptr ds:[esi]
004010F2 |. 0AC0 |or al,al
004010F4 |. 74 0A |je short cycle.00401100
004010F6 |. 3C 7E |cmp al,0x7E
004010F8 |. 7F 06 |jg short cycle.00401100
004010FA |. 3C 30 |cmp al,0x30
004010FC |. 72 02 |jb short cycle.00401100
004010FE |.^ EB F0 \jmp short cycle.004010F0
00401100 |> 83F9 11 cmp ecx,0x11 ;必须要为16个字节
00401103 |. 75 1A jnz short cycle.0040111F
接下来这几个是来检测注册码了,输入的字符秘须大于0x30小于0x7E,并且注册码要为16个字节,要不然直接跳到retn了。
6.接下来就是算法了,这个算法其实不难,但是挺麻烦的,如果不细心看的话,一会就转晕了。
00401105 |. E8 E7000000 call cycle.004011F1 ;第一个call运算
0040110A |. B9 01FF0000 mov ecx,0xFF01
0040110F |. 51 push ecx
00401110 |. E8 7B000000 call cycle.00401190 ;第二个call运算
00401115 |. 83F9 01 cmp ecx,0x1 ;经过上面的运行到这里ecx必须要等于1,如果不等于1就跳向注册失败了。
00401118 |. 74 06 je short cycle.00401120
0040111A |> E8 47000000 call cycle.00401166
0040111F |> C3 retn


这里只是一半,后面还有一半。这个算法其实就是把16位的用户名和16位的注册码分成二部分,每部分分别为8位,这二个call运行只用到了前8位,也就是说用户名的前8位和注册码的前8位经过上面运行后ecx必须要为1才行。

我们分别看这二个call.
004011F1 /$ A1 60214000 mov eax,dword ptr ds:[0x402160] ;用户名的前四位
004011F6 |. 8B1D 64214000 mov ebx,dword ptr ds:[0x402164] ;4-7位
004011FC |. 3305 71214000 xor eax,dword ptr ds:[0x402171] ;注册码的前四位
00401202 |. 331D 75214000 xor ebx,dword ptr ds:[0x402175] ;4-7位
00401208 |. 25 0F1F3F7F and eax,0x7F3F1F0F
0040120D |. 81E3 00010307 and ebx,0x7030100
这是第一个call传进来的数据,下面的运算都是围绕前8位的数据来打操作的。
接下来我们看看第二个call
004011DE |. FF05 82214000 |inc dword ptr ds:[0x402182]
注意这句,这里指向的数据就是0xFEDCBA98,开始我们说到的,这个数据是会变的,运算中会自加。这就是前8位运算的二个call了。不是很难,但是看着挺烦人的。
这二个call运算完了以后,ecx一定要等于1哦。
7.ecx==1后跳到下面运算,不是只用到了前8位嘛,现在开始运算后8位了。
00401120 |> \A1 68214000 mov eax,dword ptr ds:[0x402168]
00401125 |. 8B1D 6C214000 mov ebx,dword ptr ds:[0x40216C]
0040112B |. 33C3 xor eax,ebx
0040112D |. 3305 82214000 xor eax,dword ptr ds:[0x402182] ;前面提到的那个数据,前面会自加,在这里会进行异或运算
00401133 |. 0D 40404040 or eax,0x40404040
00401138 |. 25 77777777 and eax,0x77777777
0040113D |. 3305 79214000 xor eax,dword ptr ds:[0x402179]
00401143 |. 3305 7D214000 xor eax,dword ptr ds:[0x40217D]
00401149 |.^ 75 CF jnz short cycle.0040111A
0040114B |. E8 2B000000 call cycle.0040117B
00401150 \. C3 retn
如果ecx=1就跳到这了,看内存这里用到的就是用户名和注册码的后8位了。运算结束后ZF必须要为1,要不然就跳到注册错误了。

可以看到,ZF=1跳向正确,否则跳向错误。
下面是编写的注册机:
.386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include masm32.inc
includelib kernel32.lib
includelib user32.lib
includelib masm32.lib
crackcallA proto
crackcallB proto
crackcallC proto
crackcallD proto
.data
value dword 0fedcba98h
printname db 'input name: ',0
printpawd db 'input password: ',0
szFmt db 'Done!!!',0
username db 17 dup (0)
password db 17 dup (0)
.code
start:
invoke StdOut,addr printname
invoke StdIn,addr username,lengthof username
invoke StdOut,addr printpawd
invoke StdIn,addr password,lengthof password
xor ecx,ecx
lea esi,username
lea edi,username
usernameloop:
mov al,byte ptr [esi]
or al,al
jz usernamelab
inc ecx
inc esi
jmp usernameloop
usernamelab:
mov eax,10h
mov edx,ecx
sub eax,ecx
xchg eax,ecx
mov esi,edi
add edi,edx
cld
rep movs byte ptr es:[edi],byte ptr [esi]
xor ecx,ecx
lea esi,password
passwordloop:
inc ecx
mov al,byte ptr [esi]
or al,al
je passwordcount
inc esi
jmp passwordloop
passwordcount:
cmp ecx,011h
jnz over
call crackcallA
mov ecx,0ff01h
push ecx
call crackcallB
cmp ecx,1
je tab1
call crackcallC
tab1:
mov eax,dword ptr [username+8]
mov ebx,dword ptr [username+12]
xor eax,ebx
xor eax,dword ptr [value]
or eax,040404040h
and eax,077777777h
xor eax,dword ptr [password+8]
xor eax,dword ptr [password+12]
jz done
call crackcallD
done:
invoke StdOut,addr szFmt
over:
invoke ExitProcess,0
crackcallA proc
mov eax,dword ptr [username]
mov ebx,dword ptr [username+4]
xor eax,dword ptr [password]
xor ebx,dword ptr [password+4]
and eax,07f3f1f0fh
and ebx,07030100h
xor ecx,ecx
begin:
mov esi, eax
mov edi, ebx
shl esi, cl
shl edi, cl
and esi, 080808080h
and edi, 080808080h
mov edx, esi
shr dh, 7
shl dx, 7
shr edx, 8
shr dh, 7
shl dx, 7
shr edx, 8
shr dh, 7
shr dx, 1
mov esi, edx
mov edx, edi
shr dh, 7
shl dx, 7
shr edx, 8
shr dh, 7
shl dx, 7
shr edx, 8
shr dh, 7
shr dx, 5
mov edi, edx
xor edi, esi
mov edx, edi
and edx, 0FFh
push ecx
push edx
mov edx, 8
xchg eax, ecx
cmp eax, 3
jg lab1
mul dl
pop edx
add eax, 8
xchg eax, ecx
rol eax, cl
xor eax, edx
ror eax, cl
jmp lab2
lab1:
sub eax, 3
mul dl
pop edx
xchg eax, ecx
rol ebx, cl
xor ebx, edx
ror ebx, cl
lab2:
pop ecx
inc ecx
cmp ecx, 8
jnz begin
ret
crackcallA endp
crackcallB proc
pop edi
pop ecx
push edi
cmp ecx, 080h
jle done1
push ecx
mov esi, ecx
and ecx, 0FFh
mov edi, eax
cmp ecx, 8
jle lab1
mov edi, ebx
shr ecx, 4
lab1:
rol edi, 8
shr ecx, 1
jnz lab1
shr esi, 8
and edi, esi
and edi, 0FFh
pop ecx
lab3:
mov esi, 080h
lab4:
test esi, edi
je lab2
xor edi, esi
push edi
and ecx, 0FF00h
xchg esi, ecx
xor ch, cl
xor esi, ecx
xchg ecx, esi
push ecx
inc dword ptr [value]
call crackcallB
pop edi
jmp lab3
lab2:
shr esi, 1
jnz lab4
done1:
ret
crackcallB endp
crackcallC proc
xor ecx,ecx
tap0:
lea edi,password
mov al,byte ptr [edi]
inc al
mov byte ptr [edi],al
call crackcallA
mov ecx,0ff01h
push ecx
call crackcallB
;add esp,4
cmp ecx,1
je retncall
lea edi,password
mov al,byte ptr [edi]
;inc al
;mov byte ptr [edi],al
;mov al,byte ptr [edi]
cmp al,07eh
jle tap0
lea edi,password
mov byte ptr [edi],'0'
lea edi,password
mov al, byte ptr [edi+1]
inc al
mov byte ptr [edi+1],al
mov al,byte ptr [edi+1]
cmp al,07eh
jle tap0
lea edi,password
mov byte ptr [edi+1],'0'
lea edi,password
mov al, byte ptr [edi+2]
inc al
mov byte ptr [edi+2],al
mov al,byte ptr [edi+2]
cmp al,07eh
jle tap0
lea edi,password
mov byte ptr [edi+2],'0'
lea edi,password
mov al,byte ptr [edi+3]
inc al
mov byte ptr [edi+3],al
mov al,byte ptr [edi+3]
cmp al,07eh
jle tap0
lea edi,password
mov byte ptr [edi+3],'0'
lea edi,password
mov al,byte ptr [edi+4]
inc al
mov byte ptr [edi+4],al
mov al,byte ptr [edi+4]
cmp al,07eh
jle tap0
lea edi,password
mov byte ptr [edi+4],'0'
lea edi,password
mov al,byte ptr [edi+5]
inc al
mov byte ptr [edi+5],al
mov al,byte ptr [edi+5]
cmp al,07eh
jle tap0
lea edi,password
mov byte ptr [edi+5],'0'
lea edi,password
mov al,byte ptr [edi+6]
inc al
mov byte ptr [edi+6],al
mov al,byte ptr [edi+6]
cmp al,07eh
jle tap0
lea edi,password
mov byte ptr [edi+6],'0'
lea edi,password
mov al,byte ptr [edi+7]
inc al
mov byte ptr [edi+7],al
mov al,byte ptr [edi+7]
cmp al,07eh
jle tap0
retncall:
ret
crackcallC endp
crackcallD proc
tap0:
lea edi,password
mov al,byte ptr [edi+8]
inc al
mov byte ptr [edi+8],al
mov eax,dword ptr [username+8]
mov ebx,dword ptr [username+12]
xor eax,ebx
xor eax,dword ptr [value]
or eax,040404040h
and eax,077777777h
xor eax,dword ptr [password+8]
xor eax,dword ptr [password+12]
jz retncall
lea edi,password
mov al,byte ptr [edi+8]
cmp al,07eh
jle tap0
mov byte ptr [edi+8],'0'
lea edi,password
mov al,byte ptr [edi+9]
inc al
mov byte ptr [edi+9],al
cmp al,07eh
jle tap0
mov byte ptr [edi+9],'0'
lea edi,password
mov al,byte ptr [edi+0ah]
inc al
mov byte ptr [edi+0ah],al
cmp al,07eh
jle tap0
mov byte ptr [edi+0ah],'0'
lea edi,password
mov al,byte ptr [edi+0bh]
inc al
mov byte ptr [edi+0bh],al
cmp al,07eh
jle tap0
mov byte ptr [edi+0bh],'0'
lea edi,password
mov al,byte ptr [edi+0ch]
inc al
mov byte ptr [edi+0ch],al
cmp al,07eh
jle tap0
mov byte ptr [edi+0ch],'0'
lea edi,password
mov al,byte ptr [edi+0dh]
inc al
mov byte ptr [edi+0dh],al
cmp al,07eh
jle tap0
mov byte ptr [edi+0dh],'0'
lea edi,password
mov al,byte ptr [edi+0eh]
inc al
mov byte ptr [edi+0eh],al
cmp al,07eh
jle tap0
mov byte ptr [edi+0eh],'0'
lea edi,password
mov al,byte ptr [edi+0fh]
inc al
mov byte ptr [edi+0fh],al
cmp al,07eh
jle tap0
retncall:
ret
crackcallD endp
end start
注册机中有些算法是自已抄的原程序的,所以会看到很多眼熟的地方哦。
这是二组计算出来后正确的用户名和注册码:
obaby
19400000CQrC0000
obaby
;7422222VSpA3222

我在word上面排版好了的,怎么上来就这样了
,大家将就看看吧。图片不知道怎么没有了,我把图片打包上传附件了
