专栏名称: 看雪学苑
致力于移动与安全研究的开发者社区,看雪学院(kanxue.com)官方微信公众帐号。
目录
相关文章推荐
计算机与网络安全  ·  信息化数字化数智化、智能制造、车联网、金融政 ... ·  16 小时前  
吾爱破解论坛  ·  分享图片 ·  3 天前  
FreeBuf  ·  2025年威胁态势全景:CISO应对指南 ·  昨天  
51好读  ›  专栏  ›  看雪学苑

Android从整体加固到抽取加固的实现及原理(下)

看雪学苑  · 公众号  · 互联网安全  · 2025-05-28 17:59

正文

请到「今天看啥」查看全文


(canonical_it != oat_dex_files_. end ()) {
oat_dex_file = canonical_it->second;
} // else keep null.
} // else keep null.

// Copy the key to the string_cache_ and store the result in secondary map.
string_cache_. emplace_back (key. data (), key. length ());
std::string_view key_copy (string_cache_.back()) ;
secondary_oat_dex_files_. PutBefore (secondary_lb, key_copy, oat_dex_file);
}
}

//获取oat_dex_file文件失败
if (oat_dex_file == nullptr ) {
if (error_msg != nullptr ) {
std::string dex_canonical_location = DexFileLoader:: GetDexCanonicalLocation (dex_location);
*error_msg = "Failed to find OatDexFile for DexFile " + std:: string (dex_location)
+ " (canonical path " + dex_canonical_location + ") in OatFile " + GetLocation ();
}
return nullptr ;
}

// 验证oat_dex_file文件的校验码
if (dex_location_checksum != nullptr &&
oat_dex_file-> GetDexFileLocationChecksum () != *dex_location_checksum) {
if (error_msg != nullptr ) {
std::string dex_canonical_location = DexFileLoader:: GetDexCanonicalLocation (dex_location);
std::string checksum = StringPrintf ( "0x%08x" , oat_dex_file-> GetDexFileLocationChecksum ());
std::string required_checksum = StringPrintf ( "0x%08x" , *dex_location_checksum);
*error_msg = "OatDexFile for DexFile " + std:: string (dex_location)
+ " (canonical path " + dex_canonical_location + ") in OatFile " + GetLocation ()
+ " has checksum " + checksum + " but " + required_checksum + " was required" ;
}
return nullptr ;
}
return oat_dex_file;
}

OatDexFile::OpenDexFile

内部调用ArtDexFileLoader::Open


//art/runtime/oat_file.cc
std::unique_ptr<const DexFile> OatDexFile::OpenDexFile(std::string* error_msg)const{
ScopedTrace trace(__PRETTY_FUNCTION__);
staticconstexprbool kVerify = false;
staticconstexprbool kVerifyChecksum = false;
const ArtDexFileLoader dex_file_loader;
return dex_file_loader.Open(dex_file_pointer_,
FileSize(),
                              dex_file_location_,
                              dex_file_location_checksum_,
this,
                              kVerify,
                              kVerifyChecksum,
                              error_msg);
}

ArtDexFileLoader::Open

通过上述分析可以得知,在OatFileManager::OpenDexFilesFromOat中


OatFileAssistant::LoadDexFiles最终也调用ArtDexFileLoader::Open,参数个数有所区别


OatFileAssistant::LoadDexFiles内调用9参数的Open(比较奇怪,调用时只传递了8个参数,第9个container没传)


参数解释


◆base: 指向dex文件的内存地址

◆size: dex文件的大小

◆location: dex文件的位置

◆location_checksum: dex文件位置的校验和

◆oat_dex_file: 指向OatDexFile对象的指针

◆verify: 表示是否要对dex文件进行验证

◆verify_checksum: 表示是否要验证dex文件的校验和

◆error_msg: 指向错误信息字符串的指针


直接调用了ArtDexFileLoader::OpenCommon


