XShell 6评估版逆向分析
1. 引言
XShell作为一个强大的SSH连接工具,一直深受我喜爱。某天,我突然发现自己的XShell不能用了,就像下面这样:
XShell分为个人版和企业版,个人版是永久免费的,而企业版则需要购买。个人版与企业版的区别在于:个人版的窗口标签页被限制为4个,其余的与企业版差别不大。而我当时不知道有个人版,一直用的都是评估版,评估版是有期限的,只能用31天,于是就诞生了这篇文章。
2. 测试环境和工具
- 测试环境: Windows7 32位
- 使用工具:
- OllyDbg、火绒剑、010Editor、Resource Hacker、IDA Pro等等
3. 初步猜测分析
逆向一个软件之前,需要先猜测需要逆向的功能是如何写出来的,这样在逆向的时候将会事半功倍。这个软件我的猜测是这样的:
- 创建窗口/对话框:这个是肯定的,毕竟也有个到期窗口嘛
- 检查了时间:这里就不确定是本地检查还是联网检查,需要进一步分析
- 设置窗口标题:这个可能会设置,也可能对话框本身自己就有名称
- 程序是否有反调试/加壳:这个需要第一时间检查
4. 正式分析
根据以上的猜测,开始进行正式分析。
4.1 检查程序是否存在反调试/加壳
第一件事就是检查程序是否有加壳、是否存在反调试,这样才有继续下去的可能性。
检查是否被加壳: PEiD查看主程序
从上面可以看到,能识别出来是
VC6.0
编译的(但是链接器版本是11.0
,可能是VS2012
编译的,毕竟VC也太老了点),而且区段很正常,很明显没有加壳检查是否有反调试: 用无插件的OD和x64Dbg打开程序
这里用无插件OD和x64Dbg都能发现程序存在反调试,虽然用吾爱破解OD可以反反调试,不过这里抱着学习的态度,来找找这个反调试:
首先在关键API上下断,我这里先在
IsDebuggerPresent
下断,发现是可以断下来的:接下来让程序跑起来可以发现,
IsDebuggerPresent
这个函数被执行了很多次,需要找到关键的位置,这里的思路是在ExitProcess
函数下断,然后栈回溯:这里程序是在
RtlExitUserProcess
函数断下来的,需要注意!!!通过分析
RtlExitUserProcess
的栈回溯,找到了执行关键函数的地方,是在NsActivate_libFNP.dll
这个模块中,如下图:从上图可以看出:执行
RtlExitUserProcess
的关键函数是0x66811264
这个函数,而执行0x66811264
这个函数的地址是0x6683C342
既然找到了关键地址,那么就来分析这个地址附近的内容,分析如下:
关键就是
EAX
与ESI
必须相等,否则就退出程序我这里的目的只是为了让程序不退出,方便调试,所以我没有去具体分析
ESI
的值怎么来的等等,感兴趣的可以自行去分析一波。我这里将CALL EAX
函数中的内容给改了,使EAX = ESI
,然后Dump
之后替换文件就可以过掉反调试了,修改如下:这里需要注意一点:当替换了文件之后,运行程序可能会报如下错误,这里并不影响程序执行流程,所以可以忽略
这里要说明一下的是,用吾爱破解OD
是可以直接过掉这个反调试的,所以接下来我都是使用的吾爱破解OD
4.2 分析创建窗口/对话框
过掉反调试之后,就可以正式开始分析程序了。 逆向破解软件,从能看见的窗口入手,然后往回推是最快的方法。
首先在所有创建窗口/对话框的API上下断,断下来之后观察栈传递的参数,例如下面这样:
可以通过观察窗口的类名、名称和回调函数来确定是不是要寻找的窗口。但在这里,如果你使用的是
吾爱破解OD
的插件设置的API
断点的话,那基本上是找不到到期窗口是在哪里被创建的。因为吾爱破解OD
的这个插件是这样的:这个插件可以快捷的设置
API
断点,但这里你把所有的创建窗口/对话框的API
都勾上确定之后,的确很多API
上都能被设置上断点,可唯独DialogBoxIndirectParam(A/W)
这个API
没有设置上断点,而恰恰这个到期窗口就是使用这个API
创建的对话框(不要问我为什么知道,我也是调试了很久才找到这个原因的),所以还是手动设置这些API
的断点吧。这里以
DialogBoxIndirectParam(A/W)
被设置上断点为基础,发现被调用了一次之后,到期窗口显示出来,那么可以怀疑这次调用就是创建到期窗口,那么可以详细分析,先观察其调用时参数:对话框的名称和类都是看不到的,但是可以看到一个对话框的回调函数
10001C60
,这里可以跟进去看看,就能发现这个回调函数就是到期窗口的回调函数,在这个窗口中设置了窗口的标题,也就是最初猜测的第三点,通过在SetWindowTextA/W
下断点有时也能找到一些东西,如下:既然找到了关键创建窗口的位置,那么就可以栈回溯,找到创建窗口的位置,如下:
通过分析,
10001000
这个函数是调用DialogBoxIndirectParamW
的主要函数,而调用10001000
函数的位置是10003F88
,也就是说10003F88
才是关键需要分析的位置,10003F88
所在位置的代码如下:从上面可以看到,
10003F88
这个位置的执行是从某个地方跳转过来的,也就是上面某个位置跳转到了10003F6E
这个地方,然后紧接着执行了10001000
这个函数,随后创建了到期窗口。通过OD可以查看到是哪里跳转到了10003F6E
这里来的,如下:从上面可以看到,
10003F07
和10003F21
是跳转的位置,可以直接下断点到这两个地方,然后修改寄存器的值,就可以测试出,只要10003F21
不跳转,那么就不会提示到期,然后NOP
掉这里程序也就不会提示到期了,就像这样:可以看到已经不会提示到期了,这时就可以
Dump
下来,然后替换文件就实现了永久不到期的功能了,这里调用的模块是nslicens
,所对应的模块是XShell安装目录下的nslicens.dll
:上面是动态分析的结果,其实找到关键点之后,通过
IDA
很快就能看出逻辑:而
10001000
这个函数中是这样的:可以看到
资源ID
为103
,通过Resource Hacker
查看资源:
4.3 通过时间分析
上面是基于窗口分析的,是最快的方法。但是我因为最开始DialogBoxIndirectParamW
没下上断点,所以我是通过时间分析找到关键点的。
首先要通过时间分析,需要知道它是判断的本地时间还是网络时间,先用本地时间做做测试:
可以看到的确是判断的本地时间,也就是说如果不进行逆向,直接修改时间也能达到永久不到期的效果。
接下来就要分析它是在哪判断的时间了。需要在
GetLocalTime
下断点。这里有一点和上面有点类似,就是与创建窗口/对话框的API
一样,可能这个GetLocalTime
会被执行很多次,所以需要找到创建到期窗口之前
的那次GetLocalTime
。我这里分析的时候是第4
次执行GetLocalTime
时到了关键位置,这时的栈回溯是这样的:可以看到
OD
帮忙显示了一些很关键的信息,也就是nslicens
这个模块中的导出函数名
,而这几个函数名很可疑:CheckLicenseAndPackage
、CheckLicense
、GetCurrentDate
,很明显就是获取当前时间并检查许可证从上面可以看到,
10003E24
这个位置获取了当前时间,然后就可以从这个位置开始着手分析,我这里使用的是对比的方法分析的,也就是先把时间改成未到期的时间,观察其跳转,然后再把时间改成到期的时间,再观察其跳转,就能很快找到关键判断位置。我的最后分析如下:可以看到第二个判断的位置,也就是10003F21
的位置,就是上面通过查找窗口的方式找到的关键跳转位置,所以接下来的事情就不用多说了
5. END
这次分析算是第一个独立分析破解的程序,中途遇到的坑比这写的多了去了。例如第一个对话框API的坑,我连对话框的回调函数都找到了,就是找不到在哪创建的对话框,导致浪费了很长的时间。还有分析时间的时候,因为调用了很多次GetLocalTime
,我开始没有想到分析创建窗口之前的那个GetLocalTime
,所以我从第一个开始分析的,结果发现前面的根本没鸟用,本来一两个小时就能搞完的东西,导致搞了一整天,这也是经验太少了,这次还是增长了不少快速分析的经验。
最后:
[1] 软件版本: