feat: input plugin for java bytecode
This commit is contained in:
+12
-3
@@ -2,7 +2,11 @@ package jadx.plugins.input.dex.insns;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.plugins.input.data.*;
|
||||
import jadx.api.plugins.input.data.ICallSite;
|
||||
import jadx.api.plugins.input.data.IFieldRef;
|
||||
import jadx.api.plugins.input.data.IMethodHandle;
|
||||
import jadx.api.plugins.input.data.IMethodProto;
|
||||
import jadx.api.plugins.input.data.IMethodRef;
|
||||
import jadx.api.plugins.input.insns.InsnData;
|
||||
import jadx.api.plugins.input.insns.InsnIndexType;
|
||||
import jadx.api.plugins.input.insns.Opcode;
|
||||
@@ -82,6 +86,11 @@ public class DexInsnData implements InsnData {
|
||||
return argsReg[argNum];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultReg() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLiteral() {
|
||||
return literal;
|
||||
@@ -113,8 +122,8 @@ public class DexInsnData implements InsnData {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFieldData getIndexAsField() {
|
||||
return externalReader.getFieldData(index);
|
||||
public IFieldRef getIndexAsField() {
|
||||
return externalReader.getFieldRef(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+4
-3
@@ -1,8 +1,8 @@
|
||||
package jadx.plugins.input.dex.insns;
|
||||
|
||||
import jadx.api.plugins.input.insns.custom.impl.SwitchPayload;
|
||||
import jadx.plugins.input.dex.DexException;
|
||||
import jadx.plugins.input.dex.insns.payloads.DexArrayPayload;
|
||||
import jadx.plugins.input.dex.insns.payloads.DexSwitchPayload;
|
||||
import jadx.plugins.input.dex.sections.SectionReader;
|
||||
|
||||
public abstract class DexInsnFormat {
|
||||
@@ -158,6 +158,7 @@ public abstract class DexInsnFormat {
|
||||
regs[0] = nibble2(opcodeUnit);
|
||||
regs[1] = nibble3(opcodeUnit);
|
||||
insn.setIndex(in.readUShort());
|
||||
insn.setLiteral(0L);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -262,7 +263,7 @@ public abstract class DexInsnFormat {
|
||||
targets[i] = in.readInt();
|
||||
keys[i] = firstKey + i;
|
||||
}
|
||||
insn.setPayload(new DexSwitchPayload(size, keys, targets));
|
||||
insn.setPayload(new SwitchPayload(size, keys, targets));
|
||||
insn.setLength(size * 2 + 4);
|
||||
}
|
||||
|
||||
@@ -286,7 +287,7 @@ public abstract class DexInsnFormat {
|
||||
for (int i = 0; i < size; i++) {
|
||||
targets[i] = in.readInt();
|
||||
}
|
||||
insn.setPayload(new DexSwitchPayload(size, keys, targets));
|
||||
insn.setPayload(new SwitchPayload(size, keys, targets));
|
||||
insn.setLength(size * 4 + 2);
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -282,8 +282,8 @@ public class DexInsnInfo {
|
||||
register(arr, DexOpcodes.INVOKE_POLYMORPHIC, Opcode.INVOKE_POLYMORPHIC, DexInsnFormat.FORMAT_45CC);
|
||||
register(arr, DexOpcodes.INVOKE_POLYMORPHIC_RANGE, Opcode.INVOKE_POLYMORPHIC_RANGE, DexInsnFormat.FORMAT_4RCC);
|
||||
|
||||
register(arr, DexOpcodes.INVOKE_CUSTOM, Opcode.INVOKE_CUSTOM, DexInsnFormat.FORMAT_35C);
|
||||
register(arr, DexOpcodes.INVOKE_CUSTOM_RANGE, Opcode.INVOKE_CUSTOM_RANGE, DexInsnFormat.FORMAT_3RC);
|
||||
register(arr, DexOpcodes.INVOKE_CUSTOM, Opcode.INVOKE_CUSTOM, DexInsnFormat.FORMAT_35C, InsnIndexType.CALL_SITE);
|
||||
register(arr, DexOpcodes.INVOKE_CUSTOM_RANGE, Opcode.INVOKE_CUSTOM_RANGE, DexInsnFormat.FORMAT_3RC, InsnIndexType.CALL_SITE);
|
||||
|
||||
register(arr, DexOpcodes.CONST_METHOD_HANDLE, Opcode.CONST_METHOD_HANDLE, DexInsnFormat.FORMAT_21C);
|
||||
register(arr, DexOpcodes.CONST_METHOD_TYPE, Opcode.CONST_METHOD_TYPE, DexInsnFormat.FORMAT_21C);
|
||||
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
package jadx.plugins.input.dex.insns.payloads;
|
||||
|
||||
import jadx.api.plugins.input.insns.custom.ISwitchPayload;
|
||||
|
||||
public class DexSwitchPayload implements ISwitchPayload {
|
||||
|
||||
private final int size;
|
||||
private final int[] keys;
|
||||
private final int[] targets;
|
||||
|
||||
public DexSwitchPayload(int size, int[] keys, int[] targets) {
|
||||
this.size = size;
|
||||
this.keys = keys;
|
||||
this.targets = targets;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getKeys() {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getTargets() {
|
||||
return targets;
|
||||
}
|
||||
}
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
package jadx.plugins.input.dex.sections;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.plugins.input.data.annotations.AnnotationVisibility;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedType;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.api.plugins.input.data.annotations.IAnnotation;
|
||||
import jadx.api.plugins.input.data.attributes.IJadxAttribute;
|
||||
import jadx.api.plugins.input.data.attributes.types.AnnotationDefaultClassAttr;
|
||||
import jadx.api.plugins.input.data.attributes.types.AnnotationsAttr;
|
||||
import jadx.api.plugins.input.data.attributes.types.ExceptionsAttr;
|
||||
import jadx.api.plugins.input.data.attributes.types.InnerClassesAttr;
|
||||
import jadx.api.plugins.input.data.attributes.types.InnerClsInfo;
|
||||
import jadx.api.plugins.input.data.attributes.types.SignatureAttr;
|
||||
import jadx.api.plugins.utils.Utils;
|
||||
|
||||
public class DexAnnotationsConvert {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DexAnnotationsConvert.class);
|
||||
|
||||
public static void forClass(String cls, List<IJadxAttribute> list, List<IAnnotation> annotationList) {
|
||||
appendAnnotations(cls, list, annotationList);
|
||||
}
|
||||
|
||||
public static void forMethod(List<IJadxAttribute> list, List<IAnnotation> annotationList) {
|
||||
appendAnnotations(null, list, annotationList);
|
||||
}
|
||||
|
||||
public static void forField(List<IJadxAttribute> list, List<IAnnotation> annotationList) {
|
||||
appendAnnotations(null, list, annotationList);
|
||||
}
|
||||
|
||||
private static void appendAnnotations(String cls, List<IJadxAttribute> attributes, List<IAnnotation> annotations) {
|
||||
if (annotations.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (IAnnotation annotation : annotations) {
|
||||
if (annotation.getVisibility() == AnnotationVisibility.SYSTEM) {
|
||||
convertSystemAnnotations(cls, attributes, annotation);
|
||||
}
|
||||
}
|
||||
Utils.addToList(attributes, AnnotationsAttr.pack(annotations));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void convertSystemAnnotations(String cls, List<IJadxAttribute> attributes, IAnnotation annotation) {
|
||||
switch (annotation.getAnnotationClass()) {
|
||||
case "Ldalvik/annotation/Signature;":
|
||||
attributes.add(new SignatureAttr(extractSignature(annotation)));
|
||||
break;
|
||||
|
||||
case "Ldalvik/annotation/InnerClass;":
|
||||
Map<String, EncodedValue> values = annotation.getValues();
|
||||
String name = (String) values.get("name").getValue();
|
||||
int accFlags = (Integer) values.get("accessFlags").getValue();
|
||||
Map<String, InnerClsInfo> map = Collections.singletonMap(cls, new InnerClsInfo(cls, null, name, accFlags));
|
||||
attributes.add(new InnerClassesAttr(map));
|
||||
break;
|
||||
|
||||
case "Ldalvik/annotation/AnnotationDefault;":
|
||||
EncodedValue annValue = annotation.getDefaultValue();
|
||||
if (annValue != null && annValue.getType() == EncodedType.ENCODED_ANNOTATION) {
|
||||
IAnnotation defAnnotation = (IAnnotation) annValue.getValue();
|
||||
attributes.add(new AnnotationDefaultClassAttr(defAnnotation.getValues()));
|
||||
}
|
||||
break;
|
||||
|
||||
case "Ldalvik/annotation/Throws;":
|
||||
try {
|
||||
EncodedValue defaultValue = annotation.getDefaultValue();
|
||||
if (defaultValue != null) {
|
||||
List<String> excs = ((List<EncodedValue>) defaultValue.getValue())
|
||||
.stream()
|
||||
.map(ev -> ((String) ev.getValue()))
|
||||
.collect(Collectors.toList());
|
||||
attributes.add(new ExceptionsAttr(excs));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to convert dalvik throws annotation", e);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "ConstantConditions" })
|
||||
private static String extractSignature(IAnnotation annotation) {
|
||||
List<EncodedValue> values = (List<EncodedValue>) annotation.getDefaultValue().getValue();
|
||||
if (values.size() == 1) {
|
||||
return (String) values.get(0).getValue();
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (EncodedValue part : values) {
|
||||
sb.append((String) part.getValue());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package jadx.plugins.input.dex.sections;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jadx.api.plugins.input.data.ICallSite;
|
||||
import jadx.api.plugins.input.data.IMethodHandle;
|
||||
import jadx.api.plugins.input.data.IMethodRef;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
|
||||
public class DexCallSite implements ICallSite {
|
||||
|
||||
private final List<EncodedValue> values;
|
||||
|
||||
public DexCallSite(List<EncodedValue> values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EncodedValue> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
for (EncodedValue value : values) {
|
||||
Object obj = value.getValue();
|
||||
if (obj instanceof IMethodRef) {
|
||||
((IMethodRef) obj).load();
|
||||
} else if (obj instanceof IMethodHandle) {
|
||||
((IMethodHandle) obj).load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CallSite{" + values + '}';
|
||||
}
|
||||
}
|
||||
+28
-14
@@ -1,21 +1,27 @@
|
||||
package jadx.plugins.input.dex.sections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.api.plugins.input.data.IClassData;
|
||||
import jadx.api.plugins.input.data.IFieldData;
|
||||
import jadx.api.plugins.input.data.IMethodData;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.api.plugins.input.data.annotations.IAnnotation;
|
||||
import jadx.api.plugins.input.data.attributes.IJadxAttribute;
|
||||
import jadx.api.plugins.input.data.attributes.types.SourceFileAttr;
|
||||
import jadx.plugins.input.dex.sections.annotations.AnnotationsParser;
|
||||
import jadx.plugins.input.dex.utils.SmaliUtils;
|
||||
|
||||
public class DexClassData implements IClassData {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DexClassData.class);
|
||||
public static final int SIZE = 8 * 4;
|
||||
|
||||
private final SectionReader in;
|
||||
@@ -63,8 +69,7 @@ public class DexClassData implements IClassData {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSourceFile() {
|
||||
private String getSourceFile() {
|
||||
int strIdx = in.pos(4 * 4).readInt();
|
||||
return in.getString(strIdx);
|
||||
}
|
||||
@@ -107,12 +112,13 @@ public class DexClassData implements IClassData {
|
||||
Map<Integer, Integer> annotationOffsetMap = annotationsParser.readFieldsAnnotationOffsetMap();
|
||||
DexFieldData fieldData = new DexFieldData(annotationsParser);
|
||||
fieldData.setParentClassType(getType());
|
||||
readFields(fieldConsumer, data, fieldData, staticFieldsCount, annotationOffsetMap);
|
||||
readFields(fieldConsumer, data, fieldData, instanceFieldsCount, annotationOffsetMap);
|
||||
readFields(fieldConsumer, data, fieldData, staticFieldsCount, annotationOffsetMap, true);
|
||||
readFields(fieldConsumer, data, fieldData, instanceFieldsCount, annotationOffsetMap, false);
|
||||
}
|
||||
|
||||
private void readFields(Consumer<IFieldData> fieldConsumer, SectionReader data, DexFieldData fieldData, int count,
|
||||
Map<Integer, Integer> annOffsetMap) {
|
||||
Map<Integer, Integer> annOffsetMap, boolean staticFields) {
|
||||
List<EncodedValue> constValues = staticFields ? getStaticFieldInitValues(data.copy()) : null;
|
||||
int fieldId = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
fieldId += data.readUleb128();
|
||||
@@ -120,6 +126,7 @@ public class DexClassData implements IClassData {
|
||||
in.fillFieldData(fieldData, fieldId);
|
||||
fieldData.setAccessFlags(accFlags);
|
||||
fieldData.setAnnotationsOffset(getOffsetFromMap(fieldId, annOffsetMap));
|
||||
fieldData.setConstValue(staticFields && i < constValues.size() ? constValues.get(i) : null);
|
||||
fieldConsumer.accept(fieldData);
|
||||
}
|
||||
}
|
||||
@@ -130,9 +137,7 @@ public class DexClassData implements IClassData {
|
||||
Map<Integer, Integer> annotationOffsetMap = annotationsParser.readMethodsAnnotationOffsetMap();
|
||||
Map<Integer, Integer> paramsAnnOffsetMap = annotationsParser.readMethodParamsAnnRefOffsetMap();
|
||||
|
||||
methodData.setDirect(true);
|
||||
readMethods(mthConsumer, data, methodData, directMthCount, annotationOffsetMap, paramsAnnOffsetMap);
|
||||
methodData.setDirect(false);
|
||||
readMethods(mthConsumer, data, methodData, virtualMthCount, annotationOffsetMap, paramsAnnOffsetMap);
|
||||
}
|
||||
|
||||
@@ -167,20 +172,29 @@ public class DexClassData implements IClassData {
|
||||
return offset != null ? offset : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EncodedValue> getStaticFieldInitValues() {
|
||||
private List<EncodedValue> getStaticFieldInitValues(SectionReader reader) {
|
||||
int staticValuesOff = getStaticValuesOff();
|
||||
if (staticValuesOff == 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
in.absPos(staticValuesOff);
|
||||
return annotationsParser.parseEncodedArray(in);
|
||||
reader.absPos(staticValuesOff);
|
||||
return annotationsParser.parseEncodedArray(reader);
|
||||
}
|
||||
|
||||
private List<IAnnotation> getAnnotations() {
|
||||
annotationsParser.setOffset(getAnnotationsOff());
|
||||
return annotationsParser.readClassAnnotations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IAnnotation> getAnnotations() {
|
||||
annotationsParser.setOffset(getAnnotationsOff());
|
||||
return annotationsParser.readClassAnnotations();
|
||||
public List<IJadxAttribute> getAttributes() {
|
||||
List<IJadxAttribute> list = new ArrayList<>();
|
||||
String sourceFile = getSourceFile();
|
||||
if (sourceFile != null && !sourceFile.isEmpty()) {
|
||||
list.add(new SourceFileAttr(sourceFile));
|
||||
}
|
||||
DexAnnotationsConvert.forClass(getType(), list, getAnnotations());
|
||||
return list;
|
||||
}
|
||||
|
||||
public int getClassDefOffset() {
|
||||
|
||||
+12
-7
@@ -13,14 +13,14 @@ import jadx.api.plugins.input.data.ICatch;
|
||||
import jadx.api.plugins.input.data.ICodeReader;
|
||||
import jadx.api.plugins.input.data.IDebugInfo;
|
||||
import jadx.api.plugins.input.data.ITry;
|
||||
import jadx.api.plugins.input.data.impl.CatchData;
|
||||
import jadx.api.plugins.input.data.impl.TryData;
|
||||
import jadx.api.plugins.input.insns.InsnData;
|
||||
import jadx.plugins.input.dex.DexException;
|
||||
import jadx.plugins.input.dex.insns.DexInsnData;
|
||||
import jadx.plugins.input.dex.insns.DexInsnFormat;
|
||||
import jadx.plugins.input.dex.insns.DexInsnInfo;
|
||||
import jadx.plugins.input.dex.sections.debuginfo.DebugInfoParser;
|
||||
import jadx.plugins.input.dex.sections.trycatch.DexCatch;
|
||||
import jadx.plugins.input.dex.sections.trycatch.DexTryData;
|
||||
|
||||
public class DexCodeReader implements ICodeReader {
|
||||
|
||||
@@ -48,7 +48,12 @@ public class DexCodeReader implements ICodeReader {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInsnsCount() {
|
||||
public int getArgsStartReg() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUnitsCount() {
|
||||
return in.pos(12).readInt();
|
||||
}
|
||||
|
||||
@@ -108,7 +113,7 @@ public class DexCodeReader implements ICodeReader {
|
||||
return null;
|
||||
}
|
||||
int regsCount = getRegistersCount();
|
||||
DebugInfoParser debugInfoParser = new DebugInfoParser(in, regsCount, getInsnsCount());
|
||||
DebugInfoParser debugInfoParser = new DebugInfoParser(in, regsCount, getUnitsCount());
|
||||
debugInfoParser.initMthArgs(regsCount, in.getMethodParamTypes(mthId));
|
||||
return debugInfoParser.process(debugOff);
|
||||
}
|
||||
@@ -122,7 +127,7 @@ public class DexCodeReader implements ICodeReader {
|
||||
if (triesCount == 0) {
|
||||
return -1;
|
||||
}
|
||||
int insnsCount = getInsnsCount();
|
||||
int insnsCount = getUnitsCount();
|
||||
int padding = insnsCount % 2 == 1 ? 2 : 0;
|
||||
return 4 * 4 + insnsCount * 2 + padding;
|
||||
}
|
||||
@@ -145,7 +150,7 @@ public class DexCodeReader implements ICodeReader {
|
||||
if (catchHandler == null) {
|
||||
throw new DexException("Catch handler not found by byte offset: " + handlerOff);
|
||||
}
|
||||
triesList.add(new DexTryData(catchHandler, startAddr, insnsCount));
|
||||
triesList.add(new TryData(startAddr, startAddr + insnsCount - 1, catchHandler));
|
||||
}
|
||||
return triesList;
|
||||
}
|
||||
@@ -171,7 +176,7 @@ public class DexCodeReader implements ICodeReader {
|
||||
} else {
|
||||
catchAllAddr = -1;
|
||||
}
|
||||
map.put(byteIndex, new DexCatch(addr, types, catchAllAddr));
|
||||
map.put(byteIndex, new CatchData(addr, types, catchAllAddr));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
+18
-2
@@ -1,11 +1,15 @@
|
||||
package jadx.plugins.input.dex.sections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.plugins.input.data.IFieldData;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.api.plugins.input.data.annotations.IAnnotation;
|
||||
import jadx.api.plugins.input.data.attributes.IJadxAttribute;
|
||||
import jadx.api.plugins.utils.Utils;
|
||||
import jadx.plugins.input.dex.sections.annotations.AnnotationsParser;
|
||||
|
||||
public class DexFieldData implements IFieldData {
|
||||
@@ -17,6 +21,7 @@ public class DexFieldData implements IFieldData {
|
||||
private String name;
|
||||
private int accessFlags;
|
||||
private int annotationsOffset;
|
||||
private EncodedValue constValue;
|
||||
|
||||
public DexFieldData(@Nullable AnnotationsParser parser) {
|
||||
this.annotationsParser = parser;
|
||||
@@ -62,14 +67,25 @@ public class DexFieldData implements IFieldData {
|
||||
this.annotationsOffset = annotationsOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IAnnotation> getAnnotations() {
|
||||
public void setConstValue(EncodedValue constValue) {
|
||||
this.constValue = constValue;
|
||||
}
|
||||
|
||||
private List<IAnnotation> getAnnotations() {
|
||||
if (annotationsParser == null) {
|
||||
throw new NullPointerException("Annotation parser not initialized");
|
||||
}
|
||||
return annotationsParser.readAnnotationList(annotationsOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IJadxAttribute> getAttributes() {
|
||||
List<IJadxAttribute> list = new ArrayList<>(2);
|
||||
Utils.addToList(list, constValue);
|
||||
DexAnnotationsConvert.forField(list, getAnnotations());
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getParentClassType() + "->" + getName() + ":" + getType();
|
||||
|
||||
+14
-14
@@ -1,5 +1,6 @@
|
||||
package jadx.plugins.input.dex.sections;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -7,6 +8,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import jadx.api.plugins.input.data.ICodeReader;
|
||||
import jadx.api.plugins.input.data.IMethodData;
|
||||
import jadx.api.plugins.input.data.annotations.IAnnotation;
|
||||
import jadx.api.plugins.input.data.attributes.IJadxAttribute;
|
||||
import jadx.api.plugins.input.data.attributes.types.MethodParamsAttr;
|
||||
import jadx.api.plugins.utils.Utils;
|
||||
import jadx.plugins.input.dex.sections.annotations.AnnotationsParser;
|
||||
import jadx.plugins.input.dex.smali.SmaliPrinter;
|
||||
|
||||
@@ -17,7 +21,6 @@ public class DexMethodData implements IMethodData {
|
||||
private DexMethodRef methodRef;
|
||||
|
||||
private int accessFlags;
|
||||
private boolean isDirect;
|
||||
private int annotationsOffset;
|
||||
private int paramAnnotationsOffset;
|
||||
|
||||
@@ -46,15 +49,6 @@ public class DexMethodData implements IMethodData {
|
||||
this.accessFlags = accessFlags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirect() {
|
||||
return isDirect;
|
||||
}
|
||||
|
||||
public void setDirect(boolean direct) {
|
||||
isDirect = direct;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ICodeReader getCodeReader() {
|
||||
@@ -78,16 +72,22 @@ public class DexMethodData implements IMethodData {
|
||||
this.paramAnnotationsOffset = paramAnnotationsOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IAnnotation> getAnnotations() {
|
||||
private List<IAnnotation> getAnnotations() {
|
||||
return getAnnotationsParser().readAnnotationList(annotationsOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<List<IAnnotation>> getParamsAnnotations() {
|
||||
private List<List<IAnnotation>> getParamsAnnotations() {
|
||||
return getAnnotationsParser().readAnnotationRefList(paramAnnotationsOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IJadxAttribute> getAttributes() {
|
||||
List<IJadxAttribute> list = new ArrayList<>();
|
||||
DexAnnotationsConvert.forMethod(list, getAnnotations());
|
||||
Utils.addToList(list, MethodParamsAttr.pack(getParamsAnnotations()));
|
||||
return list;
|
||||
}
|
||||
|
||||
private AnnotationsParser getAnnotationsParser() {
|
||||
if (annotationsParser == null) {
|
||||
throw new NullPointerException("Annotation parser not initialized");
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ package jadx.plugins.input.dex.sections;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.api.plugins.input.data.IMethodProto;
|
||||
import jadx.plugins.input.dex.utils.Utils;
|
||||
import jadx.api.plugins.utils.Utils;
|
||||
|
||||
public class DexMethodProto implements IMethodProto {
|
||||
private final List<String> argTypes;
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@ package jadx.plugins.input.dex.sections;
|
||||
import java.util.List;
|
||||
|
||||
import jadx.api.plugins.input.data.IMethodRef;
|
||||
import jadx.api.plugins.utils.Utils;
|
||||
import jadx.plugins.input.dex.DexReader;
|
||||
import jadx.plugins.input.dex.utils.Utils;
|
||||
|
||||
public class DexMethodRef implements IMethodRef {
|
||||
|
||||
|
||||
+5
-4
@@ -10,9 +10,10 @@ import java.util.List;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.plugins.input.data.ICallSite;
|
||||
import jadx.api.plugins.input.data.IFieldData;
|
||||
import jadx.api.plugins.input.data.IFieldRef;
|
||||
import jadx.api.plugins.input.data.IMethodHandle;
|
||||
import jadx.api.plugins.input.data.MethodHandleType;
|
||||
import jadx.api.plugins.input.data.impl.CallSite;
|
||||
import jadx.api.plugins.input.data.impl.FieldRefHandle;
|
||||
import jadx.api.plugins.input.data.impl.MethodRefHandle;
|
||||
import jadx.plugins.input.dex.DexReader;
|
||||
@@ -177,7 +178,7 @@ public class SectionReader {
|
||||
return MUtf8.decode(this);
|
||||
}
|
||||
|
||||
public IFieldData getFieldData(int idx) {
|
||||
public IFieldRef getFieldRef(int idx) {
|
||||
DexFieldData fieldData = new DexFieldData(null);
|
||||
int clsTypeIdx = fillFieldData(fieldData, idx);
|
||||
fieldData.setParentClassType(getType(clsTypeIdx));
|
||||
@@ -205,7 +206,7 @@ public class SectionReader {
|
||||
int callSiteOff = dexReader.getHeader().getCallSiteOff();
|
||||
absPos(callSiteOff + idx * 4);
|
||||
absPos(readInt());
|
||||
return new DexCallSite(EncodedValueParser.parseEncodedArray(this, ext));
|
||||
return new CallSite(EncodedValueParser.parseEncodedArray(this, ext));
|
||||
}
|
||||
|
||||
public IMethodHandle getMethodHandle(int idx) {
|
||||
@@ -215,7 +216,7 @@ public class SectionReader {
|
||||
skip(2);
|
||||
int refId = readUShort();
|
||||
if (handleType.isField()) {
|
||||
return new FieldRefHandle(handleType, getFieldData(refId));
|
||||
return new FieldRefHandle(handleType, getFieldRef(refId));
|
||||
}
|
||||
return new MethodRefHandle(handleType, getMethodRef(refId));
|
||||
}
|
||||
|
||||
+2
-1
@@ -10,6 +10,7 @@ import java.util.Map;
|
||||
import jadx.api.plugins.input.data.annotations.AnnotationVisibility;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.api.plugins.input.data.annotations.IAnnotation;
|
||||
import jadx.api.plugins.input.data.annotations.JadxAnnotation;
|
||||
import jadx.plugins.input.dex.DexException;
|
||||
import jadx.plugins.input.dex.sections.SectionReader;
|
||||
|
||||
@@ -149,7 +150,7 @@ public class AnnotationsParser {
|
||||
values.put(name, EncodedValueParser.parseValue(in, ext));
|
||||
}
|
||||
String type = ext.getType(typeIndex);
|
||||
return new DexAnnotation(visibility, type, values);
|
||||
return new JadxAnnotation(visibility, type, values);
|
||||
}
|
||||
|
||||
private static AnnotationVisibility getVisibilityValue(int value) {
|
||||
|
||||
-39
@@ -1,39 +0,0 @@
|
||||
package jadx.plugins.input.dex.sections.annotations;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import jadx.api.plugins.input.data.annotations.AnnotationVisibility;
|
||||
import jadx.api.plugins.input.data.annotations.EncodedValue;
|
||||
import jadx.api.plugins.input.data.annotations.IAnnotation;
|
||||
|
||||
public class DexAnnotation implements IAnnotation {
|
||||
private final AnnotationVisibility visibility;
|
||||
private final String type;
|
||||
private final Map<String, EncodedValue> values;
|
||||
|
||||
public DexAnnotation(AnnotationVisibility visibility, String type, Map<String, EncodedValue> values) {
|
||||
this.visibility = visibility;
|
||||
this.type = type;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAnnotationClass() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AnnotationVisibility getVisibility() {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, EncodedValue> getValues() {
|
||||
return values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DexAnnotation{" + visibility + ", type=" + type + ", values=" + values + '}';
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -66,7 +66,7 @@ public class EncodedValueParser {
|
||||
|
||||
case ENCODED_FIELD:
|
||||
case ENCODED_ENUM:
|
||||
return new EncodedValue(EncodedType.ENCODED_FIELD, ext.getFieldData(parseUnsignedInt(in, size)));
|
||||
return new EncodedValue(EncodedType.ENCODED_FIELD, ext.getFieldRef(parseUnsignedInt(in, size)));
|
||||
|
||||
case ENCODED_ARRAY:
|
||||
return new EncodedValue(EncodedType.ENCODED_ARRAY, parseEncodedArray(in, ext));
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
package jadx.plugins.input.dex.sections.debuginfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jadx.api.plugins.input.data.IDebugInfo;
|
||||
import jadx.api.plugins.input.data.ILocalVar;
|
||||
|
||||
public class DebugInfo implements IDebugInfo {
|
||||
|
||||
private final Map<Integer, Integer> sourceLineMap;
|
||||
private final List<ILocalVar> localVars;
|
||||
|
||||
public DebugInfo(Map<Integer, Integer> sourceLineMap, List<ILocalVar> localVars) {
|
||||
this.sourceLineMap = sourceLineMap;
|
||||
this.localVars = localVars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Integer, Integer> getSourceLineMapping() {
|
||||
return sourceLineMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ILocalVar> getLocalVars() {
|
||||
return localVars;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DebugInfo{sourceLineMap=" + sourceLineMap + ", localVars=" + localVars + '}';
|
||||
}
|
||||
}
|
||||
+13
-12
@@ -9,6 +9,7 @@ import java.util.Map;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.plugins.input.data.ILocalVar;
|
||||
import jadx.api.plugins.input.data.impl.DebugInfo;
|
||||
import jadx.plugins.input.dex.sections.DexConsts;
|
||||
import jadx.plugins.input.dex.sections.SectionReader;
|
||||
|
||||
@@ -34,7 +35,7 @@ public class DebugInfoParser {
|
||||
private final SectionReader in;
|
||||
private final SectionReader ext;
|
||||
|
||||
private final LocalVar[] locals;
|
||||
private final DexLocalVar[] locals;
|
||||
private final int codeSize;
|
||||
|
||||
private List<ILocalVar> resultList;
|
||||
@@ -48,7 +49,7 @@ public class DebugInfoParser {
|
||||
public DebugInfoParser(SectionReader in, int regsCount, int codeSize) {
|
||||
this.in = in;
|
||||
this.ext = in.copy();
|
||||
this.locals = new LocalVar[regsCount];
|
||||
this.locals = new DexLocalVar[regsCount];
|
||||
this.codeSize = codeSize;
|
||||
}
|
||||
|
||||
@@ -96,7 +97,7 @@ public class DebugInfoParser {
|
||||
String name = ext.getString(nameId);
|
||||
if (name != null && i < argsCount) {
|
||||
int regNum = argRegs[i];
|
||||
startVar(new LocalVar(regNum, name, argTypes.get(i)), -1);
|
||||
startVar(new DexLocalVar(regNum, name, argTypes.get(i)), -1);
|
||||
varsInfoFound = true;
|
||||
}
|
||||
}
|
||||
@@ -123,7 +124,7 @@ public class DebugInfoParser {
|
||||
int regNum = in.readUleb128();
|
||||
int nameId = in.readUleb128() - 1;
|
||||
int type = in.readUleb128() - 1;
|
||||
LocalVar var = new LocalVar(ext, regNum, nameId, type, DexConsts.NO_INDEX);
|
||||
DexLocalVar var = new DexLocalVar(ext, regNum, nameId, type, DexConsts.NO_INDEX);
|
||||
startVar(var, addr);
|
||||
varsInfoFound = true;
|
||||
break;
|
||||
@@ -133,7 +134,7 @@ public class DebugInfoParser {
|
||||
int nameId = in.readUleb128p1();
|
||||
int type = in.readUleb128p1();
|
||||
int sign = in.readUleb128p1();
|
||||
LocalVar var = new LocalVar(ext, regNum, nameId, type, sign);
|
||||
DexLocalVar var = new DexLocalVar(ext, regNum, nameId, type, sign);
|
||||
startVar(var, addr);
|
||||
varsInfoFound = true;
|
||||
break;
|
||||
@@ -146,7 +147,7 @@ public class DebugInfoParser {
|
||||
}
|
||||
case DBG_END_LOCAL: {
|
||||
int regNum = in.readUleb128();
|
||||
LocalVar var = locals[regNum];
|
||||
DexLocalVar var = locals[regNum];
|
||||
if (var != null) {
|
||||
endVar(var, addr);
|
||||
}
|
||||
@@ -178,7 +179,7 @@ public class DebugInfoParser {
|
||||
}
|
||||
|
||||
if (varsInfoFound) {
|
||||
for (LocalVar var : locals) {
|
||||
for (DexLocalVar var : locals) {
|
||||
if (var != null && !var.isEnd()) {
|
||||
endVar(var, codeSize - 1);
|
||||
}
|
||||
@@ -208,17 +209,17 @@ public class DebugInfoParser {
|
||||
}
|
||||
|
||||
private void restartVar(int regNum, int addr) {
|
||||
LocalVar prev = locals[regNum];
|
||||
DexLocalVar prev = locals[regNum];
|
||||
if (prev != null) {
|
||||
endVar(prev, addr);
|
||||
LocalVar newVar = new LocalVar(regNum, prev.getName(), prev.getType(), prev.getSignature());
|
||||
DexLocalVar newVar = new DexLocalVar(regNum, prev.getName(), prev.getType(), prev.getSignature());
|
||||
startVar(newVar, addr);
|
||||
}
|
||||
}
|
||||
|
||||
private void startVar(LocalVar newVar, int addr) {
|
||||
private void startVar(DexLocalVar newVar, int addr) {
|
||||
int regNum = newVar.getRegNum();
|
||||
LocalVar prev = locals[regNum];
|
||||
DexLocalVar prev = locals[regNum];
|
||||
if (prev != null) {
|
||||
endVar(prev, addr);
|
||||
}
|
||||
@@ -226,7 +227,7 @@ public class DebugInfoParser {
|
||||
locals[regNum] = newVar;
|
||||
}
|
||||
|
||||
private void endVar(LocalVar var, int addr) {
|
||||
private void endVar(DexLocalVar var, int addr) {
|
||||
if (var.end(addr)) {
|
||||
resultList.add(var);
|
||||
}
|
||||
|
||||
+6
-6
@@ -3,10 +3,10 @@ package jadx.plugins.input.dex.sections.debuginfo;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import jadx.api.plugins.input.data.ILocalVar;
|
||||
import jadx.api.plugins.utils.Utils;
|
||||
import jadx.plugins.input.dex.sections.SectionReader;
|
||||
import jadx.plugins.input.dex.utils.Utils;
|
||||
|
||||
public class LocalVar implements ILocalVar {
|
||||
public class DexLocalVar implements ILocalVar {
|
||||
private final int regNum;
|
||||
private final String name;
|
||||
private final String type;
|
||||
@@ -17,15 +17,15 @@ public class LocalVar implements ILocalVar {
|
||||
private int startOffset;
|
||||
private int endOffset;
|
||||
|
||||
public LocalVar(SectionReader dex, int regNum, int nameId, int typeId, int signId) {
|
||||
public DexLocalVar(SectionReader dex, int regNum, int nameId, int typeId, int signId) {
|
||||
this(regNum, dex.getString(nameId), dex.getType(typeId), dex.getString(signId));
|
||||
}
|
||||
|
||||
public LocalVar(int regNum, String name, String type) {
|
||||
public DexLocalVar(int regNum, String name, String type) {
|
||||
this(regNum, name, type, null);
|
||||
}
|
||||
|
||||
public LocalVar(int regNum, String name, String type, @Nullable String sign) {
|
||||
public DexLocalVar(int regNum, String name, String type, @Nullable String sign) {
|
||||
this.regNum = regNum;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
@@ -99,7 +99,7 @@ public class LocalVar implements ILocalVar {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Utils.formatOffset(startOffset)
|
||||
return (startOffset == -1 ? "-1 " : Utils.formatOffset(startOffset))
|
||||
+ '-' + (isEnd ? Utils.formatOffset(endOffset) : " ")
|
||||
+ ": r" + regNum + " '" + name + "' " + type
|
||||
+ (sign != null ? ", signature: " + sign : "");
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
package jadx.plugins.input.dex.sections.trycatch;
|
||||
|
||||
import jadx.api.plugins.input.data.ICatch;
|
||||
|
||||
public class DexCatch implements ICatch {
|
||||
private final int[] addr;
|
||||
private final String[] types;
|
||||
private final int allAddr;
|
||||
|
||||
public DexCatch(int[] addr, String[] types, int allAddr) {
|
||||
this.addr = addr;
|
||||
this.types = types;
|
||||
this.allAddr = allAddr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getAddresses() {
|
||||
return addr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getTypes() {
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCatchAllAddress() {
|
||||
return allAddr;
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
package jadx.plugins.input.dex.sections.trycatch;
|
||||
|
||||
import jadx.api.plugins.input.data.ICatch;
|
||||
import jadx.api.plugins.input.data.ITry;
|
||||
|
||||
public class DexTryData implements ITry {
|
||||
|
||||
private final ICatch catchHandler;
|
||||
private final int startAddr;
|
||||
private final int insnsCount;
|
||||
|
||||
public DexTryData(ICatch catchHandler, int startAddr, int insnsCount) {
|
||||
this.catchHandler = catchHandler;
|
||||
this.startAddr = startAddr;
|
||||
this.insnsCount = insnsCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICatch getCatch() {
|
||||
return catchHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStartAddress() {
|
||||
return startAddr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInstructionCount() {
|
||||
return insnsCount;
|
||||
}
|
||||
}
|
||||
+2
-3
@@ -1,8 +1,7 @@
|
||||
package jadx.plugins.input.dex.smali;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import jadx.api.plugins.input.data.*;
|
||||
import jadx.api.plugins.input.data.AccessFlags;
|
||||
import jadx.api.plugins.input.data.ICodeReader;
|
||||
import jadx.plugins.input.dex.sections.DexMethodData;
|
||||
import jadx.plugins.input.dex.sections.DexMethodRef;
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
package jadx.plugins.input.dex.utils;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class Utils {
|
||||
|
||||
public static <T> String listToStr(List<T> collection) {
|
||||
if (collection == null) {
|
||||
return "null";
|
||||
}
|
||||
if (collection.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
Iterator<T> it = collection.iterator();
|
||||
if (it.hasNext()) {
|
||||
sb.append(it.next());
|
||||
}
|
||||
while (it.hasNext()) {
|
||||
sb.append(", ").append(it.next());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String formatOffset(int offset) {
|
||||
return String.format("0x%04x", offset);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -46,7 +46,7 @@ class DexInputPluginTest {
|
||||
System.out.println("AccessFlags: " + AccessFlags.format(cls.getAccessFlags(), AccessFlagsScope.CLASS));
|
||||
System.out.println("SuperType: " + cls.getSuperType());
|
||||
System.out.println("Interfaces: " + cls.getInterfacesTypes());
|
||||
System.out.println("SourceFile: " + cls.getSourceFile());
|
||||
System.out.println("Attributes: " + cls.getAttributes());
|
||||
count.getAndIncrement();
|
||||
|
||||
cls.visitFieldsAndMethods(
|
||||
|
||||
Reference in New Issue
Block a user