首页
社区
课程
招聘
[原创]一个国内知名WEB OFFICE OCX控件的暴力破解,很详细
发表于: 2005-5-24 10:35 35633

[原创]一个国内知名WEB OFFICE OCX控件的暴力破解,很详细

2005-5-24 10:35
35633

本文特别详细的描述了一个国内知名控件(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


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (11)
雪    币: 221
活跃值: (137)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
2
哈,行呀。静态给完全搞了
2005-5-24 11:17
0
雪    币: 442
活跃值: (1241)
能力值: ( LV12,RANK:1130 )
在线值:
发帖
回帖
粉丝
3
牛X,学习中。
2005-5-24 11:21
0
雪    币: 328
活跃值: (925)
能力值: ( LV9,RANK:1010 )
在线值:
发帖
回帖
粉丝
4
不错,学习
2005-5-24 11:41
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
hao 文章,学习
2005-5-24 14:48
0
雪    币: 235
活跃值: (191)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
6
静态能搞定真是强啊
2005-5-24 15:13
0
雪    币: 214
活跃值: (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
7
不错,学习中。
2005-5-25 00:43
0
雪    币: 107
活跃值: (54)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
顶一下
2005-5-25 04:10
0
雪    币: 218
活跃值: (1655)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
好厉害.支持
2005-5-25 11:38
0
雪    币: 198
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
静态是个好办法
呵呵
模仿一下即可
不过我早就有最新的破解了
2005-5-25 12:38
0
雪    币: 1242
活跃值: (1684)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
可以动态调试,调试浏览器网页加载控件中断
http://asp.ntko.com/v21/aspstep/step1.html
很早之前FCG里就有注册机的说:)

<param name="ProductCaption" value="LonGDikE[D/FCG]">
<param name="ProductKey" value="4B*48470*8AF5FEB*1F0403BA405*5*D">
2005-5-25 18:06
0
雪    币: 258
活跃值: (230)
能力值: ( LV12,RANK:770 )
在线值:
发帖
回帖
粉丝
12

只能说这个空件做的很失败....
2005-5-25 21:25
0
游客
登录 | 注册 方可回帖
返回
//