【JS逆向】一键hook dom节点脚本

【JS逆向】一键hook dom节点脚本

  • 前言
  • 代码
  • 效果
  • 结语

前言

用了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,仅供参考学习,请勿用于非法用途~

效果

【JS逆向】一键hook dom节点脚本_第1张图片

结语

这份代码只是一个小demo,仅供学习参考,请勿用于非法用途。

星球更新了更好的hook手段,改动了浏览器源码,达到过检测的目的。

你可能感兴趣的:(【JS逆向】,javascript,前端,开发语言)