roysue 发表于 2021-9-26 10:49

js hook 改进

## js批量hook
### 参考hook
我们可以更改上次的脚本,用来遍历所有的函数来找出其中是否有以加密命名的函数,来尝试找到js中的加密函数,参考自`http://bbs.nightteam.cn/thread-210.htm`
我们用它的代码测试一下,我们自己的网站
```js
(function() {
    'use strict';
    !function () {
      'use strict';
      var source = ['alert','decodeData','String.fromCharCode',
            'fromCharCode','base64decode','md5','decode','btoa','JSON.stringify',
            'MD5','RSA','AES','CryptoJS','encrypt',
            'strdecode',"encode",'decodeURIComponent','_t'];
      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];
            }
            return realCtx;
      }
      function getRealName(funcName) {
            let parts = funcName.split(".");
            return parts;
      }
      function test(ctx) {
            for(let i = 0; i < source.length; i++) {
                let f = source;
                let realCtx = getRealCtx(ctx, f);
                let realName = getRealName(f);
                let chars = realCtx;
                if (chars != undefined){
                  console.log("发现可疑函数:", f);
                  console.log(chars);
                  console.log("---------------------");
                }else{
                  console.log("未发现:", f);
                }
            }
      }
      test(window);
    }();
})();

```

### 改进
但是这种方式无法找到局部变量或混淆之后的方法有一定的局限性,我们壳以根据这种思路进行一下小的改进,将系统底层的对象的所有函数都hook上,那么当任何调用的时候都会经过我们重写的函数,以String为例。首先我们遇到了第一个问题,就是一些有一些属性不可被遍历如下图,所以不能用循环的方式遍历,有一些属性不能被重写,哦我们同样也是不能hook它的。

```js
for (const stringHookArrayKey in String_hook_Array) {
    let value = String_hook_Array
    if(value["writable"]
      && typeof value.value === "function"){
      console.log(stringHookArrayKey)
      value.value.hook(String)
    }
}
```
接着我们还要hook原形链中的方法,为了防止套娃调用爆栈,所以我们不处理toString方法,另外发现String中的concat方法一直在搞我们,所以把他也过滤掉。

```js
for (const stringPrototypeHookArrayKey in String_prototype_hook_Array) {
    let value = String_prototype_hook_Array
    if(value["writable"]
      && typeof value.value === "function"
      && stringPrototypeHookArrayKey !== "toString"
      && stringPrototypeHookArrayKey !== "concat"
    ){
      console.log(stringPrototypeHookArrayKey)
      value.value.hook(String.prototype)
    }
}
```
最终成品如下,这样有一个小问题,就是虽然我们能把所有东西都hook到,但是会非常的卡顿,因为我们console.log了太多的内容
```js
let String_hook_Array = Object.getOwnPropertyDescriptors(String)
let String_prototype_hook_Array = Object.getOwnPropertyDescriptors(String.prototype)

for (const stringHookArrayKey in String_hook_Array) {
    let value = String_hook_Array
    if(value["writable"]
      && typeof value.value === "function"){
      console.log(stringHookArrayKey)
      value.value.hook(String)
    }
}

for (const stringPrototypeHookArrayKey in String_prototype_hook_Array) {
    let value = String_prototype_hook_Array
    if(value["writable"]
      && typeof value.value === "function"
      && stringPrototypeHookArrayKey !== "toString"
      && stringPrototypeHookArrayKey !== "concat"
    ){
      console.log(stringPrototypeHookArrayKey)
      value.value.hook(String.prototype)
    }
}
console.log("enum hook start")

```

