补浏览器环境

一,导言

// global是node中的关键字(全局变量),在node中调用其中的元素时,可以直接引用,不用加global前缀,和浏览器中的window类似;在浏览器中可能会使用window前缀:window.location.href,也可能省略window直接调用location.href,这两种情况通过将window赋予global一样的全局属性便都可以正常调用了

window = global; // 将window变成node中的全局变量
- 电脑上安装node.js后,就可以执行JavaScript(编译器,相当于python装CPython解释器)
- 安装node.js时,会自动安装npm(第三方包管理器,相当于python中的pip)

什么是纯净V8:

在这里插入图片描述

在纯净V8中,除了V8引擎本身之外,没有其他浏览器相关的组件和功能。因此,开发人员可以使用纯净V8来构建独立的JavaScript应用程序(例如Node.js),而无需依赖于任何浏览器的特定功能和API。

什么是BOM和DOM:BOM包含DOM

在这里插入图片描述

JavaScript内置对象,所有不在内置对象的都不是v8引擎自带的,比如Regexp/Object/Proxy是v8有的, global不属于v8属于node特有的,查询连接为:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects

在这里插入图片描述

二,什么是补浏览器环境?

**浏览器环境:**是指JS代码在浏览器中的运行时环境,包括V8自动构建的对象(即ECMAScript的内容,如Date、Array),浏览器内置传递给V8的操作DOM和BOM的对象(如document、navigator)。

**Node环境:**是基于V8引擎的Js运行时环境,它包括V8与其自己的内置API,如fs, http, path。

在这里插入图片描述

因此,补浏览器环境其实是补浏览器有而node没有的环境,即补BOM和DOM对象。此外,Node环境和浏览器还具有一些区别,比如window对象区别、this指向区别、Js引擎区别,以及一些DOM操作区别。

三,为什么要补环境?

一般情况下,将加密算法扣下来能够直接执行,但是如果检测了浏览器指纹(由于Node环境与浏览器环境之间存在差异,会导致部分JS代码在浏览器中运行的结果 与在node中运行得到的结果不一样),那就比较难了。

所以需要 “补浏览器环境”,使得扣出来的 “js加密算法代码”Node环境中运行得到的加密值,与其在 浏览器环境中运行得到的加密值一致。

环境对JS代码的影响跳不过这两种方式:

  1. 用来判断,改变逻辑
  2. 值参与加密运算

四,常被检测的环境

在常被检测的环境中,有window、location、document、navigator、canvas、native方法检测等,除了这些属性外,还有针对自动化痕迹的检查(比如对chromedriver属性检测)、Node环境的检测,以及浏览器指纹检测、TLS指纹校验、驱动检测、异常堆栈调用检测等。

window检测:

  • window是否为方法
  • window对象是否freeze
  • 各属性检测

location检测:

  • hostname
  • protocol
  • host
  • hash
  • origin

navigator检测:

  • AppName
  • AppVersion
  • cookieEnabled
  • language
  • userAgent
  • product
  • platform
  • plugins浏览器插件
  • javaEnabled() 方法
  • taintEnabled() 方法

document检测:

  • referrer
  • cookie
  • createElement() 方法

canvas指纹:

  • 不同类型图片的canvas指纹应当不一样,如 .jpg、.png
  • 不同质量quality的canvas指纹应该不一样
  • 不同属性的canvas指纹应该不一样
  • 同一个条件的canvas多次绘制时应该保持一致

浏览器指纹信息:

  • window.screen屏幕分辨率/宽高
  • navigator.useragent
  • location.href/host
  • navigator.platform平台、语言等信息
  • canvas 2D图像指纹
  • navigator.plugin 浏览器插件信息
  • webgl 3D图像指纹
  • 浏览器字体信息
  • 本地存储的cookie信息

五,确定需要补那些环境?

要想 “补浏览器环境”,首先我们得知道 “js加密算法代码” 到底使用了哪些浏览器环境API,然后再对应去补上这些环境;

5.1 通过undefined报错去分析

