最近又发现一个很有意思的特性,和 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补环境慢一些。

联系作者