【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函数读取 DEX 文件 )
2023-06-13 09:18:00 时间
文章目录
前言
上一篇博客 【Android 逆向】整体加固脱壳 ( DexClassLoader 加载 dex 流程分析 | 查找 DexFile 对应的C代码 | dalvik_system_DexFile.cpp 分析 ) 中 , dalvik_system_DexFile.cpp 的 Dalvik_dalvik_system_DexFile_openDexFileNative() 方法中 , 调用了 RawDexFile.cpp 中的 dvmRawDexFileOpen() 方法 ;
一、RawDexFile.cpp 中 dvmRawDexFileOpen() 方法分析
调用 open 函数 以只读形式 , 打开了 DEX 文件 ;
dexFd = open(fileName, O_RDONLY);
校验 DEX 文件 ;
verifyMagicAndGetAdler32(dexFd, &adler32) < 0
调用 DexPrepare.cpp 中的 dvmOptimizeDexFile() 函数 , 优化 DEX 文件 ;
result = dvmOptimizeDexFile(optFd, dexOffset, fileSize,
fileName, modTime, adler32, isBootstrap);
源码示例 :
/*
* 打开一个未优化的 DEX 文件.
*/
/* 请参阅页眉中的文档注释. */
int dvmRawDexFileOpen(const char* fileName, const char* odexOutputName,
RawDexFile** ppRawDexFile, bool isBootstrap)
{
/*
* TODO: 这复制了JarFile.c 中 dvmJarFileOpen() 的大量代码。这应该被重构。
*/
DvmDex* pDvmDex = NULL;
char* cachedName = NULL;
int result = -1;
int dexFd = -1;
int optFd = -1;
u4 modTime = 0;
u4 adler32 = 0;
size_t fileSize = 0;
bool newFile = false;
bool locked = false;
// 调用 open 函数 以只读形式 , 打开了 DEX 文件
dexFd = open(fileName, O_RDONLY);
if (dexFd < 0) goto bail;
/* If we fork/exec into dexopt, don't let it inherit the open fd. */
dvmSetCloseOnExec(dexFd);
// 校验 DEX 文件
if (verifyMagicAndGetAdler32(dexFd, &adler32) < 0) {
ALOGE("Error with header for %s", fileName);
goto bail;
}
if (getModTimeAndSize(dexFd, &modTime, &fileSize) < 0) {
ALOGE("Error with stat for %s", fileName);
goto bail;
}
/*
* 查看缓存的文件是否匹配。如果是这样,optFd将成为一个参考
* 到缓存文件,并将被查找到刚刚超过“opt”
* 标题。
*/
if (odexOutputName == NULL) {
// 优化的过程
cachedName = dexOptGenerateCacheFileName(fileName, NULL);
if (cachedName == NULL)
goto bail;
} else {
cachedName = strdup(odexOutputName);
}
ALOGV("dvmRawDexFileOpen: Checking cache for %s (%s)",
fileName, cachedName);
optFd = dvmOpenCachedDexFile(fileName, cachedName, modTime,
adler32, isBootstrap, &newFile, /*createIfMissing=*/true);
if (optFd < 0) {
ALOGI("Unable to open or create cache for %s (%s)",
fileName, cachedName);
goto bail;
}
locked = true;
/*
* 如果optFd指向一个新文件(因为没有缓存
* 版本,或缓存的版本已过时),生成
* 优化的DEX。返回的文件描述符仍处于锁定状态,
* 并定位在刚好超过优化标题的位置。
*/
if (newFile) {
u8 startWhen, copyWhen, endWhen;
bool result;
off_t dexOffset;
dexOffset = lseek(optFd, 0, SEEK_CUR);
result = (dexOffset > 0);
if (result) {
startWhen = dvmGetRelativeTimeUsec();
result = copyFileToFile(optFd, dexFd, fileSize) == 0;
copyWhen = dvmGetRelativeTimeUsec();
}
if (result) {
result = dvmOptimizeDexFile(optFd, dexOffset, fileSize,
fileName, modTime, adler32, isBootstrap);
}
if (!result) {
ALOGE("Unable to extract+optimize DEX from '%s'", fileName);
goto bail;
}
endWhen = dvmGetRelativeTimeUsec();
ALOGD("DEX prep '%s': copy in %dms, rewrite %dms",
fileName,
(int) (copyWhen - startWhen) / 1000,
(int) (endWhen - copyWhen) / 1000);
}
/*
* 映射缓存的版本。这会立即倒带fd,因此
* 不需要在任何地方寻找。
*/
if (dvmDexFileOpenFromFd(optFd, &pDvmDex) != 0) {
ALOGI("Unable to map cached %s", fileName);
goto bail;
}
if (locked) {
/* unlock the fd */
if (!dvmUnlockCachedDexFile(optFd)) {
/* uh oh -- this process needs to exit or we'll wedge the system */
ALOGE("Unable to unlock DEX file");
goto bail;
}
locked = false;
}
ALOGV("Successfully opened '%s'", fileName);
*ppRawDexFile = (RawDexFile*) calloc(1, sizeof(RawDexFile));
(*ppRawDexFile)->cacheFileName = cachedName;
(*ppRawDexFile)->pDvmDex = pDvmDex;
cachedName = NULL; // don't free it below
result = 0;
bail:
free(cachedName);
if (dexFd >= 0) {
close(dexFd);
}
if (optFd >= 0) {
if (locked)
(void) dvmUnlockCachedDexFile(optFd);
close(optFd);
}
return result;
}
相关文章
- 聚焦 Android 11: 大功告成
- android studio不能输入中文_Android模拟器
- android 置灰不可点击,Android Studio 运行按钮灰色的完美解决方法
- (七十)Android O Service启动流程梳理——bindService
- Android 基于TCP的 Socket 编程实现(结合 okio)
- android toast防重_如何解决android Toast重复显示
- Android 项目开发填坑记 - 谷歌商店上架被拒 Apps On Device
- android跳转到相册需要权限,Android打开相册获取图片路径[通俗易懂]
- 【Android NDK 开发】Ubuntu 函数库交叉编译 ( Android 动态库交叉编译 | Android 静态库交叉编译 )
- 【Android RTMP】Android Camera 视频数据采集预览 ( 图像传感器方向设置 | Camera 使用流程 | 动态权限申请 )
- 【Android 高性能音频】Oboe 开发流程 ( 包含头 Oboe 头文件 | 创建音频流 | 设置音频流 | 音频流回调类 AudioStreamCallback )
- 【Android 事件分发】MotionEvent.ACTION_DOWN 按下事件分发流程( Activity | ViewGroup | View )
- 【Android 逆向】Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )
- 【Android 逆向】Android 进程代码注入原理 ( 进程注入原理 | 远程调用流程 | 获取函数地址 | 设置 IP 寄存器 | mmap 申请内存 | 设置 SP 寄存器 )
- 【Android 逆向】启动 DEX 字节码中的 Activity 组件 ( 在 PathClassLoader 和 BootClassLoader 之间插入 DexClassLoader )
- 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | dvmDexFileOpenPartial | dexFileParse | 脱壳点 | 获取 dex 文件在内存中的首地址 )
- Windows PC、Linux、Android、iOS 跨平台视频云客户端 QML 开发解决方案
- 使用Android实现连接MySQL数据库:实现快速数据交互与管理(android连接mysql数据库)
- Android中判断网络连接是否可用及监控网络状态
- 解析Android开发优化之:对Bitmap的内存优化详解