密码学学习记录|aes dfa 练习样本一

密码学学习记录 16 / 18

前言

dfa 攻击相关资料,可参考之前的文章 从黑盒攻击模型到白盒攻击模型
样本来自龙哥星球,需要获取可加星球。上述链接有二维码

unidbg

祖传操作,先把架子搭起来

package com.qinless.yirendaijiekuan.v639;

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.*;
import com.github.unidbg.memory.Memory;

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

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

    public String apkPath = "";

    AesWBTest() {
        emulator = AndroidEmulatorBuilder.for32Bit().build();
        final Memory memory = emulator.getMemory();
        memory.setLibraryResolver(new AndroidResolver(23));

        vm = emulator.createDalvikVM(new File(apkPath));
        vm.setJni(this);
        vm.setVerbose(true);

        DalvikModule dm = vm.loadLibrary("aeswb", true);
        module = dm.getModule();
        dm.callJNI_OnLoad(emulator);
    }

    public static void main(String[] args) {
        AesWBTest aesWB = new AesWBTest();
        aesWB.destroy();
    }

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

运行成功,啥也没输出,猜测都是静态注册的 so 函数,打开瞅一瞅

so

打开导出窗口,搜索 java 好家伙,这是标准函数,哪咱们就选择一个最简单的函数分析

public void callEncryptEcb() {
    DvmObject<?> dvmObject = vm.resolveClass("com/sec/MessageUtil").newObject(null);

    StringObject ret = dvmObject.callJniMethodObject(
            emulator, "encryptecb(Ljava/lang/String;)Ljava/lang/String;",
            new StringObject(vm, "abcdefg")
    );
    System.out.println("result: " + QLUtils.bytesToHexString(Base64.decodeBase64(ret.toString())));
}

再次运行,结果成功出来了,这就是 aes 的加密结果

看了前面文章的小伙伴大概都明白了,想要进行 dfa 攻击,需要通过倒数 第二轮 来注入错误的数据,实现分差攻击,所以咱们需要先找到轮数,继续分析 so

encryptecb 函数跟进来,会到这里,这里大概就是轮数了,刚好循环 10 次

public void inlineHook() {
    emulator.getBackend().hook_add_new(new CodeHook() {
        @Override
        public void hook(Backend backend, long address, int size, Object user) {
            if (address == (module.base + 0x16BE)) {
                Arm32RegisterContext ctx = emulator.getContext();

                System.out.println(ctx.getR1Int());
            }
        }

        @Override
        public void onAttach(UnHook unHook) {
        }

        @Override
        public void detach() {
        }
    }, module.base + 0x16BE, module.base + 0x16BE, null);
}

使用 inlinehook 看一下,刚好是运行 10 次

看一下 sub_165C 函数,大概率是 aes 具体的查表逻辑,这里就不用管了,主要分析 sub_165C 函数的参数即可

每次循环都会调用这个函数,咱们直接在第 9 次的时候,修改下这个函数的参数,即可实现分差攻击

public int randInt(int min, int max) {
    Random rand = new Random();
    return rand.nextInt((max - min) + 1) + min;
}

public void dfaAttack(final long offset1) {
    emulator.attach().addBreakPoint(module.base + 0x16B8 + 1, new BreakPointCallback() {
        int count = 0;
        UnidbgPointer pointer;

        @Override
        public boolean onHit(Emulator<?> emulator, long address) {
            count += 1;
            RegisterContext registerContext = emulator.getContext();

            pointer = registerContext.getPointerArg(0);

            if (count % 9 == 0) {
                pointer.setByte(offset1, (byte) randInt(0, 0xff));
            }

            return true;
        }
    });
}

public static void main(String[] args) {
    long[] ints = new long[]{
            1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10,
            11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16
    };

    for (int i = 0; i < ints.length; i++) {
        AesWBTest aesWB = new AesWBTest();
        aesWB.dfaAttack(ints[i]);
        aesWB.callEncryptEcb();
        aesWB.destroy();
    }
}

这里每个字节都修改两次,运行把所有的结果都保存起来,使用 python phoenixAES 跑一下

Tips: pip install phoenixAES

运行,成功计算出 k10 密钥

在使用 stark 项目运行,成功计算出主密钥

最后使用 cyberchef 验证,加密结果相同

8 条评论
本文作者:
本文链接: https://www.qinless.com/?p=1698
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 qinless 的博客!
100

8 条评论

菜鸟

你的 bytesToHexString 是标准的 还是去壳获取的

回复

会爬山的小脑虎

@菜鸟 自己写的哦

回复

7777

bytesToHexString 是标准的还是 去壳得到的

回复

会爬山的小脑虎

@7777 自己写的

回复

66

你的 bytesToHexString 是标准的 还是去壳获取的

回复

会爬山的小脑虎

@66 自己写的

回复

66

@会爬山的小脑虎 看到了 之前代码里有

66

@会爬山的小脑虎 感谢

发表评论

返回顶部