From bdbea44b98afd2502ea198383d8137dd77085ec3 Mon Sep 17 00:00:00 2001 From: Ben Gruver Date: Fri, 23 Aug 2019 14:04:40 -0700 Subject: [PATCH] Gracefully handle malformed array payload instructions with element width=0 These get handled as if they had element width=1 and element count=0 --- .../baksmali/ZeroArrayPayloadWidthTest.java | 44 ++++++++++++++++++ .../ZeroArrayPayloadWidthTestInput.dex | Bin 0 -> 436 bytes .../ZeroArrayPayloadWidthTestOutput.smali | 15 ++++++ .../instruction/DexBackedArrayPayload.java | 21 +++++++-- .../jf/dexlib2/dexbacked/raw/CodeItem.java | 32 +++++++------ 5 files changed, 94 insertions(+), 18 deletions(-) create mode 100644 baksmali/src/test/java/org/jf/baksmali/ZeroArrayPayloadWidthTest.java create mode 100644 baksmali/src/test/resources/ZeroArrayPayloadWidthTest/ZeroArrayPayloadWidthTestInput.dex create mode 100644 baksmali/src/test/resources/ZeroArrayPayloadWidthTest/ZeroArrayPayloadWidthTestOutput.smali diff --git a/baksmali/src/test/java/org/jf/baksmali/ZeroArrayPayloadWidthTest.java b/baksmali/src/test/java/org/jf/baksmali/ZeroArrayPayloadWidthTest.java new file mode 100644 index 00000000..b4e93f44 --- /dev/null +++ b/baksmali/src/test/java/org/jf/baksmali/ZeroArrayPayloadWidthTest.java @@ -0,0 +1,44 @@ +/* + * 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 org.junit.Test; + +public class ZeroArrayPayloadWidthTest extends DisassemblyTest { + + @Test + public void testZeroArrayPayloadWidthTest() { + // This test uses a manually modified dex file with an array-payload instruction that has an element size of 0, + // and an element count that doesn't fit in an unsigned int. + runTest("ZeroArrayPayloadWidthTest"); + } +} diff --git a/baksmali/src/test/resources/ZeroArrayPayloadWidthTest/ZeroArrayPayloadWidthTestInput.dex b/baksmali/src/test/resources/ZeroArrayPayloadWidthTest/ZeroArrayPayloadWidthTestInput.dex new file mode 100644 index 0000000000000000000000000000000000000000..37b29424301d9c3e01bae5bd53b94adce98df299 GIT binary patch literal 436 zcmYdEt>7{+Hf5M${P9f2MpyA`uMHYzaNhJg;Xb?n>k+p5TNoJ_3K$p|D#A>JfD{<$ z0L557)ih+zQ4p8>=mdI1oB0pbHtd>2T61Y(dF2!PZuAz_dh2!PB6 z0gyZhgTQ|v0MRN?0coG8)S`UHqN2pgfW*q2{KS;-%#@OhkksN5YX%{oti-ZJ{hY+S zbbbG%tkh(n7-JX%XBAKjSQ*G92w;ZWz`(!;6ygI31065{2!Jd`2F4C1Zjcxdz}y0& zVc`IBKP)UjG)N8<9;{F{C@etcg2Wd9F_QvB?*Sm2SpedHkR+o5L=6W>A(RdFD^Lwc H2o&}Jf1x@; literal 0 HcmV?d00001 diff --git a/baksmali/src/test/resources/ZeroArrayPayloadWidthTest/ZeroArrayPayloadWidthTestOutput.smali b/baksmali/src/test/resources/ZeroArrayPayloadWidthTest/ZeroArrayPayloadWidthTestOutput.smali new file mode 100644 index 00000000..6172decc --- /dev/null +++ b/baksmali/src/test/resources/ZeroArrayPayloadWidthTest/ZeroArrayPayloadWidthTestOutput.smali @@ -0,0 +1,15 @@ +.class public LZeroArrayPayloadWidthTest; +.super Ljava/lang/Object; + + +# virtual methods +.method public zeroWidth()V + .registers 3 + + return-void + + nop + + .array-data 1 + .end array-data +.end method diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java index 0f689807..dddb2125 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java @@ -31,6 +31,7 @@ package org.jf.dexlib2.dexbacked.instruction; +import com.google.common.collect.ImmutableList; import org.jf.dexlib2.Opcode; import org.jf.dexlib2.dexbacked.DexBackedDexFile; import org.jf.dexlib2.dexbacked.util.FixedSizeList; @@ -54,10 +55,18 @@ public class DexBackedArrayPayload extends DexBackedInstruction implements Array int instructionStart) { super(dexFile, OPCODE, instructionStart); - elementWidth = dexFile.getDataBuffer().readUshort(instructionStart + ELEMENT_WIDTH_OFFSET); - elementCount = dexFile.getDataBuffer().readSmallUint(instructionStart + ELEMENT_COUNT_OFFSET); - if (((long)elementWidth) * elementCount > Integer.MAX_VALUE) { - throw new ExceptionWithContext("Invalid array-payload instruction: element width*count overflows"); + int localElementWidth = dexFile.getDataBuffer().readUshort(instructionStart + ELEMENT_WIDTH_OFFSET); + + if (localElementWidth == 0) { + elementWidth = 1; + elementCount = 0; + } else { + elementWidth = localElementWidth; + + elementCount = dexFile.getDataBuffer().readSmallUint(instructionStart + ELEMENT_COUNT_OFFSET); + if (((long) elementWidth) * elementCount > Integer.MAX_VALUE) { + throw new ExceptionWithContext("Invalid array-payload instruction: element width*count overflows"); + } } } @@ -72,6 +81,10 @@ public class DexBackedArrayPayload extends DexBackedInstruction implements Array @Override public int size() { return elementCount; } } + if (elementCount == 0) { + return ImmutableList.of(); + } + switch (elementWidth) { case 1: return new ReturnedList() { diff --git a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java index e2425aed..50d22f0f 100644 --- a/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java +++ b/dexlib2/src/main/java/org/jf/dexlib2/dexbacked/raw/CodeItem.java @@ -540,22 +540,26 @@ public class CodeItem { out.indent(); out.annotate(2, "element_width = %d", elementWidth); out.annotate(4, "size = %d", elements.size()); - out.annotate(0, "elements:"); + if (elements.size() > 0) { + out.annotate(0, "elements:"); + } out.indent(); - for (int i=0; i 0) { + for (int i = 0; i < elements.size(); i++) { + if (elementWidth == 8) { + long value = elements.get(i).longValue(); + if (NumberUtils.isLikelyDouble(value)) { + out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Double.longBitsToDouble(value)); + } else { + out.annotate(elementWidth, "element[%d] = %d", i, value); + } } else { - out.annotate(elementWidth, "element[%d] = %d", i, value); - } - } else { - int value = elements.get(i).intValue(); - if (NumberUtils.isLikelyFloat(value)) { - out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Float.intBitsToFloat(value)); - } else { - out.annotate(elementWidth, "element[%d] = %d", i, value); + int value = elements.get(i).intValue(); + if (NumberUtils.isLikelyFloat(value)) { + out.annotate(elementWidth, "element[%d] = %d # %f", i, value, Float.intBitsToFloat(value)); + } else { + out.annotate(elementWidth, "element[%d] = %d", i, value); + } } } }