用了V神插件的功能之后,有感而发。自己也模仿着写了一个hook脚本,目前hook了大部分dom节点相关的方法、值,每当JS调用dom节点方法或者值的时候,就会打印在控制台。我将鼠标事件以及Object也一起hook了,这样就能更愉快的分析了~
globalMy = {};
globalMy.console_log = console.log;
globalMy.is_log = true;
globalMy.is_debug = false;
globalMy.not_log = [];
globalMy.want_debug = [];
globalMy.set_func_prop = function(func_descriptors){
let prop_track = [];
for (let name in func_descriptors){
if(name == "caller" || name == "arguments" || name == "prototype"){
continue;
}
let descriptor = func_descriptors[name];
let val = descriptor["value"];
let attr = {
configurable : descriptor["configurable"],
enumerable : descriptor["enumerable"],
}
if(descriptor["writable"]){
attr["writable"] = descriptor["writable"];
}
if(val == undefined){
debugger;
}
else{
attr["value"] = val;
}
prop_track.push({name:name,attr:attr});
}
return prop_track;
};
//保护函数,保护toString
(() => {
'use strict';
const $toString = Function.toString;
const myFunction_toString_symbol = Symbol('('.concat('', ')_', (Math.random() + '').toString(36)));
//key
const myToString = function () {
return typeof this == 'function' && this[myFunction_toString_symbol] || $toString.call(this);
};
function set_native(func, key, value) {
try {
Object.defineProperty(func, key, {
"enumerable": false,
"configurable": true,
"writable": true,
"value": value
})
} catch (e) {
globalMy.console_log("保护函数出错 => ", e)
debugger
}
}
set_native(Function.prototype, "toString", myToString);
//自己定义一个getter方法
set_native(Function.prototype.toString, myFunction_toString_symbol, "function toString() { [native code] }");
globalMy.functionprotect = (func, func_name, type) => {
set_native(func, myFunction_toString_symbol, `function ${
func_name || ''}() { [native code] }`);
}
;
}
).call(globalMy);
globalMy.check_debug = function check_debug(key) {
if (globalMy.is_debug || globalMy.want_debug.indexOf(key + '') !== -1) {
debugger;
}
}
globalMy.check_log = function check_log(obj, param_func_name, args, result) {
if (globalMy.is_log && globalMy.not_log.indexOf(param_func_name) === -1) {
let arg;
if (args.length === 1) {
arg = args[0]
} else {
arg = []
for (let i = 0; i < args.length; i++) {
arg.push(args[i]);
}
}
let property;
try {
property = JSON.stringify(obj)
} catch (e) {
property = obj
}
globalMy.console_log("[*] ", " 调用者 =>", obj, "属性值 => ", property, " 函数名 => ", param_func_name, " 传参 => ", arg, " 结果 => ", result)
}
}
// hook HTMLXxxxElement 下的所有属性的get set方法,以及方法的hook
globalMy.hook_HTML = function fuck_HTML(html) {
let html_name = html.name;
globalMy[html_name] = {};
let descriptors = Object.getOwnPropertyDescriptors(html.prototype);
for (let key in descriptors) {
if (key !== 'constructor') {
let param_value = descriptors[key].value;
if (typeof param_value === 'function') {
let attr = {
configurable: descriptors[key]['configurable'],
enumerable: descriptors[key]['enumerable'],
}
if(descriptors[key]["writable"]){
attr["writable"] = descriptors[key]["writable"];
}
let param_func_name = param_value.name;
globalMy[html_name][param_func_name] = function () {
let result = param_value.apply(this, arguments);
globalMy.check_debug(key);
globalMy.check_log(this, param_func_name, arguments, result);
return result;
}
globalMy.functionprotect(globalMy[html_name][param_func_name], param_func_name)
attr['value'] = globalMy[html_name][param_func_name];
Object.defineProperty(html.prototype, key, attr);
} else if (typeof param_value === 'undefined') {
let attr = {
configurable: descriptors[key]['configurable'],
enumerable: descriptors[key]['enumerable'],
}
if (descriptors[key]['writable']) {
attr['writable'] = descriptors[key]['writable']
}
// globalMy.console_log(descriptors[key])
if (descriptors[key]['get']) {
let param_func_name = descriptors[key]['get'].name;
globalMy[html_name][key + '_get'] = function () {
let result = descriptors[key]['get'].apply(this, arguments);
globalMy.check_debug(key);
globalMy.check_log(this, param_func_name, arguments, result);
return result;
}
let func_attr_track = globalMy.set_func_prop(Object.getOwnPropertyDescriptors(descriptors[key]['get']));
var i = 0;
while (i < func_attr_track.length){
Object.defineProperty(globalMy[html_name][key + '_get'],func_attr_track[i].name,func_attr_track[i].attr);
i++;
}
globalMy.functionprotect(globalMy[html_name][key + '_get'], param_func_name, 'get');
attr['get'] = globalMy[html_name][key + '_get'];
} else {
attr['get'] = undefined;
}
if (descriptors[key]['set']) {
let param_func_name = descriptors[key]['set'].name;
globalMy[html_name][key + '_set'] = function () {
let result = descriptors[key]['set'].apply(this, arguments);
globalMy.check_debug(key);
globalMy.check_log(this, param_func_name, arguments, result);
return result;
}
let func_attr_track = globalMy.set_func_prop(Object.getOwnPropertyDescriptors(descriptors[key]['set']));
var i = 0;
while (i < func_attr_track.length){
Object.defineProperty(globalMy[html_name][key + '_set'],func_attr_track[i].name,func_attr_track[i].attr);
i++;
}
globalMy.functionprotect(globalMy[html_name][key + '_set'], param_func_name, 'set')
attr['set'] = globalMy[html_name][key + '_set'];
} else {
attr['set'] = undefined;
}
try {
Object.defineProperty(html.prototype, key, attr);
} catch (e) {
debugger
}
}
}
}
}
// hook Object, hook 像window location 这样的属性,不得行
globalMy.hook_obj = function hook_obj(html) {
let html_name = html.name;
globalMy[html_name] = {};
let descriptors = Object.getOwnPropertyDescriptors(html);
for (let key in descriptors) {
if (key !== 'constructor') {
let param_value = descriptors[key].value;
if (typeof param_value === 'function') {
let attr = {
configurable: descriptors[key]['configurable'],
enumerable: descriptors[key]['enumerable'],
}
if(descriptors[key]["writable"]){
attr["writable"] = descriptors[key]["writable"];
}
let param_func_name = param_value.name;
globalMy[html_name][param_func_name] = function () {
let result = param_value.apply(this, arguments);
globalMy.check_debug(key);
globalMy.check_log(this, param_func_name, arguments, result);
return result;
}
globalMy.functionprotect(globalMy[html_name][param_func_name], param_func_name)
attr['value'] = globalMy[html_name][param_func_name];
Object.defineProperty(html, key, attr);
} else if (typeof param_value === 'undefined') {
let attr = {
configurable: descriptors[key]['configurable'],
enumerable: descriptors[key]['enumerable'],
}
if (descriptors[key]['writable']) {
attr['writable'] = descriptors[key]['writable']
}
// globalMy.console_log(descriptors[key])
if (descriptors[key]['get']) {
let param_func_name = descriptors[key]['get'].name;
globalMy[html_name][key + '_get'] = function () {
let result = descriptors[key]['get'].apply(this, arguments);
globalMy.check_debug(key);
globalMy.check_log(this, param_func_name, arguments, result);
return result;
}
let func_attr_track = globalMy.set_func_prop(Object.getOwnPropertyDescriptors(descriptors[key]['get']));
var i = 0;
while (i < func_attr_track.length){
Object.defineProperty(globalMy[html_name][key + '_get'],func_attr_track[i].name,func_attr_track[i].attr);
i++;
}
globalMy.functionprotect(globalMy[html_name][key + '_get'], param_func_name, 'get')
attr['get'] = globalMy[html_name][key + '_get']
} else {
attr['get'] = undefined;
}
if (descriptors[key]['set']) {
let param_func_name = descriptors[key]['set'].name;
globalMy[html_name][key + '_set'] = function () {
let result = descriptors[key]['set'].apply(this, arguments);
globalMy.check_debug(key);
globalMy.check_log(this, param_func_name, arguments, result);
return result;
}
let func_attr_track = globalMy.set_func_prop(Object.getOwnPropertyDescriptors(descriptors[key]['set']));
var i = 0;
while (i < func_attr_track.length){
Object.defineProperty(globalMy[html_name][key + '_set'],func_attr_track[i].name,func_attr_track[i].attr);
i++;
}
globalMy.functionprotect(globalMy[html_name][key + '_set'], param_func_name, 'set')
attr['set'] = globalMy[html_name][key + '_set']
} else {
attr['set'] = undefined;
}
try {
Object.defineProperty(html, key, attr);
} catch (e) {
debugger
}
}
}
}
}
globalMy.init = function() {
console.clear = function () {
};
globalMy.functionprotect(console.clear, "clear");
globalMy.dom = [MimeTypeArray, PluginArray, MimeType, Plugin, Request, Path2D, NodeList, MediaEncryptedEvent, MediaQueryList, InputDeviceCapabilities, IDBRequest, IDBOpenDBRequest, IDBFactory, CSSStyleDeclaration, Image, WebSocket, XMLHttpRequestEventTarget, XMLHttpRequest, EventTarget, Node, Element, HTMLElement, WebGLRenderingContext, CanvasRenderingContext2D, HTMLAnchorElement, HTMLImageElement, HTMLFontElement, HTMLOutputElement, HTMLAreaElement, HTMLInputElement, HTMLFormElement, HTMLParagraphElement, HTMLAudioElement, HTMLLabelElement, HTMLFrameElement, HTMLParamElement, HTMLBaseElement, HTMLLegendElement, HTMLFrameSetElement, HTMLPictureElement, HTMLBodyElement, HTMLLIElement, HTMLHeadingElement, HTMLPreElement, HTMLBRElement, HTMLLinkElement, HTMLHeadElement, HTMLProgressElement, HTMLButtonElement, HTMLMapElement, HTMLHRElement, HTMLQuoteElement, HTMLCanvasElement, HTMLMarqueeElement, HTMLHtmlElement, HTMLScriptElement, HTMLDataElement, HTMLMediaElement, HTMLIFrameElement, HTMLTimeElement, HTMLDataListElement, HTMLMenuElement, HTMLSelectElement, HTMLTitleElement, HTMLDetailsElement, HTMLMetaElement, HTMLSlotElement, HTMLTableRowElement, HTMLDialogElement, HTMLMeterElement, HTMLSourceElement, HTMLTableSectionElement, HTMLDirectoryElement, HTMLModElement, HTMLSpanElement, HTMLTemplateElement, HTMLDivElement, HTMLObjectElement, HTMLStyleElement, HTMLTextAreaElement, HTMLDListElement, HTMLOListElement, HTMLTableCaptionElement, HTMLTrackElement, HTMLEmbedElement, HTMLOptGroupElement, HTMLTableCellElement, HTMLUListElement, HTMLFieldSetElement, HTMLOptionElement, HTMLTableColElement, HTMLUnknownElement, HTMLTableElement, HTMLVideoElement]
for (var i = 0; i < globalMy.dom.length - 1; i++) {
globalMy.hook_HTML(globalMy.dom[i])
}
//不想全局debug,可以关闭全局degbug,单独将你想要debug的方法名或者属性名传入进去
globalMy.want_debug = ['cookie']
// globalMy.want_debug = ['appendChild', 'createElement', 'target']
globalMy.not_log = ['get hidden', 'get visibilityState']
// 打印 鼠标事件
globalMy.hook_HTML(MouseEvent)
globalMy.hook_HTML(Document)
//hook Object.prototype 会把toString也hook了,会打印很多不必要的数据。可以hook,但是不要hook toString
//globalMy.hook_HTML(Object)
// hook Object 可以打印对方是否使用了Object里的函数做检测
globalMy.hook_obj(Object)
}
globalMy.init()
qq群:134064772
我还添加了小功能
可以关闭全局debug,只debug住你想要的方法或者值。
globalMy.is_debug = false;
globalMy.want_debug = [‘cookie’,‘appendChild’, ‘createElement’, ‘target’];
也可以选择不打印某些方法或者值,防止恶意刷屏
globalMy.not_log = [‘get hidden’,‘get visibilityState’];
目前只是一个小demo,仅供参考学习,请勿用于非法用途~
这份代码只是一个小demo,仅供学习参考,请勿用于非法用途。
星球更新了更好的hook手段,改动了浏览器源码,达到过检测的目的。