jad

jad在线教程

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

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

  • 在 Arthas Console 上,反编译出来的源码是带语法高亮的,阅读更方便

  • 当然,反编译出来的 java 代码可能会存在语法错误,但不影响你进行阅读理解

参数说明

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

使用参考

反编译java.lang.String

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

反编译时只显示源代码

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

  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@232204a1
  4. +-sun.misc.Launcher$ExtClassLoader@7f31245a
  5. Location:
  6. /private/tmp/arthas-demo.jar
  7. public static void main(String[] args) throws InterruptedException {
  8. MathGame game = new MathGame();
  9. while (true) {
  10. /*16*/ game.run();
  11. /*17*/ TimeUnit.SECONDS.sleep(1L);
  12. }
  13. }

反编译时不显示行号

--lineNumber 参数默认值为true,显示指定为false则不打印行号。

  1. $ jad demo.MathGame main --lineNumber false
  2. ClassLoader:
  3. +-sun.misc.Launcher$AppClassLoader@232204a1
  4. +-sun.misc.Launcher$ExtClassLoader@7f31245a
  5. Location:
  6. /private/tmp/arthas-demo.jar
  7. public static void main(String[] args) throws InterruptedException {
  8. MathGame game = new MathGame();
  9. while (true) {
  10. game.run();
  11. TimeUnit.SECONDS.sleep(1L);
  12. }
  13. }

反编译时指定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.

对于只有唯一实例的ClassLoader还可以通过--classLoaderClass指定class name,使用起来更加方便:

--classLoaderClass 的值是ClassLoader的类名,只有匹配到唯一的ClassLoader实例时才能工作,目的是方便输入通用命令,而-c <hashcode>是动态变化的。