通过运行程序后的undefined报错一点一点的去补一些环境,这种方式是非常掉头发的。

5.2 使用Proxy

Proxy是ES6提供的代理器(在浏览器和Node中均可使用),用于创建一个对象的代理,从而实现基本操作的拦截和自定义。 它可以代理任何类型的对象,包括原生数组,函数,甚至另一个代理;拥有递归套娃的能力!

也就是说 我们代理某个对象后,我们就成了它的中间商,任何JS代码对它的任何操作都可以被我们所拦截!

使用 Proxy 对全局遍历window、document、navigator等常见环境检测点进行代理,拦截代理对象的读取、函数调用等操作,并通过控制台输出,这样就能够实现检测环境自吐的功能,后续再针对吐出来的环境统一进行补环境,这样就会方便的多。

Proxy基础用法:

先定义一个 target 对象,即目标对象;同时定义 handler 对象,handler 声明了代理 target 的指定行为。

// 目标对象(被代理对象)
var target = {
    name: 'JACK',
    age: 18,
};

// 代理行为对象(对目标对象进行取值或赋值行为时,会进入此对象的方法)
var handler = {
    get: function(target, property, receiver) {
        console.log("get: ", target, property, target[property]);
        return target[property]; 
    },
    set: function(target, property, value) {
        console.log("set: ", target, property, value);
        return Reflect.set(...arguments);
    }
};

// 使用 Proxy 构造函数实例出新的target对象
var target = new Proxy(target, handler)

// 取值操作 会进入handler中的get方法 并打印
target.name     //  get:  {name: 'JACK', age: 18} name JACK
// 赋值操作 会进入handler中的set方法 并打印
target.age = 25 //  set:  {name: 'JACK', age: 18} age 25

下图为Proxy的使用方法,以及补环境代码框架,主体分为三大部分:

在这里插入图片描述

当底部的代码有用到某个在浏览器中的对象时,就会在控制台输出对应的内容(前提是该对象被挂上了代理,并且触发的是get或set方法)

运行结果如下:

在这里插入图片描述

缺少的环境一目了然。后面就是缺啥补啥,只要将上图中显示undefined的对象及其属性补充在第二部分代码后面即可。(location和navigator等要补充的值在Console中查看即可)

示例代码如下:

/* 1,框架代理功能放在顶部 */
var handlerProxy = function (object) {
    return new Proxy(object, {
        get: function(target, property, receiver){
            console.log("get", target, property, target[property]);
            return target[property];
        },
        set: function(target, property, value){
            console.log("set", target, property, value);
            return Reflect.set(...arguments);
        }
    })
};

/* 2,给常见的环境对象挂上代理(挂上代理后在不影响原功能的情况下,当对象被调用时可以在控制台输出结果) */
window = global;
navigator = class navigator{};
document = class document{};
location = class location{};
window = handlerProxy(window);
navigator = handlerProxy(navigator);
document = handlerProxy(document);
location = handlerProxy(location);

/* 3,原生待补环境的js放在底部,调试输出观察 */
location.href = "https://blog.csdn.net/weixin_43411585";
location.protocol = "https:";

六,补环境的方法

6.1 手补

以下举两个例子:

1:当JS代码会判断你当前环境的window对象是否有toString方法

if (window.toString)
{
  //do some thing; 修改全局变量啥的
}

这时,只需要将 window.toString 赋值为true即可:

window = {};
window.toString = true;

这样写没有问题,只是个逻辑,如果还判断了是否为函数:

if (typeof window.toString === 'function')
{
  //do some thing; 修改全局变量啥的
}

这时我们依葫芦画瓢将其定义为函数:

window.toString = function(){};

如果对返回值进行了判断或者参与了加密运算,则直接在浏览器的控制台上运行看看返回值是啥:

在这里插入图片描述

再依照它的结果补上去就可以了:

window.toString = function() {return "[object Window]"};

2:下面是某cdn的部分代码:

document["createElement"]("img")["src"] = "/R=1&e=" + Math["random"]();

