Sublime Text 3126 Win32版本暴力破解过程

来源:互联网 发布:php项目绑定域名访问 编辑:程序博客网 时间:2024/06/06 17:03

Sublime Text是一款强大的文本编辑器,在不注册的情况下也可以使用,但标题栏的未注册字样与时不时弹出的nag窗口有时也让人感觉很不爽,于是尝试对其注册过程进行分析与破解。

这里分析的是Sublime 3126 Win32版本,目前已有更新的版本(3143版本)。这里选择分析旧版本,一方面是因为旧版本的注册逻辑相对更加清晰,并且由旧到新的分析过程中也更容易观察到Sublime的作者在注册逻辑上的一些完善。

目前我已经完成了Sublime 3143 Win32版本的破解,正在整理形成笔记,完工后即与大家分享。届时会在本帖此处增加一个链接。目前先占坑。

前戏

正所谓知己知彼,百战不殆。在正式开始分析前,先用ExeInfoPE看看对手的信息:
这里写图片描述
看到了VC2012版本的库文件和python引擎,估计核心部分是用C/C++写的,扩展功能用Python写的。
这里写图片描述
分析的时候有一点比较有趣,作者应该是直接发布了VC2012生成的Release版本程序,IDA提示exe中附带了pdb信息,从中可以看出作者开发环境所用的用户名和项目路径。

第一次尝试

在帮助菜单中选择输入注册码,随意输入一串东东,弹出错误对话框。
这时候用OD断下来,发现是调用了MessageBoxW弹的框。于是栈回溯找到了调用位置,好的开端是成功的一半!
这里写图片描述
回溯到函数入口,发现这是一个_fastcall约定的函数,仅仅是对MessageBoxW的Wrapper,可能是作者使用的框架的函数。
这里写图片描述
于是继续回溯,来到了一个switch-case。借助IDA可以看出在case 2中设置了报错信息:
这里写图片描述
下面看看判断逻辑:
这里写图片描述
这里信息量略大,咱们一件件的看:

  1. 负责校验注册码的函数已在IDA中被我改名为CheckKey了,如果序列号正确,则该函数应返回1。
  2. Sublime 3126版本是通过一个全局变量来标识是否注册的。已注册该值为1,未注册时该值为0。
  3. 注册完成后还会将注册信息发送通过网络发送到作者指定的地址(通过创建新线程搞的),这里我们将其放到下个步骤中搞定。

因此,找到负责验证序列号的函数修改其返回值为1即可:
这里写图片描述
完成后保存修改,OD提示我们改动的地方有重定位项:
这里写图片描述
应该是第一行的全局变量地址坏事了,毕竟Vista以后的系统就有ASLR机制了,为了保险起见,我们在下一行修改:
这里写图片描述
完成后运行保存的程序,在注册窗口输入任意注册码,测试OK:
这里写图片描述
然而,我们似乎高兴的有些太早了。上述过程完成了注册破解,但程序重新运行后又变成了未注册版,需要再次手工输入任意注册号注册。看来我们的破解并不彻底。革命尚未成功,咱们仍需努力啊!

第二次尝试

Sublime未注册版在保存多次后会弹出nag窗口提示用户购买,我们以此为突破口:
这里写图片描述
用OD将程序断下:
这里写图片描述
在程序领空下一条语句设置断点,运行并点击确定后程序被断下,运行到返回,主调者为0x00586083,仍然是一个Wrapper,故伎重演,发现主调者为0x004E2B02。来看看它的判据:
这里写图片描述
我们又看到了全局变量bIsValidKey的身影,下面用OD重新加载程序,并对该地址下全局写入断点。从这里可以看出,其值必须为非0才行(从上一小节可知,其值最好为1)
第一次断下,该变量值为1,且是因为运行了我们修改的函数(下图中OD的内存窗口即为断下时全局注册标志的值)
这里写图片描述
第二次断下,该值变为了0,但是上面也运行了我们修改的函数(下图中OD的内存窗口即为断下时全局注册标志的值)
这里写图片描述
来看看原因:

004BA039      E8 97820200   call sublime_.004E22D5004BA03E  |.  48            dec eax004BA03F  |.  59            pop ecx                                  ;  sublime_.0071C0BC004BA040  |.  F7D8          neg eax004BA042  |.  59            pop ecx                                  ;  sublime_.0071C0BC004BA043  |.  1AC0          sbb al,al004BA045      2005 D56F7D00 and byte ptr ds:[0x7D6FD5],al

我们修改了注册校验函数,让其返回1,结果这里正中下怀了,经过这段运算,把全局注册标志用逻辑与给弄成了0。
怎么会弄成了0了呢?用IDA看看:
这里写图片描述
哇,还有这种操作?!很明显传入三个0是一种异常情况,此时原函数应该返回0,而经过上述一系列运算最后全局注册标志不会被改。
为此,可选如下操作:

  1. 将and操作改为or操作(不影响对全局变量的重定位)
  2. 修改注册函数代码,增加传入参数的校验并在对应情况返回0

我们两处都改改,双管齐下:
首先把判断处的and改为or逻辑,这样不影响原来的重定位过程
这里写图片描述
然后把秘钥校验函数改一下,如果edx传入0则返回0
这里写图片描述
修改后保存并验证,通过!

去除网络上报与新版本检查功能

至此,我们已经完成了破解工作。但之前在分析注册流程时,曾发现Sublime开了一个线程对注册信息进行上报。
并且我们在对全局标志位下访问断点进行分析时,曾用IDA发现其中附近有在判断已注册的情况下通过Internet向作者搭建的服务器发送包含序列号经过运算的版本信息。
为了“不打扰作者,也不被作者打扰”,我们还是将这些功能干掉为好。

干掉注册上报功能:

先废掉线程函数:
这里写图片描述
再把创建线程相关代码也废掉:
这里写图片描述

去除版本检查功能

在InternetOpenW处下断点,运行程序,断下后回溯到函数头,直接将其改为ret即可(该函数有多条调用路径):
这里写图片描述

点滴积累:neg与sbb的连用

这次破解中印象最深的莫过于作者在Key验证函数上动的手脚了。当传入全0参数时,该函数应该返回0,而非表示注册成功的1。这在一开始是我们没有料到的。其下的判0操作也很有意思。
通常判零采用的是cmp或者test指令,然后接一条条件跳转指令,如果我们仅仅需要根据结果设置一个标志的逻辑值,则不需要这么麻烦,可以采用neg与sbb连用代替上述过程。现在考虑如下代码:

neg eaxsbb eax, eax

neg是取补码中的相反数的指令,作用相当于0-参与运算的数,因此会根据参与运算的数设置CF位。如果参与运算的数非0,肯定会产生借位,故CF为1;如果参与运算的数为0,则0-0为0不产生借位。
sbb是带借位的减法,用eax减去eax结果为0,但如果借位标志置位,结果必然是-1即0xFFFFFFFF,否则为0。因此可以据此得到不同的结果。如果eax为0,则进行上述操作后eax仍然为0。如果eax非0,则进行上述操作后eax值为-1。再配合算数后逻辑运算即可得到其他值,从而避免了条件跳转语句的使用。

原创粉丝点击