返回

LoadSo对比:Unidbg模拟执行子SO进阶

Android

前言

在上一篇教程中,我们尝试使用Unidbg来模拟执行一段子SO,但在运行过程中遇到了问题。这次,我们将探索另一种方法,即使用LoadSo来加载子SO,并对比这两种方法的异同。

LoadSo简介

LoadSo是一种更高级的方法,它允许我们动态地加载和执行子SO。与直接执行SO文件不同,LoadSo可以将子SO加载到Unidbg的内存空间中,并允许我们直接调用子SO中的函数。

步骤

1. 准备子SO文件

首先,我们需要准备一个子SO文件。这里,我们使用一个名为sample.so的简单SO文件,其中包含一个add函数。

#include <stdio.h>

int add(int a, int b) {
  return a + b;
}

2. 创建Unidbg环境

接下来,我们需要创建一个Unidbg环境来模拟执行子SO。

import org.unidbg.Emulator;
import org.unidbg.LibraryResolver;
import org.unidbg.Module;
import org.unidbg.arm.backend.Backend;
import org.unidbg.arm.backend.DynarmicBackend;
import org.unidbg.arm.context.RegisterContext;
import org.unidbg.file.AndrewFileBackend;
import org.unidbg.file.FileBackend;
import org.unidbg.hook.HookContext;
import org.unidbg.hook.HookListener;
import org.unidbg.memory.Memory;
import org.unidbg.pointer.UnidbgPointer;
import org.unidbg.unwind.Unwinder;
import org.unidbg.util.Debug;

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

public class LoadSoTest {

  private static final String SAMPLE_SO = "sample.so";

  public static void main(String[] args) throws IOException {
    Emulator emulator = Emulator.newBuilder()
        .setBackend(new DynarmicBackend())
        .setLibraryResolver(new MyLibraryResolver())
        .build();
    final Memory memory = emulator.getMemory();
    FileBackend backend = AndrewFileBackend.forEmulator(emulator);
    backend.createPath("/data/data");
    backend.createPath("/data/data/sample");
    backend.copyFromLocal(SAMPLE_SO, "/data/data/sample/" + SAMPLE_SO);

    Module module = emulator.loadLibrary(new File(SAMPLE_SO));
    UnidbgPointer functionPointer = module.findExportedSymbol("add");
    RegisterContext context = emulator.getContext();
    long ret = functionPointer.call(context, 1, 2);
    System.out.println("Call 'add' function: " + ret);
  }

  private static class MyLibraryResolver implements LibraryResolver {

    @Override
    public Module resolve(Emulator emulator, String libraryName) {
      // 主动加载依赖库
      if ("libc.so".equals(libraryName)) {
        try {
          return emulator.loadLibrary(new File("/system/lib/libc.so"));
        } catch (IOException e) {
          throw new IllegalStateException(e);
        }
      }
      return null;
    }
  }
}

3. 运行子SO

现在,我们可以运行子SO了。

./gradlew run

对比

使用LoadSo方法后,我们可以成功调用子SO中的add函数,并得到正确的结果。与直接执行SO文件相比,LoadSo有以下优点:

  • 更灵活: LoadSo允许我们在运行时动态加载和卸载子SO,而无需重新启动模拟器。
  • 更安全: LoadSo将子SO加载到Unidbg的内存空间中,与主程序隔离,从而提高安全性。
  • 更容易调试: LoadSo提供了更方便的调试机制,我们可以使用Unidbg的HookListener来监听和修改函数调用。

结论

LoadSo是一种强大而灵活的方法,可以用来模拟执行子SO。它比直接执行SO文件提供了更多的好处,包括灵活性、安全性、可调试性等。在实际使用中,我们可以根据不同的需求选择最合适的加载方式。

SEO优化