• 标 题:如何破解掉vt4.0的软件狗(一种医药用图像分析软件) 不错的文章 (7千字)
  • 作 者:大老
  • 时 间:2002-5-23 14:36:31
  • 链 接:http://bbs.pediy.com

硬件加密狗的解密过程[转帖]
作者:qdcrack
转载:大老
工具:trw2000,uedit
目标软件:vt4.0(一种医药用图像分析软件)
加密方式:外加密
用trw2000打开应用程序,首先进入的是novex32.dll,这个动态连接文件的用处我们很快就知道了.整段代码只调用了一个子程序,而跳过它的时候会出现要你插狗的提示框,说明novex32的作用就是对狗进行操作.到目前为止一切良好,似乎胜利在望.那么我们跳过这个子程序不执行,会有什么后果?试一试,程序执行到noverx32的最后一条指令ret。一个跳转,来到一片陌生的区域,于是很快就出错了,很明显,不能直接跳过去。什么原因?经过查阅相关技术资料,发现加密狗的外加密方式不止是检查狗这么简单。(还有内加密方式,就是在源代码中随机加入对狗的操作,那样的话只能通过虚拟并口技术实现解密。)实际上,在加密时,原应用程序已经被完全打乱并且被修改,只有读取相应狗内数据,经过相应算法恢复后才能正常执行。有的同行就会恍然大悟,说:“那么就插狗运行到程序入口,再用pedit把内存映像dump出来,就可以了(一定会有人这样想,我当时就是这样做的)“但是不行,因为在倒出内存的时候,倒出来的是跟初始时完全不同的内存数据,而由于novex32要对其中的一些数据作操作,用倒出后的内存数据来操作的话,就会引起很多无法预料的错误,(而且在novex32中也作了很多应用程序的初始化操作,如显示载入相关动态连接库之类,所以不能直接跳到dump出的程序入口)由于无法判断那些地址的数据是要被用到的,(当然,如果你愿意仔细的读他的代码,完全的理解他的执行过程,那么也可以找出那些地址的数据将被使用,不过那太。。。。。累了)唯一的办法:跟进该子程序去大致看一下。

进来了,**!我当时大吃一惊!这就是他所谓的反跟踪迷宫技术:在每2条指令之间。都插入了若干指令有比较温和的:
jmp ######### 或者 jmp ######## ------〉jmp ##########
还有小花招的
push ##########
ret
最过分的是:
push ########
push eax
push ebx
pushf
push ebp
mov ebp,esp
add dword[ebp+10],####
pop ebp
popf
pop ebx
pop eax
ret
你说过不过分?这么大一段就是一条跳转,刚开始还害我捉摸半天,尤其是那个pushf太吓人了呵呵
就在跟这些跳转语句的搏斗中,我找到了跟狗相关的子程序,仔细研读后,发现他会从狗读
出若干数据到一个固定的内存区域,这样的读写重复4次,每次数据都不同。不知道trw2000怎么读出固定内存地址的若干内容保存到文件中(debug比较简单),就在内存空白的地址里面添了几行代码,读完狗之后就执行这些代码,作用是把该内存区域的相关数据都存进一个文件,存4次。再修改这几条代码,每次要读狗时都不执行原来的函数,而执行我的代码,作用是把相应的位置的数据从文件再映像到该内存区域,这样的话,就可以正常通过这一关了。本来以为结束了,结果继续执行下去,在原程序被重组并接管控制后,居然还要检查狗在不在,原来他有两道关口!跟进去你会发现,这次的关口守的并不紧,只是一个判断而已,只要直接跳到正确的序列就可以了。通常的办法是把jz改成jmp short,但是怎么改?因为原文件是被打乱修改过的,74(jz)这个代码很有可能变成15或是别的什么东东无法在文件中找到并修改,就算找到了,改成什么好?eb(jmp short)?不行,因为在重组的时候会再修改一次,这样就不知道是什么样的了。看来只能在内存中修改,就是在执行过程中。我尝试在执行过程中添入代码,但是执行时报错,说我要写的内存地址被保护了,不能修改!妈的,那novex32那个混蛋又是怎么改的呢?我猛然想到会不会使用了virtualprotect?下一个断点,果然!那个混蛋用了这一招,我于是在它的被授权代码段中插入了跳转指令(反正他到处都是跳转,我只要改下地址就可以了)跳到我的修改内存的代码处,执行完了再跳回去,于是很成功的,正常执行了!

