Welcome Guest Search | Active Topics | Sign In | Register

JSInitCode issue with Object.defineProperty (canvas overwrite) Options
opengpl
Posted: Saturday, October 22, 2022 4:48:54 AM
Rank: Newbie
Groups: Member

Joined: 5/20/2019
Posts: 3
Im trying to spoof canvas fingerprint with the following code that i tested on google chrome and it works correctly

but for some reason it does not work with EO.

this is my code.js source code and i loaded with webView1.JSInitCode = File.ReadAllText("code.js");

Quote:


var inject = function () {
const toBlob = HTMLCanvasElement.prototype.toBlob;
const toDataURL = HTMLCanvasElement.prototype.toDataURL;
const getImageData = CanvasRenderingContext2D.prototype.getImageData;
//
var noisify = function (canvas, context) {
if (context) {
const shift = {
'r': Math.floor(Math.random() * 10) - 5,
'g': Math.floor(Math.random() * 10) - 5,
'b': Math.floor(Math.random() * 10) - 5,
'a': Math.floor(Math.random() * 10) - 5
};
//
const width = canvas.width;
const height = canvas.height;
if (width && height) {
const imageData = getImageData.apply(context, [0, 0, width, height]);
for (let i = 0; i < height; i++) {
for (let j = 0; j < width; j++) {
const n = ((i * (width * 4)) + (j * 4));
imageData.data[n + 0] = imageData.data[n + 0] + shift.r;
imageData.data[n + 1] = imageData.data[n + 1] + shift.g;
imageData.data[n + 2] = imageData.data[n + 2] + shift.b;
imageData.data[n + 3] = imageData.data[n + 3] + shift.a;
}
}
//
alert("canvas-fingerprint-defender-alert");
context.putImageData(imageData, 0, 0);
}
}
};
//
Object.defineProperty(HTMLCanvasElement.prototype, "toBlob", {
"value": function () {
noisify(this, this.getContext("2d"));
return toBlob.apply(this, arguments);
}
});
//
Object.defineProperty(HTMLCanvasElement.prototype, "toDataURL", {
"value": function () {
noisify(this, this.getContext("2d"));
return toDataURL.apply(this, arguments);
}
});
//
Object.defineProperty(CanvasRenderingContext2D.prototype, "getImageData", {
"value": function () {
noisify(this.canvas, this);
return getImageData.apply(this, arguments);
}
});
//
document.documentElement.dataset.cbscriptallow = true;
};

var script_1 = document.createElement("script");
script_1.textContent = "(" + inject + ")()";
document.documentElement.appendChild(script_1);
script_1.remove();

if (document.documentElement.dataset.cbscriptallow !== "true") {
var script_2 = document.createElement("script");
script_2.textContent = `{
const iframes = [...window.top.document.querySelectorAll("iframe[sandbox]")];
for (var i = 0; i < iframes.length; i++) {
if (iframes[i].contentWindow) {
if (iframes[i].contentWindow.CanvasRenderingContext2D) {
iframes[i].contentWindow.CanvasRenderingContext2D.prototype.getImageData = CanvasRenderingContext2D.prototype.getImageData;
}
if (iframes[i].contentWindow.HTMLCanvasElement) {
iframes[i].contentWindow.HTMLCanvasElement.prototype.toBlob = HTMLCanvasElement.prototype.toBlob;
iframes[i].contentWindow.HTMLCanvasElement.prototype.toDataURL = HTMLCanvasElement.prototype.toDataURL;
}
}
}
}`;
//
window.top.document.documentElement.appendChild(script_2);
script_2.remove();
}


After loading it, if i visit https://browserleaks.com/canvas , it suppose to give us spoofed canvas fingerprint but it

does not, it allways return some canvas fingerprint, the js code works ok on chrome. any help will be apperciated.
eo_support
Posted: Sunday, October 23, 2022 11:01:04 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,217
Hi,

This has to do with when your code is executed. JSInitCode runs your code BEFORE everything else, which could be too early for your case. You can delay your code executation with window.onload event and it should work for you. You would need to change your code to something like this:

Code: JavaScript
var inject = function () {
   ....this part does not change....
}

window.addEventListener('load', (event) => {
   ....put the rest of the code here....
});


Note that the original initialization code is wrapped around window.addEventListener so that it is only called after window.onload is fired. After this change, you would still use WebView.JSInitCode to inject the code, however the actual execution of the code is delayed until window.onload is fired.

Please let us know if this resolves the problem for you.

Thanks!
opengpl
Posted: Sunday, October 23, 2022 1:07:52 PM
Rank: Newbie
Groups: Member

Joined: 5/20/2019
Posts: 3
Hello,

Thank you for your reply, No this does not resolve the problem

in order to spoof canvas fingerprint, the js code need to redefine those native javascript functions so the code should be executed before anything else.

HTMLCanvasElement.prototype.toBlob,
HTMLCanvasElement.prototype.toDataURL
CanvasRenderingContext2D.prototype.getImageData

take a look at this google extention
https://chrome.google.com/webstore/detail/canvas-fingerprint-defend/lanfdkkpgfjfdikkncbnojekcppdebfp?hl=en

Thanks.
opengpl
Posted: Tuesday, October 25, 2022 10:44:23 AM
Rank: Newbie
Groups: Member

Joined: 5/20/2019
Posts: 3
I can send test project if you want
eo_support
Posted: Wednesday, October 26, 2022 9:25:07 AM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,217
Yes. Please see here for instructions on test project:

https://www.essentialobjects.com/forum/test_project.aspx

Thanks!
eo_support
Posted: Wednesday, October 26, 2022 1:27:06 PM
Rank: Administration
Groups: Administration

Joined: 5/27/2007
Posts: 24,217
Hi,

Upon further investiation we have found the root problem is document.documentElement is not ready when JSInitCode is executed. As such you can modify your code to avoid using this property and it should run correctly.

In fact there is no need for you to use createElement("script") to run your inject script code. You can simply run it like this:

Code: JavaScript
var inject = function() {
     .....code to override HTMLCanvasElement.prototype....

    //The following line MUST be commented out because
    //document.documentElement is not ready at this point
    //document.documentElement.dataset.cbscriptallow = true;
}

//Run the above code directly
inject();


Setting JSInitCode directly to the above code and you should be all set.

Please let us know if this works for you.

Thanks!


You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.