What do you need for hooking Java virtual methods?
Suppose you want to hook the method A within class Z and divert the control flow
to the new method B ( the “patch” method ) within class X. At least you have to:
load X into application’s memory
retrive A reference from memory and its position inside the Z vtable
modify the A entry within Z vtable with B address
Using the GetMethodID function of Java Native Interface (JNI) we can obtain the A memory reference (suppose A is already loaded in memory,true for Android APIs). The GetMethodID function returns an jobject type, which is just an alias to ArtMethod data structure.
Using relative offset, we can access to elements inside the ArtMethod object returned by GetMethodID for retriving the information needed to retrive A index value inside Zvtable. Relative offset approach is stable and reliable because ART internals are very unlikely to be subject of OEM modifications.
To achieve point 1 we use the DexClassLoader API, the “patch” method B is defined by the user and loaded from a DEX file.
Once we have got the information scanning the memory, we can achieve point 3 using just simple memory operations by native code.
Using the A memory reference returned by GetMethodID , we can parse the ArtMethod structure and access to its following elements:
The former is a reference to Z (a Class object). This class contains the method A. The latter is the A’s index value inside Z vtable.
Following the declaring_class_ pointer, we can parse the Class object from memory to access its following elements:
How does the runtime is looking up virtual methods?
First let’s try to follow the flow of a Java method called by JNI. As example we take in account the CallObjectMethod function, defined in jniinternals.c. This function is used for calling Java methods from native code, exactly only methods which returns an Object type.
(All following source code is taken from androidxref Android 6.0.1_r10 )
The called function InvokeVirtualOrInterfaceWithVarArgs (line 686) is defined in reflection.cc:
At line 540 is retrived the ArtMethod identified by the jmethodID passed as third argument, the FindVirtualMethod function is defined in reflection.cc
The real method invocation is the call to InvokeWithArgArray at line 552.
The FindVirtualMethod function is used to look up a virtual method inside its receiver object, following box shows the code.
The above code calls function FindVirtualMethodForVirtualOrInterface (line 422) defined in class-inl.h to look up the target method.
The following box show FindVirtualMethodForVirtualOrInterface code
FindVirtualMethodForVirtual, defined in class-inl.h, returns the method scanning the vtable_ array.
Analyzing the GetVtableEntry code, still defined in class-inl.h, we can see a call to function ShouldHaveEmbeddedImtAndVTable. If the returned result is True the vtable is embedded within the class, otherwise it is retrived calling the function GetVTable() (line 184)
So, what do the function ShouldHaveEmbeddedImtAndVTable do?
The GetVTable code is showed in following box:
Ok now we know that virtual methods called by JNI are looked up using the vtable_ array (embedded or not).
Let’s me try to figure out how the runtime invoke methods called by reflection.
The function involved in reflection calls is InvokeMethod defined in reflection.cc. The target method to invoke is looked up using the following code (line 600):
Finally, the looked up method is invoked at line 640:
Once we know how the runtime is lookuping virtual methods, we can exploit this mechanism to achieve Java virtual methods hooking.
Next post introduces ARTDroid, an easy-to-use library for hooking virtual methods calls under ART runtime.