android dex加载过程,[原创]菜鸟学8.1版本dex加载流程笔记--第二篇:DexFile::Open流程与简单脱壳原理...

std::unique_ptr DexFile::OpenOneDexFileFromZip(const ZipArchive& zip_archive,

const char* entry_name,

const std::string& location,

bool verify_checksum,

std::string* error_msg,

ZipOpenErrorCode* error_code) {

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 = ZipOpenErrorCode::kEntryNotFound;

return nullptr;

}

if (zip_entry->GetUncompressedLength() == 0) {

*error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());

*error_code = ZipOpenErrorCode::kDexFileError;

return nullptr;

}

std::unique_ptr map;

if (zip_entry->IsUncompressed()) {

if (!zip_entry->IsAlignedTo(alignof(Header))) {

// Do not mmap unaligned ZIP entries because

// doing so would fail dex verification which requires 4 byte alignment.

LOG(WARNING) <

<

<

} else {

// Map uncompressed files within zip as file-backed to avoid a dirty copy.

map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));

if (map == nullptr) {

LOG(WARNING) <

<

// Try again with Extraction which still has a chance of recovery.

}

}

}

if (map == nullptr) {

// Default path for compressed ZIP entries,

// and fallback for stored ZIP entries.

map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));

}

if (map == nullptr) {

*error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),

error_msg->c_str());

*error_code = ZipOpenErrorCode::kExtractToMemoryError;

return nullptr;

}

VerifyResult verify_result;

std::unique_ptr dex_file = OpenCommon(map->Begin(),

map->Size(),

location,

zip_entry->GetCrc32(),

kNoOatDexFile,

/* verify */ true,

verify_checksum,

error_msg,

&verify_result);

if (dex_file == nullptr) {

if (verify_result == VerifyResult::kVerifyNotAttempted) {

*error_code = ZipOpenErrorCode::kDexFileError;

} else {

*error_code = ZipOpenErrorCode::kVerifyError;

}

return nullptr;

}

dex_file->mem_map_ = std::move(map);

if (!dex_file->DisableWrite()) {

*error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());

*error_code = ZipOpenErrorCode::kMakeReadOnlyError;

return nullptr;

}

CHECK(dex_file->IsReadOnly()) <

if (verify_result != VerifyResult::kVerifySucceeded) {

*error_code = ZipOpenErrorCode::kVerifyError;

return nullptr;

}

*error_code = ZipOpenErrorCode::kNoError;

return dex_file;

}

3.最后我们认真分析OpenCommon这个函数,无论是通过oat_file获得的

oat_dex_file

获得

dex_file

也好,是直接打开zip或者dex文件获得

dex_file

也好,最终都得用到这个函数,所以它作为常用脱壳点的意义就很清楚了,它的前2个参数分别是dex的起始地址和大小,直接hook就可以dump出dex了。

其实只要有base地址,通过dex数据结构就可以定位size,加个偏移就行parseInt(base,16) + 0x20

std::unique_ptr DexFile::OpenCommon(const uint8_t* base,//这里是dex的开始

size_t size,//这里是dex的大小

const std::string& location,//这里是地址

uint32_t location_checksum,

const OatDexFile* oat_dex_file,//如果直接打开文件而不是通过oat文件获得dex,这个参数是kNoOatDexFile,hook打印这个参数就可以判断一些壳是否放弃了oat文件强制以dex解释运行

bool verify,

bool verify_checksum,

std::string* error_msg,

VerifyResult* verify_result) {

if (verify_result != nullptr) {

*verify_result = VerifyResult::kVerifyNotAttempted;

}

std::unique_ptr dex_file(new DexFile(base,

size,

location,

location_checksum,

oat_dex_file));//这里new了一个dex_file实例,至此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)) {//init初始化

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)) {//Verify验证

if (verify_result != nullptr) {

*verify_result = VerifyResult::kVerifyFailed;

}

return nullptr;

}

if (verify_result != nullptr) {

*verify_result = VerifyResult::kVerifySucceeded;

}

return dex_file;

}

最后,仍然是画个及其丑陋的图,辅助自己理解。

27525251119cd1aa99a3e382a35b1d09.png

4.下面贴一下frida hook脱壳脚本,很简单,每一步我都备注了,上次问我的同学仔细看一下,看看还有什么问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值