From fa86d8f4593aad650959dff2e92c9d446ad20d24 Mon Sep 17 00:00:00 2001 From: klee <1046120015@qq.com> Date: Sun, 26 Nov 2023 00:26:59 +0800 Subject: [PATCH 1/3] Fix: Resolved an issue with incorrectly generated xposedMethodSnippet when the parameter type is generic. Add: Introduced xposedGenerateFieldSnippet. --- .../jadx/gui/ui/codearea/XposedAction.java | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) 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..4d6c90c1ae7 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; @@ -23,6 +26,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,7 @@ 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 +108,18 @@ 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()); + + } } From 885a20797caf86eef5029cb21e338d62f733cad0 Mon Sep 17 00:00:00 2001 From: skylot <118523+skylot@users.noreply.github.com> Date: Sat, 25 Nov 2023 17:42:32 +0000 Subject: [PATCH 2/3] fix code format --- .../java/jadx/gui/ui/codearea/XposedAction.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 4d6c90c1ae7..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 @@ -26,6 +26,7 @@ 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", @@ -34,8 +35,7 @@ public class XposedAction extends JNodeAction { "float", "Float", "double", "Double", "char", "Char", - "boolean", "Boolean" - ); + "boolean", "Boolean"); public XposedAction(CodeArea codeArea) { super(ActionModel.XPOSED_COPY, codeArea); @@ -100,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.isGeneric() ? type.getObject() : 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); } @@ -109,7 +111,7 @@ private String generateClassSnippet(JClass jc) { String rawClassName = javaClass.getRawName(); String shortClassName = javaClass.getName(); return String.format("ClassLoader classLoader = lpparam.classLoader;\n" - + "Class %sClass = classLoader.loadClass(\"%s\");", + + "Class %sClass = classLoader.loadClass(\"%s\");", shortClassName, rawClassName); } @@ -118,8 +120,6 @@ private String generateFieldSnippet(JField jf) { 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()); - + return String.format("%s(/*runtimeObject*/, \"%s\");", xposedMethod, javaField.getName()); } } From 6e9926808bf2a9e4316629db27026c4b28b6ac85 Mon Sep 17 00:00:00 2001 From: klee <1046120015@qq.com> Date: Tue, 12 Dec 2023 00:19:36 +0800 Subject: [PATCH 3/3] Fixed: Resolved the issue where Xposed code generation was incorrect when dealing with generic parameters and alias fields. --- .../java/jadx/gui/ui/codearea/XposedAction.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) 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 956dcaef2f6..e8e51414c2e 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 @@ -101,11 +101,20 @@ private String generateMethodSnippet(JMethod jMth) { return String.format(xposedFormatStr, xposedMethod, rawClassName, methodName); } String params = mthArgs.stream() - .map(type -> (type.isGeneric() ? type.getObject() : type) + ".class, ") + .map(type -> fixTypeContent(type) + ".class, ") .collect(Collectors.joining()); return String.format(xposedFormatStr, xposedMethod, rawClassName, methodName + params); } + private String fixTypeContent(ArgType type) { + if (type.isGeneric()) { + return type.getObject(); + } else if (type.isGenericType() && type.isObject() && type.isTypeKnown()) { + return "Object"; + } + return type.toString(); + } + private String generateClassSnippet(JClass jc) { JavaClass javaClass = jc.getCls(); String rawClassName = javaClass.getRawName(); @@ -120,6 +129,6 @@ private String generateFieldSnippet(JField jf) { 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()); + return String.format("%s(/*runtimeObject*/, \"%s\");", xposedMethod, javaField.getFieldNode().getFieldInfo().getName()); } }