欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  网络运营

决战“共享资料保护专家”

程序员文章站 2022-04-22 10:42:30
文/图 TC-XB=================================== 共享资料保护专家是一款强大的文件保护软件,使用它对文件夹进行加密后,用户只能浏览该文件夹内的Word、...

文/图 TC-XB
===================================
共享资料保护专家是一款强大的文件保护软件,使用它对文件夹进行加密后,用户只能浏览该文件夹内的Word、Excel或图片文件等的内容,无法对文件夹内的文件进行修改或者拷贝。软件使用起来还是相当方便的,但是在没有注册的情况下会有一些限制,我们就尝试着分析一下这款软件吧。
老规矩,在正式破解之前先检查软件是否加壳了,用PEiD检测的结果是Borland Delphi 6.0-7.0,没有加壳。现在我们就要考虑分析的入口点了,从哪个方向进行分析呢?在这里可以选择在消息窗口上设置断点的方法进行分析,也可以选择通过OD的字符串查找功能来帮助我们搜寻重要的信息。由于这个软件在注册时有明确的提示信息,所以我们就直接通过寻找字符串的方法来寻找关键的代码。
分析的方向已经明确了,那动手吧!在OD里打开字符串查找功能,经过一番寻找,在字符串的海洋中终于找到一个令人兴奋的提示信息:“您已购买并注册《共享资料保护专家高级版》软件,谢谢支持!”。这个提示再明确不过了,双击它就来到了对应的代码处。我们还是和以往的分析过程一样,按照先流程再算法的顺序进行分析。

惊现“爆破点”
首先,要找到注册流程开始的地方,顺着注册成功的提示信息向上看,找到以下的代码:

004D3C53 . 50  push eax
; 我们在这里设置断点
004D3C54 . 8D95 F4FDFFFF lea  edx, [ebp-20C]
004D3C5A . A1 C0F14D00 mov  eax, [4DF1C0]
004D3C5F . 8B00  mov  eax, [eax]
004D3C61 . E8 1E300000 call 004D6C84
;算法CALL,要跟进!
004D3C66 . 8B85 F4FDFFFF mov  eax, [ebp-20C]
;正确的注册码已经出现了
004D3C6C . 8D95 F8FDFFFF lea  edx, [ebp-208]
004D3C72 . E8 D551F3FF call 00408E4C
;取出正确的注册码
004D3C77 . 8B95 F8FDFFFF mov  edx, [ebp-208]
;将正确的注册码放进EDX中
004D3C7D . 58  pop  eax
;将我们输入的注册码放进EAX中
004D3C7E . E8 890FF3FF call 00404C0C
;真假注册码比较
004D3C83 . 75 2C  jnz  short 004D3CB1
;不相等就注册失败
004D3C85 . 6A 40  push 40
004D3C87 . B9 58404D00 mov  ecx, 004D4058
;你已经注册
004D3C8C . BA 64404D00 mov  edx, 004D4064
;您已购买并注册《共享资料保护专家高级版》软件,谢谢支持!

短短的几行代码,正是这个软件的核心注册流程。收集注册信息,通过算法计算注册码,判断输入的注册码正确与否,根据判断的结果弹出注册成功或是注册失败的提示框。很显然,如果在这里将代码:“jnz short 004D3CB1”修改成“jz short 004D3CB1”,或者是nop语句,这个软件就可以算做被暴力破解了。但是我们必须要注意到,这个软件是采取重启验证的方式对注册码进行判断的,这样一来,如上所述的修改关键跳转进行破解的方法很可能就行不通了。不论验证的方式如何,能够分析出软件的注册算法才是王道。

深入打击
我们继续跟进算法,一探究竟。跟进“004D3C61 . E8 1E300000 call 004D6C84”,来到以下代码处。

004D6C84 $ 55 PUSH EBP ;来到了这里
004D6C85 . 8BEC MOV EBP,ESP
004D6C87 . 6A 00 PUSH 0
004D6C89 . 6A 00 PUSH 0
004D6C8B . 6A 00 PUSH 0
……省略……
004D6CBA . E8 9D000000 CALL 共享资料.004D6D5C
004D6CBF . 8B55 F4  MOV EDX,DWORD PTR SS:[EBP-C];5808328774
004D6CC2 . 66:B9 1701 MOV CX,117
004D6CC6 . 8BC3 MOV EAX,EBX
004D6CC8 . E8 BBFEFFFF CALL 共享资料.004D6B88
;第二个算法CALL
004D6CCD . 8B45 FC  MOV EAX,DWORD PTR SS:[EBP-4]
004D6CD0 . 8B55 F8  MOV EDX,DWORD PTR SS:[EBP-8]
004D6CD3 . E8 8CDBF2FF CALL 共享资料.00404864
004D6CD8 . 33C0 XOR EAX,EAX
004D6CDA . 5A POP EDX

跟进第一个算法CALL的时候,我们并没有发现明显的计算过程,是我们跟踪错了还是没有注意到呢?但是当经过“004D6CC8 .E8 BBFEFFFF CALL 共享资料.004D6B88”这句代码时,我们发现了寄存器中的值发生了明显的变化,出现了一个很长的字符串,直觉告诉我们,这个字符串肯定与注册码有着莫大的关系,进而这句代码也变得十分可疑。于是,继续跟进这个CALL看看。

