-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UC patches are detected by Function.toString() fingerprint #273
Comments
The only way to reliably patch browser is by changing its source-code. |
this is simply not true. been there done that. |
@ultrafunkamsterdam the following code says it's true: <!-- ./detector.html -->
<html>
<head>
<title>Webdriver Detector</title>
<script>
function isNativeFunction(targetFunc, toString, depth=3) {
if(typeof targetFunc != "function" || typeof toString != "function") return false;
if(depth > 0) {
return isNativeFunction(toString, toString.toString, depth - 1) && [
`function${targetFunc.name.replaceAll(" ", "")}(){[nativecode]}`,
`function${targetFunc.name.replace("get ", "").replaceAll(" ", "")}(){[nativecode]}`
].includes(targetFunc.toString().replaceAll("\n", "").replaceAll(" ", ""))
} else {
return true;
}
}
function isFakeProperty(obj, prop) {
const desc = Object.getOwnPropertyDescriptor(obj, prop);
if(typeof desc != "object") return false;
return (
("get" in desc && !isNativeFunction(desc.get, desc.get.toString)) ||
("value" in desc && "get" in desc.value && !isNativeFunction(desc.value.get, desc.value.get.toString))
);
}
function isWebdriverControlled() {
return (
navigator.webdriver ||
!isNativeFunction(Object.getOwnPropertyDescriptor, Object.getOwnPropertyDescriptor.toString) ||
(Object.getOwnPropertyDescriptor(navigator, 'webdriver') && isFakeProperty(navigator, 'webdriver')) ||
isFakeProperty(window, 'navigator')
);
}
function isMultitouchPatched() {
return isFakeProperty(navigator, "maxTouchPoints");
}
function isNotificationsPermissionPatched() {
return isFakeProperty(window, "Notification") || isFakeProperty(Notification, "permission");
}
function isChromeGlobalPatched() {
return isFakeProperty(window, "chrome");
}
function isUndetectedChromedriver() {
return isWebdriverControlled() || isMultitouchPatched() || isNotificationsPermissionPatched() || isChromeGlobalPatched();
}
</script>
<body>
<script>
const msg = document.createElement("h1");
document.body.appendChild(msg);
if(isUndetectedChromedriver()) {
msg.innerText = "You are using undetected chromedriver!!";
} else {
msg.innerText = "You are a human :)";
}
</script>
</body>
</head>
</html> then on python try import undetected_chromedriver.v2 as uc
options = ChromeOptions()
options.add_argument('--no-first-run')
options.add_argument('--no-default-browser-check')
driver = uc.Chrome(version_main=92, options=options)
try:
driver._configure_headless() # this makes it detectable as I said
driver.get("file:///tmp/test/detector.html")
input("press any key to exit...")
finally:
driver.quit() |
This test can be bypassed only if your patch go deeper than check done by |
_configure_headless is only be called when you set the headless flag (because you want a headless browser) and since it is a private method, it shouldnt even be called by user code at all). |
It's obvious I called |
It is known that Function.toString() returns
"function (){ [native code] }"
for browser-native JS functions, but for user-made functions it returns the source code. This is exploited by webdriver detection mechanisms, patches should be undetectable too.This is a recursive problem, if you mock
Function.toString()
thenFunction.toString.toString()
can be detected and so on...The text was updated successfully, but these errors were encountered: