正文
(canonical_it != oat_dex_files_.
end
()) {
oat_dex_file = canonical_it->second;
}
}
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);
}
}
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
;
}
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
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
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,
nullptr,
0u,
location,
location_checksum,
oat_dex_file,
verify,
verify_checksum,
error_msg,
std::move(container),
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打开。
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;
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";
if (IsZipMagic(magic)) {
returnOpenZip(fd, location, verify, verify_checksum, error_msg, dex_files);
}
if (IsMagicValid(magic)) {
std::unique_ptr<const DexFile> dex_file(OpenFile(fd,
location,
verify,
verify_checksum,
false,
error_msg));
if (dex_file.get() != nullptr) {
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 {
dex_files->push_back(std::move(dex_file));
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());
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))) {
LOG(WARNING) <"Can't mmap dex file " << location <"!" << entry_name <" directly; "
<"please zipalign to "
<"Falling back to extracting file.";
} else {
map = zip_entry->MapDirectlyFromFile(location.c_str(), 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.";
}
}
}
std::unique_ptr dex_file = OpenCommon(begin,
size,
nullptr,
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, false);
structstat sbuf;
memset(&sbuf, 0, sizeof(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;
map = MemMap::MapFile(length,
PROT_READ,
mmap_shared ? MAP_SHARED : MAP_PRIVATE,
fd,
0,
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);
std::unique_ptr dex_file = OpenCommon(begin,
size,
nullptr,
0u,
location,
dex_header->checksum_,
kNoOatDexFile,
verify,
verify_checksum,
error_msg,
std::make_unique(std::move(map)),
nullptr);
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
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
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;
}
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";
}
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) {
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_;
}
dex_file.reset(new CompactDexFile(base,
size,
data_base,
data_size,
location,
location_checksum,
oat_dex_file,
std::move(container)));
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;
}
if (!dex_file->Init(error_msg)) {
dex_file.reset();
return nullptr;
}
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文件头和版本号
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以及其他部分
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(){
if (!CheckHeader()) {
returnfalse;
}
if (!CheckMap()) {
returnfalse;
}
if (!CheckIntraSection()) {
returnfalse;
}
if (!CheckInterSection()) {
returnfalse;
}
returntrue;
}
DexFile::DexFile
StandardDexFile或CompactDexFile都继承自DexFile
构造函数DexFile():后的意思是赋值,将()中的变量依次赋值给()前的变量
该方法带有dex文件的base和size参数,所以可以作为一个脱壳点
内部调用了InitializeSectionsFromMapList
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_ALIGNED(begin_, alignof(Header));
InitializeSectionsFromMapList();
}
DexFile::InitializeSectionsFromMapList
通过dex文件中的map_list结构解析dex文件
void DexFile::InitializeSectionsFromMapList() {
const MapList* map_list = reinterpret_cast<const MapList*>(DataBegin() + header_->map_off_);
if (header_->map_off_ == 0 || header_->map_off_ > DataSize()) {
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()) {
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 {
}
}
}
InMemoryDexClassLoader
以下代码分析基于Android 10.0_r47 https://cs.android.com/android/platform/superproject/+/android-10.0.0_r47
Android 8.0中新增了InMemoryDexClassLoader,包含以下2个重载
publicfinalclassInMemoryDexClassLoaderextendsBaseDexClassLoader {
publicInMemoryDexClassLoader(ByteBuffer[] dexBuffers, ClassLoader parent) {
super(dexBuffers, parent);
}
publicInMemoryDexClassLoader(ByteBuffer dexBuffer, ClassLoader parent) {
this(newByteBuffer[] { dexBuffer }, parent);
}
}
publicBaseDexClassLoader(ByteBuffer[] dexFiles, ClassLoader parent) {
super(parent);
this.pathList = newDexPathList(this, dexFiles);
}
但执行壳代码进行替换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库路径
publicfinalclassInMemoryDexClassLoaderextendsBaseDexClassLoader {
publicInMemoryDexClassLoader(@NonNull ByteBuffer @NonNull [] dexBuffers,
@Nullable String librarySearchPath, @Nullable ClassLoader parent) {
super(dexBuffers, librarySearchPath, parent);
}
publicInMemoryDexClassLoader(@NonNull ByteBuffer @NonNull [] dexBuffers,
@Nullable ClassLoader parent) {
this(dexBuffers, null, parent);
}
publicInMemoryDexClassLoader(@NonNull ByteBuffer dexBuffer, @Nullable ClassLoader parent) {
this(new ByteBuffer[] { dexBuffer }, parent);
}
}
BaseDexClassLoader
InMemoryDexClassLoader继承自BaseDexClassLoader,对应方法在父类中实现,内部创建了DexPathList对象。
public BaseDexClassLoader(ByteBuffer[] dexFiles, String librarySearchPath, ClassLoader parent) {
super(parent);
this.sharedLibraryLoaders = null;
this.pathList = new DexPathList(this, librarySearchPath);
this.pathList.initByteBufferDexPath(dexFiles);
}
DexPathList::DexPathList
public DexPathList(ClassLoader definingContext, String librarySearchPath) {
if (definingContext == null) {
throw new NullPointerException("definingContext == null");
}
this.definingContext = definingContext;
this.nativeLibraryDirectories = splitPaths(librarySearchPath, false);
this.systemNativeLibraryDirectories =
splitPaths(System.getProperty("java.library.path"), true);
this.nativeLibraryPathElements = makePathElements(getAllNativeLibraryDirectories());
}
getAllNativeLibraryDirectories代码如下,将传入的lib库和系统lib库目录添加到一起并返回
private List getAllNativeLibraryDirectories() {
List allNativeLibraryDirectories = new ArrayList<>(nativeLibraryDirectories);
allNativeLibraryDirectories.addAll(systemNativeLibraryDirectories);
return allNativeLibraryDirectories;
}
DexPathList::makePathElements
@UnsupportedAppUsage
privatestaticNativeLibraryElement[] makePathElements(List files) {
NativeLibraryElement[] elements = newNativeLibraryElement[files.size()];
int elementsPos = 0;
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