004D6B88 $ 55 PUSH EBP ;来到了这里
004D6B89 . 8BEC MOV EBP,ESP
004D6B8B . 6A 00 PUSH 0
……省略……
004D6BAC . 55 push ebp ;算法就要开啦
004D6BAD . 68 2C6C4D00 push 004D6C2C
004D6BB2 . 64:FF30  push dword ptr fs:[eax]
004D6BB5 . 64:8920  mov  fs:[eax], esp
004D6BB8 . 8B45 08  mov  eax, [ebp+8]
004D6BBB . E8 50DCF2FF call 00404810
004D6BC0 . 8D45 F8  lea  eax, [ebp-8]
004D6BC3 . E8 48DCF2FF call 00404810
;取出机器码
004D6BC8 . 8BC7 mov  eax, edi
;将机器码放进EAX中
004D6BCA . E8 F9DEF2FF call 00404AC8
;取机器码的位数

程序在这里将我们的机器码放进了寄存器中,并且把机器码的位数进行了记录,看来核心的算法就要开始了。

004D6BCF . 8BD8 mov  ebx, eax
004D6BD1 . 85DB test ebx, ebx
004D6BD3 . 7E 36 jle  short 004D6C0B
004D6BD5 . BE 01000000 mov  esi, 1
;循环计算就要开始了
004D6BDA > 8D45 F0  lea  eax, [ebp-10]
004D6BDD . 8A5437 FF  mov  dl, [edi+esi-1]
;依次取机器码的每一位
004D6BE1 . E8 0ADEF2FF call 004049F0
004D6BE6 . 8B45 F0  mov  eax, [ebp-10]
004D6BE9 . E8 DE24F3FF call 004090CC
;将机器码的每一位放进EAX中
004D6BEE . 0FB755 FE  movzx edx, word ptr [ebp-2]
;取固定的数字0x117
004D6BF2 . 33C2 xor  eax, edx
;将机器码的每一位与固定数字做XOR运算
004D6BF4 . 8D55 F4  lea  edx, [ebp-C]
;保存计算的结果
004D6BF7 . E8 6C24F3FF call 00409068
;将计算的结果转换成对应的10进制
004D6BFC . 8B55 F4  mov  edx, [ebp-C]
;把10进制的结果放进EDX中
004D6BFF . 8D45 F8  lea  eax, [ebp-8]
004D6C02 . E8 C9DEF2FF call 00404AD0
;连接每一次计算的结果
004D6C07 . 46 inc  esi
;每计算一次ESI中的值加1
004D6C08 . 4B dec  ebx
;每计算一次EBX中的值减1
004D6C09 .^ 75 CF jnz  short 004D6BDA
;循环计算
004D6C0B > 8B45 08  mov  eax, [ebp+8]

这个循环计算的详细计算过程是怎样的呢?在这里,程序将机器码的每一位与固定值0x117进行异或运算。
为什么这个固定值要用0x117这样的形式表示呢?因为在这个过程中,所有的计算都是在16进制下进行的,所以其中的数字也都是16进制下的数字,16进制的0x117相当于十进制的279。机器码的每一位进行异或运算都会有一个结果,但是这个计算的结果仍是16进制的数字,所以在算法的最后,程序将16进制的计算结果统统转换成了对应的10进制数。

004D6C0E . 50   push eax
004D6C0F . 8BC7   mov  eax, edi
004D6C11 . E8 B2DEF2FF call 00404AC8
;将计算结果连接

经过循环计算,程序在这里将每一次(每一位)的计算结果连接了起来。说到这里,大家可能有些犯迷糊了,到底是怎样一个计算过程呢?还是让我们举例子说明吧。假设我们的机器码是ABCDEF,那么算法的第一步就是将每一位与定值0x117进行异或运算。具体的计算方法是:

XOR (A,0x117)= a
XOR (B,0x117)= b
XOR (C,0x117)= c
XOR (D,0x117)= d
XOR (E,0x117)= e
XOR (F,0x117)= f

这时,计算的结果还都是16进制下的数字,现在要将它们转换成对应的10进制。例如:a = 1: b = 2: c = 3: d = 4: e = 5: f = 6,最后将每一位的计算结果连接起来,最后的结果就应该是123456。当然,这里只是举例来说明的,真正的计算结果要比这里的123456长很多,应该有30位左右。现在的这个计算结果还不是最终的注册码,那在算法的最后一部分程序,又对这个计算结果进行了怎样的处理呢?

004D6C16 . 8BC8 mov  ecx, eax
004D6C18 . 33D2 xor  edx, edx
004D6C1A . 8B45 F8  mov  eax, [ebp-8]
;最后计算的结果保存在EAX中
004D6C1D . E8 FEE0F2FF call 00404D20
……省略……
004D6C66 . 5E POP ESI
004D6C67 . 5B POP EBX
004D6C68 . 8BE5 MOV ESP,EBP
;取计算结果的前十位作为注册码
004D6C6A . 5D POP EBP
004D6C6B . C2 0400  RETN 4

原来,在算法的最后,程序把计算结果的前十位取了出来,并将这十位数字作为最终的注册码。经过分析之后才发现,这个软件的注册算法是如此的简单,详细的计算过程可以归纳成以下三个主要的步骤。
1)机器码的每一位分别与固定值0x117(16进制的计算哦)作异或运算,结果转为10进制;
2)将每位的运算结果依次连接,比如我在文中提到的abcdef;
3)取以上结果的前10位即为注册码。
这款软件的功能还是相当不错的,使用起来也很方便;但是在注册验证过程中还存在没有加壳、明码比较严重的不安全因素,所以,还需要作者在软件自身的保护方面下一番工夫的