首页
社区
课程
招聘
[原创][分享] 一个用于 Web 分析的 Chrome 扩展(一键定位代码位置)
发表于: 2022-4-3 15:51 1796

[原创][分享] 一个用于 Web 分析的 Chrome 扩展(一键定位代码位置)

2022-4-3 15:51
1796

最近没事写了一个 chrome 扩展,放到 github 上了,顺便申请了一下应用商店,过审好慢啊,地址 Trace

 

分析网页隐藏行为,一键定位代码位置,拦截请求修改响应,自动反混淆

 

配置页的样子是这样的:

 

Options 配置页

 

功能基本属于一看就懂的系列,追踪的有 Cookie 的设置获取、Element 的创建调用以及 Event 的注册监听,还有变量搜索(会记录运行时产生的所有字符串变量)。在弹框页打开开关,然后刷新页面查看控制台输出就可以了,一键定位代码位置,其他说明还请移步 github。

 

这里着重介绍一下 hookProxy 函数,通过代理和反射实现的,对事件、元素对象的追踪功能也是由该函数实现的,理论上可以 hook window 和 document 的大部分属性和对象,可以追踪程序的执行过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/**
 * 使用代理 hook 任意对象
 *
 * 目前 handler function 有 construct apply get set has
 *
 * hookFunction = function(value, ...arguments){
 *     // do something;
 *     return value
 * }
 * hookFunction.handler = 'apply'
 *
 * @param {*} obj 需要 hook 对象
 * @param {string=} objName hook 对象自定义名称 (可选)
 * @param {(Function|Array.<Function>)=} hookFunctions 对代理对象不同 handler 的自定义操作函数 (可选)
 * @returns {Proxy} obj 对象的代理
 */
function hookProxy(obj, objName, hookFunctions) {
    if (obj === undefined || obj === null) {
        return obj
    }
    if (objName instanceof Function || objName instanceof Array) {
        hookFunctions = objName;
        objName = undefined;
    }
    objName = objName ? objName : obj[Symbol.toStringTag] ? obj[Symbol.toStringTag] : obj instanceof Function ? obj["name"] : Object.prototype.toString.call(obj).slice(1, -1).split(' ')[1];
    var handler = {
        construct: function (target, argumentsList, newTarget) {
            // new
            logWithLoc(objName, ' .new ', argumentsList);
            return Reflect.construct(target, argumentsList, newTarget)
        },
        apply: function (target, thisArg, argumentsList) {
            // call
            var value = Reflect.apply(target, thisArg, argumentsList);
            switch (objName) {
                case "decodeURIComponent":
                case "btoa":
                    logWithLoc(objName, ' result ', value);
                    break
                case "createElement":
                case 'addEventListener':
                    logWithLoc(objName, argumentsList);
                    break
                default:
                    logWithLoc(objName, ' .call ', argumentsList);
            }
            return value;
        },
        get: function (target, property, receiver) {
            // get
            if (property !== "prototype") { // 获取构造函数原型
                logWithLoc(objName, ' .get ', property.toString());
            }
            var value = Reflect.get(target, property, target); // 调用上下文绑定到 target // Uncaught TypeError: Illegal invocation
            if(value instanceof Function) return value.bind(target);
            return value
        },
        set: function (target, property, value, receiver) {
            // set
            logWithLoc(objName, ' .set ', property, value);
            return Reflect.set(target, property, value, target);
            // return Reflect.set(target, property, value, receiver);
        },
        has: function (target, prop) {
            // in
            logWithLoc(objName, ' .has ', prop);
            return Reflect.has(target, prop);
        },
        defineProperty: Reflect.defineProperty,
        deleteProperty: Reflect.deleteProperty,
        getOwnPropertyDescriptor: Reflect.getOwnPropertyDescriptor,
        getPrototypeOf: Reflect.getPrototypeOf,
        isExtensible: Reflect.isExtensible,
        ownKeys: Reflect.ownKeys,
        preventExtensions: Reflect.preventExtensions,
        setPrototypeOf: Reflect.setPrototypeOf
    }
    if (hookFunctions instanceof Function) {
        if (hookFunctions.handler && handler[hookFunctions.handler]) {
            let orgFunc = handler[hookFunctions.handler];
            handler[hookFunctions.handler] = function (){
                let value = orgFunc(...arguments);
                return hookFunctions(value, ...arguments)
            }
        }
    }
    if (hookFunctions instanceof Array) {
        for (let hookFunction of hookFunctions) {
            if (hookFunction.handler && handler[hookFunction.handler]) {
                let orgFunc = handler[hookFunction.handler];
                handler[hookFunction.handler] = function (){
                    let value = orgFunc(...arguments);
                    return hookFunction(value, ...arguments)
                }
            }
        }
    }
    return new Proxy(obj, handler);
}

如果只是简单查看对象调用情况的话,直接传一个对象就可以了,但是如果需要对原返回值做一些操作就需要传一个或多个 hookFunction 了。

 

效果的话可以在脚本注入或者控制台输入这么一段代码:

1
2
3
for (let i of Proxiable){
    window[i] = hookProxy(window[i]);
}

hookProxy 还有一个妙用,那就是补环境。不过因为运行环境是 Node,还是需要改动一下的,然后 hook 一下 global, window, document, require, eval 等一些顶级对象,看输出,调啥补啥就可以了

 

另一个就是基于 Babel 插件的反混淆了,扩展只写了两个示例,后期应该会更新一下常用的插件吧。

 

使用上来说就是指定需要反混淆的地址,拖拽需要使用的插件,打开反混淆开关,刷新页面,就是这样简单

 

千万不要想一步全明文那样的反混淆,路有点长,得且走一会呢

 

差不多了,具体玩法还请大家开发,如有错误或其他好思路欢迎留言,最后欢迎 Star


[培训]科锐逆向工程师培训第53期2025年7月8日开班!

最后于 2022-4-6 16:09 被SevenZang编辑 ,原因:
收藏
免费 0
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回