当前位置: 首页 > article >正文

【js逆向】hook大全

▒ 目录 ▒

    • 🛫 导读
      • 需求
    • 1️⃣ 普通函数
    • 2️⃣ 对象方法(Class.prototype)
    • 3️⃣ 对象属性(Object.defineProperty)
    • 4️⃣ Proxy
    • 5️⃣ 批量hook示例
    • 🛬 文章小结
    • 📖 参考资料

🛫 导读

需求

除了通过chrome devtool提供的各种方案分析js以外,其实js本身就是一个编程语言,我们可以根据编程语言的逻辑,进行各种hook来方便分析代码和逻辑(可以想象成C++、java等hook)。
今天就通过js语法特性,对js的hook进行分类实践。

ps小肩膀的课程,关于js逆向是很全面的了,大家可以在bilibili上看视频教程,也可以看其书籍《反爬虫AST原理与还原混淆实战》进行系统学习。

ps2:不少库都是用了hook的概念,比较有名的网络请求库ajax、axios,其自身提供hook基址,是不错的参考。除此之外,vue等大型的框架也大量使用的了hook。

1️⃣ 普通函数

js作为动态一种弱语言,直接将函数赋值即可覆盖原有逻辑,也是最简单的hook。示例如下:

window.alertMy = window.alert
window.alert = function(s) {
  console.log('Alert: ' + s);
  if (false) { // 自定义判断条件
    window.alertMy(s)
  }
}

2️⃣ 对象方法(Class.prototype)

对象的静态方法,可以当做普通函数进行hook。
对象的非静态方法,需要考虑上下文content,也就是对象的指针this。所以不能像普通函数一样直接赋值,不过js提供了原型prototype模型,我们以localStorage.getItem为例,代码如下:

var getItemMy = Storage.prototype.getItem
Storage.prototype.getItem = (key) => {
  console.log('Storage.prototype.getItem', key)
  return getItemMy.call(localStorage, key)
}
localStorage.getItem('AEGIS_ID')

执行效果如下:
在这里插入图片描述

3️⃣ 对象属性(Object.defineProperty)

对于对象属性,js提供了方法Object.defineProperty,该方法可以拦截并修改对象属性。我们以document.domain为例,做如下修改:

Object.defineProperty(document, 'domain', {
    // 改为可修改属性!!!
    configurable: true,
    enumerable: true,
    get: function() {
        return this._domain || location.host;
    },
    set: function(value) {
        this._domain = value;
    }
});

效果如下:
在这里插入图片描述

不过document.domain的这种方法只影响使用Javascript获取的数据,不会影响浏览器发送请求时带上的浏览器标识。
事实上,有多很多系统对象都是不允许使用Object.defineProperty修改的,例如:window.locationnavigator.userAgent等。

4️⃣ Proxy

Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。参考MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
由于Proxy是一个比较新的概念,所以只有高版本浏览器才支持该功能。
在这里插入图片描述

我们依然以localStorage.getItem为例进行演示,需要注意的是,最后将localStorage.getItem = proxy1。代码如下:

const proxy1 = new Proxy(localStorage.getItem, {
  // 1.目标对象
  // 2.目标对象的上下文对象(this)
  // 3.目标对象的参数数组
  apply(target, object, args) {
    console.log(target, object, args)
    return target.call(object,...args);
  }
})
// 需要将方法设置为
localStorage.getItem = proxy1
localStorage.getItem('AEGIS_ID')

效果如下:
在这里插入图片描述

5️⃣ 批量hook示例

js逆向过程,往往需要对各种关键函数进行hook,下面是找到的油猴脚本,直接复制后在控制台运行即可,可以在变量var source中增加自己关注的函数进行监控。

以函数JSON.stringify为例,说明下面脚本流程。

  • let item = source[i]; // 获取某项(字符串),即"JSON.stringify"
  • let realCtx = getRealCtx(ctx, item); // 获取函数所在的对象(类),即JSON
  • let realName = getRealName(item); // 获取函数名,即"stringify"
  • let originFunc = realCtx[realName]; // 获取函数,即JSON.stringify
  • hook(realCtx, realName, level, originFunc); // 执行hook,即将JSON.stringify赋值给自己定义的一个函数,内部调用originFunc实现原有逻辑
