整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

轻松解除网页被限制复制功能

轻松解除网页被限制复制功能

你想复制网页上的内容时发现鼠标不能选中文字,点击鼠标右键菜单也没有弹出来。不是你的鼠标坏了,是网页使用了一点“魔法”,限制你这么做。那我们就用魔法打败魔法,解除它的限制功能。

方法一:

很简单,只需要在限制的页面浏览器地址栏中输入以下魔法并按回车:

javascript:(function(){eval(function(p,a,c,k,e,r){e=function(c){return(c<a?%27%27:e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!%27%27.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return%27\w+%27};c=1};while(c--)if(k[c])p=p.replace(new RegExp(%27\b%27+e(c)+%27\b%27,%27g%27),k[c]);return p}(%275 2=8;5 3=2.K;3.7=3.k=3.e=3.9=3.6=3.y=3.7=3.z=2.7=2.k=2.e=2.9=2.6=4;2.7=2.6=2.c=2.9=p(){r t};g(8.n||8){d=4;c=4;6=4}5 a=8.15(\%27*\%27);o(5 i=a.q-1;i>=0;i--){5 b=a[i];g(b.n||b){d=4;c=4}}s(h(\%27%u%v%w%x%j%17%A%B%C%j%D\%27)+\%27\E\%27+h(\%27%F%G%H%I%J%l%L%l%M%N%O%P%Q%R%S%T%U%V%W%X%Y\%27)+\%27\Z.10.11\%27);3.m.13=\%2714!f\%27;3.m.16=\%2712!f\%27;%27,62,70,%27||doc|bd|null|var|oncontextmenu|onselectstart|document|onkeydown|arAllElements|elmOne|onmousedown|onmouseup|onpaste|important|with|unescape||u5236|oncopy|u7528|style|wrappedJSObject|for|function|length|return|alert|true|u5DF2|u89E3|u9664|u590D|onmousemove|ondragstart|u53F3|u952E|u9650|uFF01|u000d|u66F4|u591A|u7CBE|u5F69|u5B9E|body|u5e94|uFF0C|u8BF7|u5173|u6CE8|u3010|u516c|u4f17|u53f7|uff1a|u8bba|u79d1|u6280|u3011|u000dwww|lunkeji|com|text|webkitUserSelect|auto|getElementsByTagName|MozUserSelect|u4E0E%27.split(%27|%27),0,{}))})()

如果出现一个弹窗那说明已经施放了魔法,如果没有弹窗而是浏览器开始搜索这个魔法,应该是被浏览器限制了。

这时还有一个办法,如果是chrome浏览器,浏览器任何网页,在浏览器地址栏右边有一个收藏按钮

,点击把这个页面收藏起来。网页会保存在一个文件夹中,点击该文件夹名称就可以修改收藏的书签。

把上面的代码复制粘贴到网址中,名称修改为解除限制。

以后再遇到限制的网页就点击“解除限制”书签就可以解除网页的右键限制了。点击鼠标右键,熟悉的鼠标右键菜单就又出现了。

其它浏览器也是类似的操作,把解除限制的js代码保存为书签就可以了。

这招对绝大多数网站是有效的,但是有一些网站升级了他们的魔法技能,解除限制又失效了。

这时我拿出了一个大杀器

方法二:

这个大大杀器本来是同步自媒体文章用的,能实现文章一键同步到你其它平台自媒体账号,发文章省时省力,对付一个限制复制功能轻而易举。

这是一款开源的chrome插件:文章同步助手,下载链接放在评论区,如果被删可以发私信获取。

安装后在限制的网页中点击鼠标右键在弹出的菜单中选择“提取文章并同步

它就会把文章全部复制在一个新页面,在这个新页面所有被限制的功能都被解除了。

如果还被限制,那就使出最后一招,OCT文字提取。

方法三:

按键盘上的“PrintScreen”把屏幕抓取成图片,然后把图片发到你的微信文件助手,浏览图片,鼠标放在文字上就可以选中文字,复制这些文字就可以了。

前一段时间在折腾拆分 rc 的问题,已经把遇到的问题整理成文了。感兴趣的小伙伴儿可以参考这里,这里 和 这里。本以为不会有问题了,后续流程就请其它同事帮忙处理了,没想到在拆分实际项目时遇到了一个非常奇怪的链接问题。

本文总结了使用 process monitor 监听进程创建,查看进程参数、使用 gflags 设置 Image File Excution Options、使用 IDA 静态分析相关函数的业务逻辑以及使用 windbg 进行动态调试的整个过程。我认为这是一个由不良的编程习惯与 crt 的限制共同导致的问题。快来一起看看吧。

