1、获得完整的DEX
在frameworks/base/core/java/android/app/ActivityThread.java的handleBindApplication处插桩
1 | try { |
创建Fupk的实例,创建实例过程加载so文件,然后调用其unpackAfter函数,其中调用unpackNow初始化其类变量appLoader,最后调用native函数core_Fupk::unpackAll
1 | public final static String hookSo = "/data/local/tmp/libFupk3.so"; |
该so文件存在JNI_OnLoad函数,在app/src/main/cpp/main.cpp中,主要做了两部分内容:1、动态注册native函数core_Fupk::unpackAll;2、通过dlopen、dlsym函数获得libdvm.so中的接口(函数指针)
1 | core_Fupk::registerNativeMethod(env) |
回到core_Fupk::unpackAll,该函数首先将dump方法的函数绑定到app/src/main/cpp/DexHelper/DexDumper.cpp中的fupk_ExportMethod中
然后调用了app/src/main/cpp/DexHelper/Fupk.cpp中的对象的unpackAll方法
1 | void ::core_Fupk::unpackAll(JNIEnv *env, jobject obj, jstring folder) { |
在实例化Fupk对象时,通过自定义接口dlsym(libdvm, "dvmGetUserDexFiles");
获得gDvm.userDexFiles返回的HashTable,从中提取DvmDex信息
1 | auto dvmDex = mCookie.getCookieAt(i, name, mIgnoreCase); |
1 | struct DvmDex { |
这样就获得了内存中完整的Dex,下面开始主动调用方法
1 | DexDumper dumper(mEnv, dvmDex, mUpkObj); |
这个mUpkObj是内核中Fupk的实例,创建DexDumper实例后,开始主动调用其方法
1 | //app/src/main/cpp/DexHelper/DexDumper.cpp |
2、类的主动加载
- 获得内核Fupk实例的Class
- 获得ClassLoader实例systemClassLoader
- 获得tryLoadClass方法id
1 | auto jClazz = mEnv->CallObjectMethod(mUpkObj, tryLoadClass_method, jDotDescriptor);//通过tryLoadClass获取类对象 |
参数jDotDescriptor即为获得的类签名
1 | // I will load the class from java(the loader may has been replaced) |
1 | public static Class getClass(ClassLoader loader, String class_name) throws Exception{ |
通过tryLoadClass函数,使用systemClassLoader去主动加载这个类
3、主动调用方法,dump方法体
回到native层
后面通过DexDumper::fixMethodByDvm主动调用方法
1 | bool DexDumper::fixMethodByDvm(DexSharedData &shared, DexMethod *dexMethod, |
FupkImpl::fupkInvokeMethod(m)即为
app/src/main/cpp/DexHelper/DexDumper.cpp中的fupk_ExportMethod方法
该方法插桩到了内核中的invoke函数中
在fupk_ExportMethod中,将方法指针保存在了shared变量中
1 | shared->extra.append((char*)item, code_item_len);//保存方法体@cs |