
Android의 classes.dex 파일을 보호하는 데 사용되는 dex-vm
Dex-VM을 기반으로 Dalvik 바이트코드를 실행하여 dex를 보호하고 디컴파일 난이도를 높입니다. 프로젝트는 두 부분으로 나뉘며, nmm-protect는 순수 Java 프로젝트로 dex를 변환하여 dex 내의 데이터를 C 구조체로 바꾸고, opcode를 무작위화하여 NDK 프로젝트를 생성하며, 컴파일 후 강화된 apk를 생성합니다. nmmvm은 안드로이드 프로젝트로 dex-vm 구현 및 각종 dalvik 명령어 테스트 등을 포함합니다.
nmm-protect를 컴파일하지 않고, 이를 사용해 프로젝트와 최종 apk를 생성하는 방법을 바로 볼 수 있습니다, apk 처리 예제.
예제는 Linux 환경에서 테스트되었으며, Windows에서도 문제없을 것입니다. 먼저 JDK와 Android SDK 및 NDK를 설치하세요.
vm-protect.jar를 다운로드하고, 환경 변수 ANDROID_SDK_HOME, 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
실행이 완료되면 input.apk가 있는 디렉터리에 build 디렉터리가 생성되며, 그 안에는 최종 출력된 apk(build/input-protect.apk), 완전한 c 프로젝트 dex2c(cmake 기반) 및 처리 과정에서 생성된 .dex 등이 포함됩니다.
처음 실행 후 jar 위치에 tools 디렉터리가 생성되며, 그 안의 config.json을 편집하여 안드로이드 sdk, ndk 관련 경로를 설정할 수 있습니다.
친구가 GUI 인터페이스를 만들어 더 편리하게 사용할 수 있게 했습니다. 필요하신 분은 가서 사용해 보세요, https://github.com/TimScriptov/nmmp
생성된 apk는 zipalign으로 정렬하고(최신 버전은 이미 zipflinger로 apk를 처리하므로 별도의 zipalign을 사용하지 않아도 됨) apksigner로 서명해야 설치 및 사용이 가능합니다
apksigner sign --ks ~/.myapp.jks build/input-protect-align.apk
java -jar vm-protect-xxx.jar aab test.aab convertRules.txt
이후 jarsigner로 서명해야 하며, signflinger를 통합하여 서명할 수도 있습니다
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
成功后会在build/libs生成可直接执行的fatjar。
无转换规则文件,则会转换dex里所有class里的方法(除了构造方法和静态初始化方法)。规则只支持一些简单的情况:
//支持的规则比较简单,*只是被转成正则表达式的.*,支持一些简单的继承关系
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은 dex 가상 머신의 구체적인 구현이며, 진입점은 단 하나의 함수입니다:
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는 실행에 필요한 명령어, 예외 테이블 및 레지스터 공간을 제공하고, vmResolver는 field, method 등 런타임 심볼을 제공하는 함수 포인터 집합을 포함합니다. 이 두 매개변수를 사용자 정의하여 서로 다른 보강 방식을 구현할 수 있습니다. 예를 들어 프로젝트의 test.cpp에는 libdex 기반의 간단한 vmResolver가 있으며, 주로 개발 테스트에 사용됩니다. 반면 nmm-protect는 .dex 관련 데이터를 c 구조체로 변환하고 opcode 무작위화 등을 포함하여 기본적으로 실제 사용이 가능합니다.
현재 모듈 관련 보강이 구현되어 있으며, 사용법은 apk 보강과 유사합니다. 문제가 있으면 issue를 제출할 수 있습니다.
nmm-protect는 gpl 프로토콜로 배포되며, nmm-protect licence, dex-vm 부분은 Apache 프로토콜로 배포됩니다, nmmvm licence. vm 부분만 apk에 패키징되며, nmm-protect는 dex만 변환하므로 프로토콜은 생성된 결과에 영향을 미치지 않습니다.