使用unidbg

一、前言

unidbg是一个基于unicorn的逆向工具,可黑盒调用移动app中的so文件,运行时不需要模拟器或真机。有时用真机调so文件难以过反调试,而unidbg可以弥补这块缺陷。当然了,unidbg也不是万能的,怎么给unidbg补环境也是个问题。

二、步骤

1. 首先要将java、maven、IDEA配置好。

https://blog.csdn.net/pan_junbiao/article/details/104264644

2. 下载unidbg项目

https://github.com/zhkl0228/unidbg

3. 导入到IDEA中

unidbg项目是java编写的,上述下载的是一个标准maven项目。

4. 测试unidbg

项目中的测试用例:src/test/java/com/bytedance/frameworks/core/encrypt/TTEncrypt.java,直接执行其中的main方法,会出现下述的提示

三、实例

看雪2021 KCTF秋季赛第8题 群狼环伺为一道安卓逆向题

https://ctf.pediy.com/game-season_fight-187.htm

我们可以采用unidbg模拟执行,按照正常步骤运行时,会出现如下错误

[14:10:36 669]  WARN[com.github.unidbg.linux.ARM32SyscallHandler] (ARM32SyscallHandler:530) -handleInterrupt intno=2, NR=190, svcNumber=0x0, PC=RX@0x40284b5c[libc.so]0x41b5c, LR=RX@0x402725cb[libc.so]0x2f5cb, syscall=null

[14:10:36 670]  WARN[com.github.unidbg.linux.ARM32SyscallHandler] (ARM32SyscallHandler:530) -handleInterrupt intno=2, NR=358, svcNumber=0x0, PC=RX@0x40284db0[libc.so]0x41db0, LR=RX@0x40272635[libc.so]0x2f635, syscall=null

顺着该错误信息往前倒,用ida在IntelliJIDEA v23版本arm版libc.so中定位到地址0x2f5cb和0x2f635,发现是在调用popen()是出现了错误。

从下面的帖子,说这个报错较大可能性是样本在通过popen或者system执行命令

https://github.com/zhkl0228/unidbg/issues/342

事实上,Unidbg目前还不支持直接跑popen,需要手动处理一下,继承和使用自己的syscallHandler

https://blog.csdn.net/qq_38851536/article/details/118073818

下面贴出完整的运行该so的完整unidbg代码

crackeme.java

package com.vprotect;

import com.github.unidbg.AndroidEmulator;

import com.github.unidbg.Emulator;

import com.github.unidbg.Module;

import com.github.unidbg.arm.context.Arm32RegisterContext;

import com.github.unidbg.file.linux.AndroidFileIO;

import com.github.unidbg.hook.hookzz.*;

import com.github.unidbg.linux.android.AndroidARMEmulator;

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 com.github.unidbg.memory.SvcMemory;

import com.github.unidbg.unix.UnixSyscallHandler;

import java.io.File;

import java.io.FileNotFoundException;

public class crackme extends AbstractJni {

    private final AndroidEmulator emulator;

    private final Module module;

    private final VM vm;

    private final DvmClass NativeClass;

    public crackme() throws FileNotFoundException {

        AndroidEmulatorBuilder builder = new AndroidEmulatorBuilder(false) {

            @Override

            public AndroidEmulator build() {

                return new AndroidARMEmulator(processName, rootDir, backendFactories) {

                    @Override

                    protected UnixSyscallHandler createSyscallHandler(SvcMemory svcMemory) {

                        return new MyARMSyscallHandler(svcMemory);

                    }

                };

            };

        };

        emulator = builder.setProcessName("com.vprotect").build();

        final Memory memory = emulator.getMemory();

        memory.setLibraryResolver(new AndroidResolver(23));

        vm = emulator.createDalvikVM(new File("unidbg-android/src/test/resources/vprotect/KCTF2021-android-crackme.apk"));

        DalvikModule dm = vm.loadLibrary("crackme", true);

        module = dm.getModule();

        vm.setVerbose(true);

        vm.setJni(this);

        dm.callJNI_OnLoad(emulator);

        NativeClass = vm.resolveClass("www/vprotect/cn/crackme");

    }

    public static void main(String[] args) {

        crackme mainActivity = null;

        try {

            mainActivity = new crackme();

        } catch (FileNotFoundException e) {

            e.printStackTrace();

        }

        String ret = mainActivity.getGoodLuck();

        System.out.println("getGoodLuck函数返回:"+ret);

    }

    public String getGoodLuck(){

        String str1 = "4DD6F06301B04D13";

        String str2 = "6461323135643835663832623133666234313635636637383266613665363961";

        String str3 = "1234567";

        StringObject stringObject = NativeClass.newObject(null).callJniMethodObject(emulator, "GoodLuck(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", str1, str2, str3);

        return stringObject.getValue();

    }

}

MyARMSyscallHandler.java

package com.vprotect;

import com.github.unidbg.Emulator;

import com.github.unidbg.arm.context.EditableArm32RegisterContext;

import com.github.unidbg.linux.file.ByteArrayFileIO;

import com.github.unidbg.linux.file.DumpFileIO;

import com.github.unidbg.memory.SvcMemory;

import com.sun.jna.Pointer;

import java.util.concurrent.ThreadLocalRandom;

public class MyARMSyscallHandlerextends com.github.unidbg.linux.ARM32SyscallHandler{

public MyARMSyscallHandler(SvcMemory svcMemory) {

super(svcMemory);

    }

@Override

    protected boolean handleUnknownSyscall(Emulator emulator, int NR) {

switch (NR) {

case 190:

vfork(emulator);

return true;

            case 359:

pipe2(emulator);

return true;

        }

return super.handleUnknownSyscall(emulator, NR);

    }

private void vfork(Emulator emulator) {

EditableArm32RegisterContext context = (EditableArm32RegisterContext) emulator.getContext();

        int childPid = emulator.getPid() + ThreadLocalRandom.current().nextInt(256);

        int r0 =0;

        r0 = childPid;

        System.out.println("vfork pid=" + r0);

        context.setR0(r0);

    }

protected int pipe2(Emulator emulator) {

EditableArm32RegisterContext context = (EditableArm32RegisterContext) emulator.getContext();

        Pointer pipefd = context.getPointerArg(0);

        int flags = context.getIntArg(1);

        int write = getMinFd();

        this.fdMap.put(write, new DumpFileIO(write));

        int read = getMinFd();

        String stdout ="myid\n"; // getprop ro.build.id

        this.fdMap.put(read, new ByteArrayFileIO(0, "pipe2_read_side", stdout.getBytes()));

        pipefd.setInt(0, read);

        pipefd.setInt(4, write);

        System.out.println("pipe2 pipefd=" + pipefd +", flags=0x" + flags +", read=" + read +", write=" + write +", stdout=" + stdout);

        context.setR0(0);

        return 1;

    }

}

最终返回“输入错误”

你可能感兴趣的:(使用unidbg)