From 1269b5c6a8a1275b7dfdb7ec349f1990bc7c5d77 Mon Sep 17 00:00:00 2001 From: ckitagawa Date: Tue, 7 Sep 2021 21:12:21 +0000 Subject: [Zucchini] DEX Version 39 Support DEX Version 39 added: * const-method-handle containing a method_handle@BBBB reference * const-method-type containing a proto@BBBB reference This CL * Updates CodeToProtoId for const-method-type * Adds CodeToMethodHandle and WriteMethodHandle Fuzzed about 500k iterations locally and uploaded new samples to the clusterfuzz bucket. 97% coverage. Manually tested on hand-written dex files using smali as well as the dexdump test corpus. Bug: 1231885 Change-Id: Id8ab09ac8d3331902c5e6f92ac39ebd26d36e79b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3060660 Commit-Queue: Calder Kitagawa Reviewed-by: Samuel Huang Reviewed-by: Etienne Pierre-Doray Cr-Commit-Position: refs/heads/main@{#918948} NOKEYCHECK=True GitOrigin-RevId: d08c50abf7b49f3a5b97a03d5bb79bce9fdb7fad --- disassembler_dex.cc | 54 ++++++++++++++++++++++++++++++------ disassembler_dex.h | 8 +++++- testdata/const-method-type-min.smali | 16 +++++++++++ type_dex.h | 4 ++- 4 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 testdata/const-method-type-min.smali diff --git a/disassembler_dex.cc b/disassembler_dex.cc index 74c5e69..8ea0314 100644 --- a/disassembler_dex.cc +++ b/disassembler_dex.cc @@ -844,10 +844,11 @@ bool ReadDexHeader(ConstBufferView image, ReadDexHeaderResults* opt_results) { dex_version = dex_version * 10 + (header->magic[i] - '0'); } - // Only support DEX versions 35, 37, and 38. - // TODO(ckitagawa): Handle version 39. - if (dex_version != 35 && dex_version != 37 && dex_version != 38) + // Only support DEX versions 35, 37, 38, and 39 + if (dex_version != 35 && dex_version != 37 && dex_version != 38 && + dex_version != 39) { return false; + } if (header->file_size > image.size() || header->file_size < sizeof(dex::HeaderItem) || @@ -960,6 +961,9 @@ std::vector DisassemblerDex::MakeReferenceGroups() const { {{2, TypeTag(kCodeToCallSiteId), PoolTag(kCallSiteId)}, &DisassemblerDex::MakeReadCodeToCallSiteId16, &DisassemblerDex::MakeWriteCallSiteId16}, + {{2, TypeTag(kCodeToMethodHandle), PoolTag(kMethodHandle)}, + &DisassemblerDex::MakeReadCodeToMethodHandle16, + &DisassemblerDex::MakeWriteMethodHandle16}, {{4, TypeTag(kProtoIdToParametersTypeList), PoolTag(kTypeList)}, &DisassemblerDex::MakeReadProtoIdToParametersTypeList, &DisassemblerDex::MakeWriteAbs32}, @@ -1424,12 +1428,17 @@ std::unique_ptr DisassemblerDex::MakeReadCodeToProtoId16( offset_t hi) { auto filter = base::BindRepeating( [](const InstructionParser::Value& value) -> offset_t { - if (value.instr->format == dex::FormatId::c && - (value.instr->opcode == 0xFA || // invoke-polymorphic - value.instr->opcode == 0xFB)) { // invoke-polymorphic/range - // HHHH from e.g, invoke-polymorphic {vC, vD, vE, vF, vG}, - // meth@BBBB, proto@HHHH - return value.instr_offset + 6; + if (value.instr->format == dex::FormatId::c) { + if (value.instr->opcode == 0xFA || // invoke-polymorphic + value.instr->opcode == 0xFB) { // invoke-polymorphic/range + // HHHH from e.g, invoke-polymorphic {vC, vD, vE, vF, vG}, + // meth@BBBB, proto@HHHH + return value.instr_offset + 6; + } + if (value.instr->opcode == 0xFF) { // const-method-type + // BBBB from e.g., const-method-type vAA, proto@BBBB + return value.instr_offset + 2; + } } return kInvalidOffset; }); @@ -1460,6 +1469,25 @@ std::unique_ptr DisassemblerDex::MakeReadCodeToCallSiteId16( image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper)); } +std::unique_ptr DisassemblerDex::MakeReadCodeToMethodHandle16( + offset_t lo, + offset_t hi) { + auto filter = base::BindRepeating( + [](const InstructionParser::Value& value) -> offset_t { + if (value.instr->format == dex::FormatId::c && + value.instr->opcode == 0xFE) { // const-method-handle + // BBBB from e.g, const-method-handle vAA, method_handle@BBBB + return value.instr_offset + 2; + } + return kInvalidOffset; + }); + auto mapper = base::BindRepeating(ReadTargetIndex, image_, + method_handle_map_item_, + sizeof(dex::MethodHandleItem)); + return std::make_unique( + image_, lo, hi, code_item_offsets_, std::move(filter), std::move(mapper)); +} + std::unique_ptr DisassemblerDex::MakeReadCodeToFieldId16( offset_t lo, offset_t hi) { @@ -1666,6 +1694,14 @@ std::unique_ptr DisassemblerDex::MakeWriteCallSiteId16( return std::make_unique(image, std::move(writer)); } +std::unique_ptr DisassemblerDex::MakeWriteMethodHandle16( + MutableBufferView image) { + auto writer = + base::BindRepeating(WriteTargetIndex, method_handle_map_item_, + sizeof(dex::MethodHandleItem)); + return std::make_unique(image, std::move(writer)); +} + std::unique_ptr DisassemblerDex::MakeWriteRelCode8( MutableBufferView image) { auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) { diff --git a/disassembler_dex.h b/disassembler_dex.h index e75d13e..8e739d0 100644 --- a/disassembler_dex.h +++ b/disassembler_dex.h @@ -33,7 +33,7 @@ class DisassemblerDex : public Disassembler { kMethodId, // kClassDef, // Unused kCallSiteId, - // kMethodHandle, // Unused + kMethodHandle, kTypeList, kAnnotationSetRefList, kAnnotionSet, @@ -83,6 +83,8 @@ class DisassemblerDex : public Disassembler { kCodeToCallSiteId, // kCallSiteId + kCodeToMethodHandle, // kMethodHandle + kProtoIdToParametersTypeList, // kTypeList kClassDefToInterfacesTypeList, @@ -220,6 +222,8 @@ class DisassemblerDex : public Disassembler { offset_t hi); std::unique_ptr MakeReadCodeToCallSiteId16(offset_t lo, offset_t hi); + std::unique_ptr MakeReadCodeToMethodHandle16(offset_t lo, + offset_t hi); std::unique_ptr MakeReadCodeToRelCode8(offset_t lo, offset_t hi); std::unique_ptr MakeReadCodeToRelCode16(offset_t lo, @@ -240,6 +244,8 @@ class DisassemblerDex : public Disassembler { std::unique_ptr MakeWriteMethodId32(MutableBufferView image); std::unique_ptr MakeWriteCallSiteId16( MutableBufferView image); + std::unique_ptr MakeWriteMethodHandle16( + MutableBufferView image); std::unique_ptr MakeWriteRelCode8(MutableBufferView image); std::unique_ptr MakeWriteRelCode16(MutableBufferView image); std::unique_ptr MakeWriteRelCode32(MutableBufferView image); diff --git a/testdata/const-method-type-min.smali b/testdata/const-method-type-min.smali new file mode 100644 index 0000000..8a0f632 --- /dev/null +++ b/testdata/const-method-type-min.smali @@ -0,0 +1,16 @@ +# Tests const-method-type added in DEX version 39. + +# Compile using smali: https://github.com/JesusFreke/smali +# java -jar smali.jar assemble const-method-type.smali --api 28 + +.class public LConstMethodTypeTest; +.super Ljava/lang/Object; + +.method public test(I)V + .registers 4 + const-method-type v0, ()I + const-method-type v1, (C)V + const-method-type v2, (I)V + const-method-type v3, (I)I + return-void +.end method diff --git a/type_dex.h b/type_dex.h index e0ccc28..ee61ecd 100644 --- a/type_dex.h +++ b/type_dex.h @@ -12,7 +12,7 @@ namespace dex { // Contains types that models DEX executable format data structures. // See https://source.android.com/devices/tech/dalvik/dex-format -// The supported versions are 035, 037, and 038. +// The supported versions are 035, 037, 038, and 039. enum class FormatId : uint8_t { b, // 22b. @@ -114,6 +114,8 @@ constexpr Instruction kByteCode[] = { {0xFB, 4, FormatId::c}, {0xFC, 3, FormatId::c}, {0xFD, 3, FormatId::c}, + {0xFE, 2, FormatId::c}, + {0xFF, 2, FormatId::c}, }; // Supported by MSVC, g++, and clang++. Ensures no gaps in packing. -- cgit v1.2.3