承接上一节讲的讲的如何hook ,我们今天这节讲的是把上一节的内容封装成一个函数以便于反复调用。
本节内容用到了前几节的知识,不懂的话去翻看前几节的文章
(在学习js逆向之前呢给大家一点小小的建议就是先对js基础有一个了解,系统的学习一下js这门语言 这里呢我推荐一门课程)【【路飞学城】JavaScript核心编程详解】https://www.bilibili.com/video/BV1Dv411y7Z9?vd_source=ba017adc1d6555500de71f0ea6bc52dd
大家跟这个视频系统学习一下就能对js有很深的了解 对大家的逆向有很大的帮助
最终成品
window.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] }")
window.setNative=function (func,funcname){
set_native(func,mysymbol,`function ${funcname || func.name || ""}() { [native code] }`)
}
})()
//hook 实现hook插件的实现
window.hook=function (func,funcInfo,isDebug,onEnter,onLeave,isExec){
if(typeof func !=="function"){
return func
}
if(funcInfo===undefined){
funcInfo={
};
funcInfo.objname="globalThis";
funcInfo.name=func.name||"";
}
if(isDebug===undefined){
isDebug=false
}
if(!onEnter){
onEnter=function (obj){
console.log(`{hook|${funcInfo.objname}[${funcInfo.name}]正在被调用,参数事${JSON.stringify(obj.arg)}`);
};
}
if(!onLeave){
onLeave=function (obj){
console.log(`{hook|${funcInfo.objname}[${funcInfo.name}]返回值是一个${JSON.stringify(obj.res)}`);
}
}
if(!isExec){
isExec=true
}
hookFunc=function (){
if(isDebug){
debugger
}
let obj={}
obj.arg=[]
obj.res
for(let index=0;index<arguments.length;index++){
obj.arg[index]=arguments[index]
}
//原函数执行前需要执行的内容
onEnter.call(this,obj)
//原函数执行
if(isExec){
obj.res= func.apply(this,obj.arg)
}
jieguo= onLeave.call(this,obj)
return obj.res
}
window.setNative(hookFunc,funcInfo.name)
window.reNameFunc(hookFunc,funcInfo.name)
return hookFunc
}
//hook对象属性的本质就是替换属性描述符
window.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=window.hook(value,funcInfo,isDebug)
}
if(initial_prop.hasOwnProperty("get")){
let get=initial_prop.get
let funcInfo={
"objname":obj,
"name":`get ${propName}`,
}
Replacement_prop.get=window.hook(get,funcInfo,isDebug)
}
if(initial_prop.hasOwnProperty("set")){
let set=initial_prop.set
let funcInfo={
"objname":obj,
"name":`set ${propName}`,
}
Replacement_prop.set=window.hook(set,funcInfo,isDebug)
}
Object.defineProperty(obj,propName,Replacement_prop)
}
window.hookproto=function hookProto (protp,isdebug){
let protoObj=protp.prototype
let name =protp.name
for (let i in Object.getOwnPropertyDescriptors(protoObj)){
window.hookObj(protoObj,`${name}.prototype`,i,isdebug)
}
console.log(`{hook} |${name}.prototype `);
}
下面我们来看一下效果
将我们的代码添加到我们的代码段里面 点击运行
然后运行我们的函数 把Document 传进去
马上就吐出了 参数日志