当前位置:首页 » 《关注互联网》 » 正文

014.指纹浏览器开发-修改webGL指纹(二)

9 人参与  2024年11月15日 12:41  分类 : 《关注互联网》  评论

点击全文阅读


指纹浏览器开发-修改webGL指纹(二)

一、webGL指纹是什么

之前介绍过webGL指纹和常见网站绕过webGL指纹,插眼传送

二、为啥有的webGL指纹-二期

上期我们通过修改gl的参数,getSupportedExtensions()函数返回值列表的顺序,绕过部分网站的指纹检测。但还有些网站通过webGL生成图形来获取指纹,我们就需要再出一期了。还有就是:上期指纹检测未通过browserscan这个网站。

三、获取浏览器的webGL指纹(通过生成图像)

有攻才有防,先看看网站是如何通过js获取你的webGL指纹的。将下面的代码复制到F12控制台,就可以获取显示你的webGL指纹了。
async function sha256(message) {    // 把字符串转换为Uint8Array    const msgBuffer = new TextEncoder().encode(message);    // 计算散列值    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);    // 转换为数组    const hashArray = Array.from(new Uint8Array(hashBuffer));    // 转换为16进制字符串    const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');    return hashHex;}function getWebGLFingerprint() {    var canvas = document.createElement('canvas');var gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");    // 设置清除颜色为黑色,不透明    gl.clearColor(0.0, 0.0, 0.0, 1.0);    // 清除颜色缓冲区    gl.clear(gl.COLOR_BUFFER_BIT);    // 创建顶点着色器    var vsSource = `        attribute vec4 aVertexPosition;        void main(void) {          gl_Position = aVertexPosition;        }    `;    var vertexShader = gl.createShader(gl.VERTEX_SHADER);    gl.shaderSource(vertexShader, vsSource);    gl.compileShader(vertexShader);    // 创建片段着色器    var fsSource = `        void main(void) {            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);        }    `;    var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);    gl.shaderSource(fragmentShader, fsSource);    gl.compileShader(fragmentShader);    // 创建着色器程序    var shaderProgram = gl.createProgram();    gl.attachShader(shaderProgram, vertexShader);    gl.attachShader(shaderProgram, fragmentShader);    gl.linkProgram(shaderProgram);    gl.useProgram(shaderProgram);    // 定义三角形的顶点    var vertices = new Float32Array([         0.0,  1.0,  0.0,        -1.0, -1.0,  0.0,         1.0, -1.0,  0.0    ]);    // 创建顶点缓冲区对象    var vertexBuffer = gl.createBuffer();    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);    // 将缓冲区对象绑定到着色器变量    var vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");    gl.enableVertexAttribArray(vertexPositionAttribute);    gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);    // 绘制三角形    gl.drawArrays(gl.TRIANGLES, 0, 3);    // 读取渲染结果并生成指纹    //var pixels = new Uint8Array(gl.drawingBufferWidth * gl.drawingBufferHeight * 4);    //gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);    //return pixels;var res = canvas.toDataURL()return res}sha256(getWebGLFingerprint()).then(hash => console.log(hash));

可以看到:获取图像数据有2种方式,关键函数是readPixels()toDataURL()

四、修改源码的readPixels()函数

打开源码文件 \third_party\blink\renderer\modules\webgl\webgl_rendering_context_base.cc
1.找到下面的代码
void WebGLRenderingContextBase::ReadPixelsHelper(GLint x,                                                 GLint y,                                                 GLsizei width,                                                 GLsizei height,                                                 GLenum format,                                                 GLenum type,                                                 DOMArrayBufferView* pixels,                                                 int64_t offset) {  if (isContextLost())    return;
2.替换为
int getRandomIntForFoo12Modern() {    static std::mt19937 generator(static_cast<unsigned long>(time(NULL))); // 静态以确保只初始化一次    std::uniform_int_distribution<int> distribution(0, 9);    return distribution(generator);}void WebGLRenderingContextBase::ReadPixelsHelper(GLint x,                                                 GLint y,                                                 GLsizei width,                                                 GLsizei height,                                                 GLenum format,                                                 GLenum type,                                                 DOMArrayBufferView* pixels,                                                 int64_t offset) {  if (isContextLost())    return;  //追加2行  width = width - getRandomIntForFoo12Modern();  height = height - getRandomIntForFoo12Modern();

注意:这里我们通过裁剪了部分像素来实现改变ReadPixelsHelper方法的返回值

五、修改源码的toDataURL()函数

打开源码文件 \third_party\blink\renderer\core\html\canvas\html_canvas_element.cc
1.头部加上(随便加在一个#include后面)
#include <algorithm> #include <random>    #include <chrono>   
2.找到下面的代码
String HTMLCanvasElement::toDataURL(const String& mime_type,                                    const ScriptValue& quality_argument,                                    ExceptionState& exception_state) const {  if (ContextHasOpenLayers(context_)) {    exception_state.ThrowDOMException(        DOMExceptionCode::kInvalidStateError,        "`toDataURL()` cannot be called with open layers.");    return String();  }  if (!OriginClean()) {    exception_state.ThrowSecurityError("Tainted canvases may not be exported.");    return String();  }  double quality = kUndefinedQualityValue;  if (!quality_argument.IsEmpty()) {    v8::Local<v8::Value> v8_value = quality_argument.V8Value();    if (v8_value->IsNumber())      quality = v8_value.As<v8::Number>()->Value();  }    String data = ToDataURLInternal(mime_type, quality, kBackBuffer);  TRACE_EVENT_INSTANT(      TRACE_DISABLED_BY_DEFAULT("identifiability.high_entropy_api"),      "CanvasReadback", "data_url", data.Utf8());    return data;}

注意:最新源码可能和当前代码有略微差异,但基本逻辑是一样。要做的是给返回值后面加空格

3.替换为
String HTMLCanvasElement::toDataURL(const String& mime_type,                                    const ScriptValue& quality_argument,                                    ExceptionState& exception_state) const {  if (ContextHasOpenLayers(context_)) {    exception_state.ThrowDOMException(        DOMExceptionCode::kInvalidStateError,        "`toDataURL()` cannot be called with open layers.");    return String();  }  if (!OriginClean()) {    exception_state.ThrowSecurityError("Tainted canvases may not be exported.");    return String();  }  double quality = kUndefinedQualityValue;  if (!quality_argument.IsEmpty()) {    v8::Local<v8::Value> v8_value = quality_argument.V8Value();    if (v8_value->IsNumber())      quality = v8_value.As<v8::Number>()->Value();  }    String data = ToDataURLInternal(mime_type, quality, kBackBuffer);  TRACE_EVENT_INSTANT(      TRACE_DISABLED_BY_DEFAULT("identifiability.high_entropy_api"),      "CanvasReadback", "data_url", data.Utf8());    //这里追加几行  std::srand(std::time(nullptr));  int randomNum = std::rand() % 100 + 1;  std::string spaces(randomNum, ' ');  data = data + String(spaces);  //LOG(ERROR) << "data:('" << data << "') data";    return data;}

注意:data返回的是base64字符串,我们随机给后面加多个空格,这样不但不影响函数的功能,hash的也就是乱的了。

4.编译
ninja  -C  out/Default chrome

browserscan这个站要是知道的话,一定会想:这些人怎么这么坏~~

六、在线指纹验证网站:

https://abrahamjuliot.github.io/creepjs/https://www.browserscan.net/

点击全文阅读


本文链接:http://zhangshiyu.com/post/186517.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1