一. 我们首先要明白我们为什么要hook 对象的属性
就是在我们js逆向的过程中需要补环境 (补环境的过程中我们想要知道脚本中对,对象中对哪个属性进行了操作,从而我们就能知道应该要补哪个属性)
二. 下面我们简单讲解一下原理,(让小白能更好的理解)不做难的操作
需要小白先去对js对象有一定的学习
首先我们要从对象属性的描述符入手(每一个对象的属性他都会有一个描述符,这个描述符其实也是一个对象)(知道的朋友直接看下面实现原理)
1.属性的类型
[[Configurable]]
:表示属性是否可以通过
delete
删除并重新定义,是否可以修改它的特
性,以及是否可以把它改为访问器属性。默认情况下,所有直接定义在对象上的属性的这个特
性都是
true
,如前面的例子所示。
[[Enumerable]]
:表示属性是否可以通过
for-in
循环返回。默认情况下,所有直接定义在对
象上的属性的这个特性都是
true
,如前面的例子所示。
[[Writable]]
:表示属性的值是否可以被修改。默认情况下,所有直接定义在对象上的属性的
这个特性都是
true
,如前面的例子所示。
[[Value]]
:包含属性实际的值。这就是前面提到的那个读取和写入属性值的位置。这个特性
的默认值为
undefined
。
在像前面例子中那样将属性显式添加到对象之后,
[[Configurable]]
、
[[Enumerable]]
和
[[Writable]]
都会被设置为
true
,而
[[Value]]
特性会被设置为指定的值
2.
访问器属性
访问器属性不包含数据值。相反,它们包含一个获取(
getter
)函数和一个设置(
setter
)函数,不
过这两个函数不是必需的。在读取访问器属性时,会调用获取函数,这个函数的责任就是返回一个有效
的值。在写入访问器属性时,会调用设置函数并传入新值,这个函数必须决定对数据做出什么修改。访
问器属性有
4
个特性描述它们的行为。
[[Configurable]]
:表示属性是否可以通过
delete
删除并重新定义,是否可以修改它的特
性,以及是否可以把它改为数据属性。默认情况下,所有直接定义在对象上的属性的这个特性
都是
true
。
[[Enumerable]]
:表示属性是否可以通过
for-in
循环返回。默认情况下,所有直接定义在对
象上的属性的这个特性都是
true
。
[[Get]]
:获取函数,在读取属性时调用。默认值为
undefined
。
[[Set]]
:设置函数,在写入属性时调用。默认值为
undefined
。
2. 给对象设置属性描述符的方法访问器属性是不能直接定义的,必须使用 Object.defineProperty()。
这个方法需要传入三个参数
参数1 传入一个对象(要给哪一个对象设置)
参数2 属性名称 (要给对象中哪个属性设置)
参数3 传入一个对象 (这个对象里面是属性描述符)
下面是一个例子
let book = {
year_: 2017,
edition: 1
};
Object.defineProperty(book, "year", {
get() {
return this.year_;
},
set(newValue) {
if (newValue > 2017) {
this.year_ = newValue;
this.edition += newValue - 2017;
}
}
});
book.year = 2018;
console.log(book.edition);
在这个例子中,对象
book
有两个默认属性:
year_
和
edition
。
year_
中的下划线常用来表示该
属性并不希望在对象方法的外部被访问。另一个属性
year
被定义为一个访问器属性,其中获取函数简
单地返回
year_
的值,而设置函数会做一些计算以决定正确的版本(
edition
)。因此,把
year
属性修改
为
2018
会导致
year_
变成
2018
,
edition
变成
2
。这是访问器属性的典型使用场景,即设置一个属性
值会导致一些其他变化发生。
获取函数和设置函数不一定都要定义。只定义获取函数意味着属性是只读的,尝试修改属性会被忽
略。在严格模式下,尝试写入只定义了获取函数的属性会抛出错误。类似地,只有一个设置函数的属性
是不能读取的,非严格模式下读取会返回
undefined
,严格模式下会抛出错误。
在不支持
Object.defineProperty()
的浏览器中没有办法修改
[[Configurable]]
或
[[Enumerable]]
。
二. 实现原理
对一个对象的一个属性的hook 的简单原理
//假如我们有一个person对象里面有一个name属性 当然我们目前只hook一个属性,后面会讲解一个对象多个属性的hook
person={
name:"张三"
}
//hook 时机要在对象加载完之后
//我们要hook person name 属性 先要拿一个变量存起来
my_name=person.name
Object.defineProperty(person,"name",{
get:function (){
//这个方法实在对象获取属性时触发
console.log("person对象name 属性被获取",my_name)
return my_name
},
set:function (val){
//这个属性在设置值的时候触发
console.log("perosn 对象name属性被 设置",val)
my_name=val
}
})
console.log(person.name)//在属性被调用之前hook
person.name="李斯"
console.log(person.name)
person对象name 属性被获取 张三
张三
perosn 对象name属性被 设置 李斯
person对象name 属性被获取 李斯
李斯