首发于大前端
伪装成一个原生函数

伪装成一个原生函数

今天看到这样一个函数 (出自Vue src/core/util/env)

/* istanbul ignore next */
function isNative (Ctor: Function): boolean {
  return /native code/.test(Ctor.toString())
}

这是一个判断入参是否是原生函数的函数

我们知道调用函数的toString会得到函数的内容,如果是原生函数会得到

function xxx() { [native code] }

通过正则去判断,正常情况下也没什么问题,但是我们却能利用这个写一个假的原生函数。。。

function nativeFun (){
    // native code
    alert(1)
}


那有没有更加严谨的方法呢?我们可以用更严格的正则去匹配 ,来自Lodash的方法

// Used to resolve the internal `[[Class]]` of values
  var toString = Object.prototype.toString;
  
  // Used to resolve the decompiled source of functions
  var fnToString = Function.prototype.toString;
  
  // Used to detect host constructors (Safari > 4; really typed array specific)
  var reHostCtor = /^\[object .+?Constructor\]$/;

  // Compile a regexp using a common native method as a template.
  // We chose `Object#toString` because there's a good chance it is not being mucked with.
  var reNative = RegExp('^' +
    // Coerce `Object#toString` to a string
    String(toString)
    // Escape any special regexp characters
    .replace(/[.*+?^${}()|[\]\/\\]/g, '\\$&')
    // Replace mentions of `toString` with `.*?` to keep the template generic.
    // Replace thing like `for ...` to support environments like Rhino which add extra info
    // such as method arity.
    .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
  );
  
  function isNative(value) {
    var type = typeof value;
    return type == 'function'
      // Use `Function#toString` to bypass the value's own `toString` method
      // and avoid being faked out.
      ? reNative.test(fnToString.call(value))
      // Fallback to a host object check because some environments will represent
      // things like typed arrays as DOM methods which may not conform to the
      // normal native pattern.
      : (value && type == 'object' && reHostCtor.test(toString.call(value))) || false;
  }
  
  // export however you want
  module.exports = isNative;
}());

这个函数做了

1. 通过严格的正则匹配函数 toString 后的字符串

2. 通过 Function.prototype.toString 去代替函数本身的 toString ,防止其篡改

3. 添加一些兼容处理

这样就能判断出上面的假原生函数了吧

但是还有没有更高明的伪装术呢,我们来看下面这个函数

var nativeFun = (function() { alert(1); }).bind(window)

我利用原生的 bind 函数来骗过了上面的正则检验。

虽然一般不会有通过伪装成原生函数来达到一些不可告人秘密的行径。

但是,就想问一句,有没有一个 real * isNative 方法。

发布于 2017-03-03 22:25