parent
c84c09b2d5
commit
9553af5bb7
|
|
@ -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();
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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() {
|
||||||
|
|
|
||||||
|
|
@ -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"));
|
||||||
|
|
|
||||||
|
|
@ -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 "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue