hook window全局对象(hook 框架完结)

window对象下面不是所有对象下面的属性都能hook,我们只能hook 

configurable可配置属性为true 

下面是完整的hook 框架

直接上代码

ld={}
ld.reNameFunc=function reNameFunc (func,name){
    Object.defineProperty(func,"name",{
        configurable: true,
        enumerable: false,
        value: name,
        writable: false
    })
}
!(function (){
    const  $toString=Function.prototype.toString
    const mysymbol=Symbol()
    const toString=function (){
        return typeof this==="function"&& this[mysymbol]|| $toString.call(this)
    }
    function set_native(func,key,value){
       Object.defineProperty(func,key,{
           enumerable:false,
           configurable:true,
           writable:true,
           value:value
       });

    }
    delete Function.prototype.toString;
    set_native(Function.prototype,"toString",toString)
    set_native(Function.prototype.toString,mysymbol,"function toString() { [native code] }")
    ld.setNative=function (func,funcname){
        set_native(func,mysymbol,`function ${funcname || func.name || ""}() { [native code] }`)

    }
})()


//hook 实现hook插件的实现
ld.hook=function (func,funcInfo,isDebug,onEnter,onLeave,isExec){
    //第一步先判断传进来的func的类型
    if (!typeof func ==="function"){//如果传进来的不是一个函数我们就直接返回
        return func
    }
    //funcInfo 关于函数的信息如果 是undefined 我们就自己给他有点补充
    if(typeof funcInfo==="undefined"){
        funcInfo={

        }
        funcInfo.Objectname="globalThis"//如果没有设置是哪个对象下面的函数 默认是全局下面
        funcInfo.funcname=func.name  || ""   };
    //是否进行断点
    if(!isDebug){
        isDebug=false//默认是false

    }
    //onEnter在进入函数执行前执行某些操作
    if(!onEnter){
        onEnter=function (arg){
            console.log(`{hook|${funcInfo.Objectname}[${funcInfo.funcname}]} 正在被调用  调用的参数是 ${JSON.stringify(arg.args)}`);
        }

    }
    //onLeave函数结束时执行默写操作

    if(!onLeave){
        onLeave=function (arg){
                        console.log(`{hook|${funcInfo.Objectname}[${funcInfo.funcname}]} 正在被调用  返回值是 ${JSON.stringify(arg.res)}`);

            ` `
        }
    }
    //是否执行原函数
    if(!isExec){
        isExec=true

    }
    //要替换的函数

    hookFunc=function (){
        if(isDebug){
            debugger
        }
        let arg={
        }
        arg.args=[]

        for(let i=0;i<arguments.length;i++){
             arg.args[i]=arguments[i]
        }//把原函数执行的参数保存下来

        //onEnter执行
        onEnter.call(this,arg)



        //原函数执行
        if(isExec){
          let res=  func.apply(this,arg.args);
           arg.res=res
        }


        onLeave.call(this,arg)


        return arg.res
    };
   ld.setNative(hookFunc,funcInfo.funcname)
    ld.reNameFunc(hookFunc,"name",funcInfo.funcname)

    return hookFunc

}
 //hook对象属性的本质就是替换属性描述符
 ld.hookObj=function hookObj (obj,objName,propName,isDebug){
    //obj 这个参数就是需要hook的对象
     //objname 被hook对象的名字、
     //propName 需要hook对象的的属性的名字
     //isdebug 是否进行调试

     //在进行hook之前我们就先把这个对象属性的描述符先保存一份
     // 用上节讲过的这个方法获取一个对象属性描述符 Object.getOwnPropertyDescriptor
     //第一个参数就是 对哪个对象进行属性获取 , 第二个参数就是要获取哪个属性的描述符
   let initial_prop=  Object.getOwnPropertyDescriptor(obj,propName);
   //接下来声明一个我们要替换的属性描述符
     let Replacement_prop={}//属性描述符本身就是一个 字典
     //在属性描述符中有两个恒定的属性就是[[Configurable]][[Enumerable]]不知道啥意思的朋友去看上一级,有详细说明
     //我们读取原来的属性描述符 ,添加到我们要替换的属性描述符中
     //首先要看一下原先的属性描述符是不是可配置的 如果不可配置我们就无法进行替换
     if(!initial_prop.configurable){
         console.log("给属性不可以被配置")
         return
     };
     Replacement_prop.configurable= initial_prop.configurable;
     Replacement_prop.enumerable=initial_prop.enumerable;
     if(initial_prop.hasOwnProperty("writable")){
         Replacement_prop.writable=  initial_prop.writable

     }

     if(initial_prop.hasOwnProperty("value")){
         let value=initial_prop.value
         if(!typeof value==="function"){
             console.log("value不是一个函数")
             return;
         }
         let funcInfo={
            "objname":obj,
             "name":propName,
         }
         Replacement_prop.value=ld.hook(value,funcInfo,isDebug)
     }
     if(initial_prop.hasOwnProperty("get")){
         let get=initial_prop.get
         let funcInfo={
            "objname":obj,
             "name":`get ${propName}`,
         }
         Replacement_prop.get=ld.hook(get,funcInfo,isDebug)
     }
      if(initial_prop.hasOwnProperty("set")){
         let set=initial_prop.set
         let funcInfo={
            "objname":obj,
             "name":`set ${propName}`,
         }
         Replacement_prop.set=ld.hook(set,funcInfo,isDebug)
     }
      Object.defineProperty(obj,propName,Replacement_prop)


 }
 ld.hookproto=function hookProto (protp,isdebug) {
     let protoObj = protp.prototype
     let name = protp.name
     for (let i in Object.getOwnPropertyDescriptors(protoObj)) {
         ld.hookObj(protoObj, `${name}.prototype`, i, isdebug)
     }
     console.log(`{hook} |${name}.prototype `);

 };
//hook 全局对象lds



ld.hookWindow=function hookWindow(isdebug){
    for (const key in Object.getOwnPropertyDescriptors(window)){
        if(typeof  window[key] ==="function"){
            if(typeof window[key].prototype==='undefined'){
                 funcInfo={
        };
        funcInfo.objname="globalThis";
        funcInfo.name=key;
                //如果是普通函数 我们就走普通函数的流程
                ld.hook(window[key],funcInfo,isdebug)
            }else if(typeof window[key].prototype==='object'){
                //如果是一个对象我们 就用hook对象属性的方式
              ld.hookproto(window[key],isdebug)

            }
        }
    }

}

复制粘贴将代码 直接复制粘贴到 浏览器的代码片段 然后运行

执行我们的 hook函数 ld.hookWindow()

下面是效果

hook 框架完结

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值