redefine

加载外部的.class文件,redefine jvm已加载的类,结合jad/mc命令使用

推荐使用retransform命令

命令选项 描述
-c, --classloader <hash> 指定ClassLoader的哈希值
--classLoaderClass <class-name> 指定ClassLoader的类名
-h, --help 帮助
<classFilePaths> class文件路径

示例

修改MathGame代码如下

public void run() throws InterruptedException {
        System.out.println("I'm running!");
        try {
            int number = random.nextInt()/10000;
            List<Integer> primeFactors = primeFactors(number);
            print(number, primeFactors);

        } catch (Exception e) {
            System.out.println(String.format("illegalArgumentCount:%3d, ", illegalArgumentCount) + e.getMessage());
        }
    }
# 编译修改后的java文件
[arthas@13728]$ mc -d /tmp /tmp/MathGame.java
Memory compiler output:
C:\tmp\demo\MathGame.class
Affect(row-cnt:1) cost in 50 ms.
# 重定义class文件
[arthas@13728]$ redefine /tmp/demo/MathGame.class
redefine success, size: 1, classes:
demo.MathGame
# 定义后MathGame控制台输出如下
I'm running!
illegalArgumentCount:933, number is: -49676, need >= 2
I'm running!
illegalArgumentCount:934, number is: -58381, need >= 2
I'm running!
illegalArgumentCount:935, number is: -42343, need >= 2
I'm running!
illegalArgumentCount:936, number is: -14142, need >= 2
I'm running!
118346=2*47*1259
I'm running!
113905=5*11*19*109
I'm running!
illegalArgumentCount:937, number is: -128405, need >= 2
I'm running!
illegalArgumentCount:938, number is: -176102, need >= 2
I'm running!
illegalArgumentCount:939, number is: -36171, need >= 2
I'm running!
165054=2*3*27509
I'm running!

# 使用trace命令后 class文件还原
trace demo.MathGame run
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 29 ms, listenerId: 6
`---ts=2023-03-30 14:21:03;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=jdk.internal.loader.ClassLoaders$AppClassLoader@6d06d69c
    `---[2.6848ms] demo.MathGame:run()
        `---[39.61% 1.0634ms ] demo.MathGame:primeFactors() #25 [throws Exception]

# 还原源class文件
redefine /tmp/demo/MathGame.class
redefine success, size: 1, classes:
demo.MathGame

注意

  • redefine后的类不能恢复,reset命令对redefine后的类无效,需要redefine原始的字节码
  • redefine可能失败,比如增加了新的字段、方法
  • 正在运行的函数在函数没结束之前不会生效,比如MathGame中main方法的循环部分
  • redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine后,再执行前面的命令会把redefine的字节码重置
  • 建议在redefine之前先dump源class文件备份 {: .block-danger }n