diff --git a/jadx-gui/src/main/java/jadx/gui/ui/codearea/XposedAction.java b/jadx-gui/src/main/java/jadx/gui/ui/codearea/XposedAction.java index 54c4801d0cf..956dcaef2f6 100644 --- a/jadx-gui/src/main/java/jadx/gui/ui/codearea/XposedAction.java +++ b/jadx-gui/src/main/java/jadx/gui/ui/codearea/XposedAction.java @@ -1,6 +1,7 @@ package jadx.gui.ui.codearea; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import javax.swing.JOptionPane; @@ -9,11 +10,13 @@ import org.slf4j.LoggerFactory; import jadx.api.JavaClass; +import jadx.api.JavaField; import jadx.api.JavaMethod; import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.nodes.MethodNode; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.gui.treemodel.JClass; +import jadx.gui.treemodel.JField; import jadx.gui.treemodel.JMethod; import jadx.gui.treemodel.JNode; import jadx.gui.ui.action.ActionModel; @@ -24,6 +27,16 @@ public class XposedAction extends JNodeAction { private static final Logger LOG = LoggerFactory.getLogger(XposedAction.class); private static final long serialVersionUID = 2641585141624592578L; + private static final Map PRIMITIVE_TYPE_MAPPING = Map.of( + "int", "Int", + "byte", "Byte", + "short", "Short", + "long", "Long", + "float", "Float", + "double", "Double", + "char", "Char", + "boolean", "Boolean"); + public XposedAction(CodeArea codeArea) { super(ActionModel.XPOSED_COPY, codeArea); } @@ -43,7 +56,7 @@ public void runAction(JNode node) { @Override public boolean isActionEnabled(JNode node) { - return node instanceof JMethod || node instanceof JClass; + return node instanceof JMethod || node instanceof JClass || node instanceof JField; } private String generateXposedSnippet(JNode node) { @@ -53,6 +66,9 @@ private String generateXposedSnippet(JNode node) { if (node instanceof JClass) { return generateClassSnippet((JClass) node); } + if (node instanceof JField) { + return generateFieldSnippet((JField) node); + } throw new JadxRuntimeException("Unsupported node type: " + (node != null ? node.getClass() : "null")); } @@ -84,7 +100,9 @@ private String generateMethodSnippet(JMethod jMth) { if (mthArgs.isEmpty()) { return String.format(xposedFormatStr, xposedMethod, rawClassName, methodName); } - String params = mthArgs.stream().map(type -> type + ".class, ").collect(Collectors.joining()); + String params = mthArgs.stream() + .map(type -> (type.isGeneric() ? type.getObject() : type) + ".class, ") + .collect(Collectors.joining()); return String.format(xposedFormatStr, xposedMethod, rawClassName, methodName + params); } @@ -92,8 +110,16 @@ private String generateClassSnippet(JClass jc) { JavaClass javaClass = jc.getCls(); String rawClassName = javaClass.getRawName(); String shortClassName = javaClass.getName(); - return String.format("ClassLoader classLoader=lpparam.classLoader;\n" - + "Class %sClass=classLoader.loadClass(\"%s\");", + return String.format("ClassLoader classLoader = lpparam.classLoader;\n" + + "Class %sClass = classLoader.loadClass(\"%s\");", shortClassName, rawClassName); } + + private String generateFieldSnippet(JField jf) { + JavaField javaField = jf.getJavaField(); + String isStatic = javaField.getAccessFlags().isStatic() ? "Static" : ""; + String type = PRIMITIVE_TYPE_MAPPING.getOrDefault(javaField.getFieldNode().getType().toString(), "Object"); + String xposedMethod = "XposedHelpers.get" + isStatic + type + "Field"; + return String.format("%s(/*runtimeObject*/, \"%s\");", xposedMethod, javaField.getName()); + } }