/* SqlCipherHook Xposed Module * Copyright 2015 Jake Valletta (@jake_valletta) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jakev.sqlcipherhook; import android.app.Application; import android.content.Context; import android.util.Log; import de.robv.android.xposed.IXposedHookLoadPackage; import de.robv.android.xposed.XC_MethodHook; import de.robv.android.xposed.XposedBridge; import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam; import static de.robv.android.xposed.XposedHelpers.findAndHookMethod; import static de.robv.android.xposed.XposedHelpers.findClass; public class MainHook implements IXposedHookLoadPackage { private static final String TAG = "SqlCipherHook"; private static final String SQLCIPHER_CLASS_NAME = "net.sqlcipher.database.SQLiteDatabase"; private String currentPackageName = ""; public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable { currentPackageName = lpparam.packageName; findAndHookMethod(Application.class, "attach", Context.class, new XC_MethodHook() { @Override protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) throws Throwable { Context context = (Context) param.args[0]; ClassLoader cl = context.getClassLoader(); if (hasSqlCipher(cl)) { hookSqlCipher(cl); } } }); } /* Perform Hooks */ private void hookSqlCipher(ClassLoader classLoader) { Log.d(TAG, "Hooking SqlCipher libraries for: " + currentPackageName); /* We can simply hook all calls to "openDatabase(...)", and handle the slight differences */ Class<?> clazz = findClass(SQLCIPHER_CLASS_NAME, classLoader); XC_MethodHook hook = new XC_MethodHook() { @Override protected void beforeHookedMethod(MethodHookParam param) throws Throwable { /* Param 1 will always be a string. */ String path = (String)param.args[0]; /* Param 2 can be either a char[] or a String. */ String password = "ERROR"; Object inPassword = param.args[1]; if (inPassword instanceof String) { password = (String)inPassword; } else if (inPassword instanceof char[]) { password = String.valueOf((char[])inPassword); } Log.d(TAG, "[" + currentPackageName + "] SqlCipher openDatabase( ... ) called!"); Log.d(TAG, "[" + currentPackageName + "] Password Used: " + password); Log.d(TAG, "[" + currentPackageName + "] DB Path: " + path); } }; /* Perform the hook */ XposedBridge.hookAllMethods(clazz, "openDatabase", hook); } // End Hooks private boolean hasSqlCipher(ClassLoader classLoader) { try { classLoader.loadClass(SQLCIPHER_CLASS_NAME); } catch (ClassNotFoundException e) { return false; } return true; } }