Dfa还原某app白盒aes秘钥

 本期内容是关于某app模拟登录的,涉及的知识点比较多,有unidbg补环境及辅助还原算法,ida中的md5以及白盒aes,fart脱壳,frida反调试

文章老是莫名被某sdn删掉,然后还审核不通过,后面估计发自己博客了

本章所有样本及资料均上传到了123云盘

网盘发不出来,审核过不了

目录

首先抓包

fart脱壳

加密位置定位

frida反调试

unidbg搭架子

补环境

还原算法

DFA还原白盒AES密钥

小坑

md5

完整算法

本文章未经许可禁止转载,禁止任何修改后二次传播,擅自使用本文讲解的技术而导致的任何意外,作者均不负责,若有侵权,请联系作者立即删除!

总结

最后

首先抓包

image-20240301191136716

看login请求,表单和响应都是大长串,猜测是对称加密算法或者是非对称,对称常见的有des和aes,非对称常见的有rsa.

fart脱壳

正常流程下应该是拖到jadx中反编译一下,但是目标app使用了梆梆企业加固

image-20240301191604629

我换了一部由fart脱壳机定制的pixel 4后成功脱壳,后续我会把脱壳的dex放到网盘里,所以对脱壳不了解的可以略过脱壳这个步骤

寒冰的fart脱壳机

把脱下来的dex文件pull到电脑上

image-20240301193322261

对比下脱壳前后的反编译结果

image-20240301200805772

加密位置定位

接下来是定位加密位置了

尝试搜索"sd"

image-20240301200940767

框中的可能性比较大,其他几个类名都是android aliyun google tencent这种系统文件或者第三方厂商的,框中的包含类名以及retrofit框架

这个是目标字段的可能性很大,点进去看看,然后查找用例

image-20240301201431561

右下角框中的有一个decrypt函数,应该是响应的解密逻辑,那上面的应该是加密函数了

image-20240301201639119

点进去然后复制frida片段

function call(){
    Java.perform(function (){
    let CheckCodeUtils = Java.use("com.cloudy.linglingbang.model.request.retrofit2.CheckCodeUtils");
CheckCodeUtils["encrypt"].implementation = function (str, i) {
    console.log(`CheckCodeUtils.encrypt is called: str=${str}, i=${i}`);
    let result = this["encrypt"](str, i);
    console.log(`CheckCodeUtils.encrypt result=${result}`);
    return result;
};
})
}

frida反调试

frida注入 frida -UF -l hook.js

以attach方式启动frida后报错无法附加进程,这里我们使用spwan方式启动即可

image-20240301202447875

换成spwan方式后还是报错了,应该还有检测frida-server

image-20240301203133715

换成葫芦娃形式的试试

image-20240301203415751

image-20240301203520112

成功了,接下来就是发个包看看有没有结果

image-20240301195916886

对比下发现结果差不多就是hook的结果把+改成空格就是sd的值了

image-20240301203709699

接着分析jadx中的函数,checkcode点进去

image-20240301203807990

可以看到目标函数返回null,和hook的结果不一样,并且jadx给出了警告,不知道是脱壳脱的不全还是jadx的问题,后续可以用jeb试试,jeb的反编译能力比jadx强

同时可以看到下面有两个native函数,checkcode,和decheckcode,尝试hook checkcode函数

image-20240301204253358

同样有结果

这两个native函数加载自libencrypt.so

image-20240301204420922

这里我选择32位的so,拖到ida32中搜索java,发现是静态注册(如果是动态注册还可以hook libart.so来找导出函数)

image-20240301204635687

unidbg搭架子

接下来是unidbg模拟执行

搭架子

package com;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Module;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.StringObject;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class demo2 extends AbstractJni {
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;
    private final Memory memory;

    demo2(){
        // 创建模拟器实例,进程名建议依照实际进程名填写,可以规避针对进程名的校验
        emulator = AndroidEmulatorBuilder.for32Bit().setProcessName("com.cloudy.linglingbang").build();
        // 获取模拟器的内存操作接口
        memory = emulator.getMemory();
        // 设置系统类库解析
        memory.setLibraryResolver(new AndroidResolver(23));
        // 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作
        vm = emulator.createDalvikVM(new File("unidbg-android/apks/llb/llb.apk"));
        // 设置JNI
        vm.setJni(this);
        // 打印日志
        vm.setVerbose(true);
        // 加载目标SO
        DalvikModule dm = vm.loadLibrary(new File("unidbg-android/apks/llb/libencrypt.so"), true);
        //获取本SO模块的句柄,后续需要用它
        module = dm.getModule();
        // 调用JNI OnLoad
        dm.callJNI_OnLoad(emulator);
    };
	    public String callByAddress(){
        // args list
        List<Object> list = new ArrayList<>(5);
        // jnienv
        list.add(vm.getJNIEnv());
        // jclazz
        list.add(0);
        // str1
        list.add(vm.addLocalObject(new StringObject(vm, "mobile=13535535353&password=fjfjfjffk&client_id=2019041810222516127&client_secret=c5ad2a4290faa3df39683865c2e10310&state=eu4acofTmb&response_type=token")));
        // int
        list.add(2);
        // str2
        list.add(vm.addLocalObject(new StringObject(vm, "1709100421650")));
        Number number = module.callFunction(emulator, 0x13A19, list.toArray());
        String result = vm.getObject(number.intValue()).getValue().toString();
        System.out.println("======encrypt:"+result);
        return result;
    };
    public static void main(String[] args) {
        demo2 llb = new demo2();
//		llb.callByAddress();
    }
}

补环境

运行报错,currentActivityThread 通常用于一些需要获取全局上下文或执行一些与应用程序状态相关的操作的场景

image-20240301205841135

补上,这里没什么好说的,孰能生巧

@Override
    public DvmObject<?> callStaticObjectMethod(BaseVM vm, DvmClass dvmClass, String signature, VarArg varArg) {
        switch (signature){
            case "android/app/ActivityThread->currentActivityThread()Landroid/app/ActivityThread;":{
                return vm.resolveClass("android/app/ActivityThread").newObject(null);
            }
        }
        return super.callStaticObjectMethod(vm, dvmClass, signature, varArg);
    }

接着运行,SystemProperties中的get像是在获取系统的某个属性

image-20240301210325785

case "android/os/SystemProperties->get(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;":{
                String arg = varArg.getObjectArg(0).getValue().toString();
                System.out.println("SystemProperties get arg:"+arg);
            }

image-20240301210629362

获取手机序列号的

image-20240301210845607

adb shell getprop ro.serialno

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

杨如画.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值