В солнечный день мне вдруг захотелось запустить кусок кода, и тогда я открыл консоль. В этот момент он оказывается на странице. Однако, как только я открыл консоль, мое внимание привлекло кое-что, что на самом деле было водяным знаком на этой странице.
Любопытство, вызванное ОКР
После запуска моего кода я вернулся к разделу элементов и хотел его удалить (кто сказал вам быть таким большим, я присматривался). Нажмите, чтобы выбрать div, затем нажмите «Удалить».
"Кряк!", должно быть, я не нажимал. Опять "Кряк!", да? див мерцает? "Кряк!", не могу удалить! ?
Что ж, я изменю стиль. display:none, устроило!Почему я проиграл, div снова замигал, а изменения только сейчас исчезли
В этот момент вскоре появился объект подозрения — MutationObserver.
MutationObserver: предоставляет возможность отслеживать изменения, внесенные в дерево DOM. Он был разработан как замена старой функции Mutation Events, которая была частью спецификации DOM3 Events. Подробности можно посмотретьmdn
Затем общая логика заключается в том, что MutationObserver отслеживает изменения этого водяного знака, такие как удаление, модификация attr, добавление дочерних узлов, а затем напрямую перерисовывает элемент, точно такой же, как исходный, понимая, что «вы не можете измените этот узел, даже если вы откроете консоль" Эффект
Поисковые исследования в исходном коде
В разделе исходного кода я нашел файл js, относящийся к странице, искал MutationObserver и, наконец, нашел такую функцию:
function observeSelector(e) {
if (e) {
var t = e.cloneNode(!0)
, n = e.parentNode || document.body;
new MutationObserver(function (r) {
e && r.forEach(function (r) {
var o = r.target
, i = Array.prototype.slice.call(r.removedNodes)[0];
if (o === e) {
var a = t.cloneNode(!0);
n.replaceChild(a, e),
e = a
} else
i === e && (e = e.cloneNode(!0),
n.appendChild(e))
})
}
).observe(document.body, {
attributes: !0,
childList: !0,
subtree: !0
})
}
}
Измените его, чтобы улучшить читаемость:
function observeSelector(element) {
if (element) {
const parentNode = element.parentNode || document.body;
// 为什么这么做?因为这是最原始的节点了
// 如果直接拿element去replace只能拿到具有最新属性的节点
const newClonedNode = element.cloneNode(true);
new MutationObserver(mutations => {
mutations.forEach(mutationRecord => {
const currentTarget = mutationRecord.target;
const removedNode = mutationRecord.removedNodes[0];
// 修改属性的时候,target就是当前元素
if (currentTarget === element) {
const replaceNode = newClonedNode.cloneNode(true);
parentNode.replaceChild(replaceNode, element);
element = replaceNode;
} else {
// 删除元素的时候,removedNodes是一个数组,只删它一个,那第一个就是当前元素
if (removedNode === element) {
element = element.cloneNode(true);
parentNode.appendChild(element);
}
}
});
}).observe(document.body, {
attributes: true,
childList: true,
subtree: true, // 监听后代节点变化
});
}
}
-
При изменении атрибутов (когда атрибуты имеют значение true, изменение атрибутов узла может инициировать этот обратный вызов) в это время целью под мутациейRecord каждого элемента мутаций является текущий узел. Идея такова: изменить его и заменить его
-
При удалении узла массив removeNodes в MutationRecord представляет собой массив всех узлов, которые в настоящее время удалены. Конечно, здесь мы удалили только один узел, поэтому узел только один. Идея такова: удалить один и добавить его обратно
Эту функцию можно напрямую использовать в «защите элементов», добавляя MutationObserver к элементу, чтобы другие люди с техническим образованием не могли открыть консоль, чтобы изменить этот элемент, чтобы сделать некоторые другие скрытые секретные вещи (поддельные скриншоты, перекрестные разрешения, открытые данные, но с водяными знаками). )
Эту функцию можно использовать для защиты элементов, чтобы некоторые внешние интерфейсы не открывали консоль для изменения элементов, а затем делали снимки экрана. Конечно, если вам нужно использовать его в своих требованиях, вам нужно учитывать вещи: очистку обозревателя по времени, масштабируемость и совместимость.
как это победить
магический стиль
Изменение стиля родительского узла может решить проблему, но родительским водяным знаком этой страницы является тело, и изменение тела повлияет на просмотр страницы. Мы можем изменить угол и добавить прозрачный стиль фона к псевдоэлементу перед водяным знаком, чтобы он был похож на цвет водяного знака.
// 137是canvas的getimagedata知道的
var str = `.水印div的class::before {
content: '';
width: 100vw;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: 10000;
background-color: rgba(137, 137, 137, 0.95);
pointer-events: none;
}`;
var style = document.createElement('style');
style.textContent = str;
document.head.appendChild(style);
// 酌情微调一下fliter,如对比度、亮度、饱和度等
document.body.style.filter = 'contrast(6.5)'
Однако это сделает страницу мутной и покроется слоем
Удалить основной контент
Мы знаем, что им можно управлять, вмешиваясь в стиль его родительского узла, но мы боимся непредумышленного уничтожения содержимого. Итак, почему бы нам не удалить содержимое и не скрыть тело (appendChild имеет эффект «высасывания»)
// 控制台选中主内容, 即document.querySelector('水印元素选择器')
document.documentElement.appendChild($0)
Затем добавьте в тело display: none, и появится белая страница без водяных знаков!
document.body.style.display = 'none';
Владею клюшкой, но целюсь во двор. На самом деле, если вы снова используете MutationObserver для мониторинга document.documentElement и обнаружите, что добавлен новый элемент водяного знака, добавьте его обратно в тело и предотвратите это:
((targetNode) => {
new MutationObserver((mutations) => {
mutations.forEach(({ addedNodes }) => {
addedNodes.forEach(node => {
if (node === targetNode) {
document.body.appendChild(targetNode)
}
})
});
}).observe(document.documentElement, {
childList: true,
});
})(document.querySelector('水印元素选择器'));
эм... Вы когда-нибудь задумывались о том, что происходит с матрешкой, наблюдайте за новым целевым узлом под html, а затем перемещайте его в тело, наблюдайте за новым целевым узлом под телом, затем перемещайте его в html и затем добавьте новый узел в html
((targetNode) => {
new MutationObserver((mutations) => {
mutations.forEach(({ addedNodes }) => {
addedNodes.forEach(node => {
if (node === targetNode) {
document.body.appendChild(targetNode)
}
})
});
}).observe(document.documentElement, {
childList: true,
});
})(document.querySelector('水印元素选择器'));
// 新增body的observe
((targetNode) => {
new MutationObserver((mutations) => {
mutations.forEach(({ addedNodes }) => {
addedNodes.forEach(node => {
if (node === targetNode) {
document.documentElement.appendChild(targetNode)
}
})
});
}).observe(document.body, {
childList: true,
});
})(document.querySelector('水印元素选择器'));
Не говорите этого, мой компьютер сильно нагревается, предполагается, что его код работоспособности стал красным, и его нужно изолировать от меня. Бывает бесконечный цикл, нужно быть внимательным при его использовании
Если вы хотите решить проблему, связанную с тем, что MutationObserver отслеживает document.documentElement, чтобы предотвратить перемещение элемента водяного знака, все еще есть способ: добавьте элемент div в элемент documentElement и переместите элемент водяного знака в элемент div.
Поскольку div добавляется, чтобы выйти за рамки этого шага, предотвращение также может быть усилено. MutationObserver — это универсальный подход, запрещающий выполнение всех дочерних списков и поддеревьев. Если это не элемент водяного знака, удалите его и если это элемент водяного знака, поместите его обратно в тело.
Это все так бессердечно, тогда я напишу скрипт инъекций плагина для браузера Google, напрямую модифицирую глобальный MutationObserver, чтобы посмотреть, как вы играете... Давайте закончим, вещи всегда выше дьявола, давайте поговорим об этом. на сервер для борьбы с остроумием
Обратите внимание на официальный аккаунт «Другой интерфейс», изучите интерфейс с другой точки зрения, быстро развивайтесь, играйте с новейшими технологиями, изучайте различные черные технологии и делайте что-то вместе.