diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java index 4bede403f..22e885d82 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/DexBackedDexFile.java @@ -257,6 +257,12 @@ public List getReferences(int referenceType) { return getMethodSection(); case ReferenceType.FIELD: return getFieldSection(); + case ReferenceType.METHOD_PROTO: + return getMethodSection(); + case ReferenceType.METHOD_HANDLE: + return getMethodHandleSection(); + case ReferenceType.CALL_SITE: + return getCallSiteSection(); default: throw new IllegalArgumentException(String.format("Invalid reference type: %d", referenceType)); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/CallSiteReferenceRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/CallSiteReferenceRewriter.java new file mode 100644 index 000000000..6e508e4fd --- /dev/null +++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/CallSiteReferenceRewriter.java @@ -0,0 +1,92 @@ +/* + * Copyright 2014, Google Inc. + * Copyright 2022, Zimperium 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.rewriter; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import org.jf.dexlib2.base.reference.BaseCallSiteReference; +import org.jf.dexlib2.iface.reference.CallSiteReference; +import org.jf.dexlib2.iface.reference.MethodHandleReference; +import org.jf.dexlib2.iface.reference.MethodProtoReference; +import org.jf.dexlib2.iface.value.EncodedValue; + +import javax.annotation.Nonnull; +import java.util.List; + +public class CallSiteReferenceRewriter implements Rewriter { + @Nonnull protected final Rewriters rewriters; + + public CallSiteReferenceRewriter(@Nonnull Rewriters rewriters) { + this.rewriters = rewriters; + } + + @Nonnull @Override public CallSiteReference rewrite(@Nonnull CallSiteReference callSiteReference) { + return new RewrittenCallSiteReference(callSiteReference); + } + + protected class RewrittenCallSiteReference extends BaseCallSiteReference { + @Nonnull protected CallSiteReference callSiteReference; + + public RewrittenCallSiteReference(@Nonnull CallSiteReference callSiteReference) { + this.callSiteReference = callSiteReference; + } + + @Override @Nonnull public String getName() { + return callSiteReference.getName(); + } + + @Override @Nonnull public MethodHandleReference getMethodHandle() { + return RewriterUtils.rewriteMethodHandleReference( + rewriters, callSiteReference.getMethodHandle()); + } + + @Override @Nonnull public String getMethodName() { + return callSiteReference.getMethodName(); + } + + @Override @Nonnull public MethodProtoReference getMethodProto() { + return RewriterUtils.rewriteMethodProtoReference( + rewriters.getTypeRewriter(), + callSiteReference.getMethodProto()); + } + + @Override @Nonnull public List getExtraArguments() { + return Lists.transform(callSiteReference.getExtraArguments(), + new Function() { + @Nonnull @Override public EncodedValue apply(EncodedValue encodedValue) { + return RewriterUtils.rewriteValue(rewriters, encodedValue); + } + }); + } + } +} diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java index 84963aa0a..bcaca0d7b 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/DexRewriter.java @@ -36,6 +36,7 @@ import org.jf.dexlib2.iface.instruction.Instruction; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; +import org.jf.dexlib2.iface.reference.CallSiteReference; import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; @@ -79,6 +80,7 @@ public class DexRewriter implements Rewriters { private final Rewriter typeRewriter; private final Rewriter fieldReferenceRewriter; private final Rewriter methodReferenceRewriter; + private final Rewriter callSiteReferenceRewriter; private final Rewriter annotationRewriter; private final Rewriter annotationElementRewriter; private final Rewriter encodedValueRewriter; @@ -97,6 +99,7 @@ public DexRewriter(RewriterModule module) { this.typeRewriter = module.getTypeRewriter(this); this.fieldReferenceRewriter = module.getFieldReferenceRewriter(this); this.methodReferenceRewriter = module.getMethodReferenceRewriter(this); + this.callSiteReferenceRewriter = module.getCallSiteReferenceRewriter(this); this.annotationRewriter = module.getAnnotationRewriter(this); this.annotationElementRewriter = module.getAnnotationElementRewriter(this); this.encodedValueRewriter = module.getEncodedValueRewriter(this); @@ -115,6 +118,7 @@ public DexRewriter(RewriterModule module) { @Nonnull @Override public Rewriter getTypeRewriter() { return typeRewriter; } @Nonnull @Override public Rewriter getFieldReferenceRewriter() { return fieldReferenceRewriter; } @Nonnull @Override public Rewriter getMethodReferenceRewriter() { return methodReferenceRewriter; } + @Nonnull @Override public Rewriter getCallSiteReferenceRewriter() { return callSiteReferenceRewriter; } @Nonnull @Override public Rewriter getAnnotationRewriter() { return annotationRewriter; } @Nonnull @Override public Rewriter getAnnotationElementRewriter() { return annotationElementRewriter; } @Nonnull @Override public Rewriter getEncodedValueRewriter() { return encodedValueRewriter; } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/InstructionRewriter.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/InstructionRewriter.java index 6e09be913..56afd50da 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/InstructionRewriter.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/InstructionRewriter.java @@ -33,6 +33,7 @@ import org.jf.dexlib2.Opcode; import org.jf.dexlib2.ReferenceType; +import org.jf.dexlib2.iface.instruction.DualReferenceInstruction; import org.jf.dexlib2.iface.instruction.Instruction; import org.jf.dexlib2.iface.instruction.ReferenceInstruction; import org.jf.dexlib2.iface.instruction.formats.*; @@ -67,6 +68,8 @@ public InstructionRewriter(@Nonnull Rewriters rewriters) { return new RewrittenInstruction3rc((Instruction3rc)instruction); case Format45cc: return new RewrittenInstruction45cc((Instruction45cc) instruction); + case Format4rcc: + return new RewrittenInstruction4rcc((Instruction4rcc) instruction); default: throw new IllegalArgumentException(); } @@ -74,6 +77,33 @@ public InstructionRewriter(@Nonnull Rewriters rewriters) { return instruction; } + @Nonnull private Reference rewriteReference(int type, + @Nonnull Reference reference) { + switch (type) { + case ReferenceType.TYPE: + return RewriterUtils.rewriteTypeReference(rewriters.getTypeRewriter(), + (TypeReference)reference); + case ReferenceType.FIELD: + return rewriters.getFieldReferenceRewriter().rewrite((FieldReference)reference); + case ReferenceType.METHOD: + return rewriters.getMethodReferenceRewriter().rewrite((MethodReference)reference); + case ReferenceType.STRING: + return reference; + case ReferenceType.METHOD_PROTO: + return RewriterUtils.rewriteMethodProtoReference( + rewriters.getTypeRewriter(), + (MethodProtoReference)reference); + case ReferenceType.METHOD_HANDLE: + return RewriterUtils.rewriteMethodHandleReference( + rewriters, (MethodHandleReference)reference); + case ReferenceType.CALL_SITE: + return rewriters.getCallSiteReferenceRewriter().rewrite((CallSiteReference)reference); + default: + throw new ExceptionWithContext("Invalid reference type: %d", + type); + } + } + protected class BaseRewrittenReferenceInstruction implements ReferenceInstruction { @Nonnull protected T instruction; @@ -92,6 +122,9 @@ protected BaseRewrittenReferenceInstruction(@Nonnull T instruction) { case ReferenceType.METHOD: return rewriters.getMethodReferenceRewriter().rewrite((MethodReference)instruction.getReference()); case ReferenceType.STRING: + case ReferenceType.METHOD_PROTO: + case ReferenceType.METHOD_HANDLE: + case ReferenceType.CALL_SITE: return instruction.getReference(); default: throw new IllegalArgumentException(); @@ -205,9 +238,10 @@ public int getRegisterCount() { } } - protected class RewrittenInstruction45cc extends BaseRewrittenReferenceInstruction - implements Instruction45cc { - public RewrittenInstruction45cc(@Nonnull Instruction45cc instruction) { + protected class BaseRewrittenDualReferenceInstruction + extends BaseRewrittenReferenceInstruction + implements DualReferenceInstruction { + public BaseRewrittenDualReferenceInstruction(@Nonnull T instruction) { super(instruction); } @@ -221,8 +255,9 @@ public RewrittenInstruction45cc(@Nonnull Instruction45cc instruction) { case ReferenceType.METHOD: return rewriters.getMethodReferenceRewriter().rewrite((MethodReference)instruction.getReference2()); case ReferenceType.STRING: - return instruction.getReference2(); case ReferenceType.METHOD_PROTO: + case ReferenceType.METHOD_HANDLE: + case ReferenceType.CALL_SITE: return instruction.getReference2(); default: throw new IllegalArgumentException(); @@ -232,6 +267,13 @@ public RewrittenInstruction45cc(@Nonnull Instruction45cc instruction) { public int getReferenceType2() { return instruction.getReferenceType2(); } + } + + protected class RewrittenInstruction45cc extends BaseRewrittenDualReferenceInstruction + implements Instruction45cc { + public RewrittenInstruction45cc(@Nonnull Instruction45cc instruction) { + super(instruction); + } public int getRegisterC() { return instruction.getRegisterC(); @@ -257,4 +299,34 @@ public int getRegisterF() { return instruction.getRegisterF(); } } + + protected class RewrittenInstruction4rcc extends BaseRewrittenDualReferenceInstruction + implements Instruction4rcc { + public RewrittenInstruction4rcc(@Nonnull Instruction4rcc instruction) { + super(instruction); + } + + public int getStartRegister() { + return instruction.getStartRegister(); + } + + public int getRegisterCount() { + return instruction.getRegisterCount(); + } + } + + protected class RewrittenInstruction4rcc extends BaseRewrittenDualReferenceInstruction + implements Instruction4rcc { + public RewrittenInstruction4rcc(@Nonnull Instruction4rcc instruction) { + super(instruction); + } + + public int getStartRegister() { + return instruction.getStartRegister(); + } + + public int getRegisterCount() { + return instruction.getRegisterCount(); + } + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterModule.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterModule.java index 5723b6df4..3a5c5b522 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterModule.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterModule.java @@ -36,6 +36,7 @@ import org.jf.dexlib2.iface.instruction.Instruction; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; +import org.jf.dexlib2.iface.reference.CallSiteReference; import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; @@ -93,6 +94,10 @@ public class RewriterModule { return new MethodReferenceRewriter(rewriters); } + @Nonnull public Rewriter getCallSiteReferenceRewriter(@Nonnull Rewriters rewriters) { + return new CallSiteReferenceRewriter(rewriters); + } + @Nonnull public Rewriter getAnnotationRewriter(@Nonnull Rewriters rewriters) { return new AnnotationRewriter(rewriters); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterUtils.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterUtils.java index d08467ae7..a69439408 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterUtils.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/RewriterUtils.java @@ -31,8 +31,22 @@ package org.jf.dexlib2.rewriter; +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import org.jf.util.ExceptionWithContext; +import org.jf.dexlib2.MethodHandleType; +import org.jf.dexlib2.ValueType; +import org.jf.dexlib2.base.reference.BaseMethodHandleReference; +import org.jf.dexlib2.base.reference.BaseMethodProtoReference; import org.jf.dexlib2.base.reference.BaseTypeReference; +import org.jf.dexlib2.base.value.*; +import org.jf.dexlib2.iface.reference.FieldReference; +import org.jf.dexlib2.iface.reference.MethodHandleReference; +import org.jf.dexlib2.iface.reference.MethodProtoReference; +import org.jf.dexlib2.iface.reference.MethodReference; +import org.jf.dexlib2.iface.reference.Reference; import org.jf.dexlib2.iface.reference.TypeReference; +import org.jf.dexlib2.iface.value.*; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -113,6 +127,119 @@ public static TypeReference rewriteTypeReference(@Nonnull final Rewriter } }; } + + @Nonnull public static MethodHandleReference rewriteMethodHandleReference( + @Nonnull final Rewriters rewriters, + @Nonnull final MethodHandleReference methodHandleReference) { + switch (methodHandleReference.getMethodHandleType()) { + case MethodHandleType.STATIC_PUT: + case MethodHandleType.STATIC_GET: + case MethodHandleType.INSTANCE_PUT: + case MethodHandleType.INSTANCE_GET: + return new BaseMethodHandleReference() { + @Override public int getMethodHandleType() { + return methodHandleReference.getMethodHandleType(); + } + + @Nonnull @Override public Reference getMemberReference() { + return rewriters.getFieldReferenceRewriter().rewrite((FieldReference)methodHandleReference.getMemberReference()); + } + }; + case MethodHandleType.INVOKE_STATIC: + case MethodHandleType.INVOKE_INSTANCE: + case MethodHandleType.INVOKE_CONSTRUCTOR: + case MethodHandleType.INVOKE_DIRECT: + case MethodHandleType.INVOKE_INTERFACE: + return new BaseMethodHandleReference() { + @Override public int getMethodHandleType() { + return methodHandleReference.getMethodHandleType(); + } + + @Nonnull @Override public Reference getMemberReference() { + return rewriters.getMethodReferenceRewriter().rewrite((MethodReference)methodHandleReference.getMemberReference()); + } + }; + default: + throw new ExceptionWithContext("Invalid method handle type: %d", + methodHandleReference.getMethodHandleType()); + } + } + + @Nonnull public static MethodProtoReference rewriteMethodProtoReference( + @Nonnull final Rewriter typeRewriter, + @Nonnull final MethodProtoReference methodProtoReference) { + return new BaseMethodProtoReference() { + @Nonnull @Override public List getParameterTypes() { + return rewriteList(typeRewriter, + Lists.transform(methodProtoReference.getParameterTypes(), + new Function() { + @Nonnull @Override public String apply(CharSequence input) { + return input.toString(); + } + })); + } + + @Nonnull @Override public String getReturnType() { + return typeRewriter.rewrite(methodProtoReference.getReturnType()); + } + }; + } + + @Nonnull public static EncodedValue rewriteValue( + @Nonnull final Rewriters rewriters, + @Nonnull final EncodedValue encodedValue) { + switch (encodedValue.getValueType()) { + case ValueType.INT: + case ValueType.FLOAT: + case ValueType.LONG: + case ValueType.DOUBLE: + case ValueType.STRING: + return encodedValue; + + case ValueType.METHOD_TYPE: + return new BaseMethodTypeEncodedValue () { + @Override @Nonnull public MethodProtoReference getValue() { + return rewriteMethodProtoReference( + rewriters.getTypeRewriter(), + ((MethodTypeEncodedValue) encodedValue).getValue()); + } + }; + + case ValueType.METHOD_HANDLE: + return new BaseMethodHandleEncodedValue () { + @Override @Nonnull public MethodHandleReference getValue() { + return rewriteMethodHandleReference( + rewriters, + ((MethodHandleEncodedValue) encodedValue).getValue()); + } + }; + + case ValueType.TYPE: + return new BaseTypeEncodedValue () { + @Override @Nonnull public String getValue() { + return rewriters.getTypeRewriter().rewrite(((TypeEncodedValue) encodedValue).getValue()); + } + }; + + case ValueType.FIELD: + return new BaseFieldEncodedValue () { + @Override @Nonnull public FieldReference getValue() { + return rewriters.getFieldReferenceRewriter().rewrite(((FieldEncodedValue) encodedValue).getValue()); + } + }; + + case ValueType.METHOD: + return new BaseMethodEncodedValue () { + @Override @Nonnull public MethodReference getValue() { + return rewriters.getMethodReferenceRewriter().rewrite(((MethodEncodedValue) encodedValue).getValue()); + } + }; + + default: + throw new ExceptionWithContext("Unsupported encoded value type: %d", + encodedValue.getValueType()); + } + } } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriters.java b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriters.java index e64c48f39..48cb0337a 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriters.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/rewriter/Rewriters.java @@ -36,6 +36,7 @@ import org.jf.dexlib2.iface.instruction.Instruction; import org.jf.dexlib2.iface.reference.FieldReference; import org.jf.dexlib2.iface.reference.MethodReference; +import org.jf.dexlib2.iface.reference.CallSiteReference; import org.jf.dexlib2.iface.value.EncodedValue; import javax.annotation.Nonnull; @@ -56,6 +57,7 @@ public interface Rewriters { @Nonnull Rewriter getTypeRewriter(); @Nonnull Rewriter getFieldReferenceRewriter(); @Nonnull Rewriter getMethodReferenceRewriter(); + @Nonnull Rewriter getCallSiteReferenceRewriter(); @Nonnull Rewriter getAnnotationRewriter(); @Nonnull Rewriter getAnnotationElementRewriter(); diff --git a/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java b/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java index 4a18afa07..412b1fb50 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/util/Preconditions.java @@ -271,6 +271,21 @@ public static T checkReference(int referenceType, T refere throw new IllegalArgumentException("Invalid reference type, expecting a method reference"); } break; + case ReferenceType.METHOD_PROTO: + if (!(reference instanceof MethodProtoReference)) { + throw new IllegalArgumentException("Invalid reference type, expecting a method proto reference"); + } + break; + case ReferenceType.METHOD_HANDLE: + if (!(reference instanceof MethodHandleReference)) { + throw new IllegalArgumentException("Invalid reference type, expecting a method handle reference"); + } + break; + case ReferenceType.CALL_SITE: + if (!(reference instanceof CallSiteReference)) { + throw new IllegalArgumentException("Invalid reference type, expecting a call site reference"); + } + break; default: throw new IllegalArgumentException(String.format("Not a valid reference type: %d", referenceType)); } diff --git a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java index 338b2b49d..5959a7c1c 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/writer/pool/ClassPool.java @@ -173,6 +173,9 @@ private void internReference(@Nonnull Reference reference, int referenceType) { case ReferenceType.METHOD_PROTO: dexPool.protoSection.intern((MethodProtoReference)reference); break; + case ReferenceType.METHOD_HANDLE: + dexPool.methodHandleSection.intern((MethodHandleReference) reference); + break; case ReferenceType.CALL_SITE: dexPool.callSiteSection.intern((CallSiteReference) reference); break;