-
-
[原创][分享] 一个用于 Web 分析的 Chrome 扩展(一键定位代码位置)
-
发表于: 2022-4-3 15:51 1796
-
最近没事写了一个 chrome 扩展,放到 github 上了,顺便申请了一下应用商店,过审好慢啊,地址 Trace。
分析网页隐藏行为,一键定位代码位置,拦截请求修改响应,自动反混淆
配置页的样子是这样的:
功能基本属于一看就懂的系列,追踪的有 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
最后于 2022-4-6 16:09
被SevenZang编辑
,原因:
赞赏
赞赏
雪币:
留言: