最近又发现一个很有意思的特性,和 iframe 相关。
iframe 是在 HTML 页面里用来嵌入其它页面的,它有个 contentWindow 属性,会和当前页面的 window 不一样。写一段测试代码看看就知道了:
1 2 3 4 5 6 7
a = document.createElement ('iframe' ) document.body .appendChild (a) console.log (a.contentWindow != window) console.log (a.contentWindow.console != window.console) b = document.createElement ('iframe' ) document.body .appendChild (b) console.log (a.contentWindow != b.contentWindow)
在浏览器里,上面三个判断都输出 true,这就说明 iframe 里的 window 和当前页面的 window 是独立的。
如果
《console.table 用来检测浏览器自动化》
这篇文章里提到的 console.table 是从 iframe 里取的,那么直接修改 console.table 的方法就会失效——因为改的是当前页面里的 console.table,没法直接修改 iframe 里的 console.table。
如果代码是静态的还好处理:等创建好 iframe 后,再修改里面的 console.table。但如果是动态的,那就麻烦了,得再去想办法修改 iframe 里的 console.table。
在之前文章
听说你Selenium和Playwright自动化无敌,来试试这两个站点吧
里,我们说过 Selenium 和 Playwright 会被重定向到空白页,于是就研究了下,发现都无法打开开发者工具,这让我想到 disable-devtool,在
解决disable-devtool控制台反调试
里我们就有研究过这个库。从浏览器设置里,强制打开开发者工具,在 console 里看到好多日志,确定是 disable-devtool。于是大胆猜测,是因为 disable-devtool 导致浏览器自动化重定向了,即便没有打开开发者工具。
在本地写了个测试页面, 测试代码见
https://github.com/dengshilong/js_reverse/blob/main/disable_devtool/test.html,用浏览器自动化去访问,果然会被重定向到空白页面。于是就去排查disable-devtool,总共就几种测试类型,那就一种一种测试下。当测试到
Performance 类型时,发现浏览器自动化会重定向到空白页。看了下代码,找到最终原因 console.table。
在没有打开开发者工具时,浏览器自动化 console.table 输出大对象时也耗时很久,和打开开发者工具时一样,所以就被判定为打开开发者工具,会被重定向。而正常浏览器在没有打开开发者工具时,console.table 输出大对象耗时很短。原因找到了,剩下的就好办了。
我想这就是纯纯的误伤了,disable-devtool 本意是用来检测用户打开开发者工具的,没想到把自动化工具也检测出来了。不过这确实可以作为检测自动化工具的一个因素,一旦发现console.table耗时很长,是自动化爬虫的可能就很高。
那么问题来了,为什么同样是自动化工具,在没有打开开发者工具时,Selenium 和 Playwright 执行 console.table 耗时很长,而 DrissionPage 却耗时很短呢?
有道友说遇到一个 Selenium 自动化过不去的站点 aHR0cHM6Ly93d3cuemhpcGluLmNvbS9qb2JfZGV0YWlsLzgyOTI2ZjM5MDRhNjZlMDUwM1pfMHQtLUZWUlMuaHRtbA==,又有道友说遇到了一个 Playwright 过不去的 aHR0cHM6Ly9zc28uY25pcGEuZ292LmNuL2FtLyMvbG9naW4=,于是掏出自动化工具试试,毕竟之前一直认为自动化在国内无敌。
在 Selenium和Playwright 自动化工具里加上–disable-blink-features=AutomationControlled参数(这个参数在
一个非常好用的自动化参数
里写过, 不知道的可以看看)后,打开网站后都会被重定向到空白页, 这可如何是好。
既然 Selenium 和 Playwright 自动化都过不去,那就试试 DrissonPage 了,好在 DrissonPage 能过。但究竟 Selenium 和 Playwright 为啥过不去呢,这是个问题。
最近越来越喜欢自动化了,因为在量小的时候,自动化真的太舒服了,轻轻松松就解决了滑块。和道友讨论自动化的时候,道友竟然不知道 Chromium 有 –disable-blink-features=AutomationControlled 这个参数, 于是就写一下这个参数。
我是今年才正经搞了下自动化,问了 AI 怎么隐藏自动化特征,问到了这个参数,AI 真的越来越舒服了。问一下AI这个 –disable-blink-features=AutomationControlled 参数主要干啥的,可以知道这个是 Chromium 启动参数,它的核心作用是:禁用 Blink 渲染引擎中名为 AutomationControlled 的功能特性,从而隐藏浏览器正在被自动化工具(如 Selenium、Puppeteer 等)控制的痕迹,最主要的功能就是 隐藏 navigator.webdriver 属性。
也就是说加上这个参数后,可以解决一些基础检测。这就很舒服了,不用自己去写 hook 解决 navigator.webdriver 检测。
目前测试下来很好用,强的离谱,国内反爬目前还没遇到过不去的,国外倒是挺多过不去的,还需努力。
此时耳边响起嘲讽金角,理解金角,成为金角,超越金角。
目标站点 aHR0cHM6Ly9jbG91ZC50ZW5jZW50LmNvbS9wcm9kdWN0L2NhcHRjaGE=
最近遇到一个滑块,打开一看是某讯滑块。看了下加密参数,有 pow_answer 和 collect , 主要难点是 collect,在 vmp 里绕来绕去生成的。本来想用浏览器补环境生成这个参数,但后面想想反正量不大,直接自动化好了。
找同事要了一份滑块自动化的代码,他之前也搞过某讯滑块,只是和这个版本不一样。代码是用Python 的 Playwright 库写的,就着代码让 AI 帮忙修改 XPath, 写等待某个元素出现的代码,让 AI 写等待某个请求出现的代码,最后让用 FastAPI 和 uvicorn 写了个 API 服务,就跑起来了。
量不大的情况下,滑块还是自动化来得舒服。
目标站点 aHR0cHM6Ly93d3cudmFwdGNoYS5jb20vI2RlbW8=
之前写过一篇
某Vaptcha手势验证逆向
,能拿到 token, 但真的跑起来,还是会遇到很多问题。
比如能返回 token, 但拿着 token 去请求的时候,会返回参数校验失败。这是因为站点会拿着token去做二次校验,二次校验通不过就会提示参数校验失败,所以能获取到 token 并不代表真的成功。
比如Linux上 Canvas 生成服务容器跑通几次就一直获取不到 token, 本地 Mac 的 Canvas 生成
服务
容器却没问题。
比如 Windows 机器上的 Canvas 生成服务跑着跑着会变慢,本地 Mac 上的 Canvas 生成服务却一直没问题。
还有就是有的站点 50~55 分钟的时候会跑不动,因为版本发生了变化,得适配。
还有就是轨迹,看着两个轨迹加工的方法没什么大的区别,但真的跑起来效果却相差很大。
最后发现 Canvas 指纹其实随机也能行,不一定要浏览器生成的。但浏览器生成的好的一点是 token 没遇到过 00000000 的情况,随机生成会遇到。
很多时候,还是看请求量。请求量少的时候,怎么方便怎么来,但请求量多的时候,就真的考验人。
目标站点: aHR0cHM6Ly9ldGF4LmNoaW5hdGF4Lmdvdi5jbi8=
听道友说某数又更新了,很多补环境方案不能用了,于是测试了下,以前基于 jsdom 的方案果然不能用了。之前就在
当jsdom补环境被针对
里写过,如果非得用 jsdom,就只能悄咪咪的用,别声张了。但你得时刻提防着被检测,因为 jsdom 可以检测的点真的是太多了。
继续测试了之前自己搞的补环境方案,还能过,又测试了下今年研究的
浏览器补环境方案
,也能过,这就稳妥了,有两个方案在手就还行,不会被打的措手不及。
花了点时间看了下这个版本,毕竟这是22年以来,针对补环境最大的一次更新了。可以看到 rs 安全人员花了很多精力在补环境检测上,几乎把市面上开源的方案都检测过去了, V佬可以的。其中 sdenv 是重灾区。毕竟有了sdenv, 新手都能过了,这可不行。
尝试去找找之前基于 jsdom 的补环境不能通过的原因,发现还是因为检测点太多了,_ast, _runScripts等等。不想继续找了,这补环境错在哪里真难找。还是浏览器补环境来的舒服,啥也不用改,无脑渲染完事。不用去想着怎么把浏览器特性在Node环境里实现,舒服得很。而且这浏览器补环境也就比自己写的补环境方案慢了50%,这性能能接受了。不过需要处理的是,当自动化被检测时,要怎么把这些检测点找出来。至少目前还不需要,目前能过。
遗憾的是,加密算法还是没有太多的改变,估计还是因为改加密算法涉及的东西太多了,阻力太大。如果加密算法大变,再加上这 jsvmp,算法方案就又有得搞了。
不管怎样,等这个版本大规模铺开,人均某数的时代就过去了。
在
Node服务内存泄漏问题排查
一文中,我们介绍了排查内存泄漏的方法。其实最初我教道友的并不是这个方法,所以道友没有找到内存泄漏原因,后来道友把他的代码发我排查之后,给他找到了解决办法。
后来为了写Node服务内存泄漏问题排查一文,更深入的研究了下这个内存泄漏,才知道主要是看 Retained Size (指的是一个对象被垃圾回收后,能实际释放的内存量),从上往下找就行,简单易懂。所以还是得多写文章才行啊。
写完Node服务内存泄漏问题排查一文后,用新的方法,一下子就找到了是console内存泄漏了。困惑的是最右边Retained Size对不上,没搞明白。
至于解决的办法也很简单,加上 global.console = undefined 就行了,代码如下
1 2 3 4 5 6 7
app.post("/generateCookies" , (req, res) => { let url = req.body.url; let html = req.body.html; let cookies = sdk.generateCookies(url, html); global .console = undefined res.json({ code : 0 ,'data' : {'cookies' : cookies}}) }
问题是为啥 console 会引发内存泄漏?看了代码后,可以知道它重定义了 console 里的方法,像log, info这些方法。对于这个问题有两种解决办法,一种是把这些重定义代码删掉,如果重定义代码在控制流或者vmp里,就不好找到重定义代码并删除。
另一种是不让它重定义这些方法。而不让它重定义这些方法,就可以用到Object.freeze 在JavaScript逆向时的妙用一文中介绍的 Object.freeze 方法。把console给冻结了,不让它修改,也就不会有内存泄漏。最终代码如下
1 2 3 4 5 6 7
Object .freeze(console )app.post("/generateCookies" , (req, res) => { let url = req.body.url; let html = req.body.html; let cookies = sdk.generateCookies(url, html); res.json({ code: 0 ,'data' : {'cookies' : cookies}}) }
后来发现,这个禁用console 是JavaScript Obfuscator 里的逻辑,剥离业务代码后,将测试代码放在
https://github.com/dengshilong/js_reverse/tree/main/disable_console
这里,有兴趣的话可以去测试下 console 引发的内存泄漏。
在使用Express搭建Node服务时,有一个非常值得关注的问题,那就是内存泄漏。内存泄漏会导致服务越来越慢,直至服务崩溃。
最近有个道友反馈,他的服务会内存泄漏,我的服务和他的功能一样,那么也一样会内存泄漏。于是我在Express服务里再加一个接口,用于dump出服务的内存,主要就是使用v8模块的writeHeapSnapshot函数,代码如下。
1 2 3 4 5 6 7 8 9 10
const v8 = require ("v8" ) app.get("/dump" , (req, res) => { try { const fileName = v8.writeHeapSnapshot(); console_log(`Heap snapshot written to: ${fileName} `); res.status(200 ).send(`Heap snapshot written); } catch (err) { res.status(500 ).send("Internal Server Error" ); } });
接下来就是请求服务接口,等它内存泄漏之后,调用这个dump内存接口,生成如Heap.20250710.170608.4721.0.001.heapsnapshot 这种文件。之后打开Chrome 开发者调试工具,在Memory里, 导入内存镜像,开始分析内存泄漏原因。
我们可以看到Retained Size(指的是一个对象被垃圾回收后,能实际释放的内存量) 几乎都在global里, 于是重点排查这里。
点开global这里,我们能看到,Retained Size都集中在fetch这个变量,于是我们在代码的最后添加global.fetch = undefined 来释放内存,最终代码如下。之后重启服务,继续测试,内存泄漏问题不再出现, 收工。
1 2 3 4 5 6 7 8 9 10 11 12 13
function executeJs(code, cookies, initParam) { // 拼接新的 JS 代码 const newHeadJs = headJs + ";;;\n" + "window.param=" + JSON .stringify(initParam) + ";;;;\n" + code; // 执行拼接的 JS 代码 eval(newHeadJs); // 构造返回结果 const result = { cookies: utils.changeToCookies(window.document.cookie) }; // 清除全局 fetch global.fetch = undefined; return result ; }
声明: 本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码。抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!若有侵权,请在公众号 【静夜随想】 联系作者立即删除!
在看了土木佬的
某数反爬方案讨论
后,也想搞一个浏览器渲染的方案。之前同事研究cef的时候,就想让他搞一个,但他没继续研究了,这次正好补上。
在
https://github.com/dengshilong/browser_server/blob/main/node_playwright_server/simple_server.js
代码的基础上,继续问AI,
Playwright的配置参数里,有解决自动化检测的参数吗?AI又哼哧哼哧给了一大堆建议,其中建议有以下一条,加上之后进行测试。
1 2 3 4 5 6 7
browser = playwright.chromium.launch ( args=[ "--disable-blink-features=AutomationControlled" , "--no-sandbox" , "--disable-setuid-sandbox" ] )
会遇到获取cookies时还未生成的情况,于是又让AI加上等待cookies不为空之后再返回结果功能,之后就可以测试了。
先试了加速乐,搞定。再试了下vmp + wasm里生成的某乎__zse_ck,搞定。再试了下某数,也搞定。
浏览器用来补环境是真舒服了, 就是生成速度比纯js补环境慢一些。