//art/libdexfile/dex/art_dex_file_loader.cc
std::unique_ptr<const DexFile> ArtDexFileLoader::Open(
constuint8_t* base,
size_t size,
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
bool verify,
bool verify_checksum,
    std::string* error_msg,
    std::unique_ptr container)const{
ScopedTrace trace(std::string("Open dex file from RAM ") + location);
returnOpenCommon(base,
                    size,
/*data_base=*/nullptr,
/*data_size=*/0u,
                    location,
                    location_checksum,
                    oat_dex_file,
                    verify,
                    verify_checksum,
                    error_msg,
                    std::move(container),
/*verify_result=*/nullptr);
}


OatFileManager::OpenDexFilesFromOat内部调用的6参数ArtDexFileLoader::Open,参数解释如下


◆filename: dex文件名

◆location: dex文件的位置

◆verify_checksum: 表示是否要验证dex文件的校验和

◆error_msg: 指向错误信息字符串的指针

◆dex_files: 存储dex file的DexFile数组


内部调用了ArtDexFileLoader::OpenWithMagic,判断文件头,如果是zip则通过OpenZip打开,如果是dex则通过OpenFile打开。


//art/libdexfile/dex/art_dex_file_loader.cc
bool ArtDexFileLoader::Open(constchar* filename,
const std::string& location,
bool verify,
bool verify_checksum,
                            std::string* error_msg,
                            std::vector<:unique_ptr class="code-snippet__keyword">const DexFile>>* dex_files) const {
  uint32_t magic;
//打开文件并读取magic[8],OpenAndReadMagic可作为一个常用脱壳点,但此时dex还没加载到内存中
  File fd = OpenAndReadMagic(filename, &magic, error_msg);
if (fd.Fd() == -1) {
DCHECK(!error_msg->empty());
returnfalse;
  }
returnOpenWithMagic(
      magic, fd.Release(), location, verify, verify_checksum, error_msg, dex_files);
}

bool ArtDexFileLoader::OpenWithMagic(uint32_t magic,
                                     int fd,
const std::string& location,
bool verify,
bool verify_checksum,
                                     std::string* error_msg,
                                     std::vector<:unique_ptr class="code-snippet__keyword">const DexFile>>* dex_files) const {
  ScopedTrace trace(std::string("Open dex file ") + std::string(location));
DCHECK(dex_files != nullptr) <"DexFile::Open: out-param is nullptr";
// 如果是zip文件头,通过OpenZip打开zip文件
if (IsZipMagic(magic)) {
returnOpenZip(fd, location, verify, verify_checksum, error_msg, dex_files);
  }
// 如果是dex文件头,通过ArtDexFileLoader::OpenFile打开并创建DexFile对象
if (IsMagicValid(magic)) {
    std::unique_ptr<const DexFile> dex_file(OpenFile(fd,
                                                     location,
                                                     verify,
                                                     verify_checksum,
/* mmap_shared= */false,
                                                     error_msg));
if (dex_file.get() != nullptr) {
//打开dex文件成功,添加到DexFile数组中
      dex_files->push_back(std::move(dex_file));
returntrue;
    } else {
returnfalse;
    }
  }
  *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", location.c_str());
returnfalse;
}

ArtDexFileLoader::OpenZip

内部调用OpenAllDexFilesFromZip


boolArtDexFileLoader::OpenZip(int fd,
const std::string& location,
bool verify,
bool verify_checksum,
                               std::string* error_msg,
                               std::vector<: class="code-snippet__variable">unique_ptr<const DexFile>>* dex_files) const {
  ScopedTrace trace("Dex file open Zip " + std::string(location));
DCHECK(dex_files != nullptr) <"DexFile::OpenZip: out-param is nullptr";
  std::unique_ptr zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
if (zip_archive.get() == nullptr) {
DCHECK(!error_msg->empty());
returnfalse;
  }
returnOpenAllDexFilesFromZip(
      *zip_archive, location, verify, verify_checksum, error_msg, dex_files);
}

ArtDexFileLoader::OpenAllDexFilesFromZip

OpenAllDexFilesFromZip内部调用OpenOneDexFileFromZip打开dex文件


