JVMTI
字节码文件加密
Java语言是编译型和解释型混合,源代码被编译为字节码文件,JVM再将字节码解释给CPU执行
反编译很简单,字节码文件基本上可以等同于源码文件。
对Java的加密可以分为对源码的加密和对字节码的加密,有如下几种方案
源码混淆
对变量、函数、类名等进行替换、混淆
使代码不容易阅读
字节码转换
ClassLoader
自定义类加载器,读取字节码后对字节码解密后再加载
Instrumentation
自定义
ClassFileTransformer,调用transform对字节码进行解密java -javaagent:xx.jar -jar yy.jar解密后的字节码再载入JVM
JVMTI
C/C++将解密算法封装到一个动态链接库
java -agentpath:xx.dll –jar yy.jar通过
Agent_OnLoad引入ClassFileLoadHook实现运行前字节码的解密
源码混淆只是增加源码阅读障碍,JVM仍能执行
而字节码转换则完全把字节码文件换为一个没有意义的二进制文件,JVM不能执行
Instrumentation/JVMTI将对源码的保护转移到了对加解密算法的保护,如果解密的JavaAgent/动态链接库泄露了,也可能被破解。
另外,运行时JVM中的字节码已经是原本的字节码,因此通过class dump也能拿到源码。
考虑到动态链接库还可以用加壳等方式保护,下面简单实现一个基于JVMTI的加解密
在此之前先介绍一下JVMTI编程,官方文档👉https://docs.oracle.com/javase/8/docs/platform/jvmti/jvmti.html
Agent_Onload
当使用-agentlib:xxx.dll启动Java程序时,JVM会首先从动态链接库中寻找函数Agent_Onload。
JVMTI是基于事件驱动的,JVM每执行到一定的逻辑就会主动调用一些事件的回调接口,这些接口可以供开发者扩展自己的逻辑。
一般地,JVMTI程序的加载过程为如下流程
获取JVMTI环境(JVMTIEnvironment)
注册所需功能(Capabilities)
注册事件通知(Event Notification)
指定事件回调函数(Callback Method)
capabilities
capabilities函数用来使能JVMTI函数和事件,简单来说就是要添加capabilities才能实现对应的功能。
每个JVMTI环境都有它自己的一组capabilities,初始时为空,在OnLoad阶段进行capability的添加。添加capability可能会导致程序执行速度的降低。
capabilities的数据结构定义如下
下面列举一些capabilities
can_get_bytecodes
Can get bytecodes of a method GetBytecodes
can_redefine_classes
Can redefine classes with RedefineClasses
can_get_source_file_name
Can get the source file name of a class
can_access_local_variables
Can set and get local variables
can_generate_breakpoint_events
Can set and thus get Breakpoint events
can_generate_all_class_hook_events
Can generate ClassFileLoadHook events for every loaded class
can_generate_method_entry_events
Can generate method entry events on entering a method
can_retransform_classes
Can retransform classes with RetransformClasses
设置capabilities:
event&callback
agent可以响应程序中发生的event,并调用对应的回调函数进行处理
不同的event对应不同的callback,不同的函数参数保存着event发生时的附加信息
上面的能力表中看到有有些是events结尾的,即event需要的capability
按照如下步骤设置event:
AddCapabilities添加event所需的capabilitiesSetEventCallbacks设置event的回调函数SetEventNotificationMode使能event
回调event
下面是jvmtiEventCallbacks的结构体定义
可以看出,和capability一样,event也是由JVMTI预先定义的,设置相对应的字段即可
设置event回调函数
cb_Xxx为我们实现的回调函数接口的地址
不同事件的回调函数的接口参数不同,比如ClassLoad
当一个类被首次加载时,ClassLoad事件会被触发
使能event
默认所有的event为非使能状态
jvmtiEvent用于标识event,JVMTI_EVENT_回调函数名
使能event:
Build
CLion新建项目

javah -jni ByteCodeEncryptor获取头文件ByteCodeEncryptor.h
将该头文件放到工程目录下
CMakeLists.txt
library.cpp
Build得到一个动态链接库libJVMTICrypt.dll
接着创建一个jar用作测试
manifest
jar -cvfm main.jar manifest -C src .
对main.jar进行加密
java -agentlib:libJVMTICrypt -cp main_Encrypted.jar org.demo.Test运行加密的jar

Last updated
Was this helpful?