
dex-vm used to protect the android classes.dex file
Runs Dalvik bytecode based on dex-vm to protect dex and increase the difficulty of decompilation. The project is divided into two parts. nmm-protect is a pure Java project that converts dex, transforming the data in dex into C structs, and randomizes opcodes to generate an NDK project; after compilation, it produces a hardened APK. nmmvm is an Android project that includes the dex-vm implementation and tests for various Dalvik instructions, etc.
If you do not compile nmm-protect, you can directly look at using it to generate a project and the final APK, an example of APK processing.
The example was tested in a Linux environment; Windows should also work. First install the JDK, Android SDK, and NDK.
Download vm-protect.jar, and configure the environment variables ANDROID_SDK_HOME and ANDROID_NDK_HOME:
export ANDROID_SDK_HOME=/opt/android-sdk
export ANDROID_NDK_HOME=/opt/android-sdk/ndk/22.1.7171670
export CMAKE_PATH=/opt/android-sdk/cmake/3.18.1/ #可选,不配置的话直接使用/bin/cmake
java -jar vm-protect-xxx.jar apk input.apk convertRules.txt mapping.txt
After execution completes, a build directory will be generated in the directory where input.apk is located, containing the final output apk (build/input-protect.apk), the complete C project dex2c (based on cmake), and the .dex files generated during processing, etc.
After the first run, a tools directory will be generated at the jar location, which contains config.json where you can edit the Android SDK and NDK related paths.
A friend wrote a GUI interface that makes it more convenient to use. If you need it, you can go try it out: https://github.com/TimScriptov/nmmp
The generated apk needs to be aligned with zipalign (newer versions already use zipflinger to process the apk, so a separate zipalign is not necessary) and signed with apksigner before it can be installed and used
apksigner sign --ks ~/.myapp.jks build/input-protect-align.apk
java -jar vm-protect-xxx.jar aab test.aab convertRules.txt
Afterward, jarsigner is needed for signing, or signflinger can be integrated for signing.
jarsigner -keystore ~/.myapp.jks -storepass pass -keypass pass test-protect.aab keyAlias
java -jar vm-protect-xxx.jar aar testModule.aar convertRules.txt
git clone https://github.com/maoabc/nmmp.git
cd nmmp/nmm-protect
./gradlew arsc:build
./gradlew build
On success, an executable fatjar will be generated in build/libs.
If there is no conversion rule file, all methods in all classes in the dex will be converted (except constructors and static initializer methods). The rules only support some simple cases:
//支持的规则比较简单,*只是被转成正则表达式的.*,支持一些简单的继承关系
class * extends android.app.Activity
class * implements java.io.Serializable
class my.package.AClass
class my.package.* { *; }
class * extends java.util.ArrayList {
if*;
}
class A {
}
class B extends A {
}
class C extends B {
}
//比如'class * extends A' 只会匹配B而不会再匹配C
nmmvm is a concrete implementation of a dex virtual machine, with a single entry function:
jvalue vmInterpret(
JNIEnv *env,
const vmCode *code,
const vmResolver *dvmResolver
);
typedef struct {
const u2 *insns; //指令
const u4 insnsSize; //指令大小
regptr_t *regs; //寄存器
u1 *reg_flags; //寄存器数据类型标记,主要标记是否为对象
const u1 *triesHandlers; //异常表
} vmCode;
typedef struct {
const vmField *(*dvmResolveField)(JNIEnv *env, u4 idx, bool isStatic);
const vmMethod *(*dvmResolveMethod)(JNIEnv *env, u4 idx, bool isStatic);
//从类型常量池取得类型名
const char *(*dvmResolveTypeUtf)(JNIEnv *env, u4 idx);
//直接返回jclass对象,本地引用需要释放引用
jclass (*dvmResolveClass)(JNIEnv *env, u4 idx);
//根据类型名得到class
jclass (*dvmFindClass)(JNIEnv *env, const char *type);
//const_string指令加载的字符串对象
jstring (*dvmConstantString)(JNIEnv *env, u4 idx);
} vmResolver;
vmCode provides the instructions, exception tables, and register space needed for execution, while vmResolver contains a set of function pointers that provide runtime symbols such as field, method, etc. Different hardening approaches are implemented by customizing these two parameters. For example, test.cpp in the project contains a simple vmResolver based on libdex, which is mainly used for development and testing. nmm-protect, on the other hand, converts .dex-related data into C structs and also includes opcode randomization, etc., and is basically ready for practical use.
Module-related hardening has now been implemented, with usage similar to apk hardening. If you encounter any issues, feel free to open an issue.
nmm-protect is released under the GPL license, nmm-protect licence, and the dex-vm part is released under the Apache license, nmmvm licence. Only the vm part is packaged into the apk; nmm-protect only converts dex, so the license does not affect the generated results.