不少收费的前端组件一般通过添加水印来干扰使用,下面我们演示破解SpreadJS水印做示范【注:破解方法仅用于学习用途不能用于商业】。 我们随便在官网找一个页面比如:https://demo.grapecity.com.cn/spreadjs/SpreadJSTutorial/showcase/expense-budget/purejs很明显在Excel中有官方水印,如下图所示:

或许有些小伙伴觉得这还不简单吗?直接保存网页然后去搜索以下关键字不就可以了吗?好吧,我们姑且就这样试试吧。
查找关键字“西安葡萄”,很遗憾没有找到。那肯定是汉字一个一个用字符串拼接出来的,有些小伙伴不屑地说到。对,确实有可能,那我们搜关键字“版”吧,结果还是没有。
那会不会是个图片,或者是从接口中获取数据填充的呢?不错,确实会可能存在这个情况。但是too young too simple,如果真的是那样简单的话,岂不换个图片路径或者修改下接口中的数据岂不轻轻松松破解了。对字符编码有比较了解的小伙伴,肯定想到了unicode编码,拿“中国”来说,就是u4e2du56fd,16进制;葡萄就是u8461u8404。
用16进制搜,很可惜还是搜不到。还记得我在上一篇常用的字符编码与那些特殊的字符提到的代码点吗?对,其实还有一种unicode代码点与字符对应的关系。 JS的API就是String.fromCharCode,它可以将代码点直接转成字符。String.fromCharCode(20013,22269) 就是“中国”。那我们岂不在文件中直接搜水印上的代码点就可以了?
其实js作为脚本语言,它特别的灵活。比如同一种结果有多种呈现方式:String.fromCharCode(20013);中,可以写成String.fromCharCode('2'+'0'+'0'+'1'+'3');也可以在上下文定义$=String.fromCharCode;$(20000+13);还可以eval('Str'+'ing'+'.' + 'from'+'Char'+'Code('+ 0b100111000101101 +')');等各种骚写法。
如果再用各种变量以及关联上下文,简直防不胜防呀。庆幸的是我们在gc.spread.sheets.all.min.js中找到String.fromCharCode。将js下载下来并格式化,并把所有String.fromCharCode有可能转换水印的文字后面添加打印输出,类似如下:
然后用ReRes【一款可以替换资源的浏览器插件,具体可自行百度】浏览器插件配置以下匹配规则(注:谷歌浏览器版本越高安全越越来越严格,半年前我还可以用https引用本地资源,现在不行)。
将下载的js重命名成mytest.js并上传到可以支持https的服务器上,然后重新访问https://demo.grapecity.com.cn/spreadjs/SpreadJSTutorial/showcase/expense-budget/purejs或者刷新,此时我们在控制台上很清晰的看到了水印上的文案:
水印文字的转换代码就在4400行中。由于该function I是通用方法,因此我们判断下是否为水印文字,然后重新上传到服务器上,刷新重试,最后的效果如下:
大功告成,终于破解成功!
目标虽然达到了,但是还是有两个问题尚未解决:1. 水印文字到底是如何生成的?2. 如何快速定位到目标位置?那我们就解决第一个问题,我们按照以下操作来进行调试:
通过观察变量,再根据函数分析得出:编码规则就是从数组a[0]取两个字符并与a[1]两个字符拼接,然后将这种16进制的字符转成十进制的代码点,然后根据代码点来得到字符。那我们就取数组的前五个字符做测试,效果如下:
这个结果也与官方水印的前5个字符是一致的,这也难怪为什么我们直接搜葡的16进制搜不到的原因:它将汉字的16进制分在两个数组中。
通过ca函数,我们发现这个数组是从另一个js文件中定义的。也就是说我们只要修改该js定义的ls6的值就可以控制水印上的文字。以上方法只是取巧的方式,毕竟我们是通过关键词String.fromCharCode每一处进行打印来查找对应位置,如果用eval('Str'+'ing'+'.' + 'from'+'Char'+'Code('+ 0b100111000101101 +')');在加上上下文方式,是无法搜索关键词的。而且如果是英文的水印则完全不需用该API来转换。那我们继续按部就班地分析第二个问题吧,调试方式如下:
通过分析我们知道是个canvas,可惜先根据id:ssvp未能搜到,我们换样式名gcWorksheetCanvas再此搜索,很开心找到了,那我们打个断点刷新下进行快速调试(按F10)。
打断点只能靠经验了,找到调试前与调试后出现水印的那一行比如第一次第5016行,然后第二次直接从5016行可以进行断点按F11进入调试,最终找到关键行5055的k值为水印值。我们用inspect(d.e6)找到了ca函数与上面对应,也即找到了关键位置。【注:调试找关键位置需要耐心多刷新几次,找到上一行与下一行有水印变化行】


还没有评论,来说两句吧...