前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >unidbg使用笔记

unidbg使用笔记

作者头像
大A
发布2023-03-23 09:17:04
1.6K0
发布2023-03-23 09:17:04
举报
文章被收录于专栏:爱打音游的大A爱打音游的大A

搭架子

代码语言:javascript
复制
public class Main implements IOResolver {
    private final AndroidEmulator emulator;

    private final VM vm;
    private final Module module;

    Main(){
        // 创建模拟器实例,进程名建议依照实际进程名填写,可以规避针对进程名的校验
        emulator = AndroidEmulatorBuilder.for32Bit().setRootDir(new File("target/rootfs")).setProcessName("com.ashenone.demo").build();
//        emulator.getSyscallHandler().addIOResolver(this);
        // 获取模拟器的内存操作接口
        Memory memory = emulator.getMemory();
        // 设置系统类库解析
        memory.setLibraryResolver(new AndroidResolver(23));
        // 创建Android虚拟机,传入APK,Unidbg可以替我们做部分签名校验的工作
        vm = emulator.createDalvikVM(new File("apkpath"));
//        vm.setDvmClassFactory(new ProxyClassFactory());
        vm.setJni(new MyJni());
        //开启log
        vm.setVerbose(true);
        //最好调整一下log级别
        Logger.getLogger("com.github.unidbg.linux.ARM32SyscallHandler").setLevel(Level.DEBUG);
        Logger.getLogger("com.github.unidbg.unix.UnixSyscallHandler").setLevel(Level.DEBUG);
        Logger.getLogger("com.github.unidbg.AbstractEmulator").setLevel(Level.DEBUG);
        Logger.getLogger("com.github.unidbg.linux.android.dvm.DalvikVM").setLevel(Level.DEBUG);
        Logger.getLogger("com.github.unidbg.linux.android.dvm.BaseVM").setLevel(Level.DEBUG);
        Logger.getLogger("com.github.unidbg.linux.android.dvm").setLevel(Level.DEBUG);
        // 加载目标SO
        DalvikModule dm = vm.loadLibrary(new File("elfpath"), true);
        //获取本SO模块的句柄,后续需要用它
        module = dm.getModule();
        //调用JNI OnLoad
        dm.callJNI_OnLoad(emulator);
    }
}

补环境

Jni

代码语言:javascript
复制
public class MyJni extends AbstractJni {
    public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature) {
            case "android/os/Environment->getExternalStorageDirectory()Ljava/io/File;":
                return new StringObject(vm,"/sdcard/");
        }
        return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
    }

    public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
        switch (signature){
            case "java/lang/String->getAbsolutePath()Ljava/lang/String;":
                return new StringObject(vm,(String) dvmObject.getValue());
        }
        return super.callObjectMethodV(vm, dvmObject, signature, vaList);
    }
}

主动调用

Java层

static函数
代码语言:javascript
复制
public String y2(boolean b1, String configData,boolean b2,String AinfoKey) {
    DvmClass clz = vm.resolveClass("com/ashenone/demo/MyClass");
    String methodSign = "y2(ZLjava/lang/String;ZLjava/lang/String;)Ljava/lang/String;";
    StringObject obj = clz.callStaticJniMethodObject(emulator, methodSign, b1, configData,b2,AinfoKey);
    return obj.getValue();
}

native层

通过地址调用JNI函数
代码语言:javascript
复制
public String _y2(boolean b1, String configData,boolean b2,String AinfoKey){
    // args list
    List<Object> list = new ArrayList<>(10);
    // arg1 env
    list.add(vm.getJNIEnv());
    // arg2 jobject/jclazz 一般用不到,直接填0
    list.add(0);

    list.add(vm.addLocalObject(DvmBoolean.valueOf(vm,b1)));
    list.add(vm.addLocalObject(new StringObject(vm,configData)));
    list.add(vm.addLocalObject(DvmBoolean.valueOf(vm,b2)));
    list.add(vm.addLocalObject(new StringObject(vm,AinfoKey)));

    // 参数准备完成
    // call function
    Number number = module.callFunction(emulator,
            0x3f7ad,
            list.toArray());
    String result = vm.getObject(number.intValue()).getValue().toString();
    return result;
}
通过地址调用C函数
代码语言:javascript
复制
public String decodeString(String input){
    MemoryBlock block=memory.malloc(input.length(),false);
    UnidbgPointer str_ptr=block.getPointer();
    str_ptr.write(input.getBytes());
    String content= str_ptr.getString(0);
    System.out.println("decodeString:"+str_ptr.getString(0));

    Number number = module.callFunction(emulator,
            0x79ec+1,
            str_ptr);
    UnidbgPointer result = memory.pointer(number.longValue());
    return result.getString(0);
}

