darbra 发表于 2022-1-14 13:37

某咖啡app加密参数分析进阶版

本帖最后由 darbra 于 2022-1-14 13:41 编辑

>仅供学习研究 。请勿用于非法用途,本人将不承担任何法律责任。

## 前言

- app 某某咖啡
- v4.4.0
- 去年发了一篇 [某咖啡app网络请求签名算法分析与解密](https://www.52pojie.cn/thread-1388335-1-1.html),这次是进阶版。

## mitmproxy抓包





## java分析

定位到CryptoHelper类的名为md5_crypt的native静态方法。






## frida hook

脚本如下所示
```
function hook() {
    Java.perform(function() {
    var CryptoHelper = Java.use('com.l*****e.safeboxlib.CryptoHelper');
    CryptoHelper.md5_crypt.implementation = function (x, y) {
      console.log('md5_crypt_x', bytes2str(x));
      console.log('md5_crypt_y', y);
      var result = this.md5_crypt(x, y);
      console.warn('md5_crypt_ret', bytes2str(result));
      return result;
      };
}
}
```

我们可以看到,hook的结果和抓包结果一致




## so分析

使用lasting-yang的脚本hook_RegisterNatives

脚本地址:https://github.com/lasting-yang/frida_hook_libart



使用开源的cutter到so去一探究竟,我们搜索上图中的偏移0x1a981,来到android_native_md5函数。



经过一番分析,应该是md5加密完之后,还有一个bytesToInt的逻辑。




## unidbg

去年的文章里用frida就能搞定了,这次我们用lilac、qinless、qxp等大佬极力推荐的神器unidbg进行辅助分析。

首先是搭建架子

```
package com.*;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.debugger.Debugger;
import com.github.unidbg.file.IOResolver;
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.linux.android.dvm.array.IntArray;
import com.github.unidbg.linux.android.dvm.wrapper.DvmInteger;
import com.github.unidbg.memory.Memory;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

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

    public String apkPath = "/Users/darbra/Downloads/apk/com.*/temp.apk";
    public String soPath2 = "/Users/darbra/Downloads/apk/com.*/lib/armeabi-v7a/libcryptoDD.so";

    Md5Crypt440() {
      emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.*").build();
      final Memory memory = emulator.getMemory();
      memory.setLibraryResolver(new AndroidResolver(23));
      vm = emulator.createDalvikVM(new File(apkPath));
      vm.setVerbose(true);
      vm.setJni(this);
      DalvikModule dm2 = vm.loadLibrary(new File(soPath2), true);
      dm2.callJNI_OnLoad(emulator);
      module = dm2.getModule();
    }

    public void call() {
      String methodId = "md5_crypt([BI)[B";
      DvmClass SigEntity = vm.resolveClass("com/luckincoffee/safeboxlib/CryptoHelper");
      String fakeInput1 = "cid=210101;q=j***=;uid=***";
      ByteArray inputByteArray1 = new ByteArray(vm, fakeInput1.getBytes(StandardCharsets.UTF_8));
      DvmObject ret = SigEntity.callStaticJniMethodObject(
                emulator, methodId,
                inputByteArray1,
                1
      );
      byte [] strByte = (byte[]) ret.getValue();
      String strString = new String(strByte);
      System.out.println("callObject执行结果:"+ strString);
    }

    public static void main(String[] args) {
      Md5Crypt440 getSig = new Md5Crypt440();
      getSig.call();
      getSig.destroy();
    }

    private void destroy() {
      try {
            emulator.close();
      } catch (IOException e) {
            e.printStackTrace();
      }
    }
}

```

值得注意的是,这个app不用补任何环境,非常轻松地就运行出了结果。



结果和抓包、frida完全一致。


我们在md5函数打个断点。

```
public void HookByConsoleDebugger(){
    Debugger debugger = emulator.attach();
    debugger.addBreakPoint(module.base+0x13E3C);
}
```







输入mr0,我们可以看到第一个参数就是明文,但不够完整。



接着输入mr0 0x100,后面可以跟的是大小。我们欣喜地发现,之前的那坨明文后面加了个salt值,d******9



参数2,r1=0xef=239,我们去cyberchef看看这个明文长度是否为239



果不其然是的。

接着输入mr2,查看第三个参数。



看情况参数3不出重大意外是buffer,所以我们需要hook它的返回值。在这里我们先记下r2的地址--->>> 0xbffff5d8。

我们使用blr 命令用于在函数返回时设置一个一次性断点,然后c 运行函数,它在返回处断下来。

接着输入刚刚记录下来的 m0xbffff5d8



我们去cyberchef进行验证,完全正确!



md5步骤解决了,接着查看bytesToInt。



我们在0x13924那里进行hook操作

```
public void hookBytesToInt() {
      IHookZz hookZz = HookZz.getInstance(emulator);

      hookZz.wrap(module.base + 0x13924 + 1, new WrapCallback<HookZzArm32RegisterContext>() {
            @Override
            public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
                Inspector.inspect(ctx.getR0Pointer().getByteArray(0, 0x10), "参数1");
                System.out.println("参数2->>" + ctx.getR1Int());
            };
            @Override
            public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
                System.out.println("返回值->>" + ctx.getR0Int());
            }

      });
    }
```

我们看一下输出结果了,四个输出值都能对应上最后的sign结果。



其中的正负号处理应该是对应的如下逻辑





我们写个小脚本还原下,与之前的抓包、frida、unidbg都一致,大功告成。




在本人github.com/darbra/sign 有更多的一些思路交流,如果对老师们有所帮助,不甚欣喜。

朔月D 发表于 2022-1-14 15:09

不敢说学习了,,看不懂啊。{:1_909:}

你就是我的阳光 发表于 2023-9-1 15:15

cacorot 发表于 2023-8-22 11:41
打不开就对了。谁叫你是风险环境

不对,没有检测root不存在风险环境一说吧,代码没有看,米8不管怎么样打不开,今天k50 直接root了就下了个连root都没有隐藏都可以打开

huozhuang12345 发表于 2022-1-14 13:43

完全没看懂。。。。。

SakeDawn 发表于 2022-1-14 13:45

6666学习了

pxwhsh 发表于 2022-1-14 14:14

very very good.relax

不苦小和尚 发表于 2022-1-14 14:15

md5加盐???

mmmaxxx2630 发表于 2022-1-14 15:48

大佬用的工具,都木有见过啊。。。。。。。。。。。。。。

darbra 发表于 2022-1-14 17:41

pxwhsh 发表于 2022-1-14 14:14
very very good.relax

thank you very much indeed

elevo 发表于 2022-1-14 17:46

我这思路有点没理清

QingYi. 发表于 2022-1-14 18:25

你这个太干了,实操起来还有很多水分你都没说
页: [1] 2 3 4
查看完整版本: 某咖啡app加密参数分析进阶版