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) {
}
}
}