qinless 发表于 2021-11-12 14:14

某东到家 app so signkeyV1 参数分析

本帖最后由 qinless 于 2021-11-12 18:49 编辑

# 前言
> ***京东到家 app signKeyv1 参数分析,版本 8.14.0***

# charles 抓包



就是 `djencrypt` 这个参数,是一个加密串,分析一下


# java 层分析



全局搜索定位到这个函数 `base.net.volley.BaseStringRequest.getParams`,跟进 `DaojiaAesUtil.encrypt` 看看



在跟进 `AesCbcCrypto.encrypt` 这个函数



里面写的还是比较清楚的,加密方式是 `AES/CBC/PKCS5Padding` 使用 `cyberchef` 解密试试



解密成功,主要是分析这个 `signKeyV1` 参数,看长度是 `64`,猜测是 `sha256` 加密,分析一下



全局搜索定位到这里,调用 `k2 native` 函数获取的,在 `libjdpdj.so` 文件里



打开 `so` 进入 `JNI_OnLoad` 函数,这里是动态注册的,点击 `off_117004`



这里看到,函数注册列表,点进 `gk2` 函数



前面是一些数据处理,下面有个 `j_hmac_sha256` 函数,可以确实是用的 `hmac sha256` 算法



这里的符号都没去掉,`init update final` 函数都能看到,这里应该是标准的算法,因为使用的是 `openssl` 库,先写个 `frida hook` 一下

# frida hook

```js
function hook() {
    var javaString = Java.use('java.lang.String');
    var zCls = Java.use('jd.net.z');

    zCls.k2.implementation = function (a) {
      console.log('zCls.k2.a: ', javaString.$new(a));

      var res = this.k2(a);
      console.log('zCls.k2.res: ', res);

      return res;
    }
}
```

这里 `hook java k2` 函数的输入输出

```js

function hookSo1() {
    var hmac_sha256 = Module.findExportByName('libjdpdj.so', 'hmac_sha256')
    var HMAC_CTX_init = Module.findExportByName('libjdpdj.so', 'HMAC_CTX_init')
    var HMAC_Update = Module.findExportByName('libjdpdj.so', 'HMAC_Update')
    var HMAC_Init_ex = Module.findExportByName('libjdpdj.so', 'HMAC_Init_ex')

    Interceptor.attach(hmac_sha256, {
      onEnter: function (args) {
            console.log('hmac_sha256 参数 1: ', hexdump(args));
            console.log('hmac_sha256 参数 2: ', hexdump(args));
            console.log('hmac_sha256 参数 3: ', hexdump(args));
            console.log('hmac_sha256 参数 4: ', hexdump(args));
      },
      onLeave: function (retValue) {
      }
    })

    Interceptor.attach(HMAC_CTX_init, {
      onEnter: function (args) {
            console.log('HMAC_CTX_init 参数 1: ', hexdump(args));
      },
      onLeave: function (retValue) {
      }
    })

    Interceptor.attach(HMAC_Update, {
      onEnter: function (args) {
            console.log('HMAC_Update 参数 1: ', hexdump(args));
            console.log('HMAC_Update 参数 2: ', hexdump(args, {length: 1200}));
            console.log('HMAC_Update 参数 3: ', hexdump(args));
      },
      onLeave: function (retValue) {
      }
    })

    Interceptor.attach(HMAC_Init_ex, {
      onEnter: function (args) {
            console.log('HMAC_Init_ex 参数 1: ', hexdump(args));
            console.log('HMAC_Init_ex 参数 2: ', hexdump(args));
            console.log('HMAC_Init_ex 参数 3: ', hexdump(args));
            console.log('HMAC_Init_ex 参数 4: ', hexdump(args));
            console.log('HMAC_Init_ex 参数 5: ', hexdump(args));
      },
      onLeave: function (retValue) {
      }
    })
}
```

这里在 `hook` 一些 `so` 函数,`hamc` 会有个 `key` 一般在 `init` 的时候初始化

```js
function main() {
    Java.perform(function () {
      hook();
      hookSo1();
    })
}
```

启动脚本 `frida -UF -l hook.js | tee hook.log`



`k2` 函数的输入是请求参数



`HMAC_Init_ex so` 函数的参数二,长度 `32` 猜测是 `hamc key`



`HMAC_Update` 函数是请求参数



最后的加密结果 `ae07cde50402ef91660dea93dc196f7f82e7bc04322baf4022dc2879434f3fae` 是这个,来验证一下



使用 `cyberchef` 加密,结果一样,正是 `hmac sha256`

***Tips: 下面在使用 unidbg 跑起来,毕竟多掌握一些工具总有用处***

# unidbg

