crmulliner / ddi

ddi - Dynamic Dalvik Instrumentation Toolkit
http://www.mulliner.org/android/
395 stars 159 forks source link

Get classes names in dex file #19

Open vvviperrr opened 8 years ago

vvviperrr commented 8 years ago

Its pretty inconvenient to use dexstuff_defineclass, because it could be many classes in dex, including local, anonymous classes. I have found the next method in dalvik:

/*
 * private static String[] getClassNameList(int cookie)
 *
 * Returns a String array that holds the names of all classes in the
 * specified DEX file.
 */
static void Dalvik_dalvik_system_DexFile_getClassNameList(const u4* args,
    JValue* pResult)
{
    int cookie = args[0];
    DexOrJar* pDexOrJar = (DexOrJar*) cookie;
    Thread* self = dvmThreadSelf();

    if (!validateCookie(cookie))
        RETURN_VOID();

    DvmDex* pDvmDex;
    if (pDexOrJar->isDex)
        pDvmDex = dvmGetRawDexFileDex(pDexOrJar->pRawDexFile);
    else
        pDvmDex = dvmGetJarFileDex(pDexOrJar->pJarFile);
    assert(pDvmDex != NULL);
    DexFile* pDexFile = pDvmDex->pDexFile;

    int count = pDexFile->pHeader->classDefsSize;
    ClassObject* arrayClass =
        dvmFindArrayClassForElement(gDvm.classJavaLangString);
    ArrayObject* stringArray =
        dvmAllocArrayByClass(arrayClass, count, ALLOC_DEFAULT);
    if (stringArray == NULL) {
        /* probably OOM */
        ALOGD("Failed allocating array of %d strings", count);
        assert(dvmCheckException(self));
        RETURN_VOID();
    }

    int i;
    for (i = 0; i < count; i++) {
        const DexClassDef* pClassDef = dexGetClassDef(pDexFile, i);
        const char* descriptor =
            dexStringByTypeIdx(pDexFile, pClassDef->classIdx);

        char* className = dvmDescriptorToDot(descriptor);
        StringObject* str = dvmCreateStringFromCstr(className);
        dvmSetObjectArrayElement(stringArray, i, (Object *)str);
        dvmReleaseTrackedAlloc((Object *)str, self);
        free(className);
    }

    dvmReleaseTrackedAlloc((Object*)stringArray, self);
    RETURN_PTR(stringArray);
}

Seems exactly what i need!

Tried to use this code this way:

void getClassNameList(struct dexstuff_t *d, JNIEnv *env, int cookie)
{
    jvalue pResult = { 0 };
    u4 args[2] = { (u4) cookie, (u4) NULL };
    d->dvm_dalvik_system_DexFile[4].fnPtr( args , &pResult );

    jobjectArray arr = pResult.l;

    int i, size = (*env)->GetArrayLength(env, arr);

    for (i = 0; i < size; i++) {
        jstring string = (jstring) (*env)->GetObjectArrayElement(env, arr, i);
        const char *rawString = (*env)->GetStringUTFChars(env, string, 0);
        log("class in dex: %s\n", rawString);
        // Don't forget to call `ReleaseStringUTFChars` when you're done.
    }
}

but get segfault on GetArrayLength with error:

W/dalvikvm( 7457): Invalid indirect reference 0x4114d2c0 in decodeIndirectRef E/dalvikvm( 7457): VM aborting F/libc ( 7457): Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1), thread 7457 (ndroid.contacts)

can you help me, what am i doing wrong? thanks.

vvviperrr commented 8 years ago

done via java method call from jni. interesting, what pointer is Dalvik_dalvik_system_DexFile_getClassNameList returns.