Re: Can't override canvas drawing correctly
Posted: Thu Oct 17, 2024 3:06 pm
OK
The forum for BriskBard users and CEF4Delphi / WebView4Delphi / WebUI4Delphi / WebUI4CSharp developers
https://www.briskbard.com/forum/
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);
};
})();
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);
}
Thanks, but it doesn't work here. https://browserleaks.com/canvas
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.
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.
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.
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;