jad

反编译指定已加载类的源码

jad 命令将 JVM 中实际运行的 class 的 byte code 反编译成 java 代码,便于你理解业务逻辑;

  • 在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便
  • 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解

参数说明

参数名称 参数说明
class-pattern 类名表达式匹配
[c:] 类所属 ClassLoader 的 hashcode
[E] 开启正则表达式匹配,默认为通配符匹配

使用参考

编译java.lang.String

  1. $ jad java.lang.String
  2. ClassLoader:
  3. Location:
  4. /*
  5. * Decompiled with CFR 0_132.
  6. */
  7. package java.lang;
  8. import java.io.ObjectStreamField;
  9. ...
  10. public final class String
  11. implements Serializable,
  12. Comparable<String>,
  13. CharSequence {
  14. private final char[] value;
  15. private int hash;
  16. private static final long serialVersionUID = -6849794470754667710L;
  17. private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
  18. public static final Comparator<String> CASE_INSENSITIVE_ORDER = new CaseInsensitiveComparator();
  19. public String(byte[] arrby, int n, int n2) {
  20. String.checkBounds(arrby, n, n2);
  21. this.value = StringCoding.decode(arrby, n, n2);
  22. }
  23. ...

反编绎时只显示源代码

默认情况下,反编译结果里会带有ClassLoader信息,通过--source-only选项,可以只打印源代码。方便和mc/redefine命令结合使用。

  1. $ jad --source-only demo.MathGame
  2. /*
  3. * Decompiled with CFR 0_132.
  4. */
  5. package demo;
  6. import java.io.PrintStream;
  7. import java.util.ArrayList;
  8. import java.util.Iterator;
  9. import java.util.List;
  10. import java.util.Random;
  11. import java.util.concurrent.TimeUnit;
  12. public class MathGame {
  13. private static Random random = new Random();
  14. public int illegalArgumentCount = 0;
  15. ...

反编译指定的函数

  1. $ jad demo.MathGame main
  2. ClassLoader:
  3. +-sun.misc.Launcher$AppClassLoader@3d4eac69
  4. +-sun.misc.Launcher$ExtClassLoader@66350f69
  5. Location:
  6. /private/tmp/arthas-demo.jar
  7. public static void main(String[] args) throws InterruptedException {
  8. MathGame game = new MathGame();
  9. do {
  10. game.run();
  11. TimeUnit.SECONDS.sleep(1L);
  12. } while (true);
  13. }
  14. Affect(row-cnt:1) cost in 228 ms.

反编译时指定ClassLoader

当有多个 ClassLoader 都加载了这个类时,jad 命令会输出对应 ClassLoader 实例的 hashcode,然后你只需要重新执行 jad 命令,并使用参数 -c <hashcode> 就可以反编译指定 ClassLoader 加载的那个类了;

  1. $ jad org.apache.log4j.Logger
  2. Found more than one class for: org.apache.log4j.Logger, Please use jad -c hashcode org.apache.log4j.Logger
  3. HASHCODE CLASSLOADER
  4. 69dcaba4 +-monitor's ModuleClassLoader
  5. 6e51ad67 +-java.net.URLClassLoader@6e51ad67
  6. +-sun.misc.Launcher$AppClassLoader@6951a712
  7. +-sun.misc.Launcher$ExtClassLoader@6fafc4c2
  8. 2bdd9114 +-pandora-qos-service's ModuleClassLoader
  9. 4c0df5f8 +-pandora-framework's ModuleClassLoader
  10. Affect(row-cnt:0) cost in 38 ms.
  11. $ jad org.apache.log4j.Logger -c 69dcaba4
  12. ClassLoader:
  13. +-monitor's ModuleClassLoader
  14. Location:
  15. /Users/admin/app/log4j-1.2.14.jar
  16. package org.apache.log4j;
  17. import org.apache.log4j.spi.*;
  18. public class Logger extends Category
  19. {
  20. private static final String FQCN;
  21. protected Logger(String name)
  22. {
  23. super(name);
  24. }
  25. ...
  26. Affect(row-cnt:1) cost in 190 ms.