From a5c505578f54b830864016fdf28126d7595a4305 Mon Sep 17 00:00:00 2001 From: Malte <42342921+ccev@users.noreply.github.com> Date: Fri, 31 May 2024 23:19:04 +0200 Subject: [PATCH 1/2] targetfp initial commit --- xilriws-targetfp/background.js | 10 ++++ xilriws-targetfp/canvas.js | 68 ++++++++++++++++++++++ xilriws-targetfp/contentScript.js | 6 ++ xilriws-targetfp/general.js | 51 ++++++++++++++++ xilriws-targetfp/inject.js | 20 +++++++ xilriws-targetfp/manifest.json | 97 +++++++++++++++++++++++++++++++ xilriws-targetfp/screen.js | 69 ++++++++++++++++++++++ xilriws-targetfp/utils.js | 65 +++++++++++++++++++++ 8 files changed, 386 insertions(+) create mode 100644 xilriws-targetfp/background.js create mode 100644 xilriws-targetfp/canvas.js create mode 100644 xilriws-targetfp/contentScript.js create mode 100644 xilriws-targetfp/general.js create mode 100644 xilriws-targetfp/inject.js create mode 100644 xilriws-targetfp/manifest.json create mode 100644 xilriws-targetfp/screen.js create mode 100644 xilriws-targetfp/utils.js diff --git a/xilriws-targetfp/background.js b/xilriws-targetfp/background.js new file mode 100644 index 0000000..241da44 --- /dev/null +++ b/xilriws-targetfp/background.js @@ -0,0 +1,10 @@ +chrome.webNavigation.onCompleted.addListener((details) => { + console.log(details.tabId) +}) + +chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { + if (message === "getTabId") { + sendResponse(sender.tab.id) + } + return true +}) \ No newline at end of file diff --git a/xilriws-targetfp/canvas.js b/xilriws-targetfp/canvas.js new file mode 100644 index 0000000..1f54f9a --- /dev/null +++ b/xilriws-targetfp/canvas.js @@ -0,0 +1,68 @@ +import * as utils from "./utils.js" + +const typeValues = { + " monospace": 1, " sans-serif": 2, " serif": 3 +} + +const possibleFonts = ["ArialUnicodeMS", "Calibri", "Century", "Haettenschweiler", "Marlett", "Pristina", "Bauhaus93", "FuturaBkBT", "HelveticaNeue", "LucidaSans", "MYRIADPRO", "SegoeUILight"] + +export function block() { + utils.overwriteProp(CanvasRenderingContext2D.prototype, "isPointInPath", () => false) + utils.overwriteProp(CanvasRenderingContext2D.prototype, "globalCompositeOperation", "screen") + + function zeroOrOne() { + return utils.randomNumber(0, 2) + } + + // utils.overwriteProp(CanvasRenderingContext2D.prototype, "measureText", (s) => { + // const metrics = {} + // metrics.width = zeroOrOne() + // metrics.actualBoundingBoxAscent = zeroOrOne() + // metrics.actualBoundingBoxDescent = zeroOrOne() + // metrics.actualBoundingBoxLeft = zeroOrOne() + // metrics.actualBoundingBoxRight = zeroOrOne() + // return metrics + // }) + + const goodFonts = utils.randomChooseMultiple(possibleFonts, utils.randomNumber(4, 7)) + console.log("good fonts are " + goodFonts.join(",")) + + CanvasRenderingContext2D.prototype.measureText = function (text) { + let value = -10 + for (const typeValue of Object.keys(typeValues)) { + if (this.font.includes(typeValue)) { + value = typeValues[typeValue] + } + } + + for (const goodFont of goodFonts) { + if (this.font.includes(" " + goodFont + ",")) { + value = -10 + } + } + + const metrics = {} + metrics.width = value + metrics.actualBoundingBoxAscent = value + metrics.actualBoundingBoxDescent = value + metrics.actualBoundingBoxLeft = value + metrics.actualBoundingBoxRight = value + return metrics + } + + const originalArc = CanvasRenderingContext2D.prototype.arc + CanvasRenderingContext2D.prototype.arc = function (n1, n2, n3, zero, pi2, bool) { + n1 += utils.randomNumber(-1, 2) + n2 += utils.randomNumber(-1, 2) + n3 += utils.randomNumber(-1, 2) + return originalArc.bind(this, n1, n2, n3, zero, pi2, bool)() + } + + const originalPutImageData = CanvasRenderingContext2D.prototype.putImageData + CanvasRenderingContext2D.prototype.putImageData = function (img, x, y, ...args) { + // this doesn't actually do anything. however, it doesn't appear this canvas differs between different chromiums + x += utils.randomNumber(-1, 2) + y += utils.randomNumber(-1, 2) + return originalPutImageData.bind(this, img, x, y, ...args)() + } +} \ No newline at end of file diff --git a/xilriws-targetfp/contentScript.js b/xilriws-targetfp/contentScript.js new file mode 100644 index 0000000..eecdace --- /dev/null +++ b/xilriws-targetfp/contentScript.js @@ -0,0 +1,6 @@ +(async () => { + const tabId = await chrome.runtime.sendMessage("getTabId") + const div = document.createElement("div") + div.setAttribute("data-xil-tab-id", tabId) + document.body.appendChild(div) +})() \ No newline at end of file diff --git a/xilriws-targetfp/general.js b/xilriws-targetfp/general.js new file mode 100644 index 0000000..05954e3 --- /dev/null +++ b/xilriws-targetfp/general.js @@ -0,0 +1,51 @@ +import * as utils from "./utils.js" + +const baseLanguages = [ + "en-US", + "fr", + "de", + "es" +] + +const extraLanguages = [ + "en-GB", + "pt-BR", + "ru", + "tr", + "de", + "fr", + "es", + "hr", + "el", + "hu", + "no", + "ro", + "sr" +] + +const englishes = [ + "en-US", + "en-GB" +] + +export function block() { + utils.overwriteProp(navigator, "platform", "Win32") + + // language + const baseLanguage = utils.randomChoose(baseLanguages) + const languages = [baseLanguage] + + const randomExtraLangs = utils.randomNumber(0, 10) + if (randomExtraLangs > 3) { + if (englishes.includes(baseLanguage)) { + languages.push(utils.randomChoose(extraLanguages)) + } else { + languages.push(utils.randomChoose(englishes)) + } + } + console.log("languages are " + languages.join(",")) + + // TODO: seed Math.random using the tabId (or the url possibly) - the content script will be reloaded by the iframe. in some cases (like the language) this can be detcted by the script + utils.overwriteProp(navigator, "language", baseLanguage) + utils.overwriteProp(navigator, "languages", languages) +} \ No newline at end of file diff --git a/xilriws-targetfp/inject.js b/xilriws-targetfp/inject.js new file mode 100644 index 0000000..0791f00 --- /dev/null +++ b/xilriws-targetfp/inject.js @@ -0,0 +1,20 @@ +(async () => { + "use strict" + + const utils = await import("./utils.js") + const screen = await import("./screen.js") + const general = await import("./general.js") + const canvas = await import("./canvas.js") + + const div = document.querySelector("[data-xil-tab-id]") + const seed = div.getAttribute("data-xil-tab-id") + document.body.removeChild(div) + utils.setSeed(seed) + + screen.block() + general.block() + canvas.block() +})() + + + diff --git a/xilriws-targetfp/manifest.json b/xilriws-targetfp/manifest.json new file mode 100644 index 0000000..a6c7c8b --- /dev/null +++ b/xilriws-targetfp/manifest.json @@ -0,0 +1,97 @@ +{ + "manifest_version": 3, + "name": "xilriws-targetfp", + "version": "1.0", + "permissions": [ + "proxy", + "tabs", + "unlimitedStorage", + "storage", + "", + "webRequest", + "webRequestBlocking", + "devtools", + "cookies", + "storage", + "scripting", + "tabs", + "activeTab", + "webNavigation", + "runtime" + ], + "host_permissions": [ + "" + ], + "background": { + "service_worker": "background.js", + "type": "module" + }, + "content_scripts": [ + { + "matches": [ + "" + ], + "js": [ + "contentScript.js" + ], + "run_at": "document_start", + "all_frames": true, + "match_origin_as_fallback": true + }, + { + "matches": [ + "" + ], + "js": [ + "inject.js" + ], + "run_at": "document_start", + "all_frames": true, + "match_origin_as_fallback": true, + "world": "MAIN", + "type": "module" + } + ], + "web_accessible_resources": [ + { + "resources": [ + "inject.js" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "utils.js" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "screen.js" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "general.js" + ], + "matches": [ + "" + ] + }, + { + "resources": [ + "canvas.js" + ], + "matches": [ + "" + ] + } + ] +} diff --git a/xilriws-targetfp/screen.js b/xilriws-targetfp/screen.js new file mode 100644 index 0000000..9cd5996 --- /dev/null +++ b/xilriws-targetfp/screen.js @@ -0,0 +1,69 @@ +import * as utils from "./utils.js" + +const screenSizes = [ + [1680, 1050], + [1776, 1000], + [1600, 1200], + [1600, 1280], + [1920, 1080], + [1440, 1440], + [2048, 1080], + [1920, 1200], + [2048, 1152], + [1792, 1344], + [1920, 1280], + [2280, 1080], + [1856, 1392], + [2400, 1080], + [1800, 1440], + [2880, 900], + [2160, 1200], + [2048, 1280], + [1920, 1400], + [2520, 1080], + [2436, 1125], + [2538, 1080], + [1920, 1440], + [2560, 1080], + [2160, 1440], + [2048, 1536], + [2304, 1440], + [2256, 1504], + [2560, 1440], + [2576, 1450], + [2304, 1728], + [2560, 1600], + [2880, 1440], + [2960, 1440], + [2560, 1700], + [2560, 1800], + [2880, 1620], + [2560, 1920], + [3440, 1440], + [2736, 1824], + [2880, 1800], + [2880, 1920], + [2560, 2048], + [2732, 2048] +] + +export function block() { + const [screenWidth, screenHeight] = utils.randomChoose(screenSizes) + console.log("screen size is " + screenWidth + "x" + screenHeight) + utils.overwriteProp(window.screen, "width", screenWidth) + utils.overwriteProp(window.screen, "height", screenHeight) + utils.overwriteProp(window.screen, "availWidth", screenWidth) + utils.overwriteProp(window.screen, "availHeight", screenHeight - 48) + utils.overwriteProp(window.screen, "availLeft", 0) + utils.overwriteProp(window.screen, "availTop", 0) + utils.overwriteProp(window.screen, "pixelDepth", 24) + utils.overwriteProp(window.screen.orientation, "type", "landscape-primary") + + utils.overwriteProp(window, "outerWidth", screenWidth) + utils.overwriteProp(window, "outerHeight", screenHeight) + utils.overwriteProp(window, "innerWidth", screenWidth) + utils.overwriteProp(window, "innerHeight", screenHeight - 86) + utils.overwriteProp(window, "screenX", 0) + utils.overwriteProp(window, "screenY", 0) + utils.overwriteProp(window, "devicePixelRatio", 1) +} \ No newline at end of file diff --git a/xilriws-targetfp/utils.js b/xilriws-targetfp/utils.js new file mode 100644 index 0000000..1446a2d --- /dev/null +++ b/xilriws-targetfp/utils.js @@ -0,0 +1,65 @@ +let random = null + +export function setSeed(newSeed) { + random = seededRandom(newSeed) +} + +function seededRandom(seed) { + let m = 0x80000000; // 2^31 + let a = 1103515245; + let c = 12345; + let state = seed ? seed : Math.floor(Math.random() * (m - 1)); + + return function() { + state = (a * state + c) % m; + return state / (m - 1); + }; +} + +/** + * @param {Object} object + * @param {string} propName + * @param {any} propValue + */ +export function overwriteProp(object, propName, propValue) { + Object.defineProperty(object, propName, { + get: () => propValue, + set: () => {}, + configurable: true + }); +} + + +export function overwriteFunc(object, funcName, func) { + object[funcName] = func +} + +/** + * @template T + * @param {T[]} array + * @returns {T} + */ +export function randomChoose(array) { + return array[Math.floor(random() * array.length)] +} + +/** + * Generates a random number within the given bounds. + * @param {number} min - The lower bound (inclusive). + * @param {number} max - The upper bound (exclusive). + * @returns {number} A random number between min (inclusive) and max (exclusive). + */ +export function randomNumber(min, max) { + return Math.floor(random() * (max - min)) + min; +} + +/** + * @template T + * @param {T[]} arr + * @param {number} amount + * @returns {T[]} + */ +export function randomChooseMultiple(arr, amount) { + const shuffledArray = arr.sort(() => 0.5 - random()); + return shuffledArray.slice(0, amount); +} \ No newline at end of file From d2d66ef63bbb338a24041c69a21ebf15673c811c Mon Sep 17 00:00:00 2001 From: Malte <42342921+ccev@users.noreply.github.com> Date: Sun, 16 Jun 2024 21:21:04 +0200 Subject: [PATCH 2/2] targetfp adjustments --- xilriws-proxy/background.js | 1 - xilriws-targetfp/background.js | 2 +- xilriws-targetfp/contentScript.js | 5 ++ xilriws-targetfp/general.js | 38 ++++++++++++- xilriws-targetfp/inject.js | 37 +++++++++++-- xilriws-targetfp/manifest.json | 8 +++ xilriws-targetfp/screen.js | 90 +++++++++++++++++++++++++++++++ xilriws-targetfp/utils.js | 13 +++-- xilriws-targetfp/webgl.js | 56 +++++++++++++++++++ 9 files changed, 238 insertions(+), 12 deletions(-) create mode 100644 xilriws-targetfp/webgl.js diff --git a/xilriws-proxy/background.js b/xilriws-proxy/background.js index e1c92e4..846b9d5 100644 --- a/xilriws-proxy/background.js +++ b/xilriws-proxy/background.js @@ -1,4 +1,3 @@ -const STEALTH_JS = "" const ws = new WebSocket('ws://127.0.0.1:9091'); let currentProxyCreds = { diff --git a/xilriws-targetfp/background.js b/xilriws-targetfp/background.js index 241da44..f2057ed 100644 --- a/xilriws-targetfp/background.js +++ b/xilriws-targetfp/background.js @@ -7,4 +7,4 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { sendResponse(sender.tab.id) } return true -}) \ No newline at end of file +}) diff --git a/xilriws-targetfp/contentScript.js b/xilriws-targetfp/contentScript.js index eecdace..a93f9f1 100644 --- a/xilriws-targetfp/contentScript.js +++ b/xilriws-targetfp/contentScript.js @@ -2,5 +2,10 @@ const tabId = await chrome.runtime.sendMessage("getTabId") const div = document.createElement("div") div.setAttribute("data-xil-tab-id", tabId) + + while (!document.body) { + console.log("body is null, waiting 0.1s") + await new Promise(resolve => setTimeout(resolve, 100)) + } document.body.appendChild(div) })() \ No newline at end of file diff --git a/xilriws-targetfp/general.js b/xilriws-targetfp/general.js index 05954e3..ddf9d49 100644 --- a/xilriws-targetfp/general.js +++ b/xilriws-targetfp/general.js @@ -28,8 +28,45 @@ const englishes = [ "en-GB" ] +const timezones = [ + 0, 1, 2, 3, 4, 5, 6, 8, 9, -4, -5, -6, -7 +] + export function block() { utils.overwriteProp(navigator, "platform", "Win32") + utils.overwriteProp(navigator, "doNotTrack", utils.randomChoose(["unknown", "unknown", "1"])) + utils.overwriteProp(navigator, "maxTouchPoints", utils.randomChoose([0, 5, 10, 20])) + utils.overwriteProp(navigator, "productSub", "20030107") + utils.overwriteProp(navigator.connection, "rtt", utils.randomChoose([undefined, 0, 50, 100])) + utils.overwriteProp(navigator, "hardwareConcurrency", utils.randomChoose([4, 8, 12, 16, 24, 32])) + + utils.overwriteProp(window.history, "length", utils.randomNumber(1, 5)) + + const timezone = utils.randomChoose(timezones) * -60 + utils.overwriteProp(Date.prototype, "getTimezoneOffset", () => timezone) + utils.overwriteProp(Navigator.prototype, "mimeTypes", { + 0: { + suffixes: "pdf", + type: "application/pdf", + enabledPlugin: { filename: "internal-pdf-viewer" }, + }, + 1: { + suffixes: "pdf", + type: "text/pdf", + enabledPlugin: { filename: "internal-pdf-viewer" }, + }, + "application/pdf": { + suffixes: "pdf", + type: "application/pdf", + enabledPlugin: { filename: "internal-pdf-viewer" }, + }, + "text/pdf": { + suffixes: "pdf", + type: "text/pdf", + enabledPlugin: { filename: "internal-pdf-viewer" }, + }, + + }) // language const baseLanguage = utils.randomChoose(baseLanguages) @@ -45,7 +82,6 @@ export function block() { } console.log("languages are " + languages.join(",")) - // TODO: seed Math.random using the tabId (or the url possibly) - the content script will be reloaded by the iframe. in some cases (like the language) this can be detcted by the script utils.overwriteProp(navigator, "language", baseLanguage) utils.overwriteProp(navigator, "languages", languages) } \ No newline at end of file diff --git a/xilriws-targetfp/inject.js b/xilriws-targetfp/inject.js index 0791f00..39e1dca 100644 --- a/xilriws-targetfp/inject.js +++ b/xilriws-targetfp/inject.js @@ -1,19 +1,48 @@ (async () => { "use strict" + HTMLIFrameElement.prototype.addEventListener = async function (eventType, callback) { + if (eventType !== "load") { + return + } + + let fpLoaded = false + while (!fpLoaded) { + console.log("waiting for plugin load") + await new Promise(resolve => setTimeout(resolve, 200)) + if (this.contentDocument) { + fpLoaded = this.contentDocument.fpLoaded + } + } + callback() + } + const utils = await import("./utils.js") const screen = await import("./screen.js") const general = await import("./general.js") const canvas = await import("./canvas.js") + const webgl = await import("./webgl.js") - const div = document.querySelector("[data-xil-tab-id]") + let div = null + while (!div) { + div = document.querySelector("[data-xil-tab-id]") + if (!div) { + console.log("didn't find seed element, waiting 0.1s") + await new Promise(resolve => setTimeout(resolve, 100)) + } + } const seed = div.getAttribute("data-xil-tab-id") document.body.removeChild(div) utils.setSeed(seed) - screen.block() - general.block() - canvas.block() + utils.sendWs("debug:seed", seed) + + // screen.block() + // general.block() + // canvas.block() + // webgl.block() + + document.fpLoaded = true })() diff --git a/xilriws-targetfp/manifest.json b/xilriws-targetfp/manifest.json index a6c7c8b..bccb3da 100644 --- a/xilriws-targetfp/manifest.json +++ b/xilriws-targetfp/manifest.json @@ -92,6 +92,14 @@ "matches": [ "" ] + }, + { + "resources": [ + "webgl.js" + ], + "matches": [ + "" + ] } ] } diff --git a/xilriws-targetfp/screen.js b/xilriws-targetfp/screen.js index 9cd5996..6f7a379 100644 --- a/xilriws-targetfp/screen.js +++ b/xilriws-targetfp/screen.js @@ -66,4 +66,94 @@ export function block() { utils.overwriteProp(window, "screenX", 0) utils.overwriteProp(window, "screenY", 0) utils.overwriteProp(window, "devicePixelRatio", 1) + + utils.overwriteProp(window.visualViewport, "scale", 1) + utils.overwriteProp(window.visualViewport, "width", utils.randomNumber(150, screenWidth - 100)) + utils.overwriteProp(window.visualViewport, "height", utils.randomNumber(150, screenHeight - 100)) + + // mouse events + let mouseEventsActive = true + let currentMouseX = utils.randomNumber(1, screenWidth) + let currentMouseY = utils.randomNumber(1, screenHeight - 60) + let mouseOutCallback = null + let mouseOverCallback = null + + async function randomMouseOver() { + console.log("faking mouseover & mouseout") + let max = 2 + + while (mouseEventsActive && max > 0) { + max -= 1 + await new Promise(resolve => setTimeout(resolve, utils.randomNumber(50, 150))) + const eventData = { + clientX: currentMouseX, + clientY: currentMouseY, + screenX: currentMouseX, + screenY: currentMouseY - 13 + } + + mouseOutCallback(new MouseEvent("mouseout", eventData)) + mouseOverCallback(new MouseEvent("mouseover", eventData)) + } + } + + /** + * @param {(event: MouseEvent) => {}} callback + */ + async function randomMouseMove(callback) { + console.log("faking mousemove") + let max = 4 + + while (mouseEventsActive && max > 0) { + max -= 1 + await new Promise(resolve => setTimeout(resolve, utils.randomNumber(50, 200))) + + currentMouseX += utils.randomNumber(2, 20) + currentMouseY += utils.randomNumber(4, 27) + callback(new MouseEvent("mousemove", { + clientX: currentMouseX, + clientY: currentMouseY, + screenX: currentMouseX, + screenY: currentMouseY - 13 + })) + } + } + + const anyMouseEvents = utils.randomNumber(0, 10) > 2 + const anyMouseOver = utils.randomNumber(0, 10) > 2 + + const originalAddEventListener = Document.prototype.addEventListener + const originalRemoveEventListener = Document.prototype.removeEventListener + + Document.prototype.addEventListener = function(eventType, callback) { + if (!anyMouseEvents) { + return + } + + if (eventType === "mousemove") { + randomMouseMove(callback).then() + } + + if (anyMouseOver && eventType === "mouseout") { + mouseOutCallback = callback + + if (mouseOverCallback) { + randomMouseOver().then() + } + } + if (anyMouseOver && eventType === "mouseover") { + mouseOverCallback = callback + + if (mouseOutCallback) { + randomMouseOver().then() + } + } + + return originalAddEventListener.bind(this, eventType, callback)() + } + + Document.prototype.removeEventListener = function(eventType, callback) { + mouseEventsActive = false + return originalRemoveEventListener.bind(this, eventType, callback)() + } } \ No newline at end of file diff --git a/xilriws-targetfp/utils.js b/xilriws-targetfp/utils.js index 1446a2d..56a5c30 100644 --- a/xilriws-targetfp/utils.js +++ b/xilriws-targetfp/utils.js @@ -1,5 +1,13 @@ +const ws = new WebSocket('ws://127.0.0.1:9091'); + let random = null +export function sendWs(action, detail = null) { + try { + ws.send(JSON.stringify({action: action, detail: detail})) + } catch (e) {} +} + export function setSeed(newSeed) { random = seededRandom(newSeed) } @@ -29,11 +37,6 @@ export function overwriteProp(object, propName, propValue) { }); } - -export function overwriteFunc(object, funcName, func) { - object[funcName] = func -} - /** * @template T * @param {T[]} array diff --git a/xilriws-targetfp/webgl.js b/xilriws-targetfp/webgl.js new file mode 100644 index 0000000..f2637db --- /dev/null +++ b/xilriws-targetfp/webgl.js @@ -0,0 +1,56 @@ +import * as utils from "./utils.js" +import {randomChoose} from "./utils.js"; + +export function block() { + const glProto = WebGLRenderingContext.prototype + + utils.overwriteProp(glProto, "getSupportedExtensions", () => ["ANGLE_instanced_arrays","EXT_blend_minmax","EXT_clip_control","EXT_color_buffer_half_float","EXT_depth_clamp","EXT_disjoint_timer_query","EXT_float_blend","EXT_frag_depth","EXT_polygon_offset_clamp","EXT_shader_texture_lod","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","EXT_texture_mirror_clamp_to_edge","EXT_sRGB","KHR_parallel_shader_compile","OES_element_index_uint","OES_fbo_render_mipmap","OES_standard_derivatives","OES_texture_float","OES_texture_float_linear","OES_texture_half_float","OES_texture_half_float_linear","OES_vertex_array_object","WEBGL_blend_func_extended","WEBGL_color_buffer_float","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_depth_texture","WEBGL_draw_buffers","WEBGL_lose_context","WEBGL_multi_draw","WEBGL_polygon_mode"]) + + const originalGetParameter = glProto.getParameter + glProto.getParameter = function (parameter) { + if (parameter === glProto.MAX_VERTEX_UNIFORM_VECTORS) { + return utils.randomChoose([127, 128, 255, 256, 511, 512, 1023, 1024, 2047, 2048, 4095, 4096]) + } else if (parameter === glProto.MAX_VIEWPORT_DIMS) { + return utils.randomChoose([[16384, 16384], [32767, 32767], [65536, 65536]]) + } else if (parameter === glProto.RENDERER) { + return utils.randomChoose(["WebKit WebGL", "WebKit WebGL", "WebKit WebGL", "WebKit WebGL", "ANGLE (Microsoft, Microsoft Basic Render Driver Direct3D11 vs_5_0 ps_5_0), or similar", "ANGLE (Intel, Intel(R) HD Graphics Direct3D11 vs_5_0 ps_5_0), or similar", "Adreno (TM) 650, or similar"]) + } else { + const debug = this.getExtension("WEBGL_debug_renderer_info") + if (debug) { + if (parameter === debug.UNMASKED_VENDOR_WEBGL) { + return utils.randomChoose([ + "Google Inc. (Microsoft)", "Google Inc. (Intel)", "Google Inc. (NVIDIA Corporation)", "Google Inc. (ARM)", "Google Inc. (NVIDIA)", "Google Inc. (AMD)" + ]) + } else if (parameter === debug.UNMASKED_RENDERER_WEBGL) { + let randomHex = "" + for (let i = 0; i < 4; i++) { + randomHex += utils.randomChoose(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E"]) + } + const graphicsCard = utils.randomChoose([ + "NVIDIA, NVIDIA GeForce MX450", + "NVIDIA, NVIDIA GeForce 710M", + "NVIDIA, NVIDIA GeForce RTX 2050", + "NVIDIA, NVIDIA GeForce GTX 950M", + "Intel, Intel(R) UHD Graphics 620", + "Intel, Intel(R) HD Graphics 630", + "Intel, Intel(R) UHD Graphics", + "Intel, Intel(R) Iris(R) Xe Graphics", + "AMD, Radeon RX 570 Series", + "AMD, Radeon R9 380 Series", + "AMD, Radeon X800 Series", + ]) + + return "ANGLE(" + graphicsCard + " (0x0000" + randomHex + ") Direct3D11 vs_5_0 ps_5_0, D3D11)" + } + } + } + return originalGetParameter.bind(this, parameter)() + } + + utils.overwriteProp(glProto.getParameter, "name", "getParameter") + // utils.overwriteProp(glProto.getParameter, "toString", () => "function getParameter() { [native code] }") + + Function.prototype.toString = (func) => { + return "function () { [native code] }" + } +} \ No newline at end of file