可是快乐并没有持续很长时间,vt里除了vt4。0这个可执行文件外,还有一个关于数据库的可执行文件album,本来正常执行时,打开vt4。0时可以点击他窗口“open database”按钮来打开album,但是在我解开的vt4中那个按钮居然是disable状态!只有在打开album看一下,果然,他也使用了novex32!(贱人!我骂道。)这个时候问题就出来了,先不管vt4调用album的问题,看一看如果他单独执行会怎样。都是使用novex32,如果不考虑在vt里调album情况(因为novex32已加载了,所以这时的绝对地址不会变化),在单独执行album时,由于基地址不同,我添加的代码段就不能被正常执行,因为我是对绝对地址进行访问。于是急忙再回去,想办法找到一个可以做参照的东西来算相对地址,可是惨就惨在相应的映射要作4次,(还记得吗?调用deviceiocontrol的函数(以后简称:XXXX的子程序,因为他实在是很大。)被调了4次,而我添加的代码就在他里面)每一次的所有寄存器值都会变化,只有堆栈指针倒是不变,可是两个程序的堆栈指针到我所访问的地址偏移量不一样,很难找到一个不变的数值来作基准。灵光一现!堆栈里会不会有好东西?果然,在某一个固定栈偏移储存有一个很重要的数据(好像就是程序加载的基地址),可以用他定位所有的地址了!这样用相对地址,应该不会出错了吧?没想到还是不能单独的执行album,我仔细检查了内存,发现原来album读出的数据跟vt4从狗里读出的完全不同,只有为它也存一份映像文件。因为我不想改变可执行文件,
我的所有改动都是在novex32里面,不可避免的情况就是,这两份不同的映像文件不得不取同样的名字,还好两个可执行文件不在同一个子目录下,这样可以把这两个同名的文件分别放在各自的目录下,这样两个文件都能单独执行了。虽然解决了问题,但是很不痛快。

单独执行解决了,是该解决vt4调album了,这个时候我却发现了一个令人沮丧的事情,好像我解除来的文件在nt下不能正常执行,原来本来是可以的(插狗)。于是我打算先看一下到底nt下是怎么回事。很明显,由于nt严格的内存保护,几乎我自己添加的代码对内存的访问都被报错,而我又四处下不到nt下的调试器,于是只好在98下分析。看来我要重新看待这个问题了。尽量的减少对内存的操作。但是无论我如何减少对内存的操作,nt好像都不领情,还是报错,我觉得要崩溃了,于是放下这东西,休息了几天(这个我觉得很重要,千万不要拼命,我觉得那才没用。)2天后来重操旧业,仔细检查内存后发现一个极重要的情况,好像插狗与不插狗,执行完4次XXXX的子程序后,整个内存区域内容没有什么变化,这与我原先想的真是大相径庭(我本来认为读狗并经过一系列计算后的结果应该体现在内存某区域已备后用)我先检查看结果是不是反映在寄存器值里,发现寄存器值很快就被修改,没有被使用,可见很有可能是在堆栈中,一看,果然堆栈一个地址有个双字数据,如果没狗执行完后是0,有狗就是另一个值,我试着不插狗,只在执行完XXXX的子程序后修改该堆栈数据,果然执行正常(第一关)我欣喜若狂,一面也骂自己笨,早一点找到不就什么事都没有了?现在好了,nt再厉害,不能不让人访问堆栈吧?我什么访存代码也不加,只是做push pop操作,很快的,在新的修改方案下,vt4通过了,可是album却执行不了了,很正常嘛,album的该地址数据一定跟vt4不同,数据内存映像都不一样嘛!可是现在面临的问题是:由于我只修改novex32,所以需要判断现在执行的线程到底是属于album还是vt4,这就不可避免要涉及访存。我把两个可执行文件查找了一遍,在绝对可读的内存区域里找到了一个可以用作区别的数据,这样就简单了,第一关很快记过了,而album好像没有设置第二关,所以现在他就可以直接执行了。
现在来看vt4。还剩第二关,因为第二关的解决办法是直接修改内存,所以有两点坏处。一是:有可能遭遇nt的内存保护;二:因为novex32是共用的,所以在这里还要加入判断,以免修改了album的不需要修改的数据。怎么办呢?我决定搞明白重组的算法。我让trw2000显示要修改的那个内存区域,初始化时该区域是不可知的。我执行到重组的子程序,然后逐渐跟进,发现ebx存放了要重组的数据的地址,而eax存放了一个重组是要用到的数。整个重组程序应该就是用原来的那个种子数(堆栈里我们加进去的那个。)通过一系列计算
算出一个数值,放进eax,然后执行“xor [ebx],eax”(推测,也没有仔细读源代码,不过应该是这样。)这就是恢复的机制了。我找到原来的“乱码”是11,对应的al是65,异或之后,正好是74。现在有两个选择。一是改原文件,11改8e(8e异或65为eb(jmp short))而是改novex32,把al改成 fa。当然选后者,所以插入2小段代码。再异或之前,跳到第一段,作用是检查当ebx为要修改的地址时,则改al的值,然后跳回来执行异或(不是就直接跳回)异或完后,再跳到第二段,检查ebx,若是则把al改回来,然后跳回继续,不是则直接跳回。这样就完全没有访存,而且因为两个可执行文件地址不同,在album中
ebx不会有上述的那个地址值,所以不存在冲突。
到这里,才算是功德圆满。在windows平台上畅通无阻,而且由于只涉及1次访存,且使用相对地址,所以两个可执行程序也不会发生冲突,终于成功了。