初闻错误

前些日子,在家隔离办公的某日中午,收到同事发来的信息说 rc 拆分的编译问题已经解决了,但是遇到了链接错误,还发送了链接错误的截图,并且给出了一个解决方案。

尝试把 .rc 文件排除几十个就链接过去了。

听到这个问题的时候,我怀疑是不是哪里操作有问题。从错误提示看是 无法打开 xxx.res 进行读取,所以第一感觉是文件路径不对。于是赶紧跟同事聊了一下,同事觉得是 vs 的限制,可能这个限制数量是 512

但是我从没听过同一个工程中的 .rc 文件有数量限制,不管怎样,还是建个简单的工程验证下吧。

尝试重现

带着怀疑 + 好奇的心态,我快速新建了一个 MFC 对话框工程。然后在 vs 中不断复制默认对话框(大概复制了600 个,已经比同事所说的 512 上限要多了,如果有问题应该能重现了),然后使用工具把每个对话框拆分成独立的 .rc 文件并添加到工程文件中。保存好工程后,开始编译。等待一段时间后,果然报错了,错误截图如下:

从错误提示看,处理 dialog_testmultiplerccompile_dialog507.rc 文件的时候报错了。按照同事说的,删除若干个 .rc 文件,只保留 500 个,再次编译,没有报错。

看来,在同一个工程中包含太多 .rc 文件真可能有问题。难道真有限制?为什么会做这种限制呢?不管为什么要做限制,我需要找到一个解决方案。

开始深入调查前,先看看报错信息。

熟悉的错误

之前遇到过错误 LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏,是由于 link.execvtres.exe 的版本不一样导致的。这次报错不是这个原因。通过 process monitor 看,这两个程序的路径是一样的。

再看错误 error CVT1101: 无法打开“dialog_testmultiplerccompile_dialog507.res”进行读取。猜测是在读取这个文件的时候发生了错误,可以在 process monitor 中查看相关事件。

过滤相关事件

process monitor 中根据路径名进行过滤。如果路径以 dialog_testmultiplerccompile_dialog507.res 结尾则包含,如下图:

没想到一条记录都没有,一片空白。这是怎么回事?说实话,我有点不知所措,看来只能硬着头皮调试 + 用 IDA 逆向了。在调试之前,先用 IDA 看看有没有什么发现。

请出 IDA

使用 ida32 打开 cvtres.exeIDA 会提示是否查找符号(真是一个好消息),当然选择是。等待 IDA 分析完成后,在左侧的 Function window 中找到 _main,双击查看反汇编代码,直接在反汇编窗口按 F5,查看伪代码( IDAF5 真香!)。

大概浏览后,基本明白了 main() 函数的整体流程。首先,解析传入的参数,确定第一个文件在参数列表中的索引位置。然后,从此索引开始循环调用 ReadResFile() 读取每个文件,读取完所有的文件后统一调用 CvtRes() 函数进行转换。

下图是在 IDA 中对 main() 函数使用 F5 获得的伪代码的后半部分。

其中的 CvtRes() 函数应该是转换的主要函数,非常值得怀疑。迫不及待的启动 windbg 准备调试,但是 cvtres.exe 是被 link.exe 调用的,该如何调试呢?

搭建调试环境

如果 cvtres.exe 启动的时候,能够自动中断到调试器中,就可以方便的调试了。之前在 全局变量初始化顺序探究 中介绍过使用 gflags 进行设置的方法。

根据之前调试 cl.exe 的经验,如果长时间中断到调试器中,调用者会重新启动 cl.exe。猜想这里也会有类似的逻辑。为了避免这种问题,需要根据 link.exe 启动 cvtres.exe 的参数手动运行 cvtres.exe

可以通过 process monitor 很快找出 cvtres.exe 需要的参数。经过简单观察,发现传递给 cvtres.exe 的参数比较简单直接,而且根据 cvtres.exe /? 提供的帮助信息,可以很快确定各个参数的意义。

于是很快写出了一个批处理脚本,如下图:

没想到,双击脚本运行的时候,出现了如下错误:

提示找不到 cvtres.exe。看来需要使用完整路径。正确的脚本如下:

说明: 为了避免命令行参数过长,我特意简化了 .res 文件名,之前的名字太长了。而且经过测试,打开 510.res 的时候就能重现,没必要准备 600 多个 .res 进行测试,这里只准备了 511.res 文件进行测试。

猜错了

双击脚本启动 cvtres.exe,立刻就中断到了 windbg 中。

