android 從jobject、jclass獲取類名(API>19)(一)

前言

用途在Art中Hook JNI相關(guān)函數(shù)。存在jobject jclass 參數(shù)時需要得到具體的類名。

在Art虛擬機中:

jobject在內(nèi)存中表現(xiàn)為:art::mirror::Object,可從GetObjectClass方法中分析得到(art/runtime/jni_internal.cc)


  static jclass GetObjectClass(JNIEnv* env, jobject java_object) {

    CHECK_NON_NULL_ARGUMENT(java_object);

    ScopedObjectAccess soa(env);

    ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);

    return soa.AddLocalReference<jclass>(o->GetClass());

  }

jclass在內(nèi)存中表現(xiàn)為:art::mirror::Class,可從GetSuperclass方法中分析得到(art/runtime/jni_internal.cc)


  static jclass GetSuperclass(JNIEnv* env, jclass java_class) {

    CHECK_NON_NULL_ARGUMENT(java_class);

    ScopedObjectAccess soa(env);

    ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);

    return soa.AddLocalReference<jclass>(c->IsInterface() ? nullptr : c->GetSuperClass());

  }

正文

獲取類名重點在art::mirror::Class類中,通過分析Class 類發(fā)現(xiàn)在art/runtime/mirror/class-inl.h頭文件中存在一個獲取類名的方法


inline String* Class::GetName() {

  return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Class, name_));

}

上述方法存在兩個問題:

  • inline內(nèi)聯(lián)函數(shù),編譯后在libart.so不存在導(dǎo)出符號

  • 返回值String類型是art虛擬機一個內(nèi)部類,調(diào)用起來太麻煩

綜上所述,GetName不適合獲取類名

在dalvik虛擬機中存在一個方法dvmDecodeIndirectRef,可以將jobject、jclass轉(zhuǎn)為對應(yīng)的內(nèi)存結(jié)構(gòu)指針。

經(jīng)過查找發(fā)現(xiàn)在/art/runtime/thread.cc中存在一個方法DecodeJObject可以將jobject、jclass轉(zhuǎn)換為對應(yīng)的內(nèi)存結(jié)構(gòu)指針


ObjPtr<mirror::Object> Thread::DecodeJObject(jobject obj) const {

    ..............

}

DecodeJObject是Thread類的一個方法,通過dlsym拿到方法地址后,其表現(xiàn)形式如下:


void *(*DecodeJObject)(void *thisobj, jobject jobject);

第一個參數(shù)表示this即當前對象??梢酝ㄟ^如下方法獲取Thread對象的實例


void *Art::Current() {

#if defined(__aarch64__)

# define __get_tls() ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; })

#elif defined(__arm__)

# define __get_tls() ({ void** __val; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__val)); __val; })

#elif defined(__mips__)

# define __get_tls() \

    /* On mips32r1, this goes via a kernel illegal instruction trap that's optimized for v1. */ \

    ({ register void** __val asm("v1"); \

       __asm__(".set push\n" \

               ".set mips32r2\n" \

               "rdhwr %0,$29\n" \

               ".set pop\n" : "=r"(__val)); \

       __val; })

#elif defined(__i386__)

# define __get_tls() ({ void** __val; __asm__("movl %%gs:0, %0" : "=r"(__val)); __val; })

#elif defined(__x86_64__)

# define __get_tls() ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; })

#else

#error unsupported architecture

#endif

    enum {

        TLS_SLOT_SELF = 0,

        // The kernel requires this specific slot for x86.

                TLS_SLOT_THREAD_ID,

        TLS_SLOT_ERRNO,



        // These two aren't used by bionic itself, but allow the graphics code to

        // access TLS directly rather than using the pthread API.

                TLS_SLOT_OPENGL_API = 3,

        TLS_SLOT_OPENGL = 4,



        // This slot is only used to pass information from the dynamic linker to

        // libc.so when the C library is loaded in to memory. The C runtime init

        // function will then clear it. Since its use is extremely temporary,

        // we reuse an existing location that isn't needed during libc startup.

                TLS_SLOT_BIONIC_PREINIT = TLS_SLOT_OPENGL_API,



        TLS_SLOT_STACK_GUARD = 5,

        // GCC requires this specific slot for x86.

                TLS_SLOT_DLERROR,



        // Fast storage for Thread::Current() in ART.

                TLS_SLOT_ART_THREAD_SELF,



        // Lets TSAN avoid using pthread_getspecific for finding the current thread

        // state.

                TLS_SLOT_TSAN,



        BIONIC_TLS_SLOTS // Must come last!

    };

    if (sdkVersion >= Nougat) {

        //get thread form asm code

        void *thread = __get_tls()[TLS_SLOT_ART_THREAD_SELF];

        return thread;

    } else {

        if (pthread_key_self_handle == nullptr) {

            pthread_key_self_handle = fake_dlsym(libartHandle, pthread_key_self_Symbol.c_str());

        }

        pthread_key_t key = *(pthread_key_t *) pthread_key_self_handle;

        void *thread = pthread_getspecific(key);

        return thread;

    }

}

同時發(fā)現(xiàn)/art/runtime/mirror/class.cc中存在GetDescriptor方法可以獲取art::mirror::Class的類名


const char* Class::GetDescriptor(std::string* storage) {

  if (IsPrimitive()) {

    return Primitive::Descriptor(GetPrimitiveType());

  } else if (IsArrayClass()) {

    return GetArrayDescriptor(storage);

  } else if (IsProxyClass()) {

    *storage = Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(this);

    return storage->c_str();

  } else {

    const DexFile& dex_file = GetDexFile();

    const DexFile::TypeId& type_id = dex_file.GetTypeId(GetClassDef()->class_idx_);

    return dex_file.GetTypeDescriptor(type_id);

  }

}

GetDescriptor是Class類的一個方法,通過dlsym拿到方法地址后,其表現(xiàn)形式如下:


 const char *(*getClassDescriptor)(void *thisobj, void *temp);

第一個參數(shù)表示this即當前對象??梢酝ㄟ^DecodeJObject獲取Class對象的實例,

在最終可以整理得到獲取jclass類名的方法:


const char *Art::getClasstName(jclass clazz) {

    void *pVoid = DecodeJObject(Current(), clazz);

    std::string tmp;

    const char *data = getClassDescriptor(pVoid, &tmp);

    return data;

}

獲取jobject方法就簡單一點其內(nèi)存結(jié)構(gòu)可以精簡如下:


class ARTObject {

public:

    uint32_t klass_;

    uint32_t monitor_;

};

其中klass就是Class對象的指針,最終整理后的方法如下:


const char *Art::getObjectName(jobject obj) {

    void *k_class = nullptr;

    void *pVoid = DecodeJObject(Current(), obj);

    ARTObject *object_api21 = (ARTObject *) (pVoid);

    k_class = (void *) object_api21->klass_;

    std::string tmp;

    const char *data = getClassDescriptor(k_class, &tmp);

    return data;

    }

上述方法太過于麻煩,后面給出一個簡單的方法,可以模擬dalvik解析dex拿到類名。不早了,睡了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容