From 54c625cd267fa6923ea1e210f04714fce0bb46e8 Mon Sep 17 00:00:00 2001 From: kkapsner Date: Mon, 8 Apr 2024 00:05:50 +0200 Subject: [PATCH] Fix function tampering detection via prototype For #619 and #685 --- lib/extension.js | 58 +++++++++++++++++++++++++++++++++++++++++++----- releaseNotes.txt | 1 + 2 files changed, 53 insertions(+), 6 deletions(-) diff --git a/lib/extension.js b/lib/extension.js index c42c974..bb701f7 100644 --- a/lib/extension.js +++ b/lib/extension.js @@ -167,25 +167,71 @@ type: "value", changed: alteredToString }); + + const wrappedReflect = wrappedWindow.Reflect; + const originalReflectSetPrototypeOf = wrappedReflect.setPrototypeOf; + const alteredReflectSetPrototypeOf = scope.exportFunctionWithName( + function setPrototypeOf(target, prototype){ + target = scope.getWrapped(target); + if (proxies.has(target)){ + target = proxies.get(target).wrappedOriginal; + } + if (proxies.has(prototype)){ + prototype = proxies.get(prototype).wrappedOriginal; + } + const grandPrototype = wrappedReflect.getPrototypeOf(prototype); + if (proxies.has(grandPrototype)){ + const testPrototype = wrappedWindow.Object.create(proxies.get(grandPrototype).wrappedOriginal); + const value = originalReflectSetPrototypeOf.call(wrappedReflect, target, testPrototype); + if (!value){ + return false; + } + } + const value = originalReflectSetPrototypeOf.call(wrappedReflect, target, scope.getWrapped(prototype)); + return value; + }, window, "setPrototypeOf" + ); + scope.changeProperty(window, "toString", { + object: wrappedWindow.Reflect, + name: "setPrototypeOf", + type: "value", + changed: alteredReflectSetPrototypeOf + }); } scope.createProxyFunction = function createProxyFunction(window, original, replacement){ setupWindowForProxies(window); - const handler = scope.getWrapped(window).Object.create(null); - handler.apply = scope.exportFunctionWithName(function(target, thisArgs, args){ + const wrappedObject = scope.getWrapped(window).Object; + const handler = wrappedObject.create(null); + handler.apply = scope.exportFunctionWithName(function(target, thisArg, args){ try { return args.length? - replacement.call(thisArgs, ...args): - replacement.call(thisArgs); + replacement.call(thisArg, ...args): + replacement.call(thisArg); } catch (error){ try { - return original.apply(thisArgs, args); + return original.apply(thisArg, args); } catch (error){ - return target.apply(thisArgs, args); + return target.apply(thisArg, args); } } }, window, ""); + handler.setPrototypeOf = scope.exportFunctionWithName(function(target, prototype){ + target = scope.getWrapped(target); + if (proxies.has(target)){ + target = proxies.get(target).wrappedOriginal; + } + if (proxies.has(prototype)){ + prototype = proxies.get(prototype).wrappedOriginal; + } + const grandPrototype = wrappedObject.getPrototypeOf(prototype); + if (proxies.has(grandPrototype)){ + const testPrototype = wrappedObject.create(proxies.get(grandPrototype).wrappedOriginal); + wrappedObject.setPrototypeOf(target, testPrototype); + } + return wrappedObject.setPrototypeOf(target, scope.getWrapped(prototype)); + }, window, ""); const proxy = new window.Proxy(original, handler); const proxyData = { original: original, diff --git a/releaseNotes.txt b/releaseNotes.txt index b5b7965..b4f2b16 100644 --- a/releaseNotes.txt +++ b/releaseNotes.txt @@ -7,6 +7,7 @@ Version 1.10.1: fixes: - lag and functionality loss on google sites + - fix function tampering detection via prototype - isPointInPath and isPointInStroke return undefined with persistent rng known issues: