package com.cuckoodroid.droidmon; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import com.cuckoodroid.droidmon.utils.Files; import com.cuckoodroid.droidmon.utils.Logger; import com.cuckoodroid.droidmon.utils.MethodApiType; import com.google.gson.Gson; import android.content.pm.ApplicationInfo; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.IXposedHookZygoteInit; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; import de.robv.android.xposed.XC_MethodHook; import static de.robv.android.xposed.XposedHelpers.findClass; // This class will be called by Xposed public class InstrumentationManager implements IXposedHookLoadPackage, IXposedHookZygoteInit { public static String CONFIG_FILE = "/data/local/tmp/hooks.json"; public static Boolean TRACE = false; private static Set<String> OS_APPS = new HashSet<String>(Arrays.asList( "com.android.systemui" ,"com.android.inputmethod.latin" ,"com.android.phone" ,"com.android.launcher" ,"com.android.settings" ,"com.android.contacts" ,"com.android.providers.calendar" ,"android.process.media" ,"com.android.mms" ,"com.android.deskclock" ,"com.android.email" ,"com.android.exchange" ,"com.cuckoo.android.agent" ,"com.noshufou.android.su" ,"com.android.calendar" ,"com.android.droidmon" ,"de.robv.android.xposed.installer")) ; // Call when zygote initialize public void initZygote(StartupParam startupParam) throws Throwable { hookNonSystemServices(); } // Hook methods not provided by system services private void hookNonSystemServices(){ } // Call when package loaded public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable{ if(lpparam.appInfo == null || (lpparam.appInfo.flags & (ApplicationInfo.FLAG_SYSTEM | ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) !=0){ return; }else if(lpparam.isFirstApplication && !OS_APPS.contains(lpparam.packageName)) { Logger.PACKAGENAME = lpparam.packageName; try { instrumentApp(); } catch (FileNotFoundException e) { Logger.logError(e.getMessage()); } catch (IOException e) { Logger.logError(e.getMessage()); } } } public void instrumentApp() throws FileNotFoundException, IOException { Gson gson = new Gson(); String json = Files.readFile(CONFIG_FILE); InstrumentationConfiguration instrumentationConfiguration = gson.fromJson(json, InstrumentationConfiguration.class); TRACE=instrumentationConfiguration.trace; for (HookConfig hookConfig : instrumentationConfiguration.hookConfigs) { hook(new MethodHookImpl(hookConfig.class_name,hookConfig.method,hookConfig.thisObject,hookConfig.type)); } } public class InstrumentationConfiguration { public List<HookConfig> hookConfigs; public Boolean trace; } public class HookConfig { private String class_name; private String method; private Boolean thisObject; private MethodApiType type; } private static void hook(MethodHookImpl methodHook) { hook(methodHook, null); } private static void hook(final MethodHookImpl methodHook, ClassLoader classLoader) { try { // Create hook method XC_MethodHook xcMethodHook = methodHook; // Find hook class Class<?> hookClass = findClass(methodHook.getClassName(), classLoader); if (hookClass == null) { String message = String.format("Hook-Class not found: %s", methodHook.getClassName()); Logger.logError(message); return; } // Add hook if (methodHook.getMethodName() == null) { for (Constructor<?> constructor : hookClass.getDeclaredConstructors()){ XposedBridge.hookMethod(constructor, xcMethodHook); } } else{ for (Method method : hookClass.getDeclaredMethods()) if (method.getName().equals(methodHook.getMethodName())) XposedBridge.hookMethod(method, xcMethodHook); } } catch (Throwable ex) { } } }