Android app : java / JNI call hooking strategies

Dr. Jekyll

My goal is to instrument the AOSP in order to dynamically log all java or JNI calls from a targeted app, with or without the arguments and return value. I do not want to modify the application, it is why I am looking to modify the Android source code. I am not very experience with AOSP and its multitude of libs and frameworks so I am looking for advices because I don't know where to start. Moreover, because of the potential amount of lines logged, the process have to be efficient (i.e I do not believe that a debug-like method, where one must implements a hook class for each hooked method, can work)

What I understood so far :

With the relatively new ART system, it compiles the DEX app source code into a sort of machine executable code (OAT ?) and it is more complex to instrument compared to what it has been with Dalvik.

The execution flow : compiled java bytecode of the app (which depends of the compiled Android API) + libs.so -> DVM -> forked Zygote VM -> Execution of the app.

If I try to hook at the root (Android API + libs.so) it will demands a fastidious amount of work to hook each call. The ideal would be a spot where all java calls pass through. Does a such spot even exists with ART ?.

The AOSP source code is hard to understand because it seems that there are no document that states the role of each source file in the global architecture. So where it is better to hook the calls ?

EDIT(s)

This topic is not well covered, so I'll show info for anyone interested.

My researches came across this blog : http://blog.csdn.net/l173864930/article/details/45035521. (+Google translate) Who links to this interesting Java and ELF (arm) call hooking project : https://github.com/boyliang/AllHookInOne

It is not exactly what I'm seeking, but I will try to implement an AOSP patch for dynamic analysis that suits my needs.

Dr. Jekyll

I have succeed to answer my question. For what I could understand from the source code there is 3 possible entry points for the java calls :

  • ArtMethod::Invoke (art/runtime/mirror/art_method.cc)
  • Execute (art/runtime/interpreter/interpreter.cc)
  • DoCall (art/runtime/interpreter/interpreter_common.cc)

ArtMethod::Invoke seems to be used for reflection and for calling the method directly with a pointer to the OAT code section. (Again, no documentation, it can be inexact).

Execute end up calling DoCall generally.

There is some optimizations of ART that make the study of Java calls difficult, like method inlining and direct offset address calling.

The first step is the disabling of these optimizations :

In device/brand-name/model/device.mk (in my case device/lge/hammerhead/device.mk for a nexus 5) :

Add the option "interpret-only" to dex2oat. With this option, ART compile only the boot classpath, so the applications will not be compiled in OAT.

PRODUCT_PROPERTY_OVERRIDES := \
    dalvik.vm.dex2oat-filter=interpret-only

The second step is to disable inlining in art/compiler/dex/frontend.cc :

Uncomment "kSuppressMethodInlining".

/* Default optimizer/debug setting for the compiler. */
static uint32_t kCompilerOptimizerDisableFlags = 0 |  // Disable specific optimizations
  (1 << kLoadStoreElimination) |
  // (1 << kLoadHoisting) |
  // (1 << kSuppressLoads) |
  // (1 << kNullCheckElimination) |
  // (1 << kClassInitCheckElimination) |
  (1 << kGlobalValueNumbering) |
  // (1 << kPromoteRegs) |
  // (1 << kTrackLiveTemps) |
  // (1 << kSafeOptimizations) |
  // (1 << kBBOpt) |
  // (1 << kMatch) |
  // (1 << kPromoteCompilerTemps) |
  // (1 << kSuppressExceptionEdges) |
  (1 << kSuppressMethodInlining) |
  0;

The last step is to disable direct code offset invocation in art/compiler/driver/compiler_driver.cc :

-bool use_dex_cache = GetCompilerOptions().GetCompilePic();
+bool use_dex_cache = true;

With these changes all different calls will fall in the DoCall function where we can finally add our targeted logging routine.

In art/runtime/interpreter/interpreter_common.h, add at the beginning of the includes :

#ifdef HAVE_ANDROID_OS
#include "cutils/properties.h"
#endif

In art/runtime/interpreter/interpreter_common.cc, add at the beginning of the DoCall function :

#ifdef HAVE_ANDROID_OS 
  char targetAppVar[92];
  property_get("target.app.pid", targetAppVar, "0");

  int targetAppPID = atoi(targetAppVar);

  if(targetAppPID != 0 && targetAppPID == getpid())
    LOG(INFO) << "DoCall - " << PrettyMethod(method, true);
#endif

For targeting the application I use a property which set the targeted pid. For this we need the lib system/core/libcutils and this lib is only available when the AOSP is compiled for a real phone (without messing with the current makefiles).
So the solution will not work for an emulator. (Only guessing, never tried EDIT: confirmed, "cutils/properties.h" cannot be added to the build of an emulator).

After compiling and flashing the patched AOSP, start an app, ps | grep for finding the PID and set the property in root :

shell@android:/ # ps | grep contacts                                       
u0_a2     4278  129   1234668 47356 ffffffff 401e8318 S com.android.contacts

shell@android:/ # setprop target.app.pid 4278

