package mobi.acpm.inspeckage.hooks; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonSyntaxException; import org.json.JSONArray; import org.json.JSONObject; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.List; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XSharedPreferences; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.callbacks.XC_LoadPackage; import mobi.acpm.inspeckage.Module; import mobi.acpm.inspeckage.util.Config; import mobi.acpm.inspeckage.util.Replacement; import mobi.acpm.inspeckage.util.Util; import static de.robv.android.xposed.XposedBridge.log; import static de.robv.android.xposed.XposedHelpers.findClass; /** * Created by acpm on 19/04/16. */ public class UserHooks extends XC_MethodHook { public static final String TAG = "Inspeckage_UserHooks:"; private static Gson gson = new GsonBuilder().disableHtmlEscaping().create();//new Gson(); private static XSharedPreferences sPrefs; private static XC_LoadPackage.LoadPackageParam lpp; public static void loadPrefs() { sPrefs = new XSharedPreferences(Module.class.getPackage().getName(), Module.PREFS); sPrefs.makeWorldReadable(); } public static void initAllHooks(final XC_LoadPackage.LoadPackageParam loadPackageParam) { loadPrefs(); lpp = loadPackageParam; String json = "{\"hookJson\": " + sPrefs.getString(Config.SP_USER_HOOKS, "") + "}"; try { if(!json.trim().equals("{\"hookJson\":}")) { HookList hookList = gson.fromJson(json, HookList.class); for (HookItem hookItem : hookList.hookJson) { if(hookItem.state) { hook(hookItem, loadPackageParam.classLoader); } } } } catch (JsonSyntaxException ex) { } } static void hook(HookItem item, ClassLoader classLoader) { try { Class<?> hookClass = findClass(item.className, classLoader); if (hookClass != null) { if (item.method != null && !item.method.equals("")) { for (Method method : hookClass.getDeclaredMethods()) { if (method.getName().equals(item.method) && !Modifier.isAbstract(method.getModifiers())) { XposedBridge.hookMethod(method, methodHook); } } } else { for (Method method : hookClass.getDeclaredMethods()) { if(!Modifier.isAbstract(method.getModifiers())) { XposedBridge.hookMethod(method, methodHook); } } } if (item.constructor) { for (Constructor<?> constructor : hookClass.getDeclaredConstructors()) { XposedBridge.hookMethod(constructor, methodHook); } } } else { log(TAG + "class not found."); } } catch (Error e) { Module.logError(e); } } static XC_MethodHook methodHook = new XC_MethodHook() { protected void beforeHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); Replacement.parameterReplace(param, sPrefs); } protected void afterHookedMethod(MethodHookParam param) throws Throwable { loadPrefs(); Replacement.resultReplace(param, sPrefs); parseParam(param); } }; static void parseParam(XC_MethodHook.MethodHookParam param) { try { JSONObject hookData = new JSONObject(); hookData.put("class", param.method.getDeclaringClass().getName()); if(param.method!=null) hookData.put("method", param.method.getName()); JSONArray args = new JSONArray(); if(param.args!=null) { for (Object object : (Object[]) param.args) { if (object != null) { if(object.getClass().equals(byte[].class)){ String result = Util.byteArrayToString((byte[])object); args.put(gson.toJson(result)); }else{ args.put(gson.toJson(object)); } } } hookData.put("args", args); } if(param.getResult()!=null){ String result = ""; if(param.getResult().getClass().equals(byte[].class)){ result = Util.byteArrayToString((byte[])param.getResult()); hookData.put("result", gson.toJson(result)); }else{ hookData.put("result", gson.toJson(param.getResult())); } } log(TAG + hookData.toString()); } catch (Exception e) { e.getMessage(); } } } class HookList { public List<HookItem> hookJson; } class HookItem { protected int id; protected String className; protected String method; protected boolean constructor; protected boolean state; }