这种情况下,当前node环境如果没有 createElement 函数,肯定是会报错的。那该怎么去补呢,我们来分析:

document[“createElement”] 是一个函数,你可以这样定义:

document = {};
document.createElement = function(){};

它传递了一个实参 “img”,因此还需要参数,像这样:

document.createElement = function(img){};

这样肯定还不行,document"createElement" 代码后面加了个 [“src”],那说明

  1. 当实参为 "img"时,有返回值。

  2. 返回值是一个object类型。

document.createElement = function(img){
   if (img === "img")
   {
     return {};
   }
};

上面的代码就可以满足条件了,如果你想更完美,可以像下面这样:

document = {};
document.createElement = function(img)
{
 if (img === "img")
 {
   return {src:""};
 }
}

在确定需要补什么内容时,直接在在浏览器上输出相应的值即可。

6.2 借助jsdom

npm install node-gyp@latest sudo npm explore -g npm -- npm i node-gyp@latest // 更新npm
npm install jsdom -g

注意:上述安装成功后已可以模拟浏览器环境,由于今日头条中依赖canvas包,这里一并下载

npm install canvas -g

jsdom入门示例:

// npm install jsdom

const jsdom = require("jsdom");  // 引入 jsdom
const { JSDOM } = jsdom;  // 引出 JSDOM 类, 等同于 JSDOM = jsdom.JSDOM
const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`);  // 创建DOM对象
console.log(dom.window.document.querySelector("p").textContent); // Hello world

配置DOM:

const dom = new JSDOM(`<!DOCTYPE html><p>Hello world</p>`, {
    url: "https://example.org/",  // window.location,document.URL
    referrer: "https://example.com/",  // document.referrer
    contentType: "text/html",  // document.contentType
    userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36 Edg/105.0.1343.42",  // UA
    includeNodeLocations: true  // 保留由HTML解析器生成的位置信息,允许使用nodeLocation()方法
});

执行JS:

const jsdom = require("jsdom"); 
const { JSDOM } = jsdom;  
const dom = new JSDOM(
    `<body>
              <script>
              document.body.appendChild(document.createElement("hr"));
              console.log("hello world");
              </script>
           </body>`, 
    { runScripts: "dangerously" }  // 需要配置runScripts 否则不运行 JS
    );
// hello world

设置cookie:

const cookieJar = new jsdom.CookieJar(store, options);
const dom = new JSDOM(``, { cookieJar });

补充环境变量实例:

const jsdom = require("jsdom");
const {JSDOM} = jsdom;

const resourceLoader = new jsdom.ResourceLoader({
    userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36"
});

const html = `<!DOCTYPE html><p>Hello world</p>`;
const dom = new JSDOM(html, {
    url: "https://www.toutiao.com",
    referrer: "https://example.com/",
    contentType: "text/html",
    resources: resourceLoader,
});


console.log(dom.window.location)
console.log(dom.window.navigator.userAgent)
console.log(dom.window.document.referrer)

window = global; 

const params = {
    location: {
        hash: "",
        host: "www.toutiao.com",
        hostname: "www.toutiao.com",
        href: "https://www.toutiao.com",
        origin: "https://www.toutiao.com",
        pathname: "/",
        port: "",
        protocol: "https:",
        search: "",
    },
    test:{
        hahaha:"nothing at all!!!"
    }
    navigator: {
        appCodeName: "Mozilla",
        appName: "Netscape",
        appVersion: "5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36",
        cookieEnabled: true,
        deviceMemory: 8,
        doNotTrack: null,
        hardwareConcurrency: 4,
        language: "zh-CN",
        languages: ["zh-CN", "zh"],
        maxTouchPoints: 0,
        onLine: true,
        platform: "MacIntel",
        product: "Gecko",
        productSub: "20030107",
        userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36",
        vendor: "Google Inc.",
        vendorSub: "",
        webdriver: false
    }
};

Object.assign(window,params); // 为window补充环境变量


// 使用window调用或直接调用
console.log(window.location.href)
console.log(location.href)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/765378.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Latex写作工具整理(Overleaf)

一、公式&#xff08;MathType&#xff09; 先用MathType编辑好公式&#xff0c;再粘贴到Overleaf 预置-剪切和复制预置-选择“MathML或Tex"-确定 1.行内公式 粘贴到overleaf里面把两侧的" \["替换成"$" $ A $ 2.单行公式 \begin{equation}\labe…

Mysql并发控制和日志

文章目录 一、并发控制锁机制事务&#xff08;transactions&#xff09;事务隔离级别 二、日志事务日志错误日志通用日志慢查询日志二进制日志 备份在线查看二进制离线查看二进制日志 一、并发控制 锁机制 锁类型&#xff1a; 读锁&#xff1a;共享锁&#xff0c;也称为 S 锁…

方法种类的详解

1.有参无返回值 会出现在什么场景呢&#xff1f;比如我现在需要得到两个数&#xff08;哪里调用&#xff0c;哪里就给我&#xff09;&#xff0c;求和打印或者是打印三个数之和。 语法&#xff1a; 定义的语法&#xff1a; 修饰符 返回类型 方法名&#xff08;形参数1类型 …

[22] Opencv_CUDA应用之 使用背景相减法进行对象跟踪

Opencv_CUDA应用之 使用背景相减法进行对象跟踪 背景相减法是在一系列视频帧中将前景对象从背景中分离出来的过程&#xff0c;它广泛应用于对象检测和跟踪应用中去除背景 背景相减法分四步进行&#xff1a;图像预处理 -> 背景建模 -> 检测前景 -> 数据验证 预处理去除…

【Excel操作】Python Pandas判断Excel单元格中数值是否为空

判断Excel单元格中数值是为空&#xff0c;主要有下面两种方法&#xff1a; 1. pandas.isnull 2. pandas.isna判断Excel不为空&#xff0c;也有下面两种方法&#xff1a; 1. pandas.notna 2. pandas.notnull假设有这样一张Excel的表格 我们来识别出为空的单元格 import panda…

C#的五大设计原则-solid原则

什么是C#的五大设计原则&#xff0c;我们用人话来解释一下&#xff0c;希望小伙伴们能学会&#xff1a; 好的&#xff0c;让我们以一种幽默的方式来解释C#的五大设计原则&#xff08;SOLID&#xff09;&#xff1a; 单一职责原则&#xff08;Single Responsibility Principle…

【PYG】Cora数据集分类任务计算损失,cross_entropy为什么不能直接替换成mse_loss

cross_entropy计算误差方式&#xff0c;输入向量z为[1,2,3]&#xff0c;预测y为[1]&#xff0c;选择数为2&#xff0c;计算出一大坨e的式子为3.405&#xff0c;再用-23.405计算得到1.405MSE计算误差方式&#xff0c;输入z为[1,2,3]&#xff0c;预测向量应该是[1,0,0]&#xff0…

Python + 在线 + 中文文本转为英文语音,语音转为中文文本

模型 平台&#xff1a;https://huggingface.co/ars-语言转文本: pipeline("automatic-speech-recognition", model"openai/whisper-large-v3", device0 )tts-文本转语音&#xff1a;pipeline("text-to-speech", "microsoft/speecht5_tts&q…

Java8新特性之Optional、Lambda表达式、Stream、新日期Api使用总结

标题 Optional类常用Api使用说明Optional API 使用建议 Lambda表达式Lambda 表达式的局限性与解决方案 Stream案例实操优化 Stream 操作 新的日期和时间APILocalDateTime在SpringBoot中的应用 函数式接口&#xff08;Functional&#xff09; Optional博客参考地址1 Stream博客参…

【Linux从入门到放弃】探究进程如何退出以进程等待的前因后果

&#x1f9d1;‍&#x1f4bb;作者&#xff1a; 情话0.0 &#x1f4dd;专栏&#xff1a;《Linux从入门到放弃》 &#x1f466;个人简介&#xff1a;一名双非编程菜鸟&#xff0c;在这里分享自己的编程学习笔记&#xff0c;欢迎大家的指正与点赞&#xff0c;谢谢&#xff01; 进…

【C++】STL-priority_queue

目录 1、priority_queue的使用 2、实现没有仿函数的优先级队列 3、实现有仿函数的优先级队列 3.1 仿函数 3.2 真正的优先级队列 3.3 优先级队列放自定义类型 1、priority_queue的使用 priority_queue是优先级队列&#xff0c;是一个容器适配器&#xff0c;不满足先进先出…

pdf拆分,pdf拆分在线使用,pdf拆分多个pdf

在数字化的时代&#xff0c;pdf文件已经成为我们日常办公、学习不可或缺的文档格式。然而&#xff0c;有时候我们可能需要对一个大的pdf文件进行拆分&#xff0c;以方便管理和分享。那么&#xff0c;如何将一个pdf文件拆分成多个pdf呢&#xff1f;本文将为你推荐一种好用的拆分…

监控平台zabbix介绍与部署

目录 1.为什么要做监控 2.zabbix是什么&#xff1f; 3.zabbix 监控原理 4.Zabbix 6.0 新特性 5.Zabbix 6.0 功能组件 6.部署zabbix 6.1 部署 Nginx PHP 环境并测试 6.2 部署数据库 6.3 向数据库导入 zabbix 数据 6.4 编译安装 zabbix Server 服务端 6.5 修改 zabbix…

中小企业如何防止被查盗

在当前的商业环境中&#xff0c;小企业面临诸多挑战&#xff0c;其中之一便是如何在有限的预算内满足日常运营的技术需求。由于正版软件的高昂成本&#xff0c;一些小企业可能会选择使用盗版软件来降低成本。 我们联网之后存在很多风险&#xff0c;你可以打开自己的可以联网的电…

【面试系列】机器学习工程师高频面试题及详细解答

欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;欢迎订阅相关专栏&#xff1a; ⭐️ 全网最全IT互联网公司面试宝典&#xff1a;收集整理全网各大IT互联网公司技术、项目、HR面试真题. ⭐️ AIGC时代的创新与未来&#xff1a;详细讲解AIGC的概念、核心技术、…

Java--创建对象内存分析

1.如图所示&#xff0c;左边为一个主程序&#xff0c;拥有main方法&#xff0c;右边定义了一个Pet类&#xff0c;通过debug不难看出&#xff0c;当启动该方法时&#xff0c;有以下该步骤 1.运行左边的实例化Pet类对象 2.跳转至右边定义Pet类的语句 3.跳回至左边获取Pet类基本属…

代码生成器使用指南,JeecgBoot低代码平台

JeecgBoot 提供强大的代码生成器&#xff0c;让前后端代码一键生成&#xff0c;实现低代码开发。支持单表、树列表、一对多、一对一等数据模型&#xff0c;增删改查功能一键生成&#xff0c;菜单配置直接使用。 同时提供强大模板机制&#xff0c;支持自定义模板&#xff0c;目…

【bug报错已解决】ERROR: Could not find a version that satisfies the requirement

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 文章目录 引言一、问题描述1.1 报错示例1.2 报错分析 二、解决方法2.1 方法一2.2 方法二 三、总结 引言 有没有遇到过那种让人…

JSON JOLT常用示例整理

JSON JOLT常用示例整理 1、什么是jolt Jolt是用Java编写的JSON到JSON转换库&#xff0c;其中指示如何转换的"specification"本身就是一个JSON文档。以下文档中&#xff0c;我统一以 Spec 代替如何转换的"specification"json文档。以LHS(left hand side)代…

kaggle量化赛金牌方案(第七名解决方案)

获奖文章(第七名解决方案) 致谢 我要感谢 Optiver 和 Kaggle 组织了这次比赛。这个挑战提出了一个在金融市场时间序列预测领域中具有重大和复杂性的问题。 方法论 我的方法结合了 LightGBM 和神经网络模型,对神经网络进行了最少的特征工程。目标是结合这些模型以降低最终…