shell@android:/ # logcat
[...]
I/art     ( 4278): DoCall - int android.view.View.getId()
I/art     ( 4278): DoCall - void com.android.contacts.activities.PeopleActivity$ContactsUnavailableFragmentListener.onCreateNewContactAction()
I/art     ( 4278): DoCall - void android.content.Intent.<init>(java.lang.String, android.net.Uri)
I/art     ( 4278): DoCall - void android.app.Activity.startActivity(android.content.Intent)
I/ActivityManager(  498): START u0 {act=android.intent.action.INSERT dat=content://com.android.contacts/contacts cmp=com.android.contacts/.activities.ContactEditorActivity} from uid 10002 on display 0
V/WindowManager(  498): addAppToken: AppWindowToken{3a82282b token=Token{dc3f87a ActivityRecord{c0aaca5 u0 com.android.contacts/.activities.ContactEditorActivity t4}}} to stack=1 task=4 at 1
I/art     ( 4278): DoCall - void android.app.Fragment.onPause()
I/art     ( 4278): DoCall - void com.android.contacts.common.list.ContactEntryListFragment.removePendingDirectorySearchRequests()
I/art     ( 4278): DoCall - void android.os.Handler.removeMessages(int)
I/art     ( 4278): DoCall - void com.android.contacts.list.ProviderStatusWatcher.stop()
I/art     ( 4278): DoCall - boolean com.android.contacts.list.ProviderStatusWatcher.isStarted()
I/art     ( 4278): DoCall - void android.os.Handler.removeCallbacks(java.lang.Runnable)
I/art     ( 4278): DoCall - android.content.ContentResolver com.android.contacts.ContactsActivity.getContentResolver()
I/art     ( 4278): DoCall - void android.content.ContentResolver.unregisterContentObserver(android.database.ContentObserver)
I/art     ( 4278): DoCall - void android.app.Activity.onPause()
I/art     ( 4278): DoCall - void android.view.ViewGroup.drawableStateChanged()
I/art     ( 4278): DoCall - void com.android.contacts.ContactsActivity.<init>()
I/art     ( 4278): DoCall - void com.android.contacts.common.activity.TransactionSafeActivity.<init>()
I/art     ( 4278): DoCall - void android.app.Activity.<init>()
I/art     ( 4278): DoCall - void com.android.contacts.util.DialogManager.<init>(android.app.Activity)
I/art     ( 4278): DoCall - void java.lang.Object.<init>()
[...]

When it is over :

shell@android:/ # setprop target.app.pid 0

Voilà !

The overload is not noticeable from a user point of view, but the logcat will be quickly filled.

PS : File paths and names match the Android 5 version (Lollipop), they will be probably different with superior versions.

PS' : If one would wants to print the arguments of the methods, I would advice it to look at art/runtime/utils.cc for the PrettyArguments method and to find some practical implementation somewhere in the code.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Java

Android JNI - Call function on Android UI thread from C++

From Java

Overhead of a Java JNI call

From Java

Android ndk : Problem for call of Java method from c++ with jni

From Java

Hooking an existing method in Java

From Java

Java JNI call to load library

From Java

How to call java web service from android app?

From Java

Keeping java methods called from Android JNI

From Dev

Android JNI - Call AttachCurrentThread without DetachCurrentThread

From Dev

Unable to make JNI call from c++ to java in android lollipop using jni

From Dev

Measure time in Java JNI ( native call Java)

From Dev

C++ Multithread Java JNI method Call

From Dev

Call a function in java from C outside of a JNI function (Android)?

From Dev

Android app with realTime database without using FIREBASE maybe Something like hooking on server

From Dev

JNI C++ android app crashes when call function

From Dev

java call Hook by jna/ jni failed

From Dev

Call fortran dll from java using JNI

From Dev

Call Java Enum method from JNI

From Dev

Android JNI RegisterNatives: Call once with everything, or once per function

From Dev

Hooking every function call in Python

From Dev

System call hooking example arguments are incorrect

From Dev

Android device screen lock blocks JNI method call

From Dev

call android activity from jni directly from c++ process without java side

From Dev

jni call java method which take a custom java interface as parameter

From Dev

Android Java Access from JNI

From Dev

Java Program terminates after JNI method call

From Dev

Call jar file method from JNI layer in Android

From Dev

Android how to call external app like java

From Dev

Ajax call in android app

From Dev

How to call Jni object in Android Activity?

Related Related

  1. 1

    Android JNI - Call function on Android UI thread from C++

  2. 2

    Overhead of a Java JNI call

  3. 3

    Android ndk : Problem for call of Java method from c++ with jni

  4. 4

    Hooking an existing method in Java

  5. 5

    Java JNI call to load library

  6. 6

    How to call java web service from android app?

  7. 7

    Keeping java methods called from Android JNI

  8. 8

    Android JNI - Call AttachCurrentThread without DetachCurrentThread

  9. 9

    Unable to make JNI call from c++ to java in android lollipop using jni

  10. 10

    Measure time in Java JNI ( native call Java)

  11. 11

    C++ Multithread Java JNI method Call

  12. 12

    Call a function in java from C outside of a JNI function (Android)?

  13. 13

    Android app with realTime database without using FIREBASE maybe Something like hooking on server

  14. 14

    JNI C++ android app crashes when call function

  15. 15

    java call Hook by jna/ jni failed

  16. 16

    Call fortran dll from java using JNI

  17. 17

    Call Java Enum method from JNI

  18. 18

    Android JNI RegisterNatives: Call once with everything, or once per function

  19. 19

    Hooking every function call in Python

  20. 20

    System call hooking example arguments are incorrect

  21. 21

    Android device screen lock blocks JNI method call

  22. 22

    call android activity from jni directly from c++ process without java side

  23. 23

    jni call java method which take a custom java interface as parameter

  24. 24

    Android Java Access from JNI

  25. 25

    Java Program terminates after JNI method call

  26. 26

    Call jar file method from JNI layer in Android

  27. 27

    Android how to call external app like java

  28. 28

    Ajax call in android app

  29. 29

    How to call Jni object in Android Activity?

HotTag

Archive