### js版r0trace
接下来终于进入了我们今天的正题,就是如何实现一个像r0trace一样的项目,能够将浏览器的所有操作的都hook上,这样能够更方便的使用hook功能,如果我们不知道具体参数在哪,可以把整个浏览器所有的对象都hook上定位目标参数。首先第一步就是模仿r0trace定义一个黑白名单
```js
    if(!BlackList){
      BlackList = []
    }
    if(!WhiteList){
      WhiteList = []
    }
```
然后和上面一样,做2步就是将原型链和本身所有的属性都传入startHook函数
```js
    let HookObjDescriptors = Object.getOwnPropertyDescriptors(HookObj)
    if(HookObj.prototype){
      let HookObjPrototypeDescriptors = Object.getOwnPropertyDescriptors(HookObj.prototype)
      startHook(HookObjPrototypeDescriptors, HookObj.prototype)
    }
    startHook(HookObjDescriptors, HookObj)
```
最后实现startHook函数,只要做一些小的过滤处理即可,最后成品如下,白名单为空就是hook这个对象的所有函数,黑名单中把爆栈的函数过滤掉即可
```js
function batchHook(HookObj, BlackList, WhiteList){
    if(!BlackList){
      BlackList = []
    }
    if(!WhiteList){
      WhiteList = []
    }
    function startHook(Descriptors, HookObj){
      for (const descriptorsKey in Descriptors) {
            let value = Descriptors
            let rawFunc = value["value"]
            if(typeof rawFunc === "function"
                && value["writable"]
                && !BlackList.includes(descriptorsKey)
                && (WhiteList.length ? WhiteList.includes(descriptorsKey) : true))
            {
                console.log(descriptorsKey)
                rawFunc.hook(HookObj)
            }
      }
    }


    let HookObjDescriptors = Object.getOwnPropertyDescriptors(HookObj)
    if(HookObj.prototype){
      let HookObjPrototypeDescriptors = Object.getOwnPropertyDescriptors(HookObj.prototype)
      startHook(HookObjPrototypeDescriptors, HookObj.prototype)
    }
    startHook(HookObjDescriptors, HookObj)

}

batchHook(String, ["toString", "concat"], [])

```

直接就把我们之前验证码的密钥输出出来了,十分的好用,当然由于它输出的数据太多我们在浏览器里面看着不是很舒服,可以把它输出到一个log文件中,右键直接点击`save as`即可,如下图成功定位到了我们密钥的位置,当让如果不怕卡死的话还可以将console.log改成console.trace,能够更轻松的通过调用栈。找到它的函数的位置

### js版objection 内存漫游
最后介绍一下`https://github.com/CC11001100/ast-hook-for-js-RE`这个项目,借助这个工具我们可以检索浏览器中的任意数据。首先安装它,非常的简单,用git拉
```bash
git clone https://github.com/CC11001100/ast-hook-for-js-RE.git
```
然后用pycharm打开它,保证自己的nodejs版本大于14.0.0,然后在pycharm的命令行安装
```bash
npm install
```
然后用`anyproxy ca`命令去启动一个server,我们访问`127.0.0.1:8002/`去安装一个证书




然后启动proxy-serer,给浏览器配置一个代{过}{滤}理或者直接启动的时候就加代{过}{滤}理`google-chrome --proxy-server="127.0.0.1:10086" --no-sandbox`

pycharm中出现内容就说明代{过}{滤}理配置成功了

然后打开我们的试题网站做一个测试,直接用`hook.search`传入我们的参数就好了,非常的牛逼所有出现这个参数的地方都打印出来了

bp946 发表于 2021-9-26 11:26

学习学习

空欢 发表于 2021-9-26 11:56

牛蛙牛蛙

半世流离 发表于 2021-9-26 13:39

学习一下

chhzll 发表于 2021-9-26 15:12


学习学习

lcwxxf 发表于 2021-9-26 19:44

向大神努力学习中,学无止境

不一般 发表于 2021-9-27 05:03

牛蛙牛蛙{:1_899:}

cjc3528 发表于 2021-9-27 09:44

好NB的教程啊,谢谢分享

fywyk2 发表于 2021-9-27 09:44

这个方便

梦幻之神 发表于 2021-9-27 09:57

学习一下js
页: [1] 2 3 4 5
查看完整版本: js hook 改进