boolArtDexFileLoader::OpenAllDexFilesFromZip(
const ZipArchive& zip_archive,
const std::string& location,
bool verify,
bool verify_checksum,
    std::string* error_msg,
    std::vector<:unique_ptr>const DexFile>>* dex_files)const{
ScopedTrace trace("Dex file open from Zip " + std::string(location));
DCHECK(dex_files != nullptr) <"DexFile::OpenFromZip: out-param is nullptr";

  DexFileLoaderErrorCode error_code;
std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
                                                                kClassesDex,
                                                                location,
                                                                verify,
                                                                verify_checksum,
                                                                error_msg,
                                                                &error_code));
if (dex_file.get() == nullptr) {
returnfalse;
  } else {
// Had at least classes.dex.
    dex_files->push_back(std::move(dex_file));

// Now try some more.

// We could try to avoid std::string allocations by working on a char array directly. As we
// do not expect a lot of iterations, this seems too involved and brittle.

for (size_t i = 1; ; ++i) {
      std::string name = GetMultiDexClassesDexName(i);
      std::string fake_location = GetMultiDexLocation(i, location.c_str());
std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
                                                                         name.c_str(),
                                                                         fake_location,
                                                                         verify,
                                                                         verify_checksum,
                                                                         error_msg,
                                                                         &error_code));
if (next_dex_file.get() == nullptr) {
if (error_code != DexFileLoaderErrorCode::kEntryNotFound) {
LOG(WARNING) <"Zip open failed: " << *error_msg;
        }
break;
      } else {
        dex_files->push_back(std::move(next_dex_file));
      }

if (i == kWarnOnManyDexFilesThreshold) {
LOG(WARNING) << location <" has in excess of " << kWarnOnManyDexFilesThreshold
                     <" dex files. Please consider coalescing and shrinking the number to "
" avoid runtime overhead.";
      }

if (i == std::numeric_limits<size_t>::max()) {
LOG(ERROR) <"Overflow in number of dex files!";
break;
      }
    }

returntrue;
  }
}

ArtDexFileLoader::OpenOneDexFileFromZip

OpenOneDexFileFromZip内部调用OpenCommon打开dex文件


std::unique_ptr<const DexFile> ArtDexFileLoader::OpenOneDexFileFromZip(
const ZipArchive& zip_archive,
constchar* entry_name,
const std::string& location,
bool verify,
bool verify_checksum,
    std::string* error_msg,
    DexFileLoaderErrorCode* error_code) const {
  ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
CHECK(!location.empty());
//1.通过zip_archive.Find找到给定的dex文件
  std::unique_ptr zip_entry(zip_archive.Find(entry_name, error_msg));
if (zip_entry == nullptr) {
    *error_code = DexFileLoaderErrorCode::kEntryNotFound;
return nullptr;
  }
if (zip_entry->GetUncompressedLength() == 0) {
    *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
    *error_code = DexFileLoaderErrorCode::kDexFileError;
return nullptr;
  }

  MemMap map;
if (zip_entry->IsUncompressed()) {
//判断文件对齐
if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
// Do not mmap unaligned ZIP entries because
// doing so would fail dex verification which requires 4 byte alignment.
LOG(WARNING) <"Can't mmap dex file " << location <"!" << entry_name <" directly; "
                   <"please zipalign to " 
                   <"Falling back to extracting file.";
    } else {
//2.映射未压缩的文件,避免脏拷贝,例如lib库文件,arsc文件等
// Map uncompressed files within zip as file-backed to avoid a dirty copy.
      map = zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg);
if (!map.IsValid()) {
LOG(WARNING) <"Can't mmap dex file " << location <"!" << entry_name <" directly; "
                     <"is your ZIP file corrupted? Falling back to extraction.";
// Try again with Extraction which still has a chance of recovery.
      }
    }
  }
//...... MemMap检测
//3.调用OpenCommon打开dex文件
  std::unique_ptr dex_file = OpenCommon(begin,
                                                 size,
/*data_base=*/ nullptr,
/*data_size=*/0u,
                                                 location,
                                                 zip_entry->GetCrc32(),
                                                 kNoOatDexFile,
                                                 verify,
                                                 verify_checksum,
                                                 error_msg,
                                                 std::make_unique(std::move(map)),
                                                 &verify_result);
// 合法性检测
  ......
