本文特别详细的描述了一个国内知名控件(OCX)的暴力破解方法,只限学习交流,请不要非法使用,如果是作者看见了,请不要生气,我可没拿你的控件卖钱,我只是爱好破解而已,还是请作者自己提高加密意识,保护知识产权吧。
[破解控件] NTKO OFFICE 控件 V 2.5.0.3 (OCX)
[破解方法] 暴力破解
[破解工具] W32Dasm,UtrlEdit,Cabinet Manager 2001b 3.7,ChinaTcp_CodeSign,后两个是CAB包的打包和签名工具。
[控件用途] 很强大啦,做办公自动化系统的最佳控件,支持VB、DEPHI、C++、ASP、JSP、Domino等,具体参见官方网站:http://www.ntko.com。
[郑重声明] 本控件为国内知名的控件之一,非集团单位内部使用版本在2000元左右,集团用户使用可能在5千元左右,产品授权无限分发使用在2万左右,OEM就更贵了。以下破解只是为了自己私人使用,发表出来也是为了学习交流,请大家不要做违法的事情,也不要向我索取详细的破解资料和破解控件,其实,破解很简单,我也悲叹为什么优秀的东西反而加密措施这么不严密。我已经通过折中途径告知作者,希望他能在3.0版本上自己写算法加密或加壳,OCX能否加壳,以我现在的知识水平,还不清楚。
一、特别说明
本控件除在VB、DEPHI、C++中可以使用外(VC除外),也可在网页上使用。网页上使用将是一个.CAB包,使用方法和3721上网伴侣、百度上网伴侣、Flash插件一样,第一次打开含有此控件的网页时将弹出安装对话框。
在网页上嵌套代码的具体格式如下:
<object id="TANGER_OCX" classid="clsid:C9BC4DFF-4248-4a3c-8A49-63A7D317F404"
codebase="OfficeControl.cab#version=2,5,0,3" width="100%" height="500">
......
<param name="ProductCaption" value="帐号,一般是用户单位名称信息">
<param name="ProductKey" value="密码,是32位的16进制数字">
.....
<SPAN STYLE="color:red">不能装载文档控件。请在检查浏览器的选项中检查浏览器的安全设置。</SPAN>
</object>
看见输入帐号和密码的地方了吗?就在网页调用的param参数里写。
因为是CAB包,还要在浏览器上显示安装对话框,所以,此CAB包必须具有签名信息,2.5.0.3版本还是作者公司自己的签名,IE浏览器告知没有可信任的证书;3.0版本已经获得了微软的相关认证,IE浏览器告知可信任。
CAB包中一般包含有OCX控件和控件的INF(信息)文件,所以,破解过程必须经过以下步骤:
1、解包出OCX文件。用Winrar即可解开
2、破解OCX文件
3、打包破解的OCX和修改过的INF文件为CAB包。使用工具为Cabinet Manager。Winrar不能打包CAB文件的。
4、CAB包重新签名。使用工具为ChinaTcp_CodeSign。微软也有一个签名工具,就在VC5.0版本安装盘的一个目录下,具体位置我忘记了;本来微软网站也提供下载,后来好象是因为控件注册的安全问题,链接去年就已失效。
有关Cabinet Manager和ChinaTcp_CodeSign,网上有下载,但不好找的。具体使用方法,自己看它们的帮助文件即可,很简单。这里是讲OCX本身的破解。
二、破解思路
本控件有帐号和密码限制,如果不输入正确的帐号和密码,自动转成“试用”版本,试用版本有定期时间限制,从发行到过期是1个月的时间,过期将不能正常使用;如输入正确的帐号和密码,系统将不检测过期日期。
本次破解我将使用暴力破解,不探讨复杂的帐号到正确密码的算法。
首先是过期检测。因为不输入正确的帐号和密码将检测过期,所以必须破解,思路是不让其检测日期,或者将过期日期推到9999年。
再次是帐号和密码检测。做到随便输入帐号和密码都可正常使用。
还要避免一个破解后的代码执行逻辑问题,就是正确的帐号和密码也可以使用,这将不是只修改一个地方的跳转指令能解决的问题。思路是,不论输入什么帐号和密码,系统都认为是错误的,这样就可以只修改跳转指令解决。
对于一些无关紧要的提示信息,不做完美破解,可直接修改资源文件(如“关于”对话框),也可直接在源代码中将信息编码的字符抹成空格(20)。
由于是OCX控件,自身不能运行,所以不能动态跟踪,我一开始想用VB或C++做个使用此控件的程序,后来发现跟踪麻烦,很难发现关键代码处。后来用W32Dasm反编译了一下,觉得汇编代码很亲切,以我的汇编语言水平,还不如静态分析呢。破解工作就这样开始了,耗时近4个小时搞定。
破解着手点:
日期检测一般要读取本地时间,本身要用一个API函数:KERNEL32.GetLocalTime。
帐号密码检测要比较字符串,本身也要调用一个API函数:KERNEL32.lstrcmpA。
W32Dasm反汇编后就提供本控件调用的输入输出API函数,双击函数行,就可快速切换到相应的调用汇编代码处,利用这个原理,作为破解的着手点。
三、详细破解开始
因为此控件有时间限制,肯定要调用WINDOWS API函数查询当前破解机器的本地时间,这个API为KERNEL32.GetLocalTime,所以要查找汇编代码中那些地方调用了此函数。打开W32Dasm的菜单“函数”-“输入函数”列表,寻找到KERNEL32.GetLocalTime,双击之,W32Dasm汇编区域代码将切换到调用KERNEL32.GetLocalTime处。
如下代码:
* Reference To: KERNEL32.GetLocalTime, Ord:012Fh
|
:22018AE0 FF15CC000222 Call dword ptr [220200CC]
:22018AE6 6A10 push 00000010
:22018AE8 8D45E0 lea eax, dword ptr [ebp-20]
:22018AEB 6A00 push 00000000
:22018AED 50 push eax
:22018AEE E89D100000 call 22019B90
注意此时不要着急往下浏览代码,应该往上浏览,为什么呢?因为此处代码可能不是程序的主过程,很可能是一个进行过期检测的自编函数,这是因为程序可能在很多地方调用过期检测,所以一般都要编写成一个公用函数调用。那么,往上浏览到什么地方停呢?应该慢慢翻到具有调用入口的地方停,记下这些入口,后面还要继续望上追溯呢!
以下为上翻找到的调用处代码,完整的日期检测要从这里开始分析。
* Referenced by a CALL at Addresses:
|:22003CDC , :220044B3 , :22004585 , :220056FC ‘4个调用入口
|
:22018AD5 55 push ebp
:22018AD6 8BEC mov ebp, esp
:22018AD8 83EC30 sub esp, 00000030
:22018ADB 8D45D0 lea eax, dword ptr [ebp-30]
:22018ADE 56 push esi
:22018ADF 50 push eax
完整的过期检测函数代码如下:
* Referenced by a CALL at Addresses:
|:22003CDC , :220044B3 , :22004585 , :220056FC ‘4个调用入口
‘W32Dasm反汇编器告诉我们,以上地址的代码处都CALL了这里的过期检测函数,你可以按以上地址寻找并修改每个CALL代码后面的判断代码指向来完成暴力不过期。但会存在一个问题,因为判断逻辑反了,如果现在还没过期,程序会报告过期,过期了反而认为不过期,有意思吧?!所以,我们应该分析一下过期检测代码,看能不能通过修改下面的代码把过期日期往后推推呢?!如改个9999年12月28日总可以吧!
好,咱们继续往下看吧!
|
:22018AD5 55 push ebp
:22018AD6 8BEC mov ebp, esp
:22018AD8 83EC30 sub esp, 00000030
:22018ADB 8D45D0 lea eax, dword ptr [ebp-30]
:22018ADE 56 push esi
:22018ADF 50 push eax
* Reference To: KERNEL32.GetLocalTime, Ord:012Fh
|
:22018AE0 FF15CC000222 Call dword ptr [220200CC]
:22018AE6 6A10 push 00000010
:22018AE8 8D45E0 lea eax, dword ptr [ebp-20]
:22018AEB 6A00 push 00000000
:22018AED 50 push eax
:22018AEE E89D100000 call 22019B90
* Reference To: KERNEL32.SystemTimeToFileTime, Ord:02C8h
|
:22018AF3 8B35EC000222 mov esi, dword ptr [220200EC]
:22018AF9 83C40C add esp, 0000000C
:22018AFC 8D45F0 lea eax, dword ptr [ebp-10]
:22018AFF 66C745E0D507 mov [ebp-20], 07D5
'↑关键部分1找到了,就是上面那行代码,“07D5”是什么,就是10进制的“2005”,作者直接把日期写进程序了!看来,控件在2005年过期。改成:270F,即“9999”年。哈,感觉真爽。下面还有月和日的赋值代码。
:22018B05 50 push eax
:22018B06 8D45D0 lea eax, dword ptr [ebp-30]
:22018B09 50 push eax
:22018B0A 66C745E20300 mov [ebp-1E], 0003
'↑关键部分2找到了,就是上面那行代码,“0003”是什么,就是10进制的3月,看来,控件在2005年3月过期。改成:000C,即“12”月。哈,其实这是多余的,因为年改了就行了。
:22018B10 66C745E61700 mov [ebp-1A], 0017
'↑关键部分3找到了,就是上面那行代码,“0017”是什么,就是10进制的23日,看来,控件在2005年3月23日过期。改成:001C,即“28”日。哈,其实这也是多余的。
:22018B16 FFD6 call esi
:22018B18 8D45F8 lea eax, dword ptr [ebp-08]
:22018B1B 50 push eax
:22018B1C 8D45E0 lea eax, dword ptr [ebp-20]
:22018B1F 50 push eax
:22018B20 FFD6 call esi
:22018B22 8D45F8 lea eax, dword ptr [ebp-08]
:22018B25 50 push eax
:22018B26 8D45F0 lea eax, dword ptr [ebp-10]
:22018B29 50 push eax
* Reference To: KERNEL32.CompareFileTime, Ord:0023h
|
:22018B2A FF15E8000222 Call dword ptr [220200E8]
:22018B30 33C9 xor ecx, ecx
:22018B32 5E pop esi
:22018B33 85C0 test eax, eax
:22018B35 0F9FC1 setg cl
:22018B38 8BC1 mov eax, ecx
:22018B3A C9 leave
:22018B3B C3 ret
这不,我们把过期日期推到了9999年12月28日,那所有调用过期检测函数的CALL后面的判断跳转代码就不需要修改了,也不会再出逻辑问题。 *************** 因为此控件有帐号和密码检测,很可能要调用WINDOWS API函数的字符串比较函数,这个API为KERNEL32.lstrcmpA,所以要查找汇编代码中那些地方调用了此函数。打开W32Dasm的菜单“函数”-“输入函数”列表,寻找到KERNEL32. lstrcmpA,双击之,W32Dasm汇编区域代码将切换到调用KERNEL32. lstrcmpA处,这一般会有多个,因为控件中的字符串比较一般有多个,不一定都是帐号和密码检测的,这需要自己花点时间判断分析。
以下为帐号和密码检测的KERNEL32.lstrcmpA调用处。
* Reference To: KERNEL32.lstrcmpA, Ord:0329h
|
:220095CA FF1528010222 Call dword ptr [22020128]
:220095D0 F7D8 neg eax
:220095D2 1BC0 sbb eax, eax
:220095D4 40 inc eax
:220095D5 EB02 jmp 220095D9
同过期检测,注意此时不要着急往下浏览代码,应该往上浏览,为什么呢?因为此处代码可能不是程序的主过程,很可能是一个进行帐号和密码检测的自编函数,这是因为程序可能在很多地方调用帐号和密码检测,所以一般都要编写成一个公用函数调用。那么,往上浏览到什么地方停呢?应该慢慢翻到具有调用入口的地方停,记下这些入口,后面还要继续往上追溯呢!
以下为上翻找到的调用处代码:
* Referenced by a CALL at Addresses:
|:22003CD3 , :22004491 , :2200457C , :22005698 , :2200CAF5
|
:2200952C 55 push ebp
:2200952D 8BEC mov ebp, esp
:2200952F 81ECA0040000 sub esp, 000004A0
:22009535 53 push ebx
:22009536 56 push esi
:22009537 8B7508 mov esi, dword ptr [ebp+08]
以下为完整的帐号和密码检测函数:
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:2200433D(C), :2200436B(C), :22004379(U), :2200438E(C)
‘↑W32Dasm反汇编器告诉我们,以上地址的代码处都CALL了这里的帐号和密码检测,你可以按以上地址寻找并修改每个CALL代码后面的判断代码指向来完成暴力破解。但会存在一个问题,因为判断逻辑反了,如果是正确的帐号和密码,程序会报告试用,不正确的帐号和密码反而认为正版,有意思吧?!所以,我们应该分析一下帐号和密码检测代码,看能不能通过修改下面的代码,做到以下一点,就是:输入正确的帐号和密码,系统也当作错误的帐号和密码,以统一CALL处判断逻辑的指向修改。好,咱们继续往下看吧!
|
* Referenced by a CALL at Addresses: ‘读取帐号和密码的代码
|:22003CD3 , :22004491 , :2200457C , :22005698 , :2200CAF5
|
:2200952C 55 push ebp
:2200952D 8BEC mov ebp, esp
:2200952F 81ECA0040000 sub esp, 000004A0
:22009535 53 push ebx
:22009536 56 push esi
:22009537 8B7508 mov esi, dword ptr [ebp+08]
:2200953A 57 push edi
:2200953B FFB602010000 push dword ptr [esi+00000102]
:22009541 E811FF0000 call 22019457
:22009546 FFB606010000 push dword ptr [esi+00000106]
:2200954C 8BF8 mov edi, eax
:2200954E E804FF0000 call 22019457
:22009553 85FF test edi, edi
:22009555 8BD8 mov ebx, eax
:22009557 747E je 220095D7
'↑关键部分找到了,帐号和密码运算结果不符合正版要求,转EAX清0,详细不用做分析,看看跳转处的代码就一切很明白了。
:22009559 85DB test ebx, ebx
:2200955B 747A je 220095D7
'↑关键部分找到了,帐号和密码运算结果不符合正版要求,转EAX清0,详细不用做分析,看看跳转处的代码就一切很明白了。
‘如果帐号和密码符合正版要求,继续下面的代码
* Reference To: KERNEL32.lstrlenA, Ord:0335h
|
:2200955D 8B35AC010222 mov esi, dword ptr [220201AC]
:22009563 57 push edi
:22009564 FFD6 call esi
:22009566 85C0 test eax, eax
:22009568 746D je 220095D7
'↑关键部分找到了,帐号长度不符合要求,转EAX清0,详细不用做分析,看看跳转处的代码就一切很明白了。因为即使运算关系正确,但帐号和密码长度不符合也不可以算正确。
:2200956A 53 push ebx
:2200956B FFD6 call esi
:2200956D 85C0 test eax, eax
:2200956F 7466 je 220095D7
'↑关键部分找到了,密码长度不符合要求,转EAX清0。
‘后面没有跳转错误的代码了,220095D7处是一个清除EAX寄存器的代码,从这里我们知道,EAX寄存器为0,错误,为1,正版,下面的代码没做详细分析,可能是一些正版软件的信息输出,因为是暴力破解,又不是找算法,就要找关键点看,一直往下翻……
…………………………省略一大块代码…………………………...
‘……到了又一个关键地方↓
* Reference To: KERNEL32.lstrcmpA, Ord:0329h
|
:220095CA FF1528010222 Call dword ptr [22020128]
:220095D0 F7D8 neg eax
:220095D2 1BC0 sbb eax, eax
:220095D4 40 inc eax
:220095D5 EB02 jmp 220095D9
'↑这个 jmp 220095D9语句跳过了下面的“xor eax, eax”语句,说明此处应该是检测到的是正确的帐号和密码,此时EAX肯定是“1”。为了让EAX不论帐号密码正确与否都按错误对待,就是永远输出是“0”,将“jmp 220095D9”修改成两个连续的空指令“nop”即可,为什么是两个“nop”,这是因为“jmp 220095D9”指令占两个字节。
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:22009557(C), :2200955B(C), :22009568(C), :2200956F(C)
|
:220095D7 33C0 xor eax, eax ‘EAX寄存器清0
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:220095D5(U)
|
:220095D9 5F pop edi
:220095DA 5E pop esi
:220095DB 5B pop ebx
:220095DC C9 leave
:220095DD C20400 ret 0004
以上的修改够变态吧,反正我觉得没人会这么修改,所有的帐号和密码现在都是错误的,哈!
好了,现在该找找调用帐号密码检测的CALL了,找见后进行判断跳转代码的指向修改。至于过期检测CALL调用代码后的跳转指向,就不修改了,因为现在的过期日期是9999-12-28,啦啦啦,你就随便CALL吧。
如何找到“调用帐号密码检测代码的CALL”呢?前面我让记住的那些地址就是啦,再次复制粘贴如下:
* Referenced by a CALL at Addresses:
|:22003CD3 , :22004491 , :2200457C , :22005698 , :2200CAF5
从上面可以看出,有5个地方调用了帐号密码的检测函数,这5个CALL有2个是关键地方,其它3个都是些信息的判断显示,如“关于”对话框的授权显示等。因为是暴力破解,我忽略了一些其它逻辑,就是非正确的帐号和密码,会导致“About”对话框的授权显示为“试用版”,可惜我现在给改的没回头余地了,因为正确的帐号和密码也当错误看待了。怎么办?有办法,使用VC以“资源形式”打开这个控件的“关于”对话框资源,随便加一个文本框,填上正版信息,把显示“试用版”的文本框给盖住,存盘,搞定,其它的显示信息,用UrlEdit找见,全抹成空格码20,就是什么也不显示啦。因为是国内控件,信息处可不要写自己的大名啦。
看到这里,有人会喊到:变态,真变态。可是变态确实比较省事―“非常暴力破解”。
以下是一个调用帐号密码检测函数的关键CALL处,改跳转指向就可以了!
:2200448C 836DF806 sub dword ptr [ebp-08], 00000006
:22004490 56 push esi
:22004491 E896500000 call 2200952C ‘调用CALL
:22004496 85C0 test eax, eax
:22004498 7419 je 220044B3
'↑错误:EAX=0;正确:EAX=1,改跳转指令“7419”为“7519”,就是把“je 220044B3”改成“jne 220044B3”
:2200449A 8B8602010000 mov eax, dword ptr [esi+00000102]
:220044A0 85C0 test eax, eax
:220044A2 7408 je 220044AC
'↑以上代码在官方网站提供的试用版本中没有,只在正式用户版本中出现,其实eax 获得的是一个“1”,这个好象是作者专门加的“正式用户版本标志”,以和试用版本区别。我没详细分析官方网站提供的试用版本代码。
紧接着是调用过期检测函数的关键CALL处,因为过期日期已经修改为9999年12月28日,所以跳转代码就不用修改了。
:220044B3 E81D460100 call 22018AD5 ‘就是它
:220044B8 85C0 test eax, eax
:220044BA 68508F0222 push 22028F50
:220044BF 7507 jne 220044C8
因为这个控件包含有工具条,正版的工具条后面写有帐号,帐号其实就是一串用户单位名称构成的字符串。如果帐号和密码不正确,这里显示“试用版本”,程序动态判断显示。
本想连这个信息也给它抹掉,可觉得显示用户名称很规范,对使用用户来说感觉也不错,所以就需要找到这个CALL,进一步修改。这样修改了后,就可以随便输入帐号和密码,工具条后面也能正常显示帐号,不论正确与否。破解也将更完全。
这个CALL也在调用列表中,第3个,上翻自己看看去。
这是代码。
:2200457C E8AB4F0000 call 2200952C
:22004581 85C0 test eax, eax
:22004583 7523 jne 220045A8
'↑关键处啊,改“75 23”为“74 23”,就是把“jne 220045A8”改成“je 220045A8”,就是把显示“用户单位名称信息”和显示“试用版”的调用反转了一下,因为,系统现在永远没有正确的用户名和密码,所以,永远显示“用户信息”。哈,有意思吧!
:22004585 E84B450100 call 22018AD5
:2200458A 85C0 test eax, eax
:2200458C 8D45F0 lea eax, dword ptr [ebp-10]
:2200458F 6A25 push 00000025
:22004591 50 push eax
:22004592 7507 jne 2200459B
* Possible StringData Ref from Data Obj ->"XXXX控件试用版"
|
:22004594 682C430222 push 2202432C
:22004599 EB05 jmp 220045A0
至此,本控件的暴力破解完毕。
四、破解后记
此破解控件,我主要用来做私活(几千元的小活),对于公司的工程,无论大小,都是购买正版,因为,我和控件的作者已经很熟悉了,彼此的邮件和电话技术交流也1年多了,实在不忍心。都是中国IT企业,不要互相残杀,也请大家保护国内软件的正常发展。
此控件破解后,我没有分发给任何人,仅限自己小范围使用,如果大家参照我的破解方法搞定了,也请大家不要分发,因为我也是做软件的,如果别人破解我的软件赚钱,我是什么心态,互相尊敬作者吧!
如果谁有动态跟踪破解OCX控件的文章,我想学学,因为静态分析太累。
文章链接直接贴在回复帖子里吧,我会随时看的。
希望互相交流。
本文下载:附件:NTKOCRACK.rar
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!