这东东都作了半年了,一直没写文章,这次是帮朋友分析才写的,朋友说还算可以,所以才有脸往上放:)
这是某软件后半部分的注册码的实现过程,变脸王的作者注册码后半部分只用了DES一种算法!而且是标准DES,无任何变化:)脱壳后运行变脸王(不脱壳无法bpx
MessageBoxa),断点设在MessageBoxa上,设置两次鼠标主题就可以断下
了,显示"确定使用...?",继续往下走,到这里:
* Possible StringData Ref from Data Obj ->"holer@21cn.com"
|
:004CCF4A BAC4D44C00
mov edx, 004CD4C4
:004CCF4F 8B45F4
mov eax, dword ptr [ebp-0C]
:004CCF52 E84964FFFF
call 004C33A0
//那么这里就是逆推注册码的过程了
:004CCF57 8B55CC
mov edx, dword ptr [ebp-34]
:004CCF5A 8B45F8
mov eax, dword ptr [ebp-08]
:004CCF5D E82671F3FF
call 00404088
//这里是用来将逆推后的注册码
:004CCF62 7447
je 004CCFAB
//与输入的名字作比较
:004CCF64 6A40
push 00000040
跟进4C33A0:
一直到4C342E是将输入的码的后半部分转成数字的部分,然后:
:004C3430 8B55F8
mov edx, dword ptr [ebp-08]
:004C3433 8B45F4
mov eax, dword ptr [ebp-0C]
:004C3436 E8E1FCFFFF
call 004C311C
//这里跟进去研究研究
还有:
:004C3450 E8C708F4FF
call 00403D1C
//这里也要进去逛逛
:004C3455 C3
ret
进入4C311C后会发现他取"holer@21cn.com"前8位"holer@21"用来做密钥,后面要有耐心,如想看出算法就要跟进去好几层
才可以,从这里进去:
:004C319F E848FBFFFF
call 004C2CEC
进去走到这里,再进:
:004C2D11 E846FEFFFF
call 004C2B5C
然后这里,我们可以发现一些有趣的数据:)
:004C2B81
BA07000000 mov edx, 00000007
:004C2B86 E8B100F4FF call 00402C3C
:004C2B8B 33D2
xor edx, edx //设edx为i;
:004C2B8D
B800874F00 mov eax, 004F8700
//这里我们得到这样一组16进制数据
/*PC1="0x38,0x30,0x28,0x20,0x18,0x10,0x08,
0x00,0x39,0x31,0x29,0x21,0x19,0x11,
0x09,0x01,0x3A,0x32,0x2A,0x22,0x1A, 0x12,0x0A,0x02,0x3B,0x33,0x2B,0x23,
0x3E,0x36,0x2E,0x26,0x1E,0x16,0x0E,
0x06,0x3D,0x35,0x2D,0x25,0x1D,0x15,
0x0D,0x05,0x3C,0x34,0x2C,0x24,0x1C,
0x14,0x0C,0x04,0x1B,0x13,0x0B,0x03";
*///将每个数字都加上1后再一看就可以想到是DES密钥的置换子密钥的参数,有点感觉了,那就继续往下看
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004C2BE3(C)
|
:004C2B92 8A18
mov bl, byte ptr [eax] //设eax为指向这个数组的指针*p
:004C2B94 8BCB
mov ecx, ebx //temp=*p
:004C2B96
80E107 and cl, 07
//以下的操作实质是bit级的操作,较为微观:)
:004C2B99 81E1FF000000
and ecx, 000000FF
:004C2B9F 51
push ecx
//push temp&0x7
:004C2BA0 B907000000
mov ecx, 00000007 //temp&0x7和temp
mod 8
:004C2BA5 5E
pop esi //效果一样:)
:004C2BA6 2BCE
sub ecx, esi //7-temp&0x7
* Possible Reference to String Resource ID=00001: "http://www.hd1860.com"
|
:004C2BA8 BE01000000
mov esi, 00000001
:004C2BAD
D3E6 shl
esi, cl //需要将0x00000001向左移(7-temp&7)位
:004C2BAF 33C9
xor ecx, ecx //
:004C2BB1 8ACB
mov cl, bl
//temp=*p
:004C2BB3 C1E903
shr ecx, 03
//我们知道向右移位相当于除法,这里是整除以8
:004C2BB6 8B5DFC
mov ebx, dword ptr [ebp-04] //这里是"holer@21"
:004C2BB9 0FB60C0B
movzx ecx, byte ptr [ebx+ecx] //得到第(*p)bit的值
:004C2BBD
23F1 and
esi, ecx //用来判断第(*p)bit
的值是否为0
:004C2BBF 741D
je 004C2BDE //如果是0就不用操作了
:004C2BC1 8BCA
mov ecx, edx //不为0就将第i位置1
:004C2BC3
83E107 and ecx,
00000007
:004C2BC6 51
push ecx
:004C2BC7 B907000000
mov ecx, 00000007
:004C2BCC 5B
pop ebx
:004C2BCD 2BCB
sub ecx, ebx
:004C2BCF B301
mov bl, 01
:004C2BD1 D2E3
shl bl, cl
:004C2BD3 8BCA
mov ecx, edx
:004C2BD5 C1E903
shr ecx, 03
:004C2BD8
8B75F8 mov esi,
dword ptr [ebp-08] //
:004C2BDB 081C0E
or byte ptr [esi+ecx], bl
//第i位置一!
* Referenced by a (U)nconditional or (C)onditional
Jump at Address:
|:004C2BBF(C)
|
:004C2BDE 42
inc edx
//i++;hoho
:004C2BDF 40
inc eax
:004C2BE0 83FA38
cmp edx, 00000038 //计数器为56就停止工作
:004C2BE3
75AD jne
004C2B92
/*作者是这样来查表的,假设字符串"12345678",2进制表示"0011 0001......",相当于2进制数组a[8][8],要判断第i位是否为0,那就
先取第i/8组,a[i/8][?],然后再来取这个'?'的值,?就是i mod 8了,也可以用i & 0x7实现,判断的时候,先取得a[i/8]这8bit数据,然后将
0x1左移i&0x7bit,就可以通过和a[i/8]的这8bit数据的第i&0x7位相与来判断是否为0,可能有的人一看就明白,不过我一开始弄的挺迷糊
,sigh....所以说明一下
*/
上面这一部分看懂那么下面那些置换也能轻松pass了,出来之后来到这里:
:004C2D16
8A06 mov
al, byte ptr [esi]
;
..... //这一部分是将置换后得到的56bit密钥分成2部分,一部分28bit
;
:004C2D70 BF10000000
mov edi, 00000010
:004C2D75 BB68874F00
mov ebx, 004F8768 //这里d一下看看,
//turnit[]="0x1,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x1,0x2,0x2,0x2,0x2,0x2,0x2,0x1"
//正好是DES的子密钥产生过程需要的每轮旋转数
:004C2D7A 8B75FC
mov esi, dword ptr [ebp-04]
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004C2E06(C)
|
:004C2D7D 8D45F1
lea eax, dword ptr [ebp-0F] //把前28bit转一转:)
:004C2D80 8A0B
mov cl, byte ptr [ebx] //转turnit[ebx]下,一下一位
* Possible Reference to String Resource ID=00003: "http://www.hd1860.com"
|
:004C2D82 BA03000000
mov edx, 00000003
:004C2D87 E800FFFFFF
call 004C2C8C
//这个函数负责转圈的
:004C2D8C 8D45ED
lea eax, dword ptr [ebp-13] //后28也进去转转
:004C2D8F 8A0B
mov cl, byte ptr [ebx] //同样的圈数
* Possible Reference to String Resource ID=00003: "http://www.hd1860.com"
|
:004C2D91 BA03000000
mov edx, 00000003
:004C2D96 E8F1FEFFFF
call 004C2C8C
//还是这破函数:(
:004C2D9B 8A55F1
mov dl, byte ptr [ebp-0F]
:004C2D9E C1E204
shl edx, 04
圈圈函数在这儿:
:004C2C97 8A08
mov cl, byte ptr [eax]
:004C2C99 03C9
add ecx, ecx //用加法实现左移一位的效果
:004C2C9B 33DB
xor ebx, ebx
:004C2C9D 8A5801
mov bl, byte ptr [eax+01] //取下一个字节
:004C2CA0 C1EB07
shr ebx, 07 //取最高位
:004C2CA3 0ACB
or cl, bl
//下一字节最高位放入上一字节最低位
:004C2CA5 8808
mov byte ptr [eax], cl
//存储一下
;
...
//这是后3个字节的处理,相同所以省略了
;
:004C2CE0 884803
mov byte ptr [eax+03], cl
:004C2CE3
80200F and byte
ptr [eax], 0F //最后将前4位清0
:004C2CE6
4A
dec edx //这个edx就是旋转的轮数,是几就转几下
:004C2CE7 75AE
jne 004C2C97
//感觉这个函数不是很高效
//用#define
ROL(a,n) (((a)<<(n))|((a)>>(28-(n))))岂不是更好些???
继续,转完出去之后:
:004C2DF7 BA06000000
mov edx, 00000006
:004C2DFC E8F3FDFFFF
call 004C2BF4 //这里是从56取48的过程
:004C2E01
83C606 add esi,
00000006
:004C2E04 43
inc ebx
:004C2E05
4F
dec edi //要得到16个子密钥...
:004C2E06 0F8571FFFFFF jne 004C2D7D
:004C2E0C 8B7DD8
mov edi, dword ptr [ebp-28]
:004C2E0F 8B75DC
mov esi, dword ptr [ebp-24]
进去那个call里面,会有:
:004C2C23 33D2
xor edx, edx
:004C2C25 B838874F00
mov eax, 004F8738 //这也是个重要的数组
/*"0D 10 0A 17 00
04 02 1B-0E 05 14 09 16 12 0B 03
19 07 0F
06 1A 13 0C 01-28 33 1E 24 2E 36 1D 27
32
2C 20 2F 2B 30 26 37-21 34 2D 29 31 23 1C 1F "*/用来从56选48的...
* Referenced
by a (U)nconditional or (C)onditional Jump at Address:
|:004C2C7B(C)
|
:004C2C2A 8A18
mov bl, byte ptr [eax]
:004C2C2C 8BCB
mov ecx, ebx
:004C2C2E 80E107
and cl, 07
;
...
//略掉,选数过程和初始置换相同
;
* Referenced by a
(U)nconditional or (C)onditional Jump at Address:
|:004C2C57(C)
|
:004C2C76 42
inc edx
:004C2C77 40
inc eax
:004C2C78 83FA30
cmp edx, 00000030 //是否全部选完
:004C2C7B 75AD
jne 004C2C2A
出去之后跳过16次循环后到上一层:
会发现软件判断注册码是否为16的倍数,不是会导致出错...
然后从这里进去:
:004C31FA E845FDFFFF
call 004C2F44
然后到这里进去:
:004C2F82 E881F9FFFF
call 004C2908
这里面就是将明文也就是输入的注册码后半部分,进行初始置换,过程也都是类似的,省略掉,自己看就好啦
:004C2F87 84DB
test bl, bl //bl的值不同,下面的流程也不同,我猜是加解密的两个过程:)
:004C2F89
0F85B5000000 jne 004C3044//bl=1解密,bl=0加密,由于作者设bl为定值1,所以必跳
:004C3044 80FB01
cmp bl, 01
:004C3047 0F85B2000000
jne 004C30FF
:004C304D C745F8F0FFFFFF mov
[ebp-08], FFFFFFF0 //猜测的依据在这个数据上,这里-16,那里是+16:)
:004C3054
BBCA2A5000 mov ebx, 00502ACA
;
...
;
:004C3089 8BCB
mov ecx, ebx
:004C308B 8B450C
mov eax, dword ptr [ebp+0C]
:004C308E
8B5508 mov edx,
dword ptr [ebp+08]
:004C3091 E886FDFFFF
call 004C2E1C //从这里进去
里面是:
:004C2E4C
6A05 push
00000005
:004C2E4E 8D4DF6
lea ecx, dword ptr [ebp-0A]
:004C2E51 E8BAFBFFFF
call 004C2A10 //这里面是DES加解密的迭代过程
:004C2E56 BB06000000 mov
ebx, 00000006 //f函数中32变48的扩展过程,同上这里略掉不分析
:004C2E5B 8B45FC
mov eax, dword ptr [ebp-04] //上面ebx=6!!是因为48bit,每次异或一个字节!
:004C2E5E 8D55F6
lea edx, dword ptr [ebp-0A]
* Referenced by a (U)nconditional or (C)onditional
Jump at Address:
|:004C2E68(C)
|
:004C2E61 8A08
mov cl, byte ptr [eax]
:004C2E63
300A xor
byte ptr [edx], cl //膨胀后与子密钥相异或
:004C2E65
42
inc edx
:004C2E66 40
inc eax
:004C2E67 4B
dec ebx
:004C2E68 75F7
jne 004C2E61
:004C2E6A
8A45F6 mov al, byte
ptr [ebp-0A]
;
... //以下是将异或后得到的数修改,因为得到的数是连贯的48bit,所以要将他们分开成为6bit一字节
;
:004C2EE6 8BC3
mov eax, ebx
:004C2EE8 8A16
mov dl, byte ptr [esi]
:004C2EEA E831FCFFFF
call 004C2B20 //这里面是将上面得到那8个字节调整用来查表,(每6个用来查一个表)
:004C2EEF 8806
mov byte ptr [esi], al
:004C2EF1 43
inc ebx
:004C2EF2 46
inc esi
:004C2EF3
83FB08 cmp ebx,
00000008 //查8次...
:004C2EF6 75EE
jne 004C2EE6
然后再出来,好累啊.......坚持就是胜利,这里快结束了
:004C3096 B804000000 mov
eax, 00000004
:004C309B 8D55F4
lea edx, dword ptr [ebp-0C]
:004C309E 8D75F0
lea esi, dword ptr [ebp-10]
:004C30A1
8B4D0C mov ecx,
dword ptr [ebp+0C]
:004C30A4 83C104
add ecx, 00000004
:004C30A7 894DE8
mov dword ptr [ebp-18], ecx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004C30B9(C)
|
:004C30AA 8A0A
mov cl, byte ptr [edx] //经过f函数作用后,左半部分
:004C30AC 320E
xor cl, byte ptr [esi] //和右半部分异或得到下一轮的右半部分
:004C30AE 8B7DE8
mov edi, dword ptr [ebp-18]
:004C30B1 880F
mov byte ptr [edi], cl
:004C30B3 FF45E8
inc [ebp-18]
:004C30B6
46
inc esi
:004C30B7 42
inc edx
:004C30B8 48
dec eax
:004C30B9 75EF
jne 004C30AA
//每字节异或...
:004C30BB 83EB06
sub ebx, 00000006
:004C30BE FF45F8
inc [ebp-08]
//这是调整子密钥,每轮用的子密钥不同
:004C30C1 7596
jne 004C3059
下面还有一个函数是用来将得到的最后结果做初始置换的逆置换...
:004C3105
E882F8FFFF call 004C298C//不看了,全都一样的取数方式:(
就这样,这就是一个标准DES的运算过程,不知道能不能看懂,我讲的可真是够累,好长好长............睡觉去啦
- 标 题:变脸王 (12千字)
- 作 者:bbbsl
- 时 间:2003-1-23 1:42:32
- 链 接:http://bbs.pediy.com