js逆向基础11-多态代理反射常用方法

多态

多态的最根本好处在于,你不必再向对象询问“你是什么类型”而后根据得到的答案调用对象的某个行为--你只管调用该行为就是了,其他的一切多态机制都会为你安排妥当。

多态的实际含义是:同一操作作用于不同对象上,可以产生不同的解释和不同的执行结果。

function makeSound (animal) { if (animal instanceof Cat) { console.log('喵喵喵~') } else if (animal instanceof Dog) { console.log('汪汪汪!') } } class Cat {} class Dog {} makeSound(new Cat()) makeSound(new Dog())

但是上面的方法并不好,虽然实现了"多态性",但是如果我再多一种动物,我就需要再去修改一次代码,让makeSound更加完善,这显然不是我们希望的。 其实多态最根本的作用就是通过把过程化的条件语句转化为对象的多态性,从而消除这些条件分支语句。 它实际上是一种编程的思想。通俗点来说就是把"做什么"和"谁去做以及怎么去做"分离开来。 我们看下一段代码。

function makeSound(animal){if(animal.sound instanceof Function){animal.sound()}}class Cat{sound(){console.log('喵喵喵~')}}class Dog{sound(){console.log('汪汪汪!')}}class Pig{sound(){console.log('啂妮妮')}};makeSound(new Cat());makeSound(new Dog());makeSound(new Pig())

代理与反射【简单讲】

js基础用不到。我们看到的代码,大多数都和这两没啥关系。
ES6的语法降到ES5(逆向和补环境常用)

属性描述符:本质还是一个对象。


共有下面这几种属性 value:


首先了解一下什么是属性描述符。 属性描述符(Property Descriptor) 本质上是一个 JavaScript 普通对象,用于描述一个属性的相关信息,属性值 configurable:该属性的描述符是否可以修改
enumerable:该属性是否可以被枚举
writable:该属性是否可以被重新赋值存取器属性:属性描述符中如果配置了 get 和 set 中的任何一个,则该属性不再是一个普通属性,而变成了存取器属性。
get()读值函数:如果一个属性是存取器属性,则读取该属性时,会运行 get 方法,并将 get 方法得到的返回值作为属性值
set(newVal)存值函数:如果给该属性赋值,则会运行 set 方法,newVal 参数为赋值的值
存取器属性最大的意义,在于可以控制属性的读取和赋值,在函数里可以进行各种操作。
value 和 writable 属性不能与 get 和 set 属性共存,二者只能选其一
Object.getOwnPropertyDescriptor(对象, 属性名); //得到一个对象的某个属性的属性描述符 Object.getOwnPropertyDescriptors(对象); //得到某个对象的所有属性描述符 为某个对象添加属性时 或 修改属性时,配置其属性描述符,使用以下这两种方法 Object.defineProperty(对象, 属性名, 描述符); //设置一个对象的某个属性 Object.defineProperties(对象, 多个属性的描述符); //设置一个对象的多个属性
var test1 = {a: 10}
Object.getOwnPropertyDescriptor(test1, 'a')


 

Object.getOwnPropertyDescriptors(test1)(读取它们的描述符)

Object.defineProperty()修改属性描述符
Object.defineProperty() 静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象

结论
1. 当configurable 为 true 时,一切都是可以修改的
2. 当configurable 为 false 时,第二次修改为原值时不报错,如果第二次修改为相反值时存在一种特殊情况
 configurable 与 writable有一值为true 时 value 即值可修改 writable--->false
3. 除2之外,其他修改皆报错。

语法

Object.defineProperty(obj, prop, descriptor)

参数

obj

要定义属性的对象。

prop

一个字符串或 Symbol,指定了要定义或修改的属性键。

​​​​​​

要定义或修改的属性的描述符。

返回值

传入函数的对象,其指定的属性已被添加或修改。
 

configurableattributes = {
configurable: false,
enumerable: false,
writable: false,
value: 100,
}configurable

当设置为 false 时,

  • 该属性的类型不能在数据属性和访问器属性之间更改,且
  • 该属性不可被删除,且
  • 其描述符的其他属性也不能被更改(但是,如果它是一个可写的数据描述符,则 value 可以被更改,writable 可以更改为 false)。

enumerable

当且仅当该属性在对应对象的属性枚举中出现时,值为 true

数据描述符还具有以下可选键值:

value

与属性相关联的值。可以是任何有效的 JavaScript 值(数字、对象、函数等)。

writable

如果与属性相关联的值可以使用赋值运算符更改,则为 true

访问器描述符还具有以下可选键值:

get

