Move sandhook cache to /data/misc

Close #681
This commit is contained in:
LoveSy 2020-12-24 20:22:42 +08:00 committed by 双草酸酯
parent c84c09b2d5
commit 9553af5bb7
6 changed files with 57 additions and 41 deletions

View File

@ -7,7 +7,7 @@ import de.robv.android.xposed.XposedBridge;
public interface HookMaker { public interface HookMaker {
void start(Member member, XposedBridge.AdditionalHookInfo hookInfo, void start(Member member, XposedBridge.AdditionalHookInfo hookInfo,
ClassLoader appClassLoader, String dexDirPath) throws Exception; ClassLoader appClassLoader) throws Exception;
Method getHookMethod(); Method getHookMethod();
Method getBackupMethod(); Method getBackupMethod();
Method getCallBackupMethod(); Method getCallBackupMethod();

View File

@ -1,7 +1,6 @@
package com.swift.sandhook.xposedcompat.methodgen; package com.swift.sandhook.xposedcompat.methodgen;
import android.text.TextUtils; import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.swift.sandhook.SandHook; import com.swift.sandhook.SandHook;
import com.swift.sandhook.SandHookMethodResolver; import com.swift.sandhook.SandHookMethodResolver;
import com.swift.sandhook.wrapper.HookWrapper; import com.swift.sandhook.wrapper.HookWrapper;
@ -9,7 +8,6 @@ import com.swift.sandhook.xposedcompat.XposedCompat;
import com.swift.sandhook.xposedcompat.utils.DexLog; import com.swift.sandhook.xposedcompat.utils.DexLog;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Member; import java.lang.reflect.Member;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@ -33,8 +31,10 @@ import external.com.android.dx.TypeId;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.MD5; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.MD5;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoBoxIfNecessary; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoBoxIfNecessary;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoUnboxIfNecessary; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoUnboxIfNecessary;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.canCache;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getSha1Hex;
public class HookerDexMaker implements HookMaker { public class HookerDexMaker implements HookMaker {
@ -110,7 +110,6 @@ public class HookerDexMaker implements HookMaker {
private Method mHookMethod; private Method mHookMethod;
private Method mBackupMethod; private Method mBackupMethod;
private Method mCallBackupMethod; private Method mCallBackupMethod;
private String mDexDirPath;
private static TypeId<?>[] getParameterTypeIds(Class<?>[] parameterTypes, boolean isStatic) { private static TypeId<?>[] getParameterTypeIds(Class<?>[] parameterTypes, boolean isStatic) {
int parameterSize = parameterTypes.length; int parameterSize = parameterTypes.length;
@ -141,7 +140,7 @@ public class HookerDexMaker implements HookMaker {
} }
public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo, public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo,
ClassLoader appClassLoader, String dexDirPath) throws Exception { ClassLoader appClassLoader) throws Exception {
if (member instanceof Method) { if (member instanceof Method) {
Method method = (Method) member; Method method = (Method) member;
mIsStatic = Modifier.isStatic(method.getModifiers()); mIsStatic = Modifier.isStatic(method.getModifiers());
@ -174,7 +173,6 @@ public class HookerDexMaker implements HookMaker {
} }
mMember = member; mMember = member;
mHookInfo = hookInfo; mHookInfo = hookInfo;
mDexDirPath = dexDirPath;
if (appClassLoader == null if (appClassLoader == null
|| appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) { || appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) {
mAppClassLoader = this.getClass().getClassLoader(); mAppClassLoader = this.getClass().getClassLoader();
@ -190,7 +188,7 @@ public class HookerDexMaker implements HookMaker {
HookWrapper.HookEntity hookEntity = null; HookWrapper.HookEntity hookEntity = null;
//try load cache first //try load cache first
try { try {
ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(mDexDirPath), dexName); ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexName);
if (loader != null) { if (loader != null) {
hookEntity = loadHookerClass(loader, className); hookEntity = loadHookerClass(loader, className);
} }
@ -217,13 +215,12 @@ public class HookerDexMaker implements HookMaker {
generateHookMethod(); generateHookMethod();
ClassLoader loader; ClassLoader loader;
if (TextUtils.isEmpty(mDexDirPath)) { if (canCache) {
throw new IllegalArgumentException("dexDirPath should not be empty!!!"); loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexName, true);
} File dexFile = new File(ConfigManager.getCachePath(dexName));
// Create the dex file and load it. dexFile.setWritable(true, false);
try { dexFile.setReadable(true, false);
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), dexName, true); } else {
} catch (IOException e) {
//can not write file //can not write file
byte[] dexBytes = mDexMaker.generate(); byte[] dexBytes = mDexMaker.generate();
loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader); loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader);
@ -245,7 +242,7 @@ public class HookerDexMaker implements HookMaker {
} }
private String getClassName(Member originMethod) { private String getClassName(Member originMethod) {
return CLASS_NAME_PREFIX + "_" + MD5(originMethod.toString()); return CLASS_NAME_PREFIX + "_" + getSha1Hex(originMethod.toString());
} }
public Method getHookMethod() { public Method getHookMethod() {

View File

@ -1,7 +1,6 @@
package com.swift.sandhook.xposedcompat.methodgen; package com.swift.sandhook.xposedcompat.methodgen;
import android.text.TextUtils; import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.swift.sandhook.SandHook; import com.swift.sandhook.SandHook;
import com.swift.sandhook.wrapper.HookWrapper; import com.swift.sandhook.wrapper.HookWrapper;
import com.swift.sandhook.xposedcompat.hookstub.HookStubManager; import com.swift.sandhook.xposedcompat.hookstub.HookStubManager;
@ -28,8 +27,10 @@ import external.com.android.dx.TypeId;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.MD5; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.MD5;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoBoxIfNecessary; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoBoxIfNecessary;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoUnboxIfNecessary; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.autoUnboxIfNecessary;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.canCache;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.createResultLocals;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive; import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getObjTypeIdIfPrimitive;
import static com.swift.sandhook.xposedcompat.utils.DexMakerUtils.getSha1Hex;
public class HookerDexMakerNew implements HookMaker { public class HookerDexMakerNew implements HookMaker {
@ -70,7 +71,6 @@ public class HookerDexMakerNew implements HookMaker {
private Class<?> mHookClass; private Class<?> mHookClass;
private Method mHookMethod; private Method mHookMethod;
private Method mBackupMethod; private Method mBackupMethod;
private String mDexDirPath;
private static TypeId<?>[] getParameterTypeIds(Class<?>[] parameterTypes, boolean isStatic) { private static TypeId<?>[] getParameterTypeIds(Class<?>[] parameterTypes, boolean isStatic) {
int parameterSize = parameterTypes.length; int parameterSize = parameterTypes.length;
@ -101,7 +101,7 @@ public class HookerDexMakerNew implements HookMaker {
} }
public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo, public void start(Member member, XposedBridge.AdditionalHookInfo hookInfo,
ClassLoader appClassLoader, String dexDirPath) throws Exception { ClassLoader appClassLoader) throws Exception {
if (member instanceof Method) { if (member instanceof Method) {
Method method = (Method) member; Method method = (Method) member;
mIsStatic = Modifier.isStatic(method.getModifiers()); mIsStatic = Modifier.isStatic(method.getModifiers());
@ -134,7 +134,6 @@ public class HookerDexMakerNew implements HookMaker {
} }
mMember = member; mMember = member;
mHookInfo = hookInfo; mHookInfo = hookInfo;
mDexDirPath = dexDirPath;
if (appClassLoader == null if (appClassLoader == null
|| appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) { || appClassLoader.getClass().getName().equals("java.lang.BootClassLoader")) {
mAppClassLoader = this.getClass().getClassLoader(); mAppClassLoader = this.getClass().getClassLoader();
@ -150,7 +149,7 @@ public class HookerDexMakerNew implements HookMaker {
HookWrapper.HookEntity hookEntity = null; HookWrapper.HookEntity hookEntity = null;
//try load cache first //try load cache first
try { try {
ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(mDexDirPath), dexName); ClassLoader loader = mDexMaker.loadClassDirect(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexName);
if (loader != null) { if (loader != null) {
hookEntity = loadHookerClass(loader, className); hookEntity = loadHookerClass(loader, className);
} }
@ -171,14 +170,17 @@ public class HookerDexMakerNew implements HookMaker {
generateBackupMethod(); generateBackupMethod();
ClassLoader loader; ClassLoader loader;
if (TextUtils.isEmpty(mDexDirPath)) { if (!canCache) {
byte[] dexBytes = mDexMaker.generate(); byte[] dexBytes = mDexMaker.generate();
loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader); loader = new InMemoryDexClassLoader(ByteBuffer.wrap(dexBytes), mAppClassLoader);
return loadHookerClass(loader, className); return loadHookerClass(loader, className);
} }
// Create the dex file and load it. // Create the dex file and load it.
try { try {
loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(mDexDirPath), dexName, true); loader = mDexMaker.generateAndLoad(mAppClassLoader, new File(ConfigManager.getCachePath("")), dexName, true);
File dexFile = new File(ConfigManager.getCachePath(dexName));
dexFile.setWritable(true, false);
dexFile.setReadable(true, false);
} catch (IOException e) { } catch (IOException e) {
//can not write file //can not write file
byte[] dexBytes = mDexMaker.generate(); byte[] dexBytes = mDexMaker.generate();
@ -203,7 +205,7 @@ public class HookerDexMakerNew implements HookMaker {
} }
private String getClassName(Member originMethod) { private String getClassName(Member originMethod) {
return CLASS_NAME_PREFIX + "_" + MD5(originMethod.toString()); return CLASS_NAME_PREFIX + "_" + getSha1Hex(originMethod.toString());
} }
public Method getHookMethod() { public Method getHookMethod() {

View File

@ -33,13 +33,10 @@ public final class SandHookXposedBridge {
private static final Map<Member, Method> hookedInfo = new ConcurrentHashMap<>(); private static final Map<Member, Method> hookedInfo = new ConcurrentHashMap<>();
private static HookMaker defaultHookMaker = XposedCompat.useNewCallBackup ? new HookerDexMakerNew() : new HookerDexMaker(); private static HookMaker defaultHookMaker = XposedCompat.useNewCallBackup ? new HookerDexMakerNew() : new HookerDexMaker();
private static final AtomicBoolean dexPathInited = new AtomicBoolean(false);
private static File dexDir;
public static Map<Member, HookMethodEntity> entityMap = new ConcurrentHashMap<>(); public static Map<Member, HookMethodEntity> entityMap = new ConcurrentHashMap<>();
public static void onForkPost() { public static void onForkPost() {
dexPathInited.set(false);
XposedCompat.onForkProcess(); XposedCompat.onForkProcess();
} }
@ -61,16 +58,6 @@ public final class SandHookXposedBridge {
Yahfa.recordHooked(hookMethod); // in case static method got reset. Yahfa.recordHooked(hookMethod); // in case static method got reset.
try { try {
if (dexPathInited.compareAndSet(false, true)) {
try {
String fixedAppDataDir = XposedCompat.getCacheDir().getAbsolutePath();
dexDir = new File(fixedAppDataDir, "/hookers/");
if (!dexDir.exists())
dexDir.mkdirs();
} catch (Throwable throwable) {
Log.e("SandHook", "error when init dex path", throwable);
}
}
Trace.beginSection("SandXposed"); Trace.beginSection("SandXposed");
long timeStart = System.currentTimeMillis(); long timeStart = System.currentTimeMillis();
HookMethodEntity stub = null; HookMethodEntity stub = null;
@ -89,8 +76,7 @@ public final class SandHookXposedBridge {
} }
hookMaker.start(hookMethod, additionalHookInfo, hookMaker.start(hookMethod, additionalHookInfo,
ClassLoaderUtils.createProxyClassLoader( ClassLoaderUtils.createProxyClassLoader(
hookMethod.getDeclaringClass().getClassLoader()), hookMethod.getDeclaringClass().getClassLoader()));
dexDir == null ? null : dexDir.getAbsolutePath());
hookedInfo.put(hookMethod, hookMaker.getCallBackupMethod()); hookedInfo.put(hookMethod, hookMaker.getCallBackupMethod());
} }
DexLog.d("hook method <" + hookMethod.toString() + "> cost " + (System.currentTimeMillis() - timeStart) + " ms, by " + (stub != null ? "internal stub" : "dex maker")); DexLog.d("hook method <" + hookMethod.toString() + "> cost " + (System.currentTimeMillis() - timeStart) + " ms, by " + (stub != null ? "internal stub" : "dex maker"));

View File

@ -1,6 +1,11 @@
package com.swift.sandhook.xposedcompat.utils; package com.swift.sandhook.xposedcompat.utils;
import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.util.Utils;
import java.io.File;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.math.BigInteger; import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.util.HashMap; import java.util.HashMap;
@ -12,6 +17,15 @@ import external.com.android.dx.TypeId;
public class DexMakerUtils { public class DexMakerUtils {
public static boolean canCache = true;
static {
File cacheDir = new File(ConfigManager.getCachePath(""));
if(!cacheDir.canRead() || !cacheDir.canWrite()) {
Utils.logW("Cache disabled");
canCache = false;
}
}
private static volatile Method addInstMethod, specMethod; private static volatile Method addInstMethod, specMethod;
@ -221,4 +235,20 @@ public class DexMakerUtils {
} }
return source; return source;
} }
public static String getSha1Hex(String text) {
final MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-1");
byte[] result = digest.digest(text.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder();
for (byte b : result) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (Exception e) {
DexLog.e("error hashing target method: " + text, e);
}
return "";
}
} }

View File

@ -4,6 +4,7 @@ import com.elderdrivers.riru.edxp.config.ConfigManager;
import com.elderdrivers.riru.edxp.util.Utils; import com.elderdrivers.riru.edxp.util.Utils;
import java.io.File; import java.io.File;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -224,7 +225,7 @@ public class DexMakerUtils {
final MessageDigest digest; final MessageDigest digest;
try { try {
digest = MessageDigest.getInstance("SHA-1"); digest = MessageDigest.getInstance("SHA-1");
byte[] result = digest.digest(text.getBytes("UTF-8")); byte[] result = digest.digest(text.getBytes(StandardCharsets.UTF_8));
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (byte b : result) { for (byte b : result) {
sb.append(String.format("%02x", b)); sb.append(String.format("%02x", b));