返回
LoadSo对比:Unidbg模拟执行子SO进阶
Android
2023-10-28 08:59:40
前言
在上一篇教程中,我们尝试使用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文件提供了更多的好处,包括灵活性、安全性、可调试性等。在实际使用中,我们可以根据不同的需求选择最合适的加载方式。