NOD32view 9.00版 破解过程
一、NOD32view 软件介绍NOD32view 是一款俄国人编写的将ESET NOD32杀毒软件病毒库下载到本地电脑的辅助工具。利用下载的病毒库,可以在局域网建立一个病毒库升级服务器,网内所有安装ESET杀毒软件的电脑都可以连接到升级服务器免费升级病毒库。2020年以后,NOD32view 开始出现提示升级对话框,强制要求升级,无法进入升级画面。NOD32view 官网提示,NOD32view 更新到9.00版后停止更新,因此只能通过破解,恢复NOD32view 9.00正常使用。
运行软件,正常界面如下图:
2020年后,运行软件弹出窗口提示升级,然后退出,无法进入正常界面,如下图:
二、破解过程
首先用查壳工具PEID检查一下,发现软件被加了壳:
UPX 0.89.6 - 1.02 / 1.05 - 1.24 -> Markus & Laszlo
用“UPX静态脱壳机 0.3”脱壳成功,开始进行破解。
根据一般思路,首先想到的就是找到弹出这个窗口的代码位置,这段代码前面应该有个获取系统时间并判断的代码段,修改代码跳过窗口,就应该能进入正常界面。于是用OD对软件进行跟踪,一路F8、F7下来,很快找到了弹出这个窗口的代码:
0041BEAA > \B9 08000000 mov ecx, 8
0041BEAA > \B9 08000000 mov ecx, 8
0041BEAF .8D7C24 1C lea edi, dword ptr
0041BEB3 .8D7424 50 lea esi, dword ptr
0041BEB7 .33C0 xor eax, eax
0041BEB9 .F3:A6 repe cmps byte ptr es:, byte ptr
0041BEBB .74 04 je short 0041BEC1
0041BEBD .1BC0 sbb eax, eax
0041BEBF .1BC5 sbb eax, ebp
0041BEC1 >3BC3 cmp eax, ebx
0041BEC3 .0F8E FF000000 jle 0041BFC8/*跳转至正确界面
0041BEC9 .53 push ebx /*没有跳转就弹出升级窗口
0041BECA .8D4C24 64 lea ecx, dword ptr
0041BECE .E8 7DD1FEFF call 00409050
0041BED3 .8D4C24 60 lea ecx, dword ptr
0041BED7 .C78424 28020000 01000000 mov dword ptr , 1
0041BEE2 .899C24 D4000000 mov dword ptr , ebx
0041BEE9 .E8 69660400 call 00462557/*这个CALL弹出提示升级窗口
再往前看一下,有一个GetLocalTime的API调用:
0041BDD5 . FF15 70D34>call dword ptr [<&KERNEL32.GetLocalTime>] ; \GetLocalTime
很明显,调用系统时间后,进行了比较,超过了时间(2020年),强制升级。
马上动手修改代码,在CMP指令前让EAX=EBX,让程序强行跳转到正确方向:
原代码:0041BEBF .1BC5 sbb eax, ebp
修改为:0041BEBF .8BC3 mov eax, ebx
本次修改命名为:Crack1。运行Crack1之后的软件,果然跳过了升级窗口,但是出现了意外情况,如下图:
经过OD跟踪,发现在后续代码中出现非法寻址方式,也就是出现了非法指令,导致软件崩溃。尝试修复了几处非法指令,但直到进入一个子程序,有多个入口调用它,再也无法修复,Crack1失败。
Crack1虽然失败了,但有一个奇怪现象:我印象中Crack1之后好象成功进入了界面,而且一切操作正常!但再运行时,无论如何也无法正常工作了。不管怎么说,破解出现不稳定情况也是失败。
Crack1虽然失败了,但这是个很好的基础,因为它已经跳过了升级窗口,下一步只要找到出现非法指令的原因就可以了。同时还发现,Crack1虽然失败了,但将系统时间调回2019年后,Crack1可以正常运行,也就是说,可以反复比较不同系统时间下Crack1的运行状态,找到发生问题的那段代码。为了快速切换系统时间,我用VB编写了一个自动切换系统时间的小程序,如下图:
反复调整系统时间运行Crack1,发现一个重要线索:时间调到2020年运行时,就会崩溃,然而在2019年运行Crack1时,第1次也是崩溃,退出后重新运行,再往后就正常了。后来进一步发现,在2020年运行Crack1崩溃后,马上改在2019年运行NOD32view原程序,第1次运行时居然也会崩溃!!!
NOD32view原程序怎么会出错呢?马上想到:一定是软件在电脑的某个地方设置了时间标记。每次运行软件都会设置这个标记,在2020年运行Crack1时,软件在电脑中标记了一个错误时间值(只有Crack1后才会运行到这段代码,设置错误时间值),回到2019年,因为检测到错误时间标记,即使原版程序也会崩溃。
由于2019年运行原版程序只在第1次崩溃,以后都正常,因此进一步分析:软件一定是先做时间标记,后进行检测,在软件崩溃前已经完成了标记。如果是这样的话,在2019年运行软件时,它一定做了一个正确标记!为了验证这一想法,将系统时间设到2019年正常运行了一次软件后退出,马上切换到2020年运行Crack1,果然,Crack1第1次运行正常,后面再运行就是一直崩溃了。
于是第二个思路就有了:找到做标记的代码段,让它永远做正确标记,问题就解决了。
这个标记一定跟日期有关!!!
这个做标记的代码段,一定是在Crack1修改的那个代码段之后!
我首先想到会不会是在注册表中做手脚,用注册表监控软件监视Crack1运行了几次,没有发现特别的线索。于是决定再用OD跟踪一下,查找这个做标记的代码段。
把系统时间调回2020年,用OD对Crack1进行跟踪,一路F8,只要遇到让软件崩溃的CALL,就用F7跟进去,直到来到这个调用:
00460393.FF50 64 call dword ptr
在正确日期下,这个调用在整个软件运行过程中被调用了12次,每次根据EAX值不同,会转向不同入口,而在此之前的CALL都是只执行一次。Crack1就在它的第一次调用中。
在这个CALL下断点。
由于做标记的代码段一定在Crack1修改的那个代码段之后,在这个CALL之前的调用都不用管它。把日期调到2019年,运行一下Crack1,设置一下正确标记,退出,切换到2020年,在OD中打开Crack1,运行到断点,这个CALL运行0次时退出跟踪。假如做标记的代码段在这个CALL之前,再运行Crack1一定会崩溃的,经再次运行Crack1,没有崩溃,说明还没有执行到。
重复上个操作,运行到断点,让CALL运行1次(按F8)时立即退出跟踪。经再次运行Crack1,软件崩溃了,做标记的代码段就在这个CALL第1次调用中!!!
再次用OD加载Crack1,运行到断点时,按F7跟进去。
观察这段代码,里边有大量的API调用,我们关心的是与时间有关的API,另一个关注的重点是与注册表有关的API。
观察代码发现大量读注册表的API,但我们要找的是写注册表的API:RegSetValueExA
在这段调用中发现了两、三个RegSetValueExA,但观察这几处写注册表的API前后代码,都没有与时间相关的操作,按照上边寻找标记代码段的方法测试了一个,不起作用,排除了。
进一步观察代码,发现三处与时间相关的代码段:
第一段代码在:0041BDA2—0041BDD5之间,经分析,它用于获取系统时间,用于Crack1的判断,不必管它。
后两处代码段分别在:0041CBC8—0041CBt9,0041CE7A—0041CEB5,这两段代码非常相似,其中第三处如下:
这四个与时间相关的API太扎眼了:
第一个:GetFileTime/* 读文件修改时间
第二个:GetLocalTime/*读取系统当前时间
第三个:SystemTimeToFileTime /*系统时间格式转换成文件时间格式
第四个:SetFileTime/* 当前时间写入文件时间。
这段代码把当前系统时间保存为文件时间,也就是说,当软件运行结束后,这个文件的时间被修改成了当前时间,这不是一个很好的时间标记吗?
在这两处代码起点处下断点。第二处代码拦不到,说明程序正常情况下执行不到,到第三处代码中断后,按F8调试,可以发现,执行完SetFileTime这条API函数时,标记就出现了!就是下面这条代码:
0041CEB5 . FF15E8D24700call dword ptr [<&KERNEL32.SetFileTime>]; \SetFileTime
这是哪个文件呢?在这个API调用前,要设置文件句柄:
0041CE7F . 56 push esi ; |hFile = 0000011C (window)
可以看到文件句柄hFile =11C,保存在ESI寄存器中,谁打开的这个文件?往前找,看看是哪条指令让ESI=11C:
0041CD33 .A1 58764900 mov eax, dword ptr
0041CD38 .50 push eax
0041CD39 .C74424 34 010000mov dword ptr , 1
0041CD41 .E8 AA4A0200 call 004417F0
0041CD46 .8BF0 mov esi, eax
在这个子程序调用之后,EAX=11C,然后让ESI=11C。
很显然,这个子程序打开了一个文件,EAX得到文件句柄,又给了ESI,子程序只有一个参数EAX:
0041CD38 .50 push eax
查看EAX的值,它指向一个字符串:“NOD32view.psw”!!!
跟踪到此已经真相大白,NOD32view.psw保存的是ESET杀毒软件在线升级时用到的用户名和密码,如果目录下没有这个文件,软件会自动生成,然后每次运行软件时,都要更新该文件的修改时间,而这个文件的修改时间,正是判断软件是否超期的依据!!
原理搞清楚后,下面就是修改了,修改前要弄清楚两个问题,时间值保存在哪个变量(内存地址)中?合法的时间范围是多少?
第一个问题,保存文件时,时间变量的地址:
0041CEAB . 8D5424 38 lea edx, dword ptr
0041CEAF . 52 push edx ; /pLastWrite
0041CEB0 . 6A 00 push 0 ; |pLastAccess = NULL
0041CEB2 . 6A 00 push 0 ; |pCreationTime = NULL
0041CEB4 . 56 push esi ; |hFile
0041CEB5 . FF15 E8D24700 call dword ptr [<&KERNEL32.SetFileTime>] ; \SetFileTime
通过上面代码可以看到,时间变量为EDX,EDX= dword ptr =
从网上下载了一个更改文件时间的小软件,通过更改NOD32view.psw文件的修改时间为不同的合法值并运行软件,然后打开OD内存查看器,可以看到时间变量保存在: 和,这是一个64位变量,经测算,文件时间每发生1秒的变化, 低位的值变化量是989680,所以能表示的最大时间是FFFFFFFF/989680=1AD,即429秒。这么小的值,我们完全可以忽略这个变量,只关心它的高32位的值。
第二个问题,合法时间的范围是多少?
其实我们不需要太精确的时间范围,比如:2018年1月1日—2019年12月1日之间都是合法时间值,通过上述那个改文件时间的小软件,把NOD32view.psw的文件修改时间设置两次并跟踪的值,就会得出一个合法的时间范围,在这个范围内任意取一个值就行了,当然我最近比较清闲,最终还是找出它最大的时间范围:
NOD32view.psw 文件的修改时间必须在2015/12/2 7:57:14—2020/1/1 15:20:52之间,程序才能正常运行。取值范围在01D12C94—01D5C073之间,即可满足时间要求(不要取两边极限值),这里取值为 01D40000。SystemTimeToFileTime 函数没什么用处了,全部NOP掉,腾出空间放改写的代码:
0041CE9B .8D4424 38 lea eax, dword ptr
0041CE9F .C740 04 0000D401mov dword ptr , 1D40000/*强制为合法时间
0041CEA6 ?90 nop/*上面这个指令让时间永远是合法值,
0041CEA7 ?90 nop/*然后在下面API数中写入文件。
0041CEA8 ?90 nop
0041CEA9 ?90 nop
0041CEAA ?90 nop
0041CEAB . 8D5424 38 lea edx, dword ptr
0041CEAF . 52 push edx ; /pLastWrite
0041CEB0 . 6A 00 push 0 ; |pLastAccess = NULL
0041CEB2 . 6A 00 push 0 ; |pCreationTime = NULL
0041CEB4 . 56 push esi ; |hFile
0041CEB5 . FF15 E8D24700 call dword ptr [<&KERNEL32.SetFileTime>] ; \SetFileTime
修改完成,本次修改命名为:Crack2。
为什么是Crack2呢?通过运行Crack2可以发现,当NOD32view.psw的修改时间为非法值时,Crack2还是会崩溃,但在崩溃之前,已经把NOD32view.psw的修改时间改为正确值了,所以只会崩溃1次,以后再运行就会正常。另外,软件中改写用户名密码并保存时(一般一个月或几个月设置一次),也会改写NOD32view.psw的修改时间为非法值,Crack2再运行时还得崩溃1次,然后全部正常。
所以说Crack2破解不完美,但已经能够使用了。
不完美多没面子,显然软件中某处代码,在我们修改dword ptr = 之前,把这个值用来干坏事了,这个其实很简单,这个值从读出来到写回去,就那么几行代码,它在这里:
0041CE80 . FF15 ECD24700 call dword ptr [<&KERNEL32.GetFileTim>; \GetFileTime
0041CE86 . 8B4C24 3C mov ecx, dword ptr /*ECX=文件修改时间
0041CE8A . 8D5424 50 lea edx, dword ptr
0041CE8E . 52 push edx
0041CE8F . 890D 081A4A00 mov dword ptr , ecx/*干坏事!!!
0041CE95 . FF15 70D34700 call dword ptr [<&KERNEL32.GetLocalTi>; \GetLocalTime
从上面可以看到,读取的文件修改时间后,时间变量的高32位值dword ptr 保存在dword ptr 变量中,这个变量的值必须是合法时间值,否则软件会崩溃!
分析到这里,我们不仅搞清楚软件电脑中怎么做时间标记,而且明白程序中如何识别利用这个标记,我们只要把变量dword ptr 赋一个合法值,比如:
C705 081A4A00 0000D401 MOV DWORD PTR ,1D40000
NOD32view.psw的修改时间这个标记就完全失效了。到此,软件被完美破解。
总结:
破解NOD32view ,需要修改两处代码:
第一,修改软件判断时间的代码,跳过升级对话框,修改如下:
原代码:0041BEBF .1BC5 sbb eax, ebp
修改为:0041BEBF .8BC3 mov eax, ebx
或者修改0041BEC1>3BC3 cmp eax, ebx,改为:cmpeax,eax 等等,效果相同。
或者直接暴力跳转至正确入口。
第二,修改软件中对DWORD PTR 变量的赋值,让它永远正确,修改如下:
原代码:
::0041CE80::FF15 ECD24700CALL DWORD PTR >>>: KERNEL32.DLL:GetFileTime
::0041CE86::8B4C24 3C MOV ECX, DWORD PTR
::0041CE8A::8D5424 50 LEA EDX, DWORD PTR
::0041CE8E::52 PUSH EDX
::0041CE8F::890D 081A4A00 MOV DWORD PTR , ECX
:::0041CE95::FF15 70D34700CALL DWORD PTR >>>: KERNEL32.DLL:GetLocalTime
修改为:
::0041CE80::FF15 ECD24700CALL DWORD PTR >>>: KERNEL32.DLL:GetFileTime
::0041CE86::C705 081A4A00 0000D401 MOV DWORD PTR ,1D40000
::0041CE90::8D5424 50 LEA EDX,DWORD PTR
::0041CE94::52 PUSH EDX
::0041CE95::FF15 70D34700CALL DWORD PTR >>>: KERNEL32.DLL:GetLocalTime
破解完毕。
附:相关附件
看来还有不少用ESET的朋友~
看到2020年不能用了就用RunAsDate 来启动。
上传个汉化去时间限制版吧(基于楼主破解过程) bester 发表于 2020-1-15 18:55
感谢分享,这个软件跟踪过,本来是想进行shellcode修改getlocaltime,发现无论如何都是非法值,然后我就直 ...
我是在WIN7 64位系统下破解的,你是什么操作系统? 感谢分享,这个软件跟踪过,本来是想进行shellcode修改getlocaltime,发现无论如何都是非法值,然后我就直接jmp 跳过了这个过期框,发现OK了,原来后面是还有暗装的,可能我没多试几遍 进来学习一下 感谢分享!!!支持一下! 膜拜大神,,, 感谢分享 这才是真正的高手。
这种态度值得我们学习,加油!!!