Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.
Can't override canvas drawing correctly
Re: Can't override canvas drawing correctly
OK
Last edited by sodlf159 on Mon Oct 21, 2024 5:42 pm, edited 1 time in total.
Re: Can't override canvas drawing correctly
Something worked, only at Chromium1BeforeResourceLoad event, only after page refresh and only on this site https://pixelscan.net/ and only with this script.
Code: Select all
(function() {
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
HTMLCanvasElement.prototype.toDataURL = function() {
const context = this.getContext("2d");
const imageData = context.getImageData(0, 0, this.width, this.height);
for (let i = 0; i < 10; i++) {
const x = Math.floor(Math.random() * this.width);
const y = Math.floor(Math.random() * this.height);
const index = (y * this.width + x) * 4;
imageData.data[index] = Math.random() * 255;
imageData.data[index + 1] = Math.random() * 255;
imageData.data[index + 2] = Math.random() * 255;
imageData.data[index + 3] = 255;
}
context.putImageData(imageData, 0, 0);
return originalToDataURL.apply(this, arguments);
};
})();
Do you have spoofing working on this site? https://browserleaks.com/canvas It's not working for me for some reason.
Re: Can't override canvas drawing correctly
If I'm understanding this correctly, it's because of this restriction on the page: Blocked script execution in 'about:blank' because the document's frame is sandboxed and the 'allow-scripts' permission is not set.
And here's the code for a Chrome plugin that works everywhere. But how to adapt it for us?
Code: Select all
{
const port = document.createElement('div');
port.id = 'cc-blck-fp';
document.documentElement.appendChild(port);
let gshift;
const map = new WeakMap();
const revert = canvas => {
const {width, height} = canvas;
const context = canvas.getContext('2d');
const matt = getImageData.apply(context, [0, 0, width, height]);
matt.data.set(map.get(canvas));
map.delete(canvas);
canvas.getContext('2d').putImageData(matt, 0, 0);
};
const getImageData = CanvasRenderingContext2D.prototype.getImageData;
const manipulate = canvas => {
port.dispatchEvent(new Event('manipulate'));
// already manipulated
if (map.has(canvas)) {
return;
}
const {width, height} = canvas;
const context = canvas.getContext('2d');
const matt = getImageData.apply(context, [0, 0, width, height]);
map.set(canvas, matt.data);
const shift = (port.dataset.mode === 'session' && gshift) ? gshift : {
'r': port.dataset.mode === 'random' ? Math.floor(Math.random() * 10) - 5 : Number(port.dataset.red),
'g': port.dataset.mode === 'random' ? Math.floor(Math.random() * 10) - 5 : Number(port.dataset.green),
'b': port.dataset.mode === 'random' ? Math.floor(Math.random() * 10) - 5 : Number(port.dataset.blue)
};
gshift = gshift || shift;
for (let i = 0; i < height; i += Math.max(1, parseInt(height / 10))) {
for (let j = 0; j < width; j += Math.max(1, parseInt(width / 10))) {
const n = ((i * (width * 4)) + (j * 4));
matt.data[n + 0] = matt.data[n + 0] + shift.r;
matt.data[n + 1] = matt.data[n + 1] + shift.g;
matt.data[n + 2] = matt.data[n + 2] + shift.b;
}
}
context.putImageData(matt, 0, 0);
// convert back to original
setTimeout(revert, 0, canvas);
};
HTMLCanvasElement.prototype.toBlob = new Proxy(HTMLCanvasElement.prototype.toBlob, {
apply(target, self, args) {
if (port.dataset.enabled === 'true') {
try {
manipulate(self);
}
catch (e) {}
}
return Reflect.apply(target, self, args);
}
});
HTMLCanvasElement.prototype.toDataURL = new Proxy(HTMLCanvasElement.prototype.toDataURL, {
apply(target, self, args) {
if (port.dataset.enabled === 'true') {
try {
manipulate(self);
}
catch (e) {}
}
return Reflect.apply(target, self, args);
}
});
CanvasRenderingContext2D.prototype.getImageData = new Proxy(CanvasRenderingContext2D.prototype.getImageData, {
apply(target, self, args) {
if (port.dataset.enabled === 'true') {
try {
manipulate(self.canvas);
}
catch (e) {}
}
return Reflect.apply(target, self, args);
}
});
// since we are going to read it many times
HTMLCanvasElement.prototype.getContext = new Proxy(HTMLCanvasElement.prototype.getContext, {
apply(target, self, args) {
if (port.dataset.enabled === 'true' && args[0] === '2d') {
args[1] = args[1] || {};
args[1].willReadFrequently = true;
}
return Reflect.apply(target, self, args);
}
});
}
// force inject to sandbox
{
const observe = e => {
if (e.source && e.data === 'inject-script-into-source') {
try {
e.source.HTMLCanvasElement.prototype.toBlob = HTMLCanvasElement.prototype.toBlob;
e.source.HTMLCanvasElement.prototype.toDataURL = HTMLCanvasElement.prototype.toDataURL;
e.source.CanvasRenderingContext2D.prototype.getImageData = CanvasRenderingContext2D.prototype.getImageData;
e.source.addEventListener('message', observe);
}
catch (e) {
console.warn('Cannot spoof Canvas', e.source, e);
}
}
};
addEventListener('message', observe);
}
Re: Can't override canvas drawing correctly
'(() => {' +
' const storedValues = JSON.parse(localStorage.getItem("__storedValues")) || {};' +
' function hookPrototypeMethods(prefix, object) {' +
' if (!object) return;' +
' const originals = {};' +
' const prototype = Object.getPrototypeOf(object);' +
' if (!prototype) return;' +
' try {' +
' Object.getOwnPropertyNames(prototype)' +
' .filter(n => {' +
' try {' +
' return typeof prototype[n] === "function";' +
' } catch (e) {' +
' return false;' +
' }' +
' })' +
' .forEach(n => {' +
' originals[n] = prototype[n];' +
' prototype[n] = function (...args) {' +
' try {' +
' if (prefix === "2d" && (n === "strokeText" || n === "fillText")) {' +
' if (!storedValues.deviceModel) {' +
' const deviceModels = [' +
' "SM-A528B", "SM-G780G", "SM-G970F", "SM-G973F", "SM-G975F"' +
' ];' +
' storedValues.deviceModel = deviceModels[Math.floor(Math.random() * deviceModels.length)];' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' const temp = Array.from(args);' +
' temp[0] = storedValues.deviceModel;' +
' temp[1] = Math.max(0, temp[1] - 2);' +
' temp[2] = Math.max(0, temp[2] - 2);' +
' return originals[n].apply(this, temp);' +
' }' +
' return originals[n].apply(this, args);' +
' } catch (e) {' +
' console.error(`Error in method ${n}:`, e);' +
' }' +
' };' +
' });' +
' } catch (e) {' +
' console.error("Error in hookPrototypeMethods:", e);' +
' }' +
' }' +
' const gls = [];' +
' try {' +
' const canvas = document.createElement("canvas");' +
' gls.push(canvas.getContext("webgl"));' +
' gls.push(canvas.getContext("experimental-webgl"));' +
' } catch (e) {' +
' console.error("Error creating WebGL context:", e);' +
' }' +
' gls.forEach(gl => {' +
' if (gl) {' +
' const glProto = Object.getPrototypeOf(gl);' +
' const origGetParameter = glProto.getParameter;' +
' const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");' +
' if (debugInfo) {' +
' glProto.getParameter = function (param) {' +
' try {' +
' if (!storedValues.vendor) {' +
' storedValues.vendor = "TEST";' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' if (!storedValues.renderer) {' +
' storedValues.renderer = "TEST";' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' if (param === debugInfo.UNMASKED_VENDOR_WEBGL) return storedValues.vendor;' +
' if (param === debugInfo.UNMASKED_RENDERER_WEBGL) return storedValues.renderer;' +
' if (param === 37445 || param === 37446) {' +
' if (!storedValues[param]) {' +
' storedValues[param] = `RandomValue_${Math.floor(Math.random() * 1000)}`;' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' return storedValues[param];' +
' }' +
' return origGetParameter.call(this, param);' +
' } catch (e) {' +
' console.error("Error in getParameter:", e);' +
' return origGetParameter.call(this, param);' +
' }' +
' };' +
' }' +
' const origDrawArrays = glProto.drawArrays;' +
' glProto.drawArrays = function (...args) {' +
' try {' +
' if (!storedValues.randomOffset) {' +
' storedValues.randomOffset = Math.random() * 0.1 - 0.05;' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' this.clearColor(0.5 + storedValues.randomOffset, 0.5 + storedValues.randomOffset, 0.5 + storedValues.randomOffset, 1.0);' +
' this.clear(this.COLOR_BUFFER_BIT);' +
' origDrawArrays.apply(this, args);' +
' } catch (e) {' +
' console.error("Error in drawArrays:", e);' +
' }' +
' };' +
' const origDrawElements = glProto.drawElements;' +
' glProto.drawElements = function (...args) {' +
' try {' +
' if (!storedValues.randomOffset) {' +
' storedValues.randomOffset = Math.random() * 0.1 - 0.05;' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' this.clearColor(0.5 + storedValues.randomOffset, 0.5 + storedValues.randomOffset, 0.5 + storedValues.randomOffset, 1.0);' +
' this.clear(this.COLOR_BUFFER_BIT);' +
' origDrawElements.apply(this, args);' +
' } catch (e) {' +
' console.error("Error in drawElements:", e);' +
' }' +
' };' +
' }' +
' });' +
' HTMLCanvasElement.prototype.toDataURL = function () {' +
' try {' +
' if (!storedValues.canvasDataURL) {' +
' const randomString = Math.random().toString(36).substring(2, 15);' +
' storedValues.canvasDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA" +' +
' "AAAFCAYAAACNbyblAAAAHElEQVQI12P4" +' +
' "//8/w38GIAXDIBKE0DHxgljNBAAO" +' +
' "9TXL0Y4OHw" + randomString + "AAAABJRU5ErkJggg==";' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' return storedValues.canvasDataURL;' +
' } catch (e) {' +
' console.error("Error in toDataURL:", e);' +
' }' +
' };' +
' hookPrototypeMethods("webgl", document.createElement("canvas").getContext("webgl"));' +
' hookPrototypeMethods("experimental-webgl", document.createElement("canvas").getContext("experimental-webgl"));' +
' hookPrototypeMethods("2d", document.createElement("canvas").getContext("2d"));' +
'})();';
' const storedValues = JSON.parse(localStorage.getItem("__storedValues")) || {};' +
' function hookPrototypeMethods(prefix, object) {' +
' if (!object) return;' +
' const originals = {};' +
' const prototype = Object.getPrototypeOf(object);' +
' if (!prototype) return;' +
' try {' +
' Object.getOwnPropertyNames(prototype)' +
' .filter(n => {' +
' try {' +
' return typeof prototype[n] === "function";' +
' } catch (e) {' +
' return false;' +
' }' +
' })' +
' .forEach(n => {' +
' originals[n] = prototype[n];' +
' prototype[n] = function (...args) {' +
' try {' +
' if (prefix === "2d" && (n === "strokeText" || n === "fillText")) {' +
' if (!storedValues.deviceModel) {' +
' const deviceModels = [' +
' "SM-A528B", "SM-G780G", "SM-G970F", "SM-G973F", "SM-G975F"' +
' ];' +
' storedValues.deviceModel = deviceModels[Math.floor(Math.random() * deviceModels.length)];' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' const temp = Array.from(args);' +
' temp[0] = storedValues.deviceModel;' +
' temp[1] = Math.max(0, temp[1] - 2);' +
' temp[2] = Math.max(0, temp[2] - 2);' +
' return originals[n].apply(this, temp);' +
' }' +
' return originals[n].apply(this, args);' +
' } catch (e) {' +
' console.error(`Error in method ${n}:`, e);' +
' }' +
' };' +
' });' +
' } catch (e) {' +
' console.error("Error in hookPrototypeMethods:", e);' +
' }' +
' }' +
' const gls = [];' +
' try {' +
' const canvas = document.createElement("canvas");' +
' gls.push(canvas.getContext("webgl"));' +
' gls.push(canvas.getContext("experimental-webgl"));' +
' } catch (e) {' +
' console.error("Error creating WebGL context:", e);' +
' }' +
' gls.forEach(gl => {' +
' if (gl) {' +
' const glProto = Object.getPrototypeOf(gl);' +
' const origGetParameter = glProto.getParameter;' +
' const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");' +
' if (debugInfo) {' +
' glProto.getParameter = function (param) {' +
' try {' +
' if (!storedValues.vendor) {' +
' storedValues.vendor = "TEST";' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' if (!storedValues.renderer) {' +
' storedValues.renderer = "TEST";' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' if (param === debugInfo.UNMASKED_VENDOR_WEBGL) return storedValues.vendor;' +
' if (param === debugInfo.UNMASKED_RENDERER_WEBGL) return storedValues.renderer;' +
' if (param === 37445 || param === 37446) {' +
' if (!storedValues[param]) {' +
' storedValues[param] = `RandomValue_${Math.floor(Math.random() * 1000)}`;' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' return storedValues[param];' +
' }' +
' return origGetParameter.call(this, param);' +
' } catch (e) {' +
' console.error("Error in getParameter:", e);' +
' return origGetParameter.call(this, param);' +
' }' +
' };' +
' }' +
' const origDrawArrays = glProto.drawArrays;' +
' glProto.drawArrays = function (...args) {' +
' try {' +
' if (!storedValues.randomOffset) {' +
' storedValues.randomOffset = Math.random() * 0.1 - 0.05;' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' this.clearColor(0.5 + storedValues.randomOffset, 0.5 + storedValues.randomOffset, 0.5 + storedValues.randomOffset, 1.0);' +
' this.clear(this.COLOR_BUFFER_BIT);' +
' origDrawArrays.apply(this, args);' +
' } catch (e) {' +
' console.error("Error in drawArrays:", e);' +
' }' +
' };' +
' const origDrawElements = glProto.drawElements;' +
' glProto.drawElements = function (...args) {' +
' try {' +
' if (!storedValues.randomOffset) {' +
' storedValues.randomOffset = Math.random() * 0.1 - 0.05;' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' this.clearColor(0.5 + storedValues.randomOffset, 0.5 + storedValues.randomOffset, 0.5 + storedValues.randomOffset, 1.0);' +
' this.clear(this.COLOR_BUFFER_BIT);' +
' origDrawElements.apply(this, args);' +
' } catch (e) {' +
' console.error("Error in drawElements:", e);' +
' }' +
' };' +
' }' +
' });' +
' HTMLCanvasElement.prototype.toDataURL = function () {' +
' try {' +
' if (!storedValues.canvasDataURL) {' +
' const randomString = Math.random().toString(36).substring(2, 15);' +
' storedValues.canvasDataURL = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA" +' +
' "AAAFCAYAAACNbyblAAAAHElEQVQI12P4" +' +
' "//8/w38GIAXDIBKE0DHxgljNBAAO" +' +
' "9TXL0Y4OHw" + randomString + "AAAABJRU5ErkJggg==";' +
' localStorage.setItem("__storedValues", JSON.stringify(storedValues));' +
' }' +
' return storedValues.canvasDataURL;' +
' } catch (e) {' +
' console.error("Error in toDataURL:", e);' +
' }' +
' };' +
' hookPrototypeMethods("webgl", document.createElement("canvas").getContext("webgl"));' +
' hookPrototypeMethods("experimental-webgl", document.createElement("canvas").getContext("experimental-webgl"));' +
' hookPrototypeMethods("2d", document.createElement("canvas").getContext("2d"));' +
'})();';
Re: Can't override canvas drawing correctly
Fvert Good Luck
Re: Can't override canvas drawing correctly
Thanks, but it doesn't work here. https://browserleaks.com/canvas
Re: Can't override canvas drawing correctly
sodlf159 wrote: Wed Oct 30, 2024 9:10 pm It works well, but what part is it?
Are you saying it can't be changed?
That needs to be injected before the page loads.
In which event to execute this code? Have you checked it yourself on that site? That site has some kind of special protection against custom scripts, sort of.
Re: Can't override canvas drawing correctly
I checked it myself on your site.Fvert wrote: Wed Oct 30, 2024 9:20 pmsodlf159 wrote: Wed Oct 30, 2024 9:10 pm It works well, but what part is it?
Are you saying it can't be changed?
That needs to be injected before the page loads.
In which event to execute this code? Have you checked it yourself on that site? That site has some kind of special protection against custom scripts, sort of.
It changes well even when turned on and off.
It must be injected before page load.
Re: Can't override canvas drawing correctly
Which event? I can't get it to load in any event for some reason. What's the correct way to inject?sodlf159 wrote: Thu Oct 31, 2024 9:31 am I checked it myself on your site.
It changes well even when turned on and off.
It must be injected before page load.
Chromium1LoadStart work only there https://pixelscan.net/
Code: Select all
procedure TJSSimpleExtensionFrm.Chromium1LoadStart(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame; transitionType: Cardinal);
var tmpSL:TStringList;
begin
tmpSL:=TStringList.Create;
tmpSL.LoadFromFile('test.txt');
frame.ExecuteJavaScript(tmpSL.Text, frame.Url, 0);
tmpSL.Free;
end;