return dex_file;
}

ArtDexFileLoader::OpenFile

内部调用ArtDexFileLoader::OpenCommon打开dex文件


std::unique_ptr<const DexFile> ArtDexFileLoader::OpenFile(int fd,
const std::string& location,
bool verify,
bool verify_checksum,
bool mmap_shared,
                                                          std::string* error_msg)const{
ScopedTrace trace(std::string("Open dex file ") + std::string(location));
CHECK(!location.empty());
  MemMap map;
  {
File delayed_close(fd, /* check_usage= */false);
structstat sbuf;
memset(&sbuf, 0sizeof(sbuf));
if (fstat(fd, &sbuf) == -1) {
      *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
strerror(errno));
returnnullptr;
    }
if (S_ISDIR(sbuf.st_mode)) {
      *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
returnnullptr;
    }
size_t length = sbuf.st_size;
//1.将dex文件映射到内存
    map = MemMap::MapFile(length,
                          PROT_READ,
                          mmap_shared ? MAP_SHARED : MAP_PRIVATE,
                          fd,
0,
/*low_4gb=*/false,
                          location.c_str(),
                          error_msg);
if (!map.IsValid()) {
DCHECK(!error_msg->empty());
returnnullptr;
    }
  }

constuint8_t* begin = map.Begin();
size_t size = map.Size();
if (size sizeof(DexFile::Header)) {
    *error_msg = StringPrintf(
"DexFile: failed to open dex file '%s' that is too short to have a header",
        location.c_str());
returnnullptr;
  }

const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(begin);

//2.调用OpenCommon打开dex文件
  std::unique_ptr dex_file = OpenCommon(begin,
                                                 size,
/*data_base=*/nullptr,
/*data_size=*/0u,
                                                 location,
                                                 dex_header->checksum_,
                                                 kNoOatDexFile,
                                                 verify,
                                                 verify_checksum,
                                                 error_msg,
                                                 std::make_unique(std::move(map)),
/*verify_result=*/nullptr);

// Opening CompactDex is only supported from vdex files.
if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
    *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
                              location.c_str());
returnnullptr;
  }
return dex_file;
}

ArtDexFileLoader::OpenCommon

无论是ArtDexFileLoader::OpenZip还是ArtDexFileLoader::OpenFile,最终都调用OpenCommon打开dex文件(Android 7对应函数为OpenMemory)


内部调用了DexFileLoader::OpenCommon


//art/libdexfile/dex/art_dex_file_loader.cc
std::unique_ptr ArtDexFileLoader::OpenCommon (constuint8_t* base,
size_t size,
constuint8_t* data_base,
size_t data_size,
const std::string& location,
uint32_t location_checksum,
const OatDexFile* oat_dex_file,
bool verify,
bool verify_checksum,
                                                      std::string* error_msg,
                                                      std::unique_ptr container,
                                                      VerifyResult* verify_result){
return DexFileLoader::OpenCommon(base,
                                   size,
                                   data_base,
                                   data_size,
                                   location,
                                   location_checksum,
                                   oat_dex_file,
                                   verify,
                                   verify_checksum,
                                   error_msg,
                                   std::move(container),
                                   verify_result);
}

DexFileLoader::OpenCommon


1.根据不同情况,调用StandardDexFile或CompactDexFile的构造函数创建DexFile对象


◆如果magic == “dex\n”则证明dex文件是标准型的,调用new StandardDexFile()

◆如果magic == “cdex” 则证明dex文件是紧凑型的,调用new CompactDexFile()

◆StandardDexFile与CompactDexFile都继承与DexFile,所以都会去调用DexFile::DexFile()构造函数


2.调用DexFile.Init方法进行初始化


3.调用DexFileVerifier::Verify对DexFile进行验证


4.返回DexFile


