未验证 提交 873aabb4 编写于 作者: O Ori Perry 提交者: GitHub

fix: use raw class names in Frida action (#1365)(PR #1366)

* Use raw_name instead of full_name for the names of class in generated frida snippet.
Also cleaned the code a bit

* Fixed getting method parameters from inlined methods

* fixed generating code for constructor overloads, more cleaning

* Fixed getting method parameters from inlined methods for real this time

* made the option for a frida snippet only appear if clicked on a relevant node

* added support for generating a frida snippet for fields

* apply spotless

* Update jadx-gui/src/main/java/jadx/gui/ui/codearea/FridaAction.java
Co-authored-by: Nskylot <118523+skylot@users.noreply.github.com>

* moved the overload check from NodeMethod to FridaAction

* added semicolons in the end of lines of the generated frida snippet

* fix code formatting
上级 4bed9dc3
...@@ -28,6 +28,10 @@ public final class JavaField implements JavaNode { ...@@ -28,6 +28,10 @@ public final class JavaField implements JavaNode {
return parent.getFullName() + '.' + getName(); return parent.getFullName() + '.' + getName();
} }
public String getRawName() {
return field.getName();
}
@Override @Override
public JavaClass getDeclaringClass() { public JavaClass getDeclaringClass() {
return parent; return parent;
......
...@@ -105,6 +105,7 @@ public final class CodeArea extends AbstractCodeArea { ...@@ -105,6 +105,7 @@ public final class CodeArea extends AbstractCodeArea {
popup.add(new CommentSearchAction(this)); popup.add(new CommentSearchAction(this));
popup.add(rename); popup.add(rename);
popup.addPopupMenuListener(findUsage); popup.addPopupMenuListener(findUsage);
popup.addPopupMenuListener(frida);
popup.addPopupMenuListener(goToDeclaration); popup.addPopupMenuListener(goToDeclaration);
popup.addPopupMenuListener(comment); popup.addPopupMenuListener(comment);
popup.addPopupMenuListener(rename); popup.addPopupMenuListener(rename);
......
...@@ -5,10 +5,7 @@ import java.awt.datatransfer.Clipboard; ...@@ -5,10 +5,7 @@ import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.Comparator; import java.util.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.swing.*; import javax.swing.*;
...@@ -17,12 +14,16 @@ import org.jetbrains.annotations.Nullable; ...@@ -17,12 +14,16 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import jadx.api.JavaClass;
import jadx.api.JavaField;
import jadx.api.JavaMethod;
import jadx.api.data.annotations.VarDeclareRef; import jadx.api.data.annotations.VarDeclareRef;
import jadx.core.dex.info.MethodInfo; import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.args.ArgType; import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.ClassNode; import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.gui.treemodel.JClass; import jadx.gui.treemodel.JClass;
import jadx.gui.treemodel.JField;
import jadx.gui.treemodel.JMethod; import jadx.gui.treemodel.JMethod;
import jadx.gui.treemodel.JNode; import jadx.gui.treemodel.JNode;
import jadx.gui.utils.NLS; import jadx.gui.utils.NLS;
...@@ -30,15 +31,13 @@ import jadx.gui.utils.NLS; ...@@ -30,15 +31,13 @@ import jadx.gui.utils.NLS;
import static javax.swing.KeyStroke.getKeyStroke; import static javax.swing.KeyStroke.getKeyStroke;
public final class FridaAction extends JNodeMenuAction<JNode> { public final class FridaAction extends JNodeMenuAction<JNode> {
private static final Logger LOG = LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); private static final Logger LOG = LoggerFactory.getLogger(FridaAction.class);
private static final long serialVersionUID = 4692546569977976384L; private static final long serialVersionUID = 4692546569977976384L;
private Map<String, Boolean> isInitial = new HashMap<>(); private final Map<String, Boolean> isInitial = new HashMap<>();
private String methodName;
public FridaAction(CodeArea codeArea) { public FridaAction(CodeArea codeArea) {
super(NLS.str("popup.frida") + " (f)", codeArea); super(NLS.str("popup.frida") + " (f)", codeArea);
LOG.info("triggered meee");
KeyStroke key = getKeyStroke(KeyEvent.VK_F, 0); KeyStroke key = getKeyStroke(KeyEvent.VK_F, 0);
codeArea.getInputMap().put(key, "trigger frida"); codeArea.getInputMap().put(key, "trigger frida");
codeArea.getActionMap().put("trigger frida", new AbstractAction() { codeArea.getActionMap().put("trigger frida", new AbstractAction() {
...@@ -46,143 +45,130 @@ public final class FridaAction extends JNodeMenuAction<JNode> { ...@@ -46,143 +45,130 @@ public final class FridaAction extends JNodeMenuAction<JNode> {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
node = getNodeByOffset(codeArea.getWordStart(codeArea.getCaretPosition())); node = getNodeByOffset(codeArea.getWordStart(codeArea.getCaretPosition()));
copyFridaCode();
String fridaSnippet = generateFridaSnippet();
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection selection = new StringSelection(fridaSnippet);
clipboard.setContents(selection, selection);
} }
}); });
} }
private void copyFridaCode() { private String generateFridaSnippet() {
if (node instanceof JMethod) {
if (node != null) { LOG.debug("node is jmethod");
if (node instanceof JMethod) { return generateMethodSnippet((JMethod) node);
JMethod n = (JMethod) node; } else if (node instanceof JClass) {
MethodNode methodNode = n.getJavaMethod().getMethodNode(); LOG.debug("node is jclass");
MethodInfo mi = methodNode.getMethodInfo(); return generateClassSnippet((JClass) node);
methodName = mi.getName(); } else if (node instanceof JField) {
if (methodName.equals("<init>") || methodName.equals("onCreate")) { LOG.debug("node is jfield");
methodName = "$init"; return generateFieldSnippet((JField) node);
} }
String fullClassName = methodNode.getParentClass().getFullName(); LOG.debug("cannot generate frida snippet from node");
String className = methodNode.getParentClass().getShortName(); return "";
LOG.debug("node is jmethod");
ClassNode tmp = methodNode.getParentClass(); }
while (true) {
if (!tmp.isTopClass()) { private String generateMethodSnippet(JMethod jMth) {
fullClassName = fullClassName.substring(0, fullClassName.lastIndexOf(".")) + "$" JavaMethod javaMethod = jMth.getJavaMethod();
+ fullClassName.substring(fullClassName.lastIndexOf(".") + 1, fullClassName.length()); MethodInfo methodInfo = javaMethod.getMethodNode().getMethodInfo();
} else { String methodName = methodInfo.getName();
break; if (methodName.equals("<init>") || methodName.equals("onCreate")) {
} methodName = "$init";
tmp = tmp.getParentClass(); }
} String rawClassName = javaMethod.getDeclaringClass().getRawName();
JMethod jMth = (JMethod) node; String shortClassName = javaMethod.getDeclaringClass().getName();
int mthLine = jMth.getLine();
List<String> argNames = jMth.getRootClass().getCodeInfo().getAnnotations().entrySet().stream() String functionUntilImplementation;
.filter(e -> e.getKey().getLine() == mthLine && e.getValue() instanceof VarDeclareRef) if (isOverloaded(javaMethod.getMethodNode())) {
List<ArgType> methodArgs = methodInfo.getArgumentsTypes();
String overloadStr = methodArgs.stream().map(this::parseArgType).collect(Collectors.joining(", "));
functionUntilImplementation = String.format("%s.%s.overload(%s).implementation", shortClassName, methodName, overloadStr);
} else {
functionUntilImplementation = String.format("%s.%s.implementation", shortClassName, methodName);
}
String functionParametersString =
Objects.requireNonNull(javaMethod.getTopParentClass().getCodeInfo()).getAnnotations().entrySet().stream()
.filter(e -> e.getKey().getLine() == jMth.getLine() && e.getValue() instanceof VarDeclareRef)
.sorted(Comparator.comparingInt(e -> e.getKey().getPos())) .sorted(Comparator.comparingInt(e -> e.getKey().getPos()))
.map(e -> ((VarDeclareRef) e.getValue()).getName()) .map(e -> ((VarDeclareRef) e.getValue()).getName())
.collect(Collectors.toList()); .collect(Collectors.joining(", "));
StringBuilder functionParameters = new StringBuilder();
for (String argName : argNames) {
functionParameters.append(argName + ", ");
}
if (functionParameters.toString().length() > 2) {
functionParameters.setLength(functionParameters.length() - 2);
}
List<MethodNode> methods = methodNode.getParentClass().getMethods();
List<MethodNode> filteredmethod = methods.stream().filter(m -> m.getName().equals(methodName)).collect(Collectors.toList());
StringBuilder sb = new StringBuilder();
String overloadStr = "";
if (filteredmethod.size() > 1) {
List<ArgType> methodArgs = mi.getArgumentsTypes();
for (ArgType argType : methodArgs) {
sb.append("'" + parseArgType(argType) + "', ");
}
if (sb.length() > 2) {
sb.setLength(sb.length() - 2);
}
overloadStr = sb.toString();
}
String functionUntilImplementation = "";
if (!overloadStr.equals("")) {
functionUntilImplementation = String.format("%s.%s.overload(%s).implementation", className, methodName, overloadStr);
} else {
functionUntilImplementation = String.format("%s.%s.implementation", className, methodName);
}
String functionParameterAndBody = "";
String functionParametersString = functionParameters.toString();
if (!functionParametersString.equals("")) {
functionParameterAndBody = String.format(
"%s = function(%s){\n\tconsole.log('%s is called')\n\tlet ret = this.%s(%s)\n\tconsole.log('%s ret value is ' + ret)\n\treturn ret\n}",
functionUntilImplementation, functionParametersString, methodName, methodName, functionParametersString,
methodName);
} else {
functionParameterAndBody = String.format(
"%s = function(){\n\tconsole.log('%s is called')\n\tlet ret = this.%s()\n\tconsole.log('%s ret value is ' + ret)\n\treturn ret\n}",
functionUntilImplementation, methodName, methodName, methodName);
}
String finalFridaCode = "";
if (isInitial.getOrDefault(fullClassName, true)) {
finalFridaCode = String.format("let %s = Java.use(\"%s\")\n%s", className, fullClassName, functionParameterAndBody);
isInitial.put(fullClassName, false);
} else {
finalFridaCode = functionParameterAndBody;
}
LOG.debug("frida code : " + finalFridaCode);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection selection = new StringSelection(finalFridaCode);
clipboard.setContents(selection, selection);
} else if (node instanceof JClass) { String functionParameterAndBody = String.format(
LOG.debug("node is jclass"); "%s = function(%s){\n\tconsole.log('%s is called');\n\tlet ret = this.%s(%s);\n\tconsole.log('%s ret value is ' + ret);\n\treturn ret;\n}",
JClass jc = (JClass) node; functionUntilImplementation, functionParametersString, methodName, methodName, functionParametersString, methodName);
String fullClassName = jc.getCls().getClassNode().getClassInfo().getFullName();
String className = jc.getCls().getClassNode().getClassInfo().getShortName(); String finalFridaCode;
ClassNode tmp = jc.getCls().getClassNode(); if (isInitial.getOrDefault(rawClassName, true)) {
while (true) { String classSnippet = generateClassSnippet(jMth.getJParent());
if (!tmp.isTopClass()) { finalFridaCode = classSnippet + "\n" + functionParameterAndBody;
fullClassName = fullClassName.substring(0, fullClassName.lastIndexOf(".")) + "$" } else {
+ fullClassName.substring(fullClassName.lastIndexOf(".") + 1, fullClassName.length()); finalFridaCode = functionParameterAndBody;
} else { }
break; LOG.debug("frida code : " + finalFridaCode);
} return finalFridaCode;
tmp = tmp.getParentClass(); }
}
String finalFridaCode = String.format("let %s = Java.use(\"%s\")", className, fullClassName);
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
StringSelection selection = new StringSelection(finalFridaCode);
clipboard.setContents(selection, selection);
LOG.debug("frida code : " + finalFridaCode);
isInitial.put(fullClassName, false);
} else {
LOG.debug("node is something else");
}
private String generateClassSnippet(JClass jc) {
JavaClass javaClass = jc.getCls();
String rawClassName = javaClass.getRawName();
String shortClassName = javaClass.getName();
String finalFridaCode = String.format("let %s = Java.use(\"%s\");", shortClassName, rawClassName);
LOG.debug("frida code : " + finalFridaCode);
isInitial.put(rawClassName, false);
return finalFridaCode;
}
private String generateFieldSnippet(JField jf) {
JavaField javaField = jf.getJavaField();
String rawFieldName = javaField.getRawName();
String fieldName = javaField.getName();
List<MethodNode> methodNodes = javaField.getFieldNode().getParentClass().getMethods();
for (MethodNode methodNode : methodNodes) {
if (methodNode.getName().equals(rawFieldName)) {
rawFieldName = "_" + rawFieldName;
break;
}
} }
JClass jc = jf.getRootClass();
String classSnippet = generateClassSnippet(jc);
String finalFridaCode = String.format("%s\n%s = %s.%s.value;", classSnippet, fieldName, jc.getName(), rawFieldName);
LOG.debug("frida code : " + finalFridaCode);
return finalFridaCode;
}
public Boolean isOverloaded(MethodNode methodNode) {
ClassNode parentClass = methodNode.getParentClass();
List<MethodNode> methods = parentClass.getMethods();
return methods.stream()
.anyMatch(m -> m.getName().equals(methodNode.getName())
&& !Objects.equals(methodNode.getMethodInfo().getShortId(), m.getMethodInfo().getShortId()));
} }
private String parseArgType(ArgType x) { private String parseArgType(ArgType x) {
StringBuilder parsedArgType = new StringBuilder(); StringBuilder parsedArgType = new StringBuilder("'");
if (x.isArray()) { if (x.isArray()) {
parsedArgType.append(x.getPrimitiveType().getShortName()); parsedArgType.append(x.getPrimitiveType().getShortName());
parsedArgType.append(x.getArrayElement().getPrimitiveType().getShortName()); parsedArgType.append(x.getArrayElement().getPrimitiveType().getShortName());
if (!x.getArrayElement().isPrimitive()) { if (!x.getArrayElement().isPrimitive()) {
parsedArgType.append(x.getArrayElement().toString() + ";"); parsedArgType.append(x.getArrayElement().toString()).append(";");
} }
} else { } else {
parsedArgType.append(x.toString()); parsedArgType.append(x);
} }
return parsedArgType.toString(); return parsedArgType.append("'").toString();
} }
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
node = codeArea.getNodeUnderCaret(); node = codeArea.getNodeUnderCaret();
copyFridaCode(); generateFridaSnippet();
} }
@Nullable @Nullable
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册