用作属性 getter 的函数,如果没有 getter 则为 undefined。当访问该属性时,将不带参地调用此函数,并将 this 设置为通过该属性访问的对象(因为可能存在继承关系,这可能不是定义该属性的对象)。返回值将被用作该属性的值。

set

用作属性 setter 的函数,如果没有 setter 则为 undefined。当该属性被赋值时,将调用此函数,并带有一个参数(要赋给该属性的值),并将 this 设置为通过该属性分配的对象。

如果描述符没有 valuewritableget 和 set 键中的任何一个,它将被视为数据描述符。如果描述符同时具有 [value 或 writable] 和 [get 或 set] 键,则会抛出异常。

浏览器环境下 delete window.window 是false是不可删除的
但是node.js中可以删除。

批量设置描述符的方法

语法

Object.defineProperties(obj, props)

参数

obj

在其上定义或修改属性的对象。

props

一个对象,其中每个键表示要定义或修改的属性的名称,每个值是描述该属性的对象。在 中的每个值必须是且只能是数据描述符或访问器描述符之一;不能同时为两者(更多详细信息,请参见Object.defineProperty())。props

数据描述符和访问器描述符可以包含以下可选键:

configurable

如果此属性描述符的类型可以更改并且属性可以从相应的对象中删除,则为 true

enumerable

如果此属性在枚举相应对象的属性时应显示出来,则为true

数据描述符还具有以下可选键:

value

与属性关联的值。可以是任何有效的 JavaScript 值(数字、对象、函数等)。

writable

如果与属性关联的值可以使用赋值运算符更改,则为 true

访问器描述符还具有以下可选键:

get

作为该属性的 getter 函数,如果没有 getter 则为 undefined。函数返回值将被用作属性的值。

set

作为该属性的 setter 函数,如果没有 setter 则为 undefined。该函数将只接收一个参数,即被分配给属性的新值。

如果一个属性描述符没有 、、、 键中的任何一个,那么它被视为一个数据描述符。如果一个属性描述符同时具有 或 和 或 键中的任意一个组合,就会抛出异常。valuewritablegetsetvaluewritablegetset

返回值

传递给函数的对象。

get 与 set(在js逆向中常用,因为有HOOK某种对象的属性的时候)

 

test3 = {a: 10}
attributes = {
get: function (){console.log('我已经触发了get属性,我要把你嘿嘿嘿'); return '你叉叉'},
set: function (){console.log('我已经触发了set属性');console.log(arguments);},
}
Object.defineProperty(test3, 'a', attributes)
console.log(test3.a)
test3.a = 1000;

上述处理破坏了原来的功能或结构,在HOOK的时候如果不破坏原来的功能和结构,用下述代码

test4 = {a: 10}
_test4_a_cache = test4.a;
attributes = {
get: function (){debugger; return _test4_a_cache},
set: function (val){debugger;_test4_a_cache=val; return val},
}
Object.defineProperty(test4, 'a', attributes)
console.log(test4.a)
test4.a = 1000;

有HOOK就有抵抗HOOK

Reflect:
ReflectReflect 是一个内置的 JS 对象,它提供了一系列方法,可以让开发者通过调用这些方法,访问一些 JS 底层功能。由于它类似于其他语言的反射,因此取名为 Reflect。 使用 Reflect 可以实现诸如:属性的赋值与取值、调用普通函数、调用构造函数、判断属性是否存在与对象中 等等功能。 有一个重要的理念,在 ES5 就被提出:减少魔法、让代码更加纯粹(语言的方法使用 API 实现,而不使用特殊语法实现),这种理念很大程度上是受到函数式编程的影响。ES6 进一步贯彻了这种理念,它认为,对属性内存的控制、原型链的修改、函数的调用等等,这些都属于底层实现,属于一种魔法,因此,需要将它们提取出来,形成一个正常的 API,并高度聚合到某个对象中,于是就造就了 Reflect 对象。因此,你可以看到 Reflect 对象中有很多的 API 都可以使用过去的某种语法或其他 API 实现。

Proxy

ES6 新增的代理和反射为开发者提供了拦截并向基本操作嵌入额外行为的能力。具体地说,可以给目标对象(target)定义一个关联的代理对象,而这个代理对象可当作一个抽象的目标对象来使用。因此在对目标对象的各种操作影响到目标对象之前,我们可以在代理对象中对这些操作加以控制,并且最终也可能会改变操作返回的结果。代理(Proxy)能使我们开发者拥有一种间接修改底层方法的能力,从而控制用户的操作【在逆向中多用来进行hook】。

Proxy用法

JavaScript 标准内置对象




 

下面我们根据文档去介绍常用的内置函数。 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Number https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值