简介
Java虚拟机工具接口(JVMTI)提供了一个编程接口,允许开发人员创建可以监视和控制Java编程语言应用程序的软件代理。关于JVMTI的官方说明:
通俗的说,就是用外部平台(例如C/C++)生成动态链接库(windows ⇒ dll,linux ⇒
so),给指定的二进制的class文件中插入一段数字,进行篡改,使其无法被JD-GUI用简单的AST抽象语法树进行反编译,在运行 jar
包时,再通过dll/so文件实现解密。
JNI结构图
JNI code映射
更多想要了解JVMTI的参考 https://developer.ibm.com/zh/articles/j-lo-jpda2/
反编译软件 JD-GUI :http://java-decompiler.github.io/http://java-decompiler.github.io/
动态链接库
分加密模块和解密模块,由c实现,windows下面是dll,linux下面是so
加密模块通过JNI native方式调用,解密通过JVMTI的Agent_OnLoad实现
代码已上传到github https://github.com/wangshulun/jvmti-encrypt
C功能的目录结构如下
需要额外引入java的头文件jni.h、jni_md.h、jvmti.h、jvmtiagent.h,文件位置在jdk根目录的include文件夹和include/windows(linux)下。
framework.h pch.h是vscode2017默认生成的,build时存在一些强校验,在CLion等其他ide里面不会有这种,不用在意。
SourceFiles下面的jarencrypt.cpp jvmtiagent.cpp jvmtimain.app是具体的实现
在windows下build会生成dll文件,加解密会用到
步骤
1、加密实现
定义加密的native code实现,需要注意的一点是定义JNICALL的方法时的命名规则:Java_package{.换成下划线}_类名_方法名,这个需要和java code 注册的位置保持一致,否则native方法注册失败
下面代码是通过c语言对Java class文件的一个简单加密方式,可替换成自定义的加密实现
#include <iostream>
#include <stdlib.h>
#include "jni.h"
using namespace std;
//https://www3.ntu.edu.sg/home/ehchua/programming/java/JavaNativeInterface.html
extern "C" JNIEXPORT jbyteArray JNICALL Java_com_allen_bytecode_ByteCodeEncryptor_encrypt(
JNIEnv * jni_env,
jobject arg,
jbyteArray _buf) {
jbyte * jbuf = jni_env->GetByteArrayElements(_buf, 0);
jsize length = jni_env->GetArrayLength(_buf);
jbyte *dbuf = (jbyte *)malloc(length);
int index = 0;