// ==UserScript==
// @name         HOOK ALL end
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  day day up!
// @author       FY
// @include      *
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';
    var source = ['DeCode','EnCode','decodeData','base64decode','md5','decode','btoa','MD5','RSA','AES','CryptoJS','encrypt','strdecode',"encode",'decodeURIComponent','_t','JSON.stringify','String.fromCharCode','fromCharCode'];
    console.log("开始测试是否有解密函数");
    let realCtx, realName;
    function getRealCtx(ctx, funcName) {
        let parts = funcName.split(".");
        let realCtx = ctx;
        for(let i = 0; i < parts.length - 1; i++) {
            realCtx = realCtx[parts[i]];
        }
        return realCtx;
    }
    function getRealName(funcName) {
        let parts = funcName.split(".");
        return parts[parts.length - 1];
    }
    function hook(ctx, funcName, level, originFunc) {
        ctx[funcName] = function(a){
            console.log("level:" + level + " function:" + funcName,a);
            console.log(originFunc.toString());
            console.log(originFunc.toString);
            debugger;
            return originFunc(a);
        };
    }
    function test(ctx, level) {
        for(let i = 0; i < source.length; i++) {
            let item = source[i];
            let realCtx = getRealCtx(ctx, item);
            let realName = getRealName(item);
            let originFunc = realCtx[realName];
            hook(realCtx, realName, level, originFunc);
        }
    }
    test(window, 1);
})();

🛬 文章小结

上面各种方案中,Proxy可以实现各种hook,可以说是一劳永逸的方案。而且代码耦合性更低,实现hook更简单明了。
js逆向依托于浏览器,技术点特别多,我们需要基于现有知识储备,不断探索新的方案,从而实现目标。

📖 参考资料

  • JavaScript常用的Hook脚本 https://www.cnblogs.com/xiaoweigege/p/14954648.html
  • 爬虫从入门到精通(11) | JS逆向hook详解 https://blog.csdn.net/qq_40558166/article/details/123525365
  • js逆向:无所不能的 hook 钩子函数 https://blog.csdn.net/qq_36078992/article/details/114484218
  • 浅谈Javascript中的Hook技术 https://cloud.tencent.com/developer/article/1639578
  • 刚学的油猴脚本hook住js https://www.jianshu.com/p/1bf123b3c8bf
  • 爬虫从入门到精通(11) | JS逆向hook详解 https://blog.csdn.net/qq_40558166/article/details/123525365

**ps:**文章中内容仅用于技术交流,请勿用于违规违法行为。


http://www.kler.cn/a/926.html

相关文章:

  • JavaScript动态渲染页面爬取之Splash
  • 【容器逃逸实践】挂载/dev方法
  • python-42-使用selenium-wire爬取微信公众号下的所有文章列表
  • 机器学习基础-机器学习的常用学习方法
  • mysql存储过程创建与删除(参数输入输出)
  • Mysql--运维篇--空间管理(表空间,索引空间,临时表空间,二进制日志,数据归档等)
  • 线程池的使用:如何写出高效的多线程程序?
  • SPI读写SD卡速度有多快?
  • 「SAP ABAP」OPEN SQL(四)【FROM语句】
  • HTTP 协议
  • 体验攻略 | Persona VS. Profile,谁才是研究用户的最佳工具?
  • 手把手教你使用vue创建第一个vis.js
  • 【C++】list的使用 | 模拟实现
  • 5 全面认识java的控制流程
  • 系统集成项目管理工程师:第18章项目风险管理学习笔记
  • 4.类的基本概念
  • 【java】Java并发编程系列-基础知识(非常详细哦)
  • 【Python】正则表达式re库
  • JDBC指南
  • 网易C++实习一面
  • 重构·改善既有代码的设计.04之重构手法(下)完结
  • 【Pytorch】 理解张量Tensor
  • Golang每日一练(leetDay0007)
  • 【基础算法】单链表的OJ练习(6) # 复制带随机指针的链表 #
  • 【前端】深入浅出缓存原理
  • 彻底理解Session、Cookie、Token,入门及实战