refactor: use own dex parser instead deprecated dx lib

This commit is contained in:
Skylot
2020-04-29 17:24:44 +01:00
parent 09e267f8bc
commit 0d69e0ac97
181 changed files with 6779 additions and 3072 deletions
@@ -0,0 +1,5 @@
package jadx.api.plugins;
public interface JadxPlugin {
JadxPluginInfo getPluginInfo();
}
@@ -0,0 +1,30 @@
package jadx.api.plugins;
public class JadxPluginInfo {
private final String pluginId;
private final String name;
private final String description;
public JadxPluginInfo(String id, String name, String description) {
this.pluginId = id;
this.name = name;
this.description = description;
}
public String getPluginId() {
return pluginId;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return name + " - '" + description + '\'';
}
}
@@ -0,0 +1,44 @@
package jadx.api.plugins;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceLoader;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jadx.api.plugins.input.JadxInputPlugin;
public class JadxPluginManager {
private static final Logger LOG = LoggerFactory.getLogger(JadxPluginManager.class);
private final Map<Class<? extends JadxPlugin>, JadxPlugin> allPlugins = new HashMap<>();
public JadxPluginManager() {
ServiceLoader<JadxPlugin> jadxPlugins = ServiceLoader.load(JadxPlugin.class);
for (JadxPlugin jadxPlugin : jadxPlugins) {
register(jadxPlugin);
}
}
public void register(JadxPlugin plugin) {
Objects.requireNonNull(plugin);
LOG.debug("Loaded plugin: {}", plugin.getPluginInfo().getName());
allPlugins.put(plugin.getClass(), plugin);
}
public List<JadxPlugin> getAllPlugins() {
return new ArrayList<>(allPlugins.values());
}
public List<JadxInputPlugin> getInputPlugins() {
return allPlugins.values().stream()
.filter(JadxInputPlugin.class::isInstance)
.map(JadxInputPlugin.class::cast)
.collect(Collectors.toList());
}
}
@@ -0,0 +1,11 @@
package jadx.api.plugins.input;
import java.nio.file.Path;
import java.util.List;
import jadx.api.plugins.JadxPlugin;
import jadx.api.plugins.input.data.ILoadResult;
public interface JadxInputPlugin extends JadxPlugin {
ILoadResult loadFiles(List<Path> input);
}
@@ -0,0 +1,91 @@
package jadx.api.plugins.input.data;
public class AccessFlags {
public static final int PUBLIC = 0x1;
public static final int PRIVATE = 0x2;
public static final int PROTECTED = 0x4;
public static final int STATIC = 0x8;
public static final int FINAL = 0x10;
public static final int SYNCHRONIZED = 0x20;
public static final int SUPER = 0x20;
public static final int VOLATILE = 0x40;
public static final int BRIDGE = 0x40;
public static final int TRANSIENT = 0x80;
public static final int VARARGS = 0x80;
public static final int NATIVE = 0x100;
public static final int INTERFACE = 0x200;
public static final int ABSTRACT = 0x400;
public static final int STRICT = 0x800;
public static final int SYNTHETIC = 0x1000;
public static final int ANNOTATION = 0x2000;
public static final int ENUM = 0x4000;
public static final int CONSTRUCTOR = 0x10000;
public static final int DECLARED_SYNCHRONIZED = 0x20000;
public static boolean hasFlag(int flags, int flagValue) {
return (flags & flagValue) != 0;
}
public static String format(int flags, AccessFlagsScope scope) {
StringBuilder code = new StringBuilder();
if (hasFlag(flags, PUBLIC)) {
code.append("public ");
}
if (hasFlag(flags, PRIVATE)) {
code.append("private ");
}
if (hasFlag(flags, PROTECTED)) {
code.append("protected ");
}
if (hasFlag(flags, STATIC)) {
code.append("static ");
}
if (hasFlag(flags, FINAL)) {
code.append("final ");
}
if (hasFlag(flags, ABSTRACT)) {
code.append("abstract ");
}
if (hasFlag(flags, NATIVE)) {
code.append("native ");
}
switch (scope) {
case METHOD:
if (hasFlag(flags, SYNCHRONIZED)) {
code.append("synchronized ");
}
if (hasFlag(flags, BRIDGE)) {
code.append("bridge ");
}
if (hasFlag(flags, VARARGS)) {
code.append("varargs ");
}
break;
case FIELD:
if (hasFlag(flags, VOLATILE)) {
code.append("volatile ");
}
if (hasFlag(flags, TRANSIENT)) {
code.append("transient ");
}
break;
case CLASS:
if (hasFlag(flags, STRICT)) {
code.append("strict ");
}
if (hasFlag(flags, SUPER)) {
code.append("super ");
}
if (hasFlag(flags, ENUM)) {
code.append("enum ");
}
break;
}
if (hasFlag(flags, SYNTHETIC)) {
code.append("synthetic ");
}
return code.toString();
}
}
@@ -0,0 +1,5 @@
package jadx.api.plugins.input.data;
public enum AccessFlagsScope {
CLASS, FIELD, METHOD
}
@@ -0,0 +1,9 @@
package jadx.api.plugins.input.data;
public interface ICatch {
String[] getTypes();
int[] getAddresses();
int getCatchAllAddress();
}
@@ -0,0 +1,35 @@
package jadx.api.plugins.input.data;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import jadx.api.plugins.input.data.annotations.EncodedValue;
import jadx.api.plugins.input.data.annotations.IAnnotation;
public interface IClassData {
String getType();
int getAccessFlags();
@Nullable
String getSuperType();
List<String> getInterfacesTypes();
String getSourceFile();
Path getInputPath();
void visitFieldsAndMethods(Consumer<IFieldData> fieldsConsumer, Consumer<IMethodData> mthConsumer);
List<EncodedValue> getStaticFieldInitValues();
List<IAnnotation> getAnnotations();
// TODO: make api methods to get dissembled code
int getClassDefOffset();
}
@@ -0,0 +1,25 @@
package jadx.api.plugins.input.data;
import java.util.List;
import java.util.function.Consumer;
import org.jetbrains.annotations.Nullable;
import jadx.api.plugins.input.insns.InsnData;
public interface ICodeReader {
ICodeReader copy();
void visitInstructions(Consumer<InsnData> insnConsumer);
int getRegistersCount();
int getInsnsCount();
@Nullable
IDebugInfo getDebugInfo();
int getCodeOffset();
List<ITry> getTries();
}
@@ -0,0 +1,14 @@
package jadx.api.plugins.input.data;
import java.util.List;
import java.util.Map;
public interface IDebugInfo {
/**
* Map instruction offset to source line number
*/
Map<Integer, Integer> getSourceLineMapping();
List<ILocalVar> getLocalVars();
}
@@ -0,0 +1,17 @@
package jadx.api.plugins.input.data;
import java.util.List;
import jadx.api.plugins.input.data.annotations.IAnnotation;
public interface IFieldData {
String getParentClassType();
String getType();
String getName();
int getAccessFlags();
List<IAnnotation> getAnnotations();
}
@@ -0,0 +1,10 @@
package jadx.api.plugins.input.data;
import java.io.Closeable;
import java.util.function.Consumer;
public interface ILoadResult extends Closeable {
void visitClasses(Consumer<IClassData> consumer);
void visitResources(Consumer<IResourceData> consumer);
}
@@ -0,0 +1,18 @@
package jadx.api.plugins.input.data;
import org.jetbrains.annotations.Nullable;
public interface ILocalVar {
String getName();
int getRegNum();
String getType();
@Nullable
String getSignature();
int getStartOffset();
int getEndOffset();
}
@@ -0,0 +1,30 @@
package jadx.api.plugins.input.data;
import java.util.List;
import org.jetbrains.annotations.Nullable;
import jadx.api.plugins.input.data.annotations.IAnnotation;
public interface IMethodData {
String getParentClassType();
String getName();
int getAccessFlags();
String getReturnType();
List<String> getArgTypes();
boolean isDirect();
@Nullable
ICodeReader getCodeReader();
String disassembleMethod();
List<IAnnotation> getAnnotations();
List<List<IAnnotation>> getParamsAnnotations();
}
@@ -0,0 +1,4 @@
package jadx.api.plugins.input.data;
public interface IResourceData {
}
@@ -0,0 +1,9 @@
package jadx.api.plugins.input.data;
public interface ITry {
ICatch getCatch();
int getStartAddress();
int getInstructionCount();
}
@@ -0,0 +1,7 @@
package jadx.api.plugins.input.data.annotations;
public enum AnnotationVisibility {
BUILD,
RUNTIME,
SYSTEM
}
@@ -0,0 +1,20 @@
package jadx.api.plugins.input.data.annotations;
public enum EncodedType {
ENCODED_NULL,
ENCODED_BOOLEAN,
ENCODED_BYTE,
ENCODED_SHORT,
ENCODED_CHAR,
ENCODED_INT,
ENCODED_LONG,
ENCODED_FLOAT,
ENCODED_DOUBLE,
ENCODED_STRING,
ENCODED_TYPE,
ENCODED_ENUM,
ENCODED_FIELD,
ENCODED_METHOD,
ENCODED_ARRAY,
ENCODED_ANNOTATION
}
@@ -0,0 +1,33 @@
package jadx.api.plugins.input.data.annotations;
public class EncodedValue {
public static final EncodedValue NULL = new EncodedValue(EncodedType.ENCODED_NULL, new Object());
private final EncodedType type;
private final Object value;
public EncodedValue(EncodedType type, Object value) {
this.type = type;
this.value = value;
}
public EncodedType getType() {
return type;
}
public Object getValue() {
return value;
}
@Override
public String toString() {
switch (type) {
case ENCODED_STRING:
return (String) value;
case ENCODED_ARRAY:
return "[" + value + "]";
default:
return "{" + type + ": " + value + '}';
}
}
}
@@ -0,0 +1,18 @@
package jadx.api.plugins.input.data.annotations;
import java.util.Map;
import org.jetbrains.annotations.Nullable;
public interface IAnnotation {
String getAnnotationClass();
AnnotationVisibility getVisibility();
Map<String, EncodedValue> getValues();
@Nullable
default EncodedValue getDefaultValue() {
return getValues().get("value");
}
}
@@ -0,0 +1,25 @@
package jadx.api.plugins.input.data.impl;
import java.io.IOException;
import java.util.function.Consumer;
import jadx.api.plugins.input.data.IClassData;
import jadx.api.plugins.input.data.ILoadResult;
import jadx.api.plugins.input.data.IResourceData;
public class EmptyLoadResult implements ILoadResult {
public static final EmptyLoadResult INSTANCE = new EmptyLoadResult();
@Override
public void visitClasses(Consumer<IClassData> consumer) {
}
@Override
public void visitResources(Consumer<IResourceData> consumer) {
}
@Override
public void close() throws IOException {
}
}
@@ -0,0 +1,41 @@
package jadx.api.plugins.input.insns;
import org.jetbrains.annotations.Nullable;
import jadx.api.plugins.input.data.IFieldData;
import jadx.api.plugins.input.data.IMethodData;
import jadx.api.plugins.input.insns.custom.ICustomPayload;
public interface InsnData {
void decode();
int getOffset();
Opcode getOpcode();
InsnIndexType getIndexType();
int getRawOpcodeUnit();
int getRegsCount();
int getReg(int argNum);
long getLiteral();
int getTarget();
int getIndex();
String getIndexAsString();
String getIndexAsType();
IFieldData getIndexAsField();
IMethodData getIndexAsMethod();
@Nullable
ICustomPayload getPayload();
}
@@ -0,0 +1,9 @@
package jadx.api.plugins.input.insns;
public enum InsnIndexType {
NONE,
TYPE_REF,
STRING_REF,
FIELD_REF,
METHOD_REF
}
@@ -0,0 +1,193 @@
package jadx.api.plugins.input.insns;
public enum Opcode {
UNKNOWN,
NOP,
ADD_DOUBLE,
ADD_FLOAT,
ADD_INT,
ADD_INT_LIT,
ADD_LONG,
AND_INT,
AND_INT_LIT,
AND_LONG,
AGET,
AGET_BOOLEAN,
AGET_BYTE,
AGET_CHAR,
AGET_OBJECT,
AGET_SHORT,
AGET_WIDE,
APUT,
APUT_BOOLEAN,
APUT_BYTE,
APUT_CHAR,
APUT_OBJECT,
APUT_SHORT,
APUT_WIDE,
ARITH,
ARRAY_LENGTH,
CAST,
CHECK_CAST,
CMPG_DOUBLE,
CMPG_FLOAT,
CMPL_DOUBLE,
CMPL_FLOAT,
CMP_G,
CMP_L,
CMP_LONG,
CONST,
CONST_CLASS,
CONST_STRING,
CONST_WIDE,
DIV_DOUBLE,
DIV_FLOAT,
DIV_INT,
DIV_INT_LIT,
DIV_LONG,
DOUBLE_TO_FLOAT,
DOUBLE_TO_INT,
DOUBLE_TO_LONG,
FLOAT_TO_DOUBLE,
FLOAT_TO_INT,
FLOAT_TO_LONG,
GOTO,
IF,
IF_EQ,
IF_EQZ,
IF_GE,
IF_GEZ,
IF_GT,
IF_GTZ,
IF_LE,
IF_LEZ,
IF_LT,
IF_LTZ,
IF_NE,
IF_NEZ,
INSTANCE_OF,
INT_TO_BYTE,
INT_TO_CHAR,
INT_TO_DOUBLE,
INT_TO_FLOAT,
INT_TO_LONG,
INT_TO_SHORT,
INVOKE_DIRECT,
INVOKE_DIRECT_RANGE,
INVOKE_INTERFACE,
INVOKE_INTERFACE_RANGE,
INVOKE_STATIC,
INVOKE_STATIC_RANGE,
INVOKE_SUPER,
INVOKE_SUPER_RANGE,
INVOKE_VIRTUAL,
INVOKE_VIRTUAL_RANGE,
IGET,
IPUT,
SGET,
SPUT,
LONG_TO_DOUBLE,
LONG_TO_FLOAT,
LONG_TO_INT,
MONITOR_ENTER,
MONITOR_EXIT,
MOVE,
MOVE_EXCEPTION,
MOVE_OBJECT,
MOVE_RESULT,
MOVE_WIDE,
MUL_DOUBLE,
MUL_FLOAT,
MUL_INT,
MUL_INT_LIT,
MUL_LONG,
NEG,
NEG_DOUBLE,
NEG_FLOAT,
NEG_INT,
NEG_LONG,
NEW_INSTANCE,
NOT,
NOT_INT,
NOT_LONG,
OR_INT,
OR_INT_LIT,
OR_LONG,
REM_DOUBLE,
REM_FLOAT,
REM_INT,
REM_INT_LIT,
REM_LONG,
RETURN,
RETURN_VOID,
RSUB_INT,
SHL_INT,
SHL_INT_LIT,
SHL_LONG,
SHR_INT,
SHR_INT_LIT,
SHR_LONG,
SUB_DOUBLE,
SUB_FLOAT,
SUB_INT,
SUB_LONG,
THROW,
USHR_INT,
USHR_INT_LIT,
USHR_LONG,
XOR_INT,
XOR_INT_LIT,
XOR_LONG,
NEW_ARRAY,
FILLED_NEW_ARRAY,
FILLED_NEW_ARRAY_RANGE,
FILL_ARRAY,
FILL_ARRAY_DATA,
FILL_ARRAY_DATA_PAYLOAD,
SWITCH,
PACKED_SWITCH,
PACKED_SWITCH_PAYLOAD,
SPARSE_SWITCH,
SPARSE_SWITCH_PAYLOAD,
INVOKE_POLYMORPHIC,
INVOKE_POLYMORPHIC_RANGE,
INVOKE_CUSTOM,
INVOKE_CUSTOM_RANGE,
CONST_METHOD_HANDLE,
CONST_METHOD_TYPE,
}
@@ -0,0 +1,9 @@
package jadx.api.plugins.input.insns.custom;
public interface IArrayPayload extends ICustomPayload {
int getSize();
int getElementSize();
Object getData();
}
@@ -0,0 +1,4 @@
package jadx.api.plugins.input.insns.custom;
public interface ICustomPayload {
}
@@ -0,0 +1,9 @@
package jadx.api.plugins.input.insns.custom;
public interface ISwitchPayload extends ICustomPayload {
int getSize();
int[] getKeys();
int[] getTargets();
}