Closed paulo-raca closed 2 years ago
This means ArtMethod
will be movable now which may cause many other problems in the future.
@kiceargy can you explain the issues on Android 10?
I've been using it without issues (although I use an Internal fork that has diverged a bit)
Good to hear :)
Back to Android 11, I did some progress and it actually works!
Both art::Runtime:instance_
and JniIdManager::DecodeMethodId
are available on libart.so, so it is more-or-less straightforward to decode it. Here is my snippet:
typedef art::ArtMethod* (decode_method_t)(art::jni::JniIdManager* jniIdManager, jmethodID method);
static art::ArtMethod* decodeMethodId(jmethodID methodId) {
if (((int)methodId) & 1) {
art::Runtime** runtime = lookup_symbol<art::Runtime*>("libart.so", "_ZN3art7Runtime9instance_E"); // art::Runtime:instance_;
decode_method_t* decodeMethod = lookup_symbol<decode_method_t>("libart.so", "_ZN3art3jni12JniIdManager14DecodeMethodIdEP10_jmethodID"); // art::jni::JniIdManager::DecodeMethodId(jmethodID)
if (!runtime || !*runtime || !decodeMethod) {
return nullptr;
}
art::jni::JniIdManager* jniIdManager = (*runtime)->GetJniIdManager();
return decodeMethod(jniIdManager, methodId);
} else {
return (art::ArtMethod*) methodId;
}
}
However, the tricky part is looking up the symbols, as it appears that Android's linker prevent us from accessing libart.so
from an app. Right now I'm using a non-FOSS library to perform the lookup. Any suggestion on alternatives that could be used on YAHFA?
Also, I've included AOSPs headers instead of working with void* and offsets -- Should be easy to translate.
On the actual hooking side of things, it seems like there are no changes since Q and no tweaks were necessary :balloon: :tada:
Thanks!
I think there are several tools for dlopen
bypassing, such as https://github.com/avs333/Nougat_dlfunctions
The basic idea is parsing ELF file for dynamic symbols.
I've just created a new branch Android_R
for it.
dl_iterate_phdr
is used for iterating the ELFs in memory. Function __loader_dlopen
is then resolved from linker
and the address of libnativeloader.so
is used as caller_addr
since it's in the same namespace(art
): https://github.com/PAGalaxyLab/YAHFA/commit/3386f7d02bde4448f4c427485a0b3d9a270efc73#diff-ff7f2400b6d9e63cb68ba9f54db86bce
Then art::Runtime:instance_
and DecodeMethodId
can be resolved and used as @paulo-raca showed.
Fantastic, thank you!
I just tried android-11-preview-2, and it worked after recompiling with updated headers.
In @rk700 code's it will probably translate into updated offsets to retrieve idManager
Offsets updated for preview-2 images.
I have a new idea...
In Java, both Method
and Constructor
extend from Executable
, and Executable
has a member called artMethod
, and it still seems to hold the real ArtMethod*
(See art/runtime/mirror/executable.h):
ArtMethod* GetArtMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
return reinterpret_cast64<ArtMethod*>(GetField64<kVerifyFlags>(ArtMethodOffset()));
}
This member can be accessed through reflection, so there is no need to obtain the JniIdManager
through a hard-coded offset and use it to convert the ArtMethod*
.
Sounds like a good idea!
Thank you @canyie, just updated the way for ArtMethod
as you suggested: https://github.com/PAGalaxyLab/YAHFA/commit/9c516f1175b4d16d612e9a4aaed83a82a1e9ff00
Android 11 is still on beta 1, very early on its lifecycle, but in the past I've seem little or no changes to ART during the beta period, with most changes happening in higher-level frameworks. Also I need YAHFA before I can start looking into the other changes, so I'm eager to get it supported.
I looked briefly into ArtMethod data structure, and there seem to be no difference compared to Q.
However, we previously assumed that
(*env)->FromReflectedMethod(env, method)
would return a direct pointer toArtMethod
data structure. This is no longer true, and the runtime must callart::jni::DecodeArtMethod(jmethodID method)
to retrieve theArtMethod*