未验证 提交 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 {
return parent.getFullName() + '.' + getName();
}
public String getRawName() {
return field.getName();
}
@Override
public JavaClass getDeclaringClass() {
return parent;
......
......@@ -105,6 +105,7 @@ public final class CodeArea extends AbstractCodeArea {
popup.add(new CommentSearchAction(this));
popup.add(rename);
popup.addPopupMenuListener(findUsage);
popup.addPopupMenuListener(frida);
popup.addPopupMenuListener(goToDeclaration);
popup.addPopupMenuListener(comment);
popup.addPopupMenuListener(rename);
......
......@@ -5,10 +5,7 @@ import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
import javax.swing.*;
......@@ -17,12 +14,16 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.JavaClass;
import jadx.api.JavaField;
import jadx.api.JavaMethod;
import jadx.api.data.annotations.VarDeclareRef;
import jadx.core.dex.info.MethodInfo;
import jadx.core.dex.instructions.args.ArgType;
import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.MethodNode;
import jadx.gui.treemodel.JClass;
import jadx.gui.treemodel.JField;
import jadx.gui.treemodel.JMethod;
import jadx.gui.treemodel.JNode;
import jadx.gui.utils.NLS;
......@@ -30,15 +31,13 @@ import jadx.gui.utils.NLS;
import static javax.swing.KeyStroke.getKeyStroke;
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 Map<String, Boolean> isInitial = new HashMap<>();
private String methodName;
private final Map<String, Boolean> isInitial = new HashMap<>();
public FridaAction(CodeArea codeArea) {
super(NLS.str("popup.frida") + " (f)", codeArea);
LOG.info("triggered meee");
KeyStroke key = getKeyStroke(KeyEvent.VK_F, 0);
codeArea.getInputMap().put(key, "trigger frida");
codeArea.getActionMap().put("trigger frida", new AbstractAction() {
......@@ -46,143 +45,130 @@ public final class FridaAction extends JNodeMenuAction<JNode> {
public void actionPerformed(ActionEvent e) {
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() {
if (node != null) {
if (node instanceof JMethod) {
JMethod n = (JMethod) node;
MethodNode methodNode = n.getJavaMethod().getMethodNode();
MethodInfo mi = methodNode.getMethodInfo();
methodName = mi.getName();
if (methodName.equals("<init>") || methodName.equals("onCreate")) {
methodName = "$init";
}
String fullClassName = methodNode.getParentClass().getFullName();
String className = methodNode.getParentClass().getShortName();
LOG.debug("node is jmethod");
ClassNode tmp = methodNode.getParentClass();
while (true) {
if (!tmp.isTopClass()) {
fullClassName = fullClassName.substring(0, fullClassName.lastIndexOf(".")) + "$"
+ fullClassName.substring(fullClassName.lastIndexOf(".") + 1, fullClassName.length());
} else {
break;
}
tmp = tmp.getParentClass();
}
JMethod jMth = (JMethod) node;
int mthLine = jMth.getLine();
List<String> argNames = jMth.getRootClass().getCodeInfo().getAnnotations().entrySet().stream()
.filter(e -> e.getKey().getLine() == mthLine && e.getValue() instanceof VarDeclareRef)
private String generateFridaSnippet() {
if (node instanceof JMethod) {
LOG.debug("node is jmethod");
return generateMethodSnippet((JMethod) node);
} else if (node instanceof JClass) {
LOG.debug("node is jclass");
return generateClassSnippet((JClass) node);
} else if (node instanceof JField) {
LOG.debug("node is jfield");
return generateFieldSnippet((JField) node);
}
LOG.debug("cannot generate frida snippet from node");
return "";
}
private String generateMethodSnippet(JMethod jMth) {
JavaMethod javaMethod = jMth.getJavaMethod();
MethodInfo methodInfo = javaMethod.getMethodNode().getMethodInfo();
String methodName = methodInfo.getName();
if (methodName.equals("<init>") || methodName.equals("onCreate")) {
methodName = "$init";
}
String rawClassName = javaMethod.getDeclaringClass().getRawName();
String shortClassName = javaMethod.getDeclaringClass().getName();
String functionUntilImplementation;
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()))
.map(e -> ((VarDeclareRef) e.getValue()).getName())
.collect(Collectors.toList());
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);
.collect(Collectors.joining(", "));
} else if (node instanceof JClass) {
LOG.debug("node is jclass");
JClass jc = (JClass) node;
String fullClassName = jc.getCls().getClassNode().getClassInfo().getFullName();
String className = jc.getCls().getClassNode().getClassInfo().getShortName();
ClassNode tmp = jc.getCls().getClassNode();
while (true) {
if (!tmp.isTopClass()) {
fullClassName = fullClassName.substring(0, fullClassName.lastIndexOf(".")) + "$"
+ fullClassName.substring(fullClassName.lastIndexOf(".") + 1, fullClassName.length());
} else {
break;
}
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");
}
String 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);
String finalFridaCode;
if (isInitial.getOrDefault(rawClassName, true)) {
String classSnippet = generateClassSnippet(jMth.getJParent());
finalFridaCode = classSnippet + "\n" + functionParameterAndBody;
} else {
finalFridaCode = functionParameterAndBody;
}
LOG.debug("frida code : " + finalFridaCode);
return finalFridaCode;
}
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) {
StringBuilder parsedArgType = new StringBuilder();
StringBuilder parsedArgType = new StringBuilder("'");
if (x.isArray()) {
parsedArgType.append(x.getPrimitiveType().getShortName());
parsedArgType.append(x.getArrayElement().getPrimitiveType().getShortName());
if (!x.getArrayElement().isPrimitive()) {
parsedArgType.append(x.getArrayElement().toString() + ";");
parsedArgType.append(x.getArrayElement().toString()).append(";");
}
} else {
parsedArgType.append(x.toString());
parsedArgType.append(x);
}
return parsedArgType.toString();
return parsedArgType.append("'").toString();
}
@Override
public void actionPerformed(ActionEvent e) {
node = codeArea.getNodeUnderCaret();
copyFridaCode();
generateFridaSnippet();
}
@Nullable
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册