//art/libdexfile/dex/dex_file_loader.cc
std::unique_ptr DexFileLoader::OpenCommon(const uint8_t* base,
                                                   size_t size,
const uint8_t* data_base,
                                                   size_t data_size,
const std::string& location,
                                                   uint32_t location_checksum,
const OatDexFile* oat_dex_file,
bool verify,
bool verify_checksum,
                                                   std::string* error_msg,
                                                   std::unique_ptr container,
                                                   VerifyResult* verify_result) {
if (verify_result != nullptr) {
    *verify_result = VerifyResult::kVerifyNotAttempted;
  }
//1.创建DexFile对象
  std::unique_ptr dex_file;
if (size >= sizeof(StandardDexFile::Header) && StandardDexFile::IsMagicValid(base)) {
if (data_size != 0) {
CHECK_EQ(base, data_base) <"Unsupported for standard dex";
    }
//调用StandardDexFile构造函数进行创建,定义在art/libdexfile/dex/standard_dex_file.h,继承自DexFile
    dex_file.reset(new StandardDexFile(base,
                                       size,
                                       location,
                                       location_checksum,
                                       oat_dex_file,
                                       std::move(container)));
  } elseif (size >= sizeof(CompactDexFile::Header) && CompactDexFile::IsMagicValid(base)) {
if (data_base == nullptr) {
// TODO: Is there a clean way to support both an explicit data section and reading the one
// from the header.
CHECK_EQ(data_size, 0u);
const CompactDexFile::Header* const header = CompactDexFile::Header::At(base);
      data_base = base + header->data_off_;
      data_size = header->data_size_;
    }
// 调用CompactDexFile构造函数进行创建,定义在art/libdexfile/dex/compact_dex_file.h,继承自DexFile
    dex_file.reset(new CompactDexFile(base,
                                      size,
                                      data_base,
                                      data_size,
                                      location,
                                      location_checksum,
                                      oat_dex_file,
                                      std::move(container)));
// Disable verification for CompactDex input.
    verify = false;
  } else {
    *error_msg = "Invalid or truncated dex file";
  }
if (dex_file == nullptr) {
    *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
                              error_msg->c_str());
return nullptr;
  }
//2.init初始化dexfile
if (!dex_file->Init(error_msg)) {
    dex_file.reset();
return nullptr;
  }
//3.对dexfile进行验证
if (verify && !DexFileVerifier::Verify(dex_file.get(),
                                         dex_file->Begin(),
                                         dex_file->Size(),
                                         location.c_str(),
                                         verify_checksum,
                                         error_msg)) {
if (verify_result != nullptr) {
      *verify_result = VerifyResult::kVerifyFailed;
    }
return nullptr;
  }
if (verify_result != nullptr) {
    *verify_result = VerifyResult::kVerifySucceeded;
  }
return dex_file;
}

DexFile::Init

检查dex文件头和版本号


//art/libdexfile/dex/dex_file.cc
bool DexFile::Init(std::string* error_msg) {
if (!CheckMagicAndVersion(error_msg)) {
returnfalse;
  }
returntrue;
}
bool DexFile::CheckMagicAndVersion(std::string* error_msg) const {
if (!IsMagicValid()) {
    std::ostringstream oss;
    oss <"Unrecognized magic number in " 
            <" " << header_->magic_[0]
            <" " << header_->magic_[1]
            <" " << header_->magic_[2]
            <" " << header_->magic_[3];
    *error_msg = oss.str();
returnfalse;
  }
if (!IsVersionValid()) {
    std::ostringstream oss;
    oss <"Unrecognized version number in " 
            <" " << header_-> magic_[4]
            <" " << header_->magic_[5]
            <" " << header_->magic_[6]
            <" " << header_->magic_[7];
    *error_msg = oss.str();
returnfalse;
  }
returntrue;
}

DexFileVerifier::Verify

检查dex文件头,maplist以及其他部分


//art/libdexfile/dex/dex_file_verifier.cc
boolDexFileVerifier::Verify(const DexFile* dex_file,
constuint8_t* begin,
size_t size,
constchar* location,
bool verify_checksum,
                             std::string* error_msg){
std::unique_ptr verifier(
new DexFileVerifier(dex_file, begin, size, location, verify_checksum));
if (!verifier->Verify()) {
    *error_msg = verifier->FailureReason();
returnfalse;
  }
returntrue;
}

