Android加壳native实现

    本例仅在Android2.3模拟器跑通过,如果要适配其他机型,请自行研究,这里只是抛砖引玉。

    0x00

    在Android中的Apk的加固(加壳)原理解析和实现,一文中脱壳代码都写在了java层很容易被识别出来,很多需求需要把脱壳的程序转移到native层,其实转移的思路也很简单,就是在native层通过JNI调用Java层代码。

    运行前,首先把ForceApkObj.apk放在/sdcard/payload_odex/目录下。

    代码已上传至github,地址为https://github.com/jltxgcy/AndroidNativeShell。


    0x01

    public class ProxyApplication extends Application {
	
	@Override
	protected void attachBaseContext(Context base) {
		super.attachBaseContext(base);
		DexLoader.load("com.jltxgcy.dynamicdex");
	}


	@Override
	public void onCreate() {
		DexLoader.run();
	}
}
    还记得原来这两个方法有着一大堆代码,这里仅仅有一行代码就搞定。

    我们再看来DexLoader类。

public class DexLoader {
	static {
		System.loadLibrary("dexloader");
	}

	public static native void load(String path);

	public static native void run();
}

    原来核心脱壳代码放在了native层。

    

    0x02

    JNI的实现如下,大家可以看到本质上就是把java层的代码通过JNI转移到native层了。

static void loadApk(JNIEnv * env, jclass clazz, jstring package) {
	jclass activityThreadClazz;
	jmethodID currentActivityThreadMethodID;
	jobject activityThreadObject;
	const char *packageName;
	const char *className;
	const char *methodName;
	int codeoff;

	jfieldID mPackagesFieldID;
	jobject mPackagesJObject;
	jclass mPackagesClazz;
	jmethodID getMethodID;

	jobject weakReferenceJObject;
	jclass weakReferenceJClazz;
	jmethodID getweakMethodID;

	jobject loadedApkJObject;
	jclass loadedApkJClazz;
	jfieldID mClassLoaderFieldID;
	jobject mClassLoaderJObject;
	jstring dexPath;
	jstring dexOptPath;

	jclass dexClassLoaderClazz;
	jmethodID initDexLoaderMethod;
	jobject dexClassLoaderJObject;

	activityThreadClazz = env->FindClass("android/app/ActivityThread");
	currentActivityThreadMethodID = env->GetStaticMethodID(activityThreadClazz, "currentActivityThread",
            "()Landroid/app/ActivityThread;");
	activityThreadObject = env->CallStaticObjectMethod(activityThreadClazz, currentActivityThreadMethodID);
	packageName = env->GetStringUTFChars(package, JNI_FALSE);
	mPackagesFieldID = env->GetFieldID(activityThreadClazz, "mPackages", "Ljava/util/HashMap;");
	mPackagesJObject = env->GetObjectField(activityThreadObject, mPackagesFieldID);
	mPackagesClazz = env->GetObjectClass(mPackagesJObject);
	getMethodID = env->GetMethodID(mPackagesClazz, "get",
            "(Ljava/lang/Object;)Ljava/lang/Object;");
	weakReferenceJObject = env->CallObjectMethod(mPackagesJObject, getMethodID, package);
	weakReferenceJClazz = env->GetObjectClass(weakReferenceJObject);
	getweakMethodID = env->GetMethodID(weakReferenceJClazz, "get",
            "()Ljava/lang/Object;");
	loadedApkJObject = env->CallObjectMethod(weakReferenceJObject, getweakMethodID);
	loadedApkJClazz = env->GetObjectClass(loadedApkJObject);
	mClassLoaderFieldID = env->GetFieldID(loadedApkJClazz, "mClassLoader", "Ljava/lang/ClassLoader;");
	mClassLoaderJObject = env->GetObjectField(loadedApkJObject, mClassLoaderFieldID);
	dexPath = env->NewStringUTF("/sdcard/payload_odex/ForceApkObj.apk");
	dexOptPath = env->NewStringUTF("/sdcard/payload_odex/");
	dexClassLoaderClazz = env->FindClass("dalvik/system/DexClassLoader");
	initDexLoaderMethod = env->GetMethodID(dexClassLoaderClazz, "<init>","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/ClassLoader;)V");
	dexClassLoaderJObject = env->NewObject(dexClassLoaderClazz,initDexLoaderMethod, dexPath, dexOptPath, NULL, mClassLoaderJObject);
	env->SetObjectField(loadedApkJObject, mClassLoaderFieldID, dexClassLoaderJObject);
	ALOGD("packageName:%s", packageName);
}