参数构造

通过list来存放每个参数,最后调用toArray()传入callFunction中,但是各种类型的参数在传入list之前需要进行包装

Env

代码语言:javascript
复制
vm.getJNIEnv()

String

代码语言:javascript
复制
vm.addLocalObject(new StringObject(vm,"Hello"))

Boolean

代码语言:javascript
复制
vm.addLocalObject(DvmBoolean.valueOf(vm,true))

Context

代码语言:javascript
复制
DvmObject<?> context = vm.resolveClass("android/content/Context").newObject(null);// context
list.add(vm.addLocalObject(context));

byte[]

代码语言:javascript
复制
ByteArray inputByteArray = new ByteArray(vm,inputByte);
list.add(vm.addLocalObject(inputByteArray));

Patch

直接写bytecode

代码语言:javascript
复制
int patchCode = 0x4FF00100;
emulator.getMemory().pointer(module.base + offset1).setInt(offset2,patchCode);

或者用Keystone,参考SO逆向入门实战教程二:calculateS

代码语言:javascript
复制
Pointer pointer = UnidbgPointer.pointer(emulator, module.base + offset);
assert pointer != null;
byte[] code = pointer.getByteArray(0, 4);
if (!Arrays.equals(code, new byte[]{ (byte)0xFF, (byte) 0xF7, (byte) 0xEB, (byte) 0xFE })) { // BL sub_1C60
    throw new IllegalStateException(Inspector.inspectString(code, "patch32 code=" + Arrays.toString(code)));
}
try (Keystone keystone = new Keystone(KeystoneArchitecture.Arm, KeystoneMode.ArmThumb)) {
    KeystoneEncoded encoded = keystone.assemble("mov r0,1");
    byte[] patch = encoded.getMachineCode();
    if (patch.length != code.length) {
        throw new IllegalStateException(Inspector.inspectString(patch, "patch32 length=" + patch.length));
    }
    pointer.write(0, patch, 0, patch.length);
}

Hook

有多种Hook框架,只看HookZz

代码语言:javascript
复制
public void HookMDStringold(){
    // 加载HookZz
    IHookZz hookZz = HookZz.getInstance(emulator);

    hookZz.wrap(module.base + offset, new WrapCallback<HookZzArm32RegisterContext>() { // inline wrap导出函数
        @Override
        // 类似于 frida onEnter
        public void preCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
            // 类似于Frida args[0]
            Pointer input = ctx.getPointerArg(0);
            System.out.println("input:" + input.getString(0));
        };

        @Override
        // 类似于 frida onLeave
        public void postCall(Emulator<?> emulator, HookZzArm32RegisterContext ctx, HookEntryInfo info) {
            Pointer result = ctx.getPointerArg(0);
            System.out.println("input:" + result.getString(0));
        }
    });
}

trace

代码语言:javascript
复制
//trace指令执行
emulator.traceCode(long begin, long end);
//trace内存读写
emulator.traceRead(long begin, long end);
emulator.traceWrite(long begin, long end);
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-05-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 搭架子
  • 补环境
    • Jni
    • 主动调用
      • Java层
        • static函数
      • native层
        • 通过地址调用JNI函数
        • 通过地址调用C函数
    • 参数构造
      • Env
        • String
          • Boolean
            • Context
              • byte[]
              • Patch
              • Hook
              • trace
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档