```java
package com.xiayu.jingdongdaojia;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.LibraryResolver;
import com.github.unidbg.Module;
import com.github.unidbg.debugger.Debugger;
import com.github.unidbg.debugger.DebuggerType;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.*;
import com.github.unidbg.linux.android.dvm.array.ByteArray;
import com.github.unidbg.memory.Memory;

import java.io.File;
import java.io.IOException;

public class SignKeyV1Test extends AbstractJni {
    private final AndroidEmulator emulator;
    private final Module module;
    private final VM vm;

    public String apkPath = "apk path";
    public String soPath = "so path";

    private static LibraryResolver createLibraryResolver() {
      return new AndroidResolver(23);
    }

    private static AndroidEmulator createARMEmulator() {
      return AndroidEmulatorBuilder.for32Bit().build();
    }

    public SignKeyV1Test() {
      emulator = createARMEmulator();
      final Memory memory = emulator.getMemory();
      memory.setLibraryResolver(createLibraryResolver());
      vm = emulator.createDalvikVM(new File(apkPath));
      vm.setVerbose(true);

      DalvikModule dm = vm.loadLibrary(new File(soPath), false);
      vm.setJni(this);

      dm.callJNI_OnLoad(emulator);
      module = dm.getModule();
    }

    public void callGetSignKeyV1() {
      DvmClass zClass = vm.resolveClass("jd/net/z");

      DvmObject<?> strRc = zClass.callStaticJniMethodObject(
                emulator,
                "k2([B)Ljava/lang/String;",
                new ByteArray(vm, "参数".getBytes())
      );

      System.out.println("callGetSignKeyV1: " + strRc.getValue());
    }

    public static void main(String[] args) throws IOException {
      SignKeyV1Test signKeyV1 = new SignKeyV1Test();

      signKeyV1.callGetSignKeyV1();
      signKeyV1.destroy();
    }

    private void destroy() throws IOException {
      emulator.close();
    }
}
```

代码写完跑起来



这报错了,缺少函数 `jd/utils/StatisticsReportUtil->getSign()Ljava/lang/String;` 调用的是京东到家 `apk` 的 `java` 代码



点进来看一下,打开逻辑是获取 `apk` 的签名之类的,这里的依赖比较多,不是很好补,一般签名啥的都是固定,直接 `frida call` 一下,获取返回值

```js
function callGetSign() {
    var StatisticsReportUtil = Java.use('jd.utils.StatisticsReportUtil');

    var res = StatisticsReportUtil.getSign();
    console.log(res)
}
```

运行成功,获取返回值



`unidbg` 补一下,直接写死字符串



再次运行结果出来了,结果相同

***Tips: 后面在打算学习学习 ida gdb 动态调试,暂时留空***

# IDA 动态调试
// TODO

# GDB 动态调试
// TODO

ccb0429 发表于 2021-11-12 20:04

看到一个也是原创的图片都一模一样   如果是一个人 当我没说   支持分享
https://bbs.pediy.com/thread-270228.htm

qinless 发表于 2021-11-14 11:00

GeekPwn 发表于 2021-11-13 16:37
最近正在与研究这个

老哥有啥问题一起交流哈

qinless 发表于 2021-11-17 16:53

Hmily 发表于 2021-11-17 15:47
@qinless 看雪这个帖子是本人发的吗?

对,是的

qinless 发表于 2021-11-12 22:59

Jack150 发表于 2021-11-12 21:55
能用 frida和 Unidbg 两个工具搞出来,厉害。。如果可以出个能够更详细的分析so文件的就更好了。

目前本人还很菜,只能分析这种简单没啥对抗的 so,遇到有对抗的就歇菜了,大佬如果有兴趣可以看看个人博客,会定期分享一些学习成果,https://www.qinless.com

qinless 发表于 2021-11-12 14:32

初次发帖,没注意图片顺序搞反了,管理组看到麻烦帮忙删了,稍后重新发帖

Jack150 发表于 2021-11-12 21:55

能用 frida和 Unidbg 两个工具搞出来,厉害。。如果可以出个能够更详细的分析so文件的就更好了。

qinless 发表于 2021-11-12 22:57

ccb0429 发表于 2021-11-12 20:04
看到一个也是原创的图片都一模一样   如果是一个人 当我没说   支持分享
https://bbs.pediy.com/thread- ...

谢谢大佬支持

ysy2001 发表于 2021-11-13 07:47

只能膜拜大佬,谢谢。

dazhujianhui 发表于 2021-11-13 10:08

膜拜真的是看不懂

hxd97244 发表于 2021-11-13 10:26

ccb0429 发表于 2021-11-12 20:04
看到一个也是原创的图片都一模一样   如果是一个人 当我没说   支持分享
https://bbs.pediy.com/thread- ...

害我专门跑去原贴看了下,确实一样。

shiina0831 发表于 2021-11-13 10:36

过来学习{:301_1000:}
页: [1] 2 3 4 5 6 7 8
查看完整版本: 某东到家 app so signkeyV1 参数分析