I have the following Javassist code to modify a logging method to make it only log certain cases (in an attempt to detect hackers transferring large sums of money in a game, for context):
CtClass ctClass = ClassPool.getDefault().getCtClass(Trade.class.getName());
CtMethod commandMethod = ctClass.getDeclaredMethod("log");
commandMethod.setBody("if (/* conditions */) {"
+ " fw.write(sender + \" [\" + senderUser.getMoney() + \"/\" + senderOldBal + \"] sent \" + pay.getMoney() + \" to \" + receiver + \"[\" + receiverOldBal + \"/\" + receiverUser.getMoney() + \"]\");"
+ "}");
I understand that simply calling ctClass.toClass()
will not replace the currently loaded class, and that in order to achieve this I need to make use of the Instrumentation API in Java. However I have not been able to find much in the way of explanations of how to use the Instrumentation API.
Any advice on how to do this would be appreciated.
Sample javaagent project: java-agent-asm-javassist-sample (found in google, not my code).
In order to benefit from Instrumentation API you need to build your own javaagent:
public class Agent {
public static void premain(String agentArgs, Instrumentation inst) {
inst.addTransformer(new ClassFileTransformer() {
@Override
public byte[] transform(ClassLoader classLoader, String s, Class<?> aClass, ProtectionDomain protectionDomain, byte[] bytes) throws IllegalClassFormatException {
if ("your/package/Trade".equals(s)) {
try {
ClassPool cp = ClassPool.getDefault();
CtClass ctClass = cp.get("your.package.Trade");
CtMethod commandMethod = ctClass.getDeclaredMethod("log");
commandMethod.setBody("if (/* conditions */) {"
+ " fw.write(sender + \" [\" + senderUser.getMoney() + \"/\" + senderOldBal + \"] sent \" + pay.getMoney() + \" to \" + receiver + \"[\" + receiverOldBal + \"/\" + receiverUser.getMoney() + \"]\");"
+ "}");
byte[] byteCode = ctClass.toBytecode();
ctClass.detach();
return byteCode;
} catch (Exception ex) {
ex.printStackTrace();
}
}
return null;
}
});
}
}
Compile it and package into agent.jar with 'Premain-Class' in manifest.
Pass your javagent via JVM argument: java -javaagent:some/path/agent.jar -jar your-main-app.jar