static void run(JNIEnv * env, jclass clazz) {
	jclass activityThreadClazz;
	jmethodID currentActivityThreadMethodID;
	jobject activityThreadObject;

	jfieldID mBoundApplicationFieldID;
	jobject mBoundApplicationJObject;
	jclass mBoundApplicationClazz;
	jfieldID mInfoFieldID;
	jobject mInfoJObject;
	jclass mInfoClazz;

	jfieldID mApplicationFieldID;
	jobject mApplicationJObject;

	jfieldID mInitialApplicationFieldID;
	jobject mInitialApplicationJObject;

	jfieldID mAllApplicationsFieldID;
	jobject mAllApplicationsJObject;
	jclass mAllApplicationsClazz;
	jmethodID removeMethodID;

	jfieldID mApplicationInfoFieldID;
	jobject mApplicationInfoJObject;
	jclass mApplicationInfoClazz;

	jfieldID mBindApplicationInfoFieldID;
	jobject mBindApplicationInfoJObject;
	jclass mBindApplicationInfoClazz;

	jfieldID classNameFieldID;
	jfieldID mBindClassNameFieldID;
	jstring applicationName;

	jmethodID makeApplicationMethodID;
	jobject ApplicationJObject;
	jclass ApplicationClazz;
	jmethodID onCreateMethodID;

	activityThreadClazz = env->FindClass("android/app/ActivityThread");
	currentActivityThreadMethodID = env->GetStaticMethodID(activityThreadClazz, "currentActivityThread",
	            "()Landroid/app/ActivityThread;");
	activityThreadObject = env->CallStaticObjectMethod(activityThreadClazz, currentActivityThreadMethodID);
	mBoundApplicationFieldID = env->GetFieldID(activityThreadClazz, "mBoundApplication", "Landroid/app/ActivityThread$AppBindData;");
	mBoundApplicationJObject = env->GetObjectField(activityThreadObject, mBoundApplicationFieldID);
	mBoundApplicationClazz = env->GetObjectClass(mBoundApplicationJObject);
	mInfoFieldID = env->GetFieldID(mBoundApplicationClazz, "info", "Landroid/app/LoadedApk;");
	mInfoJObject = env->GetObjectField(mBoundApplicationJObject, mInfoFieldID);
	mInfoClazz = env->GetObjectClass(mInfoJObject);
	mApplicationFieldID = env->GetFieldID(mInfoClazz, "mApplication", "Landroid/app/Application;");
	mApplicationJObject = env->GetObjectField(mInfoJObject, mApplicationFieldID);
	env->SetObjectField(mInfoJObject, mApplicationFieldID, NULL);
	mInitialApplicationFieldID = env->GetFieldID(activityThreadClazz, "mInitialApplication", "Landroid/app/Application;");
	mInitialApplicationJObject = env->GetObjectField(activityThreadObject, mInitialApplicationFieldID);
	mAllApplicationsFieldID = env->GetFieldID(activityThreadClazz, "mAllApplications", "Ljava/util/ArrayList;");
	mAllApplicationsJObject = env->GetObjectField(activityThreadObject, mAllApplicationsFieldID);
	mAllApplicationsClazz = env->GetObjectClass(mAllApplicationsJObject);
	removeMethodID = env->GetMethodID(mAllApplicationsClazz, "remove",
            "(Ljava/lang/Object;)Z");
	jboolean isTrue = env->CallBooleanMethod(mAllApplicationsJObject, removeMethodID, mInitialApplicationJObject);
	mApplicationInfoFieldID = env->GetFieldID(mInfoClazz, "mApplicationInfo", "Landroid/content/pm/ApplicationInfo;");
	mApplicationInfoJObject = env->GetObjectField(mInfoJObject, mApplicationInfoFieldID);
	mApplicationInfoClazz = env->GetObjectClass(mApplicationInfoJObject);
	mBindApplicationInfoFieldID = env->GetFieldID(mBoundApplicationClazz, "appInfo", "Landroid/content/pm/ApplicationInfo;");
	mBindApplicationInfoJObject = env->GetObjectField(mBoundApplicationJObject, mBindApplicationInfoFieldID);
	mBindApplicationInfoClazz = env->GetObjectClass(mBindApplicationInfoJObject);
	classNameFieldID = env->GetFieldID(mApplicationInfoClazz, "className", "Ljava/lang/String;");
	mBindClassNameFieldID = env->GetFieldID(mBindApplicationInfoClazz, "className", "Ljava/lang/String;");
	applicationName = env->NewStringUTF("com.example.forceapkobj.MyApplication");
	env->SetObjectField(mApplicationInfoJObject, classNameFieldID, applicationName);
	env->SetObjectField(mBindApplicationInfoJObject, mBindClassNameFieldID, applicationName);
	makeApplicationMethodID = env->GetMethodID(mInfoClazz, "makeApplication","(ZLandroid/app/Instrumentation;)Landroid/app/Application;");
	ApplicationJObject = env->CallObjectMethod(mInfoJObject, makeApplicationMethodID, JNI_FALSE, NULL);
	env->SetObjectField(activityThreadObject, mInitialApplicationFieldID, ApplicationJObject);
	ApplicationClazz = env->GetObjectClass(ApplicationJObject);
	onCreateMethodID = env->GetMethodID(ApplicationClazz, "onCreate","()V");
	env->CallVoidMethod(ApplicationJObject, onCreateMethodID);
}

JNIEXPORT void JNICALL Java_com_jltxgcy_dynamicdex_DexLoader_load
  (JNIEnv * env, jclass clazz, jstring packageName) {
	loadApk(env, clazz, packageName);
	ALOGD("Java_com_jltxgcy_dynamicdex_DexLoader_load");
}

JNIEXPORT void JNICALL Java_com_jltxgcy_dynamicdex_DexLoader_run
  (JNIEnv * env, jclass clazz) {
	run(env, clazz);
	ALOGD("Java_com_jltxgcy_dynamicdex_DexLoader_run");
}

你可能感兴趣的:(Android加壳native实现)