1
0
mirror of https://github.com/LSPosed/DexBuilder.git synced 2024-11-22 06:06:28 +00:00
DexBuilder/include/slicer/reader.h
2024-06-04 21:04:21 +08:00

183 lines
6.9 KiB
C++

/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include "common.h"
#include "dex_format.h"
#include "dex_ir.h"
#include <assert.h>
#include <stdlib.h>
#include <map>
#include <memory>
namespace dex {
inline constexpr uint8_t opcode_len[] = {
1, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 2, 3, 5, 2, 2, 3, 2, 1, 1, 2,
2, 1, 2, 2, 3, 3, 3, 1, 1, 2, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1,
1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 1, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2,
2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, // removed in Android 12
1, 1, 1, 1, 1, 1, 1, 4, 4, 3, 3, 2, 2};
static_assert(sizeof(opcode_len) == 256);
// Provides both a low level iteration over the .dex
// structures and incremental .dex IR creation.
//
// NOTES:
// - only little-endian .dex files and host machines are supported
// - aggresive structure validation & minimal semantic validation
//
class Reader {
public:
Reader(const dex::u1* image, size_t size, const dex::u1* data = nullptr, size_t data_size = 0);
~Reader() = default;
Reader(Reader&&) = default;
Reader& operator=(Reader&&) = default;
// No copy semantics
Reader(const Reader&) = delete;
Reader& operator=(const Reader&) = delete;
public:
// Low level dex format interface
const dex::Header* Header() const { return header_; }
const bool IsCompact() const { return is_compact_; }
const char* GetStringMUTF8(dex::u4 index) const;
slicer::ArrayView<const dex::ClassDef> ClassDefs() const;
slicer::ArrayView<const dex::StringId> StringIds() const;
slicer::ArrayView<const dex::TypeId> TypeIds() const;
slicer::ArrayView<const dex::FieldId> FieldIds() const;
slicer::ArrayView<const dex::MethodId> MethodIds() const;
slicer::ArrayView<const dex::ProtoId> ProtoIds() const;
const dex::MapList* DexMapList() const;
static bool IsCompact(const void* image) {
const auto *header = reinterpret_cast<const struct Header*>(image);
if (header->magic[0] == 'd' && header->magic[1] == 'e' && header->magic[2] == 'x' && header->magic[3] == '\n') {
return false;
} else if (header->magic[0] == 'c' && header->magic[1] == 'd' && header->magic[2] == 'e' && header->magic[3] == 'x') {
return true;
}
return false;
}
// IR creation interface
std::shared_ptr<ir::DexFile> GetIr() const { return dex_ir_; }
void CreateFullIr();
void CreateClassIr(dex::u4 index);
dex::u4 FindClassIndex(const char* class_descriptor) const;
// Convert a file pointer (absolute offset) to an in-memory pointer
template <class T>
const T* ptr(u4 offset) const {
SLICER_CHECK(offset >= 0 && offset + sizeof(T) <= size_);
return reinterpret_cast<const T*>(image_ + offset);
}
// Convert a data section file pointer (absolute offset) to an in-memory pointer
// (offset should be inside the data section)
template <class T>
const T* dataPtr(size_t offset) const {
SLICER_CHECK((is_compact_ || offset >= header_->data_off) && offset + sizeof(T) <= data_size_);
return reinterpret_cast<const T*>(data_ + offset);
}
private:
// Internal access to IR nodes for indexed .dex structures
ir::Class* GetClass(dex::u4 index);
ir::Type* GetType(dex::u4 index);
ir::FieldDecl* GetFieldDecl(dex::u4 index);
ir::MethodDecl* GetMethodDecl(dex::u4 index);
ir::Proto* GetProto(dex::u4 index);
ir::String* GetString(dex::u4 index);
// Parsing annotations
ir::AnnotationsDirectory* ExtractAnnotations(dex::u4 offset);
ir::Annotation* ExtractAnnotationItem(dex::u4 offset);
ir::AnnotationSet* ExtractAnnotationSet(dex::u4 offset);
ir::AnnotationSetRefList* ExtractAnnotationSetRefList(dex::u4 offset);
ir::FieldAnnotation* ParseFieldAnnotation(const dex::u1** pptr);
ir::MethodAnnotation* ParseMethodAnnotation(const dex::u1** pptr);
ir::ParamAnnotation* ParseParamAnnotation(const dex::u1** pptr);
ir::EncodedField* ParseEncodedField(const dex::u1** pptr, dex::u4* baseIndex);
ir::Annotation* ParseAnnotation(const dex::u1** pptr);
// Parse encoded values and arrays
ir::EncodedValue* ParseEncodedValue(const dex::u1** pptr);
ir::EncodedArray* ParseEncodedArray(const dex::u1** pptr);
ir::EncodedArray* ExtractEncodedArray(dex::u4 offset);
// Parse root .dex structures
ir::Class* ParseClass(dex::u4 index);
ir::EncodedMethod* ParseEncodedMethod(const dex::u1** pptr, dex::u4* baseIndex);
ir::Type* ParseType(dex::u4 index);
ir::FieldDecl* ParseFieldDecl(dex::u4 index);
ir::MethodDecl* ParseMethodDecl(dex::u4 index);
ir::TypeList* ExtractTypeList(dex::u4 offset);
ir::Proto* ParseProto(dex::u4 index);
ir::String* ParseString(dex::u4 index);
// Parse code and debug information
ir::DebugInfo* ExtractDebugInfo(dex::u4 offset);
ir::Code* ExtractCode(dex::u4 offset);
void ParseInstructions(slicer::ArrayView<const dex::u2> code);
// Map an indexed section to an ArrayView<T>
template <class T>
slicer::ArrayView<const T> section(int offset, int count) const {
return slicer::ArrayView<const T>(ptr<T>(offset), count);
}
// Simple accessor for a MUTF8 string data
const dex::u1* GetStringData(dex::u4 index) const {
auto& stringId = StringIds()[index];
return dataPtr<dex::u1>(stringId.string_data_off);
}
void ValidateHeader();
private:
// the in-memory .dex image
const dex::u1* image_;
[[maybe_unused]] size_t size_;
const dex::u1* data_;
[[maybe_unused]] size_t data_size_;
// .dex image header
const dex::Header* header_;
// .dex IR associated with the reader
std::shared_ptr<ir::DexFile> dex_ir_;
bool is_compact_;
// maps for de-duplicating items identified by file pointers
std::map<dex::u4, ir::TypeList*> type_lists_;
std::map<dex::u4, ir::Annotation*> annotations_;
std::map<dex::u4, ir::AnnotationSet*> annotation_sets_;
std::map<dex::u4, ir::AnnotationsDirectory*> annotations_directories_;
std::map<dex::u4, ir::EncodedArray*> encoded_arrays_;
};
} // namespace dex