IO重定向

来源:互联网 发布:c 面向对象编程 编辑:程序博客网 时间:2024/06/05 19:14

IO重定向

其实所谓的“重定向”不过就是替换一下要访问的路径。插件程序的所有数据都是放在宿主程序的目录下的,方便统一管理。

因此,当插件访问“/data/data/插件包名/xxx”时,需要把路径替换成“/data/data/插件宿主包名/Plugin/插件包名/data/插件

包名/xxx”。具体是实现在LibCoreHookHandle里,libcore主要是一些系统调用的实现(如open(), remove(), mkdir()等等),

因此需要在进行系统调用之前把路径替换掉。

结构图

LibCoreHookHandle的结构图如下,


HookFactory的installHook方法有关LibCoreHook的代码如下,

installHook(new LibCoreHook(context), classLoader);

LibCoreHook的createHookHandle方法如下,

protected BaseHookHandle createHookHandle() {        return new LibCoreHookHandle(mHostContext);    }

LibCoreHook的onInstall方法如下,

protected void onInstall(ClassLoader classLoader) throws Throwable {        if (!installHook1()) {            installHook2();        }    }

根据android版本不同分别进行Hook,

installHook2方法如下,

private void installHook2() throws ClassNotFoundException, IllegalAccessException {        Class LibCore = Class.forName("libcore.io.Libcore");        Object oldObj = FieldUtils.readStaticField(LibCore, "os");        setOldObj(oldObj);        Class<?> aClass = mOldObj.getClass();        Class<?>[] interfaces = getAllInterfaces(aClass);        Object proxyObj = MyProxy.newProxyInstance(mOldObj.getClass().getClassLoader(), interfaces, this);        FieldUtils.writeStaticField(LibCore, "os", proxyObj);    }

主要是Hook Libcore.java里面的os变量,

/libcore/luni/src/main/java/libcore/io/Libcore.java的代码如下,

package libcore.io;public final class Libcore {    private Libcore() { }    public static Os os = new BlockGuardOs(new Posix());}

所以,被替换的是BlockGuardOs对象。

BlockGuardOs.java也位于/libcore/luni/src/main/java/libcore/io/路径下面。

Hook 分析

LibCoreHookHandle的init方法如下,

protected void init() {   sHookedMethodHandlers.put("access", new access(mHostContext));   sHookedMethodHandlers.put("chmod", new chmod(mHostContext));   sHookedMethodHandlers.put("chown", new chown(mHostContext));   sHookedMethodHandlers.put("execv", new execv(mHostContext));   sHookedMethodHandlers.put("execve", new execve(mHostContext));   sHookedMethodHandlers.put("mkdir", new mkdir(mHostContext));   sHookedMethodHandlers.put("open", new open(mHostContext));   sHookedMethodHandlers.put("remove", new remove(mHostContext));   sHookedMethodHandlers.put("rename", new rename(mHostContext));   sHookedMethodHandlers.put("stat", new stat(mHostContext));   sHookedMethodHandlers.put("statvfs", new statvfs(mHostContext));   sHookedMethodHandlers.put("symlink", new symlink(mHostContext));}

一共Hook了BlockGuardOs 的12种方法。这些类都继承于BaseLibCore类, BaseLibCore的beforeInvoke方法如下,

protected boolean beforeInvoke(Object receiver, Method method, Object[] args) throws Throwable {//  Log.i(TAG, "Old %s(%s)", method.getName(), Arrays.toString(args));     int index = 0;    replace(args, index);//Log.i(TAG, "New %s(%s)", method.getName(), Arrays.toString(args));     return super.beforeInvoke(receiver, method, args);}

直接调用replace 方法,replace方法如下,

protected void replace(Object[] args, int index) {     if (args != null && args.length > index && args[index] instanceof String) {          String path = (String) args[index];          String newPath = tryReplacePath(path);          if (newPath != null) {               args[index] = newPath;          }      }}

调用tryReplacePath方法,如下,

private String tryReplacePath(String tarDir) {   if (tarDir != null && tarDir.length() > mDataDir.length() && !TextUtils.equals(tarDir, mDataDir) && tarDir.startsWith(mDataDir)) {     if (!tarDir.startsWith(mHostDataDir) && !TextUtils.equals(tarDir, mHostDataDir)) {           String pkg = tarDir.substring(mDataDir.length() + 1);           int index = pkg.indexOf("/");           if (index > 0) {              pkg = pkg.substring(0, index);           }              if (!TextUtils.equals(pkg, mHostPkg)) {                  tarDir = tarDir.replace(pkg, String.format("%s/Plugin/%s/data/%s", mHostPkg, pkg, pkg));                   return tarDir;           }       }   }  return null;}

这个方法很简单:

传入一个路径,比如/data/data/com.xxx.plugin/xxx 会替换成/data/data/插件宿主包名/Plugin/插件包名/data/插件包名。