windbg 中执行 x cvtres!*main 即可找到入口函数,输入 bp cvtres!wmain 即可在 wmain() 函数入口处设置好断点。

同理,执行 x cvtres!*CvtRes 即可找到 cvtres!CvtRes() 函数,输入 bp cvtres!CvtRes 即可在 CvtRes() 函数入口处设置好断点。

设置好断点后,输入 g 让程序跑起来,可以发现 wmain() 函数内的断点命中了,但是 CvtRes() 函数内的断点并没有命中,进程直接退出了。

有些出乎意料,居然不是在 CvtRes() 函数里出的错。没(有)关(点)系(懵),继续挖掘有效信息。

继续努力

虽然进程退出了,但是依然可以通过 k 系列命令查看调用栈,在 windbg 中输入 kp,如下图:

上图中红色高亮部分就是关键调用栈。从上图还可以得到一个非常有用的信息 —— exit code 的值是 1。可以猜测,link.exe 就是根据 cvtres.exe 的返回值来判断其是否执行成功的。

调用栈中的 OurFileOpen() 函数,应该是负责打开文件的函数。在继续调试之前,先在 IDA 中看看 OurFileOpen() 函数的实现。

回到 IDA

双击 OurFileOpen,当然是直接查看 F5 的结果啦,有细节需要确认再看反汇编代码。

可以看到这个函数实现的非常简单,就是调用 _wfsopen(),如果失败(result==0)那么调用 ErrorPrint() 打印错误信息。如果 open_mode(第二个参数)是 0,那么传递给 ErrorPrint() 的第一个参数是 1101,否则是 1108

而调用 OurFileOpen 时传递的第二个参数是通过 edx 传递的,对应的值是 0,所以如果出错,那么会传递 1101

说实话,看到 OurOpenFile() 函数中的 1101 ,我太激动了,因为在vs 中看到的错误提示是 error CVT1101: 无法打开“xxx.res”进行读取。为了进一步确认猜想,在 IDA 中查看 ErrorPrint() 函数的反汇编代码,如下图:

从上方红色高亮语句 CVTRES: fatal error CVT%04u: 基本可以确定猜测是正确的。从上图底部的红色高亮区域还可以知道该函数内部确实会调用 exit(1) 来结束进程。

接下来需要调查的问题是 _wfsopen 为什么失败了?

为什么 _wfsopen 会失败?

windbg 中输入 .restart 重启目标程序,输入 bp MSVCR120!_wfsopen,然后执行 g 命令。因为已经设置好了符号查找路径,所以 windbg 自动打开了对应的源码文件。

这个函数虽然很简单,加上注释不到 50 行。但是会被调用很多次,根据经验,前面的 500 多次调用都没有问题,在尝试打开 510.res 的时候会有问题,所以设置一个条件断点非常有必要。

简单查看反汇编代码发现,_wfsopen() 函数的第一个参数是通过 ecx 传递的,可以设置如下的条件断点(真是烧脑还不好理解,我不会告诉你,我尝试了很久才写出了下面这段蹩脚的脚本):

bp MSVCR120!_wfsopen "aS /mu $myFileName @ecx; .block {.echo $myFileName; r @$t0=$spat(@\"$myFileName\", @\"*510.res\"); .if(1==$t0){.echo **** bang ****} .else{ gc;} };"

耐心等待一会就中断下来了,如下图:

单步走两步,发现是 _getstream() 出错了。

_getstream 错在哪里了?

输入 .restart 重启目标程序,并且设置好条件断点,重新运行程序,当中断到 _wfsopen() 函数后,单步步入到 _getstream() 函数中。

可以看到 _getstream() 函数逻辑也不复杂,根据注释可以很简单的理解此函数的逻辑 —— 从 __piob 中(大小是 _nstream,通过 dt _nstream 可知其大小是 512)找到一条可用的记录项。判断一条记录项是否可用的标准是 __piob[i]==NULL ,或者 !inuse( (FILE *)__piob[i] ) && !str_locked( (FILE *)__piob[i] )

直接在函数末尾加好断点,g 起来,发现确实没有找到一条可用的记录项。

至此,我大概明白了整个过程。cvtres.exemain() 函数中会循环调用 ReadResFile() 函数(内部会调用 _wfsopen())读取所有的 .res 文件,但是读取完一个 .res 文件后,并没有关闭,当打开一定数量的文件后会导致 __piob 被占满。再尝试打开一个文件的时候就报错了。

