There are a number of tools(e.g. JavaAssist, ASM) to re-generate bytecodes at runtime for various purposes. One case is Application permformance Management(APM), which provides agents to rewrite existing bytecodes during application startup.
For example, an original class A
has a method: void sayHello(String name){}
, and a new method can be generated by these agents in a such way:
void NewA:sayHello(String name){
Long start = System.currentMillseconds()
A::sayHello(name)
Long elpased = System.currentMillseconds()-start
}
and the JVM will interprete the class newA
after classloaded instead of the original A
.
So my question is: is it possible to detect these kind of modification inside of origin A
at runtime so that to alert that the executed bytecodes is not the raw bytecodes we deliveried?
There's no official way to detect modification to a class as it is understood that a user with sufficient permission to install an agent is already on the other side of the security door.
It's possible to prevent agents from being attached at runtime by either disabling all tools from attaching (-XX:+DisableAttachMechanism
) or by just disabling dynamic agents in JDK9+ (-XX:-EnableDynamicAgentLoading
).
Neither of those prevent agents from being attached during startup of the JVM.
There are some hacky ways to attempt to tell that a class has been modified but they aren't perfect:
Add your own agent and listen for additional ClassFileLoadHook (CFLH) events for the classes you want to protect. A second CFLH event means that the class is being modified.
Use the JVMTI native APIs to compare the bytecodes and constantpools to the those stored on disk. Don't expect a 1-1 correspondence (ie: indexes may be different) but the results should be equivalent.
There's probably JFR (Hotspot) or -Xtrace
(OpenJ9) events that fire if a class is redefined. Add a listener to those events.
But overall, there really isn't a reliable way to do this. As @Holger said, an agent could modify any test to always return false or remove it entirely.