mirror of
https://github.com/revanced/smali.git
synced 2025-05-23 18:16:23 +02:00
Improve how invalid references are handled
This adds a validateReference() method to the Reference interface, where subclasses can check themselves and throw an InvalidReferenceException
This commit is contained in:
parent
ad8f15d61d
commit
4eb5e48578
@ -31,18 +31,21 @@ package org.jf.baksmali.Adaptors;
|
||||
import org.jf.baksmali.BaksmaliOptions;
|
||||
import org.jf.dexlib2.AccessFlags;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||
import org.jf.dexlib2.iface.*;
|
||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
||||
import org.jf.dexlib2.iface.reference.FieldReference;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
import org.jf.dexlib2.util.ReferenceUtil;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.jf.util.StringUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class ClassDefinition {
|
||||
@Nonnull public final BaksmaliOptions options;
|
||||
@ -79,16 +82,14 @@ public class ClassDefinition {
|
||||
case SPUT_SHORT:
|
||||
case SPUT_WIDE: {
|
||||
Instruction21c ins = (Instruction21c)instruction;
|
||||
FieldReference fieldRef = null;
|
||||
FieldReference fieldRef = (FieldReference)ins.getReference();
|
||||
try {
|
||||
fieldRef = (FieldReference)ins.getReference();
|
||||
} catch (InvalidItemIndex ex) {
|
||||
// just ignore it for now. We'll deal with it later, when processing the instructions
|
||||
// themselves
|
||||
}
|
||||
if (fieldRef != null &&
|
||||
fieldRef.getDefiningClass().equals((classDef.getType()))) {
|
||||
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
|
||||
fieldRef.validateReference();
|
||||
if (fieldRef.getDefiningClass().equals((classDef.getType()))) {
|
||||
fieldsSetInStaticConstructor.add(ReferenceUtil.getShortFieldDescriptor(fieldRef));
|
||||
}
|
||||
} catch (Reference.InvalidReferenceException ex) {
|
||||
// Just ignore for now. We'll deal with it when processing the instruction
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -32,12 +32,10 @@ import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition.InvalidSwitchPayload;
|
||||
import org.jf.baksmali.Adaptors.MethodItem;
|
||||
import org.jf.baksmali.Adaptors.ReferenceFormatter;
|
||||
import org.jf.baksmali.Renderers.LongRenderer;
|
||||
import org.jf.baksmali.BaksmaliOptions;
|
||||
import org.jf.baksmali.Renderers.LongRenderer;
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.VerificationError;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||
import org.jf.dexlib2.iface.instruction.*;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction20bc;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
|
||||
@ -81,14 +79,6 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
return opcode.isVolatileFieldAccessor() || opcode == Opcode.THROW_VERIFICATION_ERROR;
|
||||
}
|
||||
|
||||
private String writeInvalidItemIndex(InvalidItemIndex ex, int type, IndentingWriter writer)
|
||||
throws IOException {
|
||||
writer.write("#");
|
||||
writer.write(ex.getMessage());
|
||||
writer.write("\n");
|
||||
return String.format("%s@%d", ReferenceType.toString(type), ex.getInvalidIndex());
|
||||
}
|
||||
|
||||
private interface Writable {
|
||||
void writeTo(IndentingWriter writer) throws IOException;
|
||||
}
|
||||
@ -122,8 +112,11 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
classContext = null;
|
||||
}
|
||||
|
||||
Reference reference = referenceInstruction.getReference();
|
||||
|
||||
try {
|
||||
Reference reference = referenceInstruction.getReference();
|
||||
reference.validateReference();
|
||||
|
||||
if (reference instanceof CallSiteReference) {
|
||||
referenceWritable = indentingWriter -> {
|
||||
ReferenceFormatter.writeCallSiteReference(indentingWriter, (CallSiteReference)reference);
|
||||
@ -133,16 +126,14 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
indentingWriter.write(ReferenceUtil.getReferenceString(reference, classContext));
|
||||
};
|
||||
}
|
||||
} catch (InvalidItemIndex ex) {
|
||||
} catch (Reference.InvalidReferenceException ex) {
|
||||
commentOutInstruction = true;
|
||||
String referenceString = writeInvalidItemIndex(ex, referenceInstruction.getReferenceType(),
|
||||
writer);
|
||||
referenceWritable = indentingWriter -> writer.write(referenceString);
|
||||
} catch (ReferenceType.InvalidReferenceTypeException ex) {
|
||||
writer.write("#invalid reference type: ");
|
||||
writer.printSignedIntAsDec(ex.getReferenceType());
|
||||
commentOutInstruction = true;
|
||||
referenceWritable = indentingWriter -> writer.write("invalid_reference");
|
||||
writer.write("#");
|
||||
writer.write(ex.getMessage());
|
||||
writer.write("\n");
|
||||
referenceWritable = indentingWriter -> {
|
||||
indentingWriter.write(ex.getInvalidReferenceRepresentation());
|
||||
};
|
||||
}
|
||||
|
||||
if (instruction instanceof DualReferenceInstruction) {
|
||||
@ -150,19 +141,19 @@ public class InstructionMethodItem<T extends Instruction> extends MethodItem {
|
||||
(DualReferenceInstruction) instruction;
|
||||
try {
|
||||
Reference reference2 = dualReferenceInstruction.getReference2();
|
||||
reference2.validateReference();
|
||||
|
||||
referenceWritable2 = indentingWriter -> {
|
||||
indentingWriter.write(ReferenceUtil.getReferenceString(reference2, classContext));
|
||||
};
|
||||
} catch (InvalidItemIndex ex) {
|
||||
} catch (Reference.InvalidReferenceException ex) {
|
||||
commentOutInstruction = true;
|
||||
String referenceString = writeInvalidItemIndex(ex,
|
||||
dualReferenceInstruction.getReferenceType2(), writer);
|
||||
referenceWritable2 = indentingWriter -> indentingWriter.write(referenceString);
|
||||
} catch (ReferenceType.InvalidReferenceTypeException ex) {
|
||||
writer.write("#invalid reference type: ");
|
||||
writer.printSignedIntAsDec(ex.getReferenceType());
|
||||
commentOutInstruction = true;
|
||||
referenceWritable2 = indentingWriter -> indentingWriter.write("invalid reference");
|
||||
writer.write("#");
|
||||
writer.write(ex.getMessage());
|
||||
writer.write("\n");
|
||||
referenceWritable = indentingWriter -> {
|
||||
indentingWriter.write(ex.getInvalidReferenceRepresentation());
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.analysis.AnalysisException;
|
||||
import org.jf.dexlib2.analysis.AnalyzedInstruction;
|
||||
import org.jf.dexlib2.analysis.MethodAnalyzer;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile.InvalidItemIndex;
|
||||
import org.jf.dexlib2.iface.*;
|
||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
@ -48,6 +47,7 @@ import org.jf.dexlib2.iface.instruction.OffsetInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31t;
|
||||
import org.jf.dexlib2.iface.reference.MethodReference;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
import org.jf.dexlib2.immutable.instruction.ImmutableInstruction31t;
|
||||
import org.jf.dexlib2.util.InstructionOffsetMap;
|
||||
import org.jf.dexlib2.util.InstructionOffsetMap.InvalidInstructionOffset;
|
||||
@ -437,21 +437,21 @@ public class MethodDefinition {
|
||||
Opcode opcode = instruction.getOpcode();
|
||||
|
||||
if (opcode.referenceType == ReferenceType.METHOD) {
|
||||
MethodReference methodReference = null;
|
||||
try {
|
||||
methodReference = (MethodReference)((ReferenceInstruction)instruction).getReference();
|
||||
} catch (InvalidItemIndex ex) {
|
||||
// just ignore it for now. We'll deal with it later, when processing the instructions
|
||||
// themselves
|
||||
}
|
||||
MethodReference methodReference =
|
||||
(MethodReference)((ReferenceInstruction)instruction).getReference();
|
||||
|
||||
if (methodReference != null &&
|
||||
SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
|
||||
AccessedMember accessedMember =
|
||||
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
|
||||
if (accessedMember != null) {
|
||||
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
|
||||
try {
|
||||
methodReference.validateReference();
|
||||
|
||||
if (SyntheticAccessorResolver.looksLikeSyntheticAccessor(methodReference.getName())) {
|
||||
AccessedMember accessedMember =
|
||||
classDef.options.syntheticAccessorResolver.getAccessedMember(methodReference);
|
||||
if (accessedMember != null) {
|
||||
methodItems.add(new SyntheticAccessCommentMethodItem(accessedMember, currentCodeAddress));
|
||||
}
|
||||
}
|
||||
} catch (Reference.InvalidReferenceException e) {
|
||||
// Just ignore for now. We'll deal with it when processing the instruction
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright 2019, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.baksmali;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import org.jf.baksmali.Adaptors.ClassDefinition;
|
||||
import org.jf.baksmali.Adaptors.Format.InstructionMethodItem;
|
||||
import org.jf.baksmali.Adaptors.MethodDefinition;
|
||||
import org.jf.baksmali.Adaptors.RegisterFormatter;
|
||||
import org.jf.dexlib2.Format;
|
||||
import org.jf.dexlib2.Opcode;
|
||||
import org.jf.dexlib2.ReferenceType;
|
||||
import org.jf.dexlib2.base.reference.BaseMethodReference;
|
||||
import org.jf.dexlib2.base.reference.BaseStringReference;
|
||||
import org.jf.dexlib2.base.reference.BaseTypeReference;
|
||||
import org.jf.dexlib2.iface.*;
|
||||
import org.jf.dexlib2.iface.debug.DebugItem;
|
||||
import org.jf.dexlib2.iface.instruction.Instruction;
|
||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c;
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class InstructionMethodItemTest {
|
||||
|
||||
@Test
|
||||
public void testInvalidReference() throws IOException {
|
||||
|
||||
Instruction21c instruction = new Instruction21c() {
|
||||
@Override
|
||||
public int getRegisterA() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Reference getReference() {
|
||||
return new BaseStringReference() {
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
throw new InvalidReferenceException("blahblahblah");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getString() {
|
||||
throw new RuntimeException("invalid reference");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getReferenceType() {
|
||||
return ReferenceType.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Opcode getOpcode() {
|
||||
return Opcode.CONST_STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCodeUnits() {
|
||||
return Format.Format21c.size / 2;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
MethodImplementation methodImplementation = new MethodImplementation() {
|
||||
@Override
|
||||
public int getRegisterCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterable<? extends Instruction> getInstructions() {
|
||||
return ImmutableList.of(instruction);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterable<? extends DebugItem> getDebugItems() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
};
|
||||
|
||||
Method method = new TestMethod(methodImplementation);
|
||||
|
||||
ClassDefinition classDefinition = new ClassDefinition(
|
||||
new BaksmaliOptions(), new TestClassDef());
|
||||
|
||||
MethodDefinition methodDefinition = new MethodDefinition(classDefinition, method, methodImplementation);
|
||||
methodDefinition.registerFormatter = new RegisterFormatter(new BaksmaliOptions(), 1, 0);
|
||||
|
||||
InstructionMethodItem methodItem = new InstructionMethodItem<Instruction21c>(methodDefinition, 0, instruction);
|
||||
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
IndentingWriter indentingWriter = new IndentingWriter(stringWriter);
|
||||
methodItem.writeTo(indentingWriter);
|
||||
|
||||
Assert.assertEquals("#Invalid reference\n#const-string v0, blahblahblah\nnop", stringWriter.toString());
|
||||
}
|
||||
|
||||
private static class TestMethod extends BaseMethodReference implements Method {
|
||||
private final MethodImplementation methodImplementation;
|
||||
|
||||
public TestMethod(MethodImplementation methodImplementation) {
|
||||
this.methodImplementation = methodImplementation;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends MethodParameter> getParameters() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAccessFlags() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<? extends Annotation> getAnnotations() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public MethodImplementation getImplementation() {
|
||||
return methodImplementation;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getDefiningClass() {
|
||||
return "Ltest;";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return "test";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<? extends CharSequence> getParameterTypes() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getReturnType() {
|
||||
return "V";
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestClassDef extends BaseTypeReference implements ClassDef {
|
||||
@Override
|
||||
public int getAccessFlags() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSuperclass() {
|
||||
return "Ljava/lang/Object;";
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<String> getInterfaces() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getSourceFile() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Set<? extends Annotation> getAnnotations() {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterable<? extends Field> getStaticFields() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterable<? extends Field> getInstanceFields() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterable<? extends Field> getFields() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterable<? extends Method> getDirectMethods() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterable<? extends Method> getVirtualMethods() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Iterable<? extends Method> getMethods() {
|
||||
return ImmutableList.of();
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getType() {
|
||||
return "Ltest;";
|
||||
}
|
||||
}
|
||||
}
|
@ -44,27 +44,6 @@ public final class ReferenceType {
|
||||
public static final int METHOD_HANDLE = 6;
|
||||
public static final int NONE = 7;
|
||||
|
||||
public static String toString(int referenceType) {
|
||||
switch (referenceType) {
|
||||
case STRING:
|
||||
return "string";
|
||||
case TYPE:
|
||||
return "type";
|
||||
case FIELD:
|
||||
return "field";
|
||||
case METHOD:
|
||||
return "method";
|
||||
case METHOD_PROTO:
|
||||
return "method_proto";
|
||||
case CALL_SITE:
|
||||
return "call_site";
|
||||
case METHOD_HANDLE:
|
||||
return "method_handle";
|
||||
default:
|
||||
throw new InvalidReferenceTypeException(referenceType);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getReferenceType(Reference reference) {
|
||||
if (reference instanceof StringReference) {
|
||||
return STRING;
|
||||
|
@ -33,7 +33,7 @@ package org.jf.dexlib2.base.reference;
|
||||
|
||||
import org.jf.dexlib2.iface.reference.CallSiteReference;
|
||||
|
||||
public abstract class BaseCallSiteReference implements CallSiteReference {
|
||||
public abstract class BaseCallSiteReference extends BaseReference implements CallSiteReference {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getName().hashCode();
|
||||
|
@ -37,7 +37,7 @@ import org.jf.dexlib2.util.ReferenceUtil;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class BaseFieldReference implements FieldReference {
|
||||
public abstract class BaseFieldReference extends BaseReference implements FieldReference {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getDefiningClass().hashCode();
|
||||
|
@ -39,7 +39,7 @@ import org.jf.dexlib2.iface.reference.Reference;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public abstract class BaseMethodHandleReference implements MethodHandleReference {
|
||||
public abstract class BaseMethodHandleReference extends BaseReference implements MethodHandleReference {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getMethodHandleType();
|
||||
|
@ -41,7 +41,7 @@ import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
public abstract class BaseMethodProtoReference implements MethodProtoReference {
|
||||
public abstract class BaseMethodProtoReference extends BaseReference implements MethodProtoReference {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getReturnType().hashCode();
|
||||
|
@ -40,7 +40,7 @@ import org.jf.util.CollectionUtils;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class BaseMethodReference implements MethodReference {
|
||||
public abstract class BaseMethodReference extends BaseReference implements MethodReference {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hashCode = getDefiningClass().hashCode();
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2019, Google Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name of Google Inc. nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package org.jf.dexlib2.base.reference;
|
||||
|
||||
import org.jf.dexlib2.iface.reference.Reference;
|
||||
|
||||
public abstract class BaseReference implements Reference {
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
// A reference is valid by default
|
||||
}
|
||||
}
|
@ -36,7 +36,7 @@ import org.jf.dexlib2.iface.reference.StringReference;
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class BaseStringReference implements StringReference {
|
||||
public abstract class BaseStringReference extends BaseReference implements StringReference {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getString().hashCode();
|
||||
|
@ -35,7 +35,7 @@ import org.jf.dexlib2.iface.reference.TypeReference;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
public abstract class BaseTypeReference implements TypeReference {
|
||||
public abstract class BaseTypeReference extends BaseReference implements TypeReference {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getType().hashCode();
|
||||
|
@ -52,8 +52,19 @@ public class DexBackedInstruction20bc extends DexBackedInstruction implements In
|
||||
@Nonnull
|
||||
@Override
|
||||
public Reference getReference() {
|
||||
int referenceType = getReferenceType();
|
||||
return DexBackedReference.makeReference(dexFile, referenceType, dexFile.readUshort(instructionStart + 2));
|
||||
int referenceIndex = dexFile.readUshort(instructionStart + 2);
|
||||
try {
|
||||
int referenceType = getReferenceType();
|
||||
return DexBackedReference.makeReference(dexFile, referenceType, referenceIndex);
|
||||
} catch (ReferenceType.InvalidReferenceTypeException ex) {
|
||||
return new Reference() {
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
throw new InvalidReferenceException(String.format("%d@%d", ex.getReferenceType(), referenceIndex),
|
||||
ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int getReferenceType() {
|
||||
|
@ -157,4 +157,11 @@ public class DexBackedCallSiteReference extends BaseCallSiteReference {
|
||||
}
|
||||
return callSiteOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
if (callSiteIndex < 0 || callSiteIndex >= dexFile.getCallSiteCount()) {
|
||||
throw new InvalidReferenceException("callsite@" + callSiteIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,29 +39,30 @@ import javax.annotation.Nonnull;
|
||||
|
||||
public class DexBackedFieldReference extends BaseFieldReference {
|
||||
@Nonnull public final DexBackedDexFile dexFile;
|
||||
public final int fieldIdItemOffset;
|
||||
private final int fieldIndex;
|
||||
|
||||
public DexBackedFieldReference(@Nonnull DexBackedDexFile dexFile, int fieldIndex) {
|
||||
this.dexFile = dexFile;
|
||||
this.fieldIdItemOffset = dexFile.getFieldIdItemOffset(fieldIndex);
|
||||
this.fieldIndex = fieldIndex;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getDefiningClass() {
|
||||
return dexFile.getType(dexFile.readUshort(fieldIdItemOffset + FieldIdItem.CLASS_OFFSET));
|
||||
return dexFile.getType(dexFile.readUshort(dexFile.getFieldIdItemOffset(fieldIndex) + FieldIdItem.CLASS_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return dexFile.getString(dexFile.readSmallUint(fieldIdItemOffset + FieldIdItem.NAME_OFFSET));
|
||||
return dexFile.getString(dexFile.readSmallUint(dexFile.getFieldIdItemOffset(fieldIndex) +
|
||||
FieldIdItem.NAME_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getType() {
|
||||
return dexFile.getType(dexFile.readUshort(fieldIdItemOffset + FieldIdItem.TYPE_OFFSET));
|
||||
return dexFile.getType(dexFile.readUshort(dexFile.getFieldIdItemOffset(fieldIndex) + FieldIdItem.TYPE_OFFSET));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,4 +75,11 @@ public class DexBackedFieldReference extends BaseFieldReference {
|
||||
public int getSize() {
|
||||
return FieldIdItem.ITEM_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
if (fieldIndex < 0 || fieldIndex >= dexFile.getFieldCount()) {
|
||||
throw new InvalidReferenceException("field@" + fieldIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -76,4 +76,17 @@ public class DexBackedMethodHandleReference extends BaseMethodHandleReference {
|
||||
throw new ExceptionWithContext("Invalid method handle type: %d", getMethodHandleType());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
if (methodHandleIndex < 0 || methodHandleIndex >= dexFile.getMethodHandleCount()) {
|
||||
throw new InvalidReferenceException("methodhandle@" + methodHandleIndex);
|
||||
}
|
||||
|
||||
try {
|
||||
getMemberReference();
|
||||
} catch (ExceptionWithContext ex) {
|
||||
throw new InvalidReferenceException("methodhandle@" + methodHandleIndex, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,22 +38,23 @@ import org.jf.dexlib2.dexbacked.raw.ProtoIdItem;
|
||||
import org.jf.dexlib2.dexbacked.raw.TypeListItem;
|
||||
import org.jf.dexlib2.dexbacked.util.FixedSizeList;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
||||
public class DexBackedMethodProtoReference extends BaseMethodProtoReference {
|
||||
@Nonnull public final DexBackedDexFile dexFile;
|
||||
private final int protoIdItemOffset;
|
||||
private final int protoIndex;
|
||||
|
||||
public DexBackedMethodProtoReference(@Nonnull DexBackedDexFile dexFile, int protoIndex) {
|
||||
this.dexFile = dexFile;
|
||||
this.protoIdItemOffset = dexFile.getProtoIdItemOffset(protoIndex);
|
||||
this.protoIndex = protoIndex;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public List<String> getParameterTypes() {
|
||||
final int parametersOffset = dexFile.readSmallUint(protoIdItemOffset + ProtoIdItem.PARAMETERS_OFFSET);
|
||||
final int parametersOffset = dexFile.readSmallUint(dexFile.getProtoIdItemOffset(protoIndex) +
|
||||
ProtoIdItem.PARAMETERS_OFFSET);
|
||||
if (parametersOffset > 0) {
|
||||
final int parameterCount = dexFile.readSmallUint(parametersOffset + TypeListItem.SIZE_OFFSET);
|
||||
final int paramListStart = parametersOffset + TypeListItem.LIST_OFFSET;
|
||||
@ -72,7 +73,8 @@ public class DexBackedMethodProtoReference extends BaseMethodProtoReference {
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getReturnType() {
|
||||
return dexFile.getType(dexFile.readSmallUint(protoIdItemOffset + ProtoIdItem.RETURN_TYPE_OFFSET));
|
||||
return dexFile.getType(dexFile.readSmallUint(dexFile.getProtoIdItemOffset(protoIndex) +
|
||||
ProtoIdItem.RETURN_TYPE_OFFSET));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,4 +92,11 @@ public class DexBackedMethodProtoReference extends BaseMethodProtoReference {
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
if (protoIndex < 0 || protoIndex >= dexFile.getProtoCount()) {
|
||||
throw new InvalidReferenceException("proto@" + protoIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -44,24 +44,26 @@ import java.util.List;
|
||||
|
||||
public class DexBackedMethodReference extends BaseMethodReference {
|
||||
@Nonnull public final DexBackedDexFile dexFile;
|
||||
public final int methodIdItemOffset;
|
||||
private final int methodIndex;
|
||||
private int protoIdItemOffset;
|
||||
|
||||
public DexBackedMethodReference(@Nonnull DexBackedDexFile dexFile, int methodIndex) {
|
||||
this.dexFile = dexFile;
|
||||
this.methodIdItemOffset = dexFile.getMethodIdItemOffset(methodIndex);
|
||||
this.methodIndex = methodIndex;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getDefiningClass() {
|
||||
return dexFile.getType(dexFile.readUshort(methodIdItemOffset + MethodIdItem.CLASS_OFFSET));
|
||||
return dexFile.getType(dexFile.readUshort(dexFile.getMethodIdItemOffset(methodIndex) +
|
||||
MethodIdItem.CLASS_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public String getName() {
|
||||
return dexFile.getString(dexFile.readSmallUint(methodIdItemOffset + MethodIdItem.NAME_OFFSET));
|
||||
return dexFile.getString(dexFile.readSmallUint(dexFile.getMethodIdItemOffset(methodIndex) +
|
||||
MethodIdItem.NAME_OFFSET));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@ -94,7 +96,7 @@ public class DexBackedMethodReference extends BaseMethodReference {
|
||||
private int getProtoIdItemOffset() {
|
||||
if (protoIdItemOffset == 0) {
|
||||
protoIdItemOffset = dexFile.getProtoIdItemOffset(
|
||||
dexFile.readUshort(methodIdItemOffset + MethodIdItem.PROTO_OFFSET));
|
||||
dexFile.readUshort(dexFile.getMethodIdItemOffset(methodIndex) + MethodIdItem.PROTO_OFFSET));
|
||||
}
|
||||
return protoIdItemOffset;
|
||||
}
|
||||
@ -109,4 +111,11 @@ public class DexBackedMethodReference extends BaseMethodReference {
|
||||
public int getSize() {
|
||||
return MethodIdItem.ITEM_SIZE; //ushort + ushort + uint for indices
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
if (methodIndex < 0 || methodIndex >= dexFile.getMethodCount()) {
|
||||
throw new InvalidReferenceException("method@" + methodIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -73,4 +73,11 @@ public class DexBackedStringReference extends BaseStringReference {
|
||||
size += reader.peekStringLength(utf16Length);
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
if (stringIndex < 0 || stringIndex >= dexFile.getStringCount()) {
|
||||
throw new InvalidReferenceException("string@" + stringIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,4 +62,11 @@ public class DexBackedTypeReference extends BaseTypeReference {
|
||||
public int getSize() {
|
||||
return TypeIdItem.ITEM_SIZE; //uint for descriptor_idx
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateReference() throws InvalidReferenceException {
|
||||
if (typeIndex < 0 || typeIndex >= dexFile.getTypeCount()) {
|
||||
throw new InvalidReferenceException("type@" + typeIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,8 +32,49 @@
|
||||
package org.jf.dexlib2.iface.reference;
|
||||
|
||||
/**
|
||||
* This class is the base interface for field/method/string/type references in a dex file. It has no functionality or
|
||||
* contract itself.
|
||||
* This class is the base interface for field/method/string/type references in a dex file.
|
||||
*/
|
||||
public interface Reference {
|
||||
|
||||
/**
|
||||
* Verifies that this reference is valid.
|
||||
*
|
||||
* @throws InvalidReferenceException If the reference is not valid.
|
||||
*/
|
||||
void validateReference() throws InvalidReferenceException;
|
||||
|
||||
class InvalidReferenceException extends Exception {
|
||||
private final String invalidReferenceRepresentation;
|
||||
|
||||
public InvalidReferenceException(String invalidReferenceRepresentation) {
|
||||
super("Invalid reference");
|
||||
this.invalidReferenceRepresentation = invalidReferenceRepresentation;
|
||||
}
|
||||
|
||||
public InvalidReferenceException(String invalidReferenceRepresentation, String msg) {
|
||||
super(msg);
|
||||
this.invalidReferenceRepresentation = invalidReferenceRepresentation;
|
||||
}
|
||||
|
||||
public InvalidReferenceException(String invalidReferenceRepresentation, String s, Throwable throwable) {
|
||||
super(s, throwable);
|
||||
this.invalidReferenceRepresentation = invalidReferenceRepresentation;
|
||||
}
|
||||
|
||||
public InvalidReferenceException(String invalidReferenceRepresentation, Throwable throwable) {
|
||||
super(throwable);
|
||||
this.invalidReferenceRepresentation = invalidReferenceRepresentation;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A string representation of the invalid reference. This should be a human-readable string that gives
|
||||
* enough information to identify the reference in question.
|
||||
*
|
||||
* The format of the string is not specified, although as an illustrative example "string@123" could be
|
||||
* used for a reference to the string at index 123.
|
||||
*/
|
||||
public String getInvalidReferenceRepresentation() {
|
||||
return invalidReferenceRepresentation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user