PAGalaxyLab / YAHFA

Yet Another Hook Framework for ART
GNU General Public License v3.0
1.56k stars 347 forks source link

Support for Android 11 #124

Closed paulo-raca closed 2 years ago

paulo-raca commented 4 years ago

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 to ArtMethod data structure. This is no longer true, and the runtime must call art::jni::DecodeArtMethod(jmethodID method) to retrieve the ArtMethod*

ghost commented 4 years ago

This means ArtMethod will be movable now which may cause many other problems in the future.

paulo-raca commented 4 years ago

@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)

paulo-raca commented 4 years ago

Good to hear :)

paulo-raca commented 4 years ago

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:

rk700 commented 4 years ago

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.

rk700 commented 4 years ago

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.

paulo-raca commented 4 years ago

Fantastic, thank you!

paulo-raca commented 4 years ago

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

rk700 commented 4 years ago

Offsets updated for preview-2 images.

canyie commented 4 years ago

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*.

paulo-raca commented 4 years ago

Sounds like a good idea!

rk700 commented 4 years ago

Thank you @canyie, just updated the way for ArtMethod as you suggested: https://github.com/PAGalaxyLab/YAHFA/commit/9c516f1175b4d16d612e9a4aaed83a82a1e9ff00