看来,crt 还有最大打开文件数的限制,赶紧 google 搜索是否有什么设置可以调整最大文件打开数量。

google 一下

google 中输入 crt max open file 找到了几个相关的网址。

虽然可以通过 _setmaxstdio() 调整 crt 的最大文件打开数,但是好像不能通过修改配置文件或者修改注册表的方式调整。

发帖询问

说实话,第一次分析到这个结果的时候我是有些不信的。于是我再三确认了 ReadResFile() 函数内部确实没有关闭文件的操作。难道有什么特殊的理由不关闭打开的文件?但是我实在想不出有什么理由。所以我觉得这是一个 bug,于是我在微软官方论坛上发了一个帖子,希望能得到一些回复。

帖子地址是 https://docs.microsoft.com/en-us/answers/questions/709392/cvt1101-can39t-open-xxxres-for-reading.html

目前只有一位网友回复(另外一个是我自己),为了方便大家阅读,截图如下:

虽然到现在还没收到官方的确认回复,不过我依然认为这是一个 bug,而不是 feature

解决方案

既然没有设置选项或者配置文件可以简单的调整最大文件打开数量,对 cvtres.exe 打补丁又不太现实(每台机器上都要做处理),等待微软修复这个问题也不现实(远水解不了近渴)。所以我们的解决方案是通过合并一些 .rc 以减少工程中的 .rc 文件数量来规避这个问题。

虽然问题已经调查清楚了,但是还有几个问题值得探究。

几个值得深究的问题

  1. 为什么链接的时候需要调用 cvtres.exe 呢?
  2. 有没有更好的设置条件断点的方式?目前的语法实在是太难用了。
  3. 有什么简单的办法可以查看 __piob 数组中元素的内容吗?
  4. 为什么在打开 510.res 的时候就报错了?应该可以打开 512 个文件才对?

由于本篇已经太长了,下一篇文章中继续把残留的这几个问题解答。

总结

  • crt 有最大打开文件数的限制,可以通过 _setmaxstdio() 进行调整。
  • 在一个工程中最好不要同时包含太多 .rc 文件,一般应该不会遇到我遇到的这种情况。
  • 在不需要使用文件的时候,一定要及时关闭。
  • 进程退出后,依然可以使用 k 系列命令查看调用栈,有时候可以快速定位进程退出的原因。

参考资料

https://stackoverflow.com/questions/61581826/visual-studio-2019-cvt1101-lnk1123-fatal-error

https://docs.microsoft.com/en-us/cpp/build/reference/dot-res-files-as-linker-input?view=msvc-170

https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/setmaxstdio?view=msvc-170

vs2013 自带的 crt 源码

信大家都遇到过这样的情况,在网上查找资料,好不容易找到却不能复制,其实这是因为网页中有限制复制的代码~

蓝瘦,心碎一地!

不要担心,跟着小予快速解决这个小问题,而且还很简单!

方法一:打印输出

这个方法非常简单,按住组合键【Ctrl+P】,打印网页的界面就会弹出,打印预览界面是没有复制限制的,按住快捷键ctrl+C就可以快速复制自己想要的文字啦,超级方便!

值得注意的是:该方法只适合预览内容不是很长的,内容过长则该方法就不是很适用了哦

方法二:代码解除

找到无法复制内容的网页,在浏览器地址栏中输入代码:javascript:void($={} 再按回车键就能轻松复制了哦!

注意:必须手动输入,复制粘贴无效,符号都是英文格式

方法三:审查元素复制

这也是个超easy的小方法,网页空白处右击鼠标,点击【审查元素】

进入审查元素页面之后,点击【网络】之后点击【文档】,然后按F5刷新,下面就会出现一个.html链接

点击.html链接,文档内容就会清晰展现在旁边,按需选择按住快捷键进行复制即可

方法四:截图识别复制

截图识别是一个一定能行的方法,这款迅捷ocr文字识别软件不仅可以实现多图识别及多栏文字图片识别,还可以实现长图拍照识字、表格识别、照片扫描、卡证扫描等

识别速度快的同时准确率还很高,即使是在光线较差或是图片文字潦草的情况下也都能帮我识别出来,来从我自身实测来看没有任何错误,爱了爱了~

在左侧菜单栏中可根据自己需要选择服务,如选择的是【批量识别】,添加文件后,等待几秒,就全部识别完成啦,识别结果支持DOCX、DOC、TXT三种格式!

有了这四个快速复制网站文字的方法,再也不担心网页限制复制代码了,随心复制文字,啦噜~

以上就是今天的分享,码字不易,别忘了点赞收藏后再走哟~