表哥,你也不想碰上toString检测吧--toString检测,蜜罐陷阱

查看 6|回复 0
作者:nangongxt07   
首先我们需要补充一点前置的知识,第一个就是什么是原生函数,原生函数就是指由JavaScript引擎(如V8、SpiderMonkey等)暴露接口提供给开发者进行调用的函数,原生函数的实现是通过C/C++代码,并不是我们的js代码.举个例子,比如JSON.parse/stringify当我们直接把函数名称打在浏览器开发者工具控制台回车,就会发现都有native code这种关键字,native code翻译过来就是原生的代码,你是无法看到他的具体实现逻辑的,因为他在底层进行的实现,不像我们自己用js写的函数一样,可以看到实现的逻辑.
ƒ parse() { [native code] }
ƒ stringify() { [native code] }
基于这个概念,我们在来想想我们的jshook,我们的hook不就是把底层C/C++实现的函数改成我们的js去实现吗?保留一份原始函数,然后重写原生函数的逻辑.
那么我们的hook真的不会被检测吗?真的安全吗?没有不漏风的窗,茅和盾是彼此彼此的,你hook肯定会留下一些痕迹,我可以去检测你有没有这些痕迹进而制止你篡改我的原生函数.
当我们对一个原生函数进行重写的时候,我在控制台输出这个函数的名称
ƒ (params){
  var _parse=JSON.parse;
  console.log(params);
  return _parse(params);
}
这个函数的实现从C/C++层面变成了js层面的,输出的是我的hook代码,与没有重写的做个对比,也不难发现,你重写了我的原生函数后,不外加处理,肯定没有native code这样的关键字,那我的思路就是先把函数转成字符串在通过正则去匹配有没有native code这样的关键字,如果没有则返回true,有的话则返回false.
我们接下来直接看demo
function Ce(func){
  if(typeof func === "function"){
    var Sd=func["toString"]()["replace"](new RegExp("\\s", "g"), "");
    var N_="{[nativecode]}";
    return Sd["substring"](Sd["length"] - N_["length"]) === N_;
  }
}
console.log(Ce(console["debug"]));
console.log(Ce(JSON.parse));
这份检测的函数Ce的具体逻辑来自于Caplusa(reese84)的某个代码段,我是对其进行反混淆和精简处理过的.
Ce函数的大体逻辑就是先判断是不是函数类型,如果是函数类型,就将这个函数转成字符串正则去掉字符串多余的空格,在截取字符串的总长-关键字长度为索引判断截取的内容是否为关键字,如果是就返回true不是就false.
toString检测一般的作用在防止函数被篡改和浏览器环境检测
所以,我们平时写hook脚本也好,补环境补函数也好,都要对做toString保护对抗toString检测.
对抗toString检测的思路有很多,我就讲一个比较简单的吧
竟然你是通过调用函数的toString属性获取值,那我不可以覆盖toString属性的值来返回关键字native code进行绕过吗,这是我们的一个思路
我们认识一下一个新的方法Object.defineProperty,他的作用是用于直接在对象上定义一个新属性,或者修改对象的现有属性,并返回该对象.
这个方法有三个入参Object.defineProperty(targetObject, propertyName, descriptor)
分别是
targetObject    要操作的目标对象
propertyName    要定义/修改的属性名(符串或 Symbol)
descriptor  属性描述符对象,控制属性行为
描述符又有两种类型:
[ol]
  • 数据描述符(控制值)
    {
    value: any,         // 属性值
    writable: boolean,   // 是否可修改(默认 false)
    enumerable: boolean, // 是否可枚举(for-in/Object.keys,默认 false)
    configurable: boolean // 是否可删除/修改描述符(默认 false)
    }
  • 存取描述符(控制访问)
    {
    get: function() { / 获取值时调用 / },
    set: function(newVal) { / 设置值时调用 / },
    enumerable: boolean,
    configurable: boolean
    }
    [/ol]
    我们这里主要用到第一种描述符,当调用目标函数的toString属性时,我通过Object.defineProperty方法修改原有对象的toString属性也叫覆盖他原有的属性为native code关键字,不就可以进行绕过了嘛,在配置一下不可修改,不可删除防止被额外的覆盖.
    Object.defineProperty(funcs, 'toString', {
      value: function() {
        return `function ${this.name}() {
          [native code]
        }`;
      },
      writable: false,
      configurable: false,
      enumerable: false
    });

    函数, 属性

  • 您需要登录后才可以回帖 登录 | 立即注册

    返回顶部