boolDexFileVerifier::Verify(){
// Check the header.
if (!CheckHeader()) {
returnfalse;
  }

// Check the map section.
if (!CheckMap()) {
returnfalse;
  }

// Check structure within remaining sections.
if (!CheckIntraSection()) {
returnfalse;
  }

// Check references from one section to another.
if (!CheckInterSection()) {
returnfalse;
  }

returntrue;
}

DexFile::DexFile

StandardDexFile或CompactDexFile都继承自DexFile


构造函数DexFile():后的意思是赋值,将()中的变量依次赋值给()前的变量


该方法带有dex文件的base和size参数,所以可以作为一个脱壳点


内部调用了InitializeSectionsFromMapList


//art/libdexfile/dex/dex_file.cc
DexFile::DexFile(const uint8_t* base,
                 size_t size,
                 const uint8_t* data_begin,
                 size_t data_size,
                 const std::string& location,
                 uint32_t location_checksum,
                 const OatDexFile* oat_dex_file,
                 std::unique_ptr container,
                 bool is_compact_dex)
    : begin_(base),
size_(size),
data_begin_(data_begin),
data_size_(data_size),
location_(location),
location_checksum_(location_checksum),
header_(reinterpret_cast(base)),
string_ids_(reinterpret_cast(base + header_->string_ids_off_)),
type_ids_(reinterpret_cast(base + header_->type_ids_off_)),
field_ids_(reinterpret_cast(base + header_->field_ids_off_)),
method_ids_(reinterpret_cast(base + header_->method_ids_off_)),
proto_ids_(reinterpret_cast(base + header_->proto_ids_off_)),
class_defs_(reinterpret_cast(base + header_->class_defs_off_)),
method_handles_(nullptr),
num_method_handles_(0),
call_site_ids_(nullptr),
num_call_site_ids_(0),
hiddenapi_class_data_(nullptr),
oat_dex_file_(oat_dex_file),
container_(std::move(container)),
is_compact_dex_(is_compact_dex),
hiddenapi_domain_(hiddenapi::Domain::kApplication) {
CHECK(begin_ != nullptr) ();
CHECK_GT(size_, 0U) ();
// Check base (=header) alignment.
// Must be 4-byte aligned to avoid undefined behavior when accessing
// any of the sections via a pointer.
CHECK_ALIGNED(begin_, alignof(Header));

InitializeSectionsFromMapList();
}

DexFile::InitializeSectionsFromMapList

通过dex文件中的map_list结构解析dex文件


//art/libdexfile/dex/dex_file.cc
void DexFile::InitializeSectionsFromMapList() {
const MapList* map_list = reinterpret_cast<const MapList*>(DataBegin() + header_->map_off_);
if (header_->map_off_ == 0 || header_->map_off_ > DataSize()) {
// Bad offset. The dex file verifier runs after this method and will reject the file.
return;
  }
const size_t count = map_list->size_;

  size_t map_limit = header_->map_off_ + count * sizeof(MapItem);
if (header_->map_off_ >= map_limit || map_limit > DataSize()) {
// Overflow or out out of bounds. The dex file verifier runs after
// this method and will reject the file as it is malformed.
return;
  }

for (size_t i = 0; i < count; ++i) {
const MapItem& map_item = map_list->list_[i];
if (map_item.type_ == kDexTypeMethodHandleItem) {
      method_handles_ = reinterpret_cast<const MethodHandleItem*>(Begin() + map_item.offset_);
      num_method_handles_ = map_item.size_;
    } elseif (map_item.type_ == kDexTypeCallSiteIdItem) {
      call_site_ids_ = reinterpret_cast<const CallSiteIdItem*>(Begin() + map_item.offset_);
      num_call_site_ids_ = map_item.size_;
    } elseif (map_item.type_ == kDexTypeHiddenapiClassData) {
      hiddenapi_class_data_ = GetHiddenapiClassDataAtOffset(map_item.offset_);
    } else {
// Pointers to other sections are not necessary to retain in the DexFile struct.
// Other items have pointers directly into their data.
    }
  }
}

InMemoryDexClassLoader

以下代码分析基于Android 10.0_r47 https://cs.android.com/android/platform/superproject/+/android-10.0.0_r47


