← На главную

V8 на std::tanh — Math.tanh сливает ОС, Scrapfly эмулирует macOS

12.07.2026 21:12 · hackernews

Math.tanh(0.8) — не константа. На Linux в Chrome она даёт 0.6640367702678491, на macOS — 0.664036770267849, на Windows — 0.6640367702678489. Разница в один бит в последнем разряде (1 ULP). Раньше V8 сам считал tanh через встроенную fdlibm, и результаты были одинаковыми на всех ОС. Но с коммита c148629ae5 (Chrome 148) V8 переключился на std::tanh — то есть на математическую библиотеку операционной системы. И теперь по одному вызову Math.tanh можно определить, с какой ОС пришёл запрос.

Проблема не только в Math.tanh. В CSS-функциях вроде sin(), cos(), atan2() Blink вызывает системную libm напрямую — все семь тригонометрических функций в CSS тоже утекают. На macOS ситуация ещё сложнее: есть скалярная библиотека libsystem_m и векторные функции из Accelerate (vvsin, vvtanh). Они дают разные результаты. Например, cos(0) в скалярной версии даёт ровно 1.0, а в Accelerate — 0.9999999999999999. Chrome на Mac использует обе: Math.tanh и CSS-тригонометрию работают через скалярную libsystem_m, а Web Audio (FFT, биквадратные фильтры) — через Accelerate. Если подменить математику неправильно, отпечаток пальца сломается.

Просто «подкрутить» выводы не получится — это создаст новый, уникальный паттерн, которого нет ни у одной реальной ОС. Вместо этого нужно точно воспроизвести алгоритм. Это значит: достать из целевой libm коэффициенты minimax-полиномов, таблицы экспонент и константы редукции, переписать всё на переносимом C. Каждый fma() (fused multiply-add) должен быть явным — компилятору нельзя позволять добавлять или убирать свои слияния. Для Windows проще: можно загрузить настоящий ucrtbase.dll в память и напрямую вызывать его функции. Но тут есть нюанс: нужно поправить ABI (Windows x64 использует ms_abi, а не System V) и принудительно включить FMA-путь в самой DLL, иначе она вернёт биты с медленного scalar-кода, которые не совпадут с реальной Windows.

Scrapfly решили задачу. Они воспроизводят математику macOS (скалярную libsystem_m) бит-в-бит для Math.tanh и всех семи CSS-триг-функций. Проверяют на 871 000 входных значений — плотные сетки, границы интервалов, субнормальные числа, знаковые нули, бесконечности, NaN. Сверяются с реальным Chrome на реальном Mac через Debugging Protocol. Результат: запрос через API с маскировкой под macOS держится вплоть до последнего бита косинуса.

Math — детерминированный, дешёвый и почти никогда не попадает в поле зрения систем подмены отпечатков. Это делает его сильным сигналом для защиты и слабым местом для скрапера.

Читать оригинал →