Android 8.0中新增了InMemoryDexClassLoader,包含以下2个重载


//libcore/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java
publicfinalclassInMemoryDexClassLoaderextendsBaseDexClassLoader {

publicInMemoryDexClassLoader(ByteBuffer[] dexBuffers, ClassLoader parent) {
super(dexBuffers, parent);//调用父类BaseDexClassLoader构造函数
    }

publicInMemoryDexClassLoader(ByteBuffer dexBuffer, ClassLoader parent) {
this(newByteBuffer[] { dexBuffer }, parent);//调用另一个重载
    }
}

//libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
publicBaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) {
super(parent);
this.pathList = newDexPathList(this, dexFiles);//通过DexPathList进行处理
}


但执行壳代码进行替换classloader时,容易出现找不到lib库的情况,可参考以下文章解决so找不到的问题:


https://blog.csdn.net/q610098308/article/details/105246355

http://www.yxhuang.com/2020/03/28/android-so-load/


Android 10.0中新增了一个重载,支持传递lib库路径


//libcore/dalvik/src/main/java/dalvik/system/InMemoryDexClassLoader.java
publicfinalclassInMemoryDexClassLoaderextendsBaseDexClassLoader {
publicInMemoryDexClassLoader(@NonNull ByteBuffer @NonNull [] dexBuffers,
@Nullable String librarySearchPath, @Nullable ClassLoader parent) {
super(dexBuffers, librarySearchPath, parent);//调用父类BaseDexClassLoader构造函数
    }

publicInMemoryDexClassLoader(@NonNull ByteBuffer @NonNull [] dexBuffers,
@Nullable ClassLoader parent) {
this(dexBuffers, null, parent);//调用第1个重载
    }

publicInMemoryDexClassLoader(@NonNull ByteBuffer dexBuffer, @Nullable ClassLoader parent) {
this(new ByteBuffer[] { dexBuffer }, parent);//调用第2个重载
    }
}

BaseDexClassLoader

InMemoryDexClassLoader继承自BaseDexClassLoader,对应方法在父类中实现,内部创建了DexPathList对象。


//libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java    
public BaseDexClassLoader(ByteBuffer[] dexFiles, String librarySearchPath, ClassLoader parent) {
super(parent);
this.sharedLibraryLoaders = null;
this.pathList = new DexPathList(this, librarySearchPath);//创建对象并设置lib库目录
this.pathList.initByteBufferDexPath(dexFiles);//根据字节流创建dex文件
    }

DexPathList::DexPathList

//libcore/dalvik/src/main/java/dalvik/system/DexPathList.java    
public DexPathList(ClassLoader definingContext, String librarySearchPath) {
if (definingContext == null) {
throw new NullPointerException("definingContext == null");
        }

this.definingContext = definingContext;
//分割传入的lib库目录(支持通过一个String传递多个)
this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);
//系统lib库目录
this.systemNativeLibraryDirectories =
                splitPaths(System.getProperty("java.library.path"), true);
//将所有lib库目录封装为NativeLibraryElement对象并添加到elements数组
this.nativeLibraryPathElements = makePathElements(getAllNativeLibraryDirectories());
    }


getAllNativeLibraryDirectories代码如下,将传入的lib库和系统lib库目录添加到一起并返回


private List getAllNativeLibraryDirectories() {
        List allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
        allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
return allNativeLibraryDirectories;
    }

DexPathList::makePathElements

//libcore/dalvik/src/main/java/dalvik/system/DexPathList.java    
@UnsupportedAppUsage
privatestaticNativeLibraryElement[] makePathElements(List files) {
NativeLibraryElement[] elements = newNativeLibraryElement[files.size()];
        int elementsPos = 0;
//遍历files,将存在的lib库封装为NativeLibraryElement对象,并添加到elements中
for (File file : files) {
String path = file.getPath();

if (path.contains(zipSeparator)) {
String split[] = path.split(zipSeparator, 2);
File zip = newFile(split[0]);
String dir = split[1];
                elements[elementsPos++] = newNativeLibraryElement(zip, dir);
            } elseif






请到「今天看啥」查看全文