很多脱壳教程里面经常看到在dvmDexFileOpenPartial这个函数下断点,但是为什么在这个函数下断点就能把dex dump下来呢,下面从源码来看看dex的优化流程。
源码传送门:http://androidxref.com/4.4_r1/xref/dalvik/dexopt/OptMain.cpp
OptMain中的main函数就是优化dex的原始入口:
int main(int argc, char* const argv[])
{
set_process_name(“dexopt”);
setvbuf(stdout, NULL, _IONBF, 0);
if (argc > 1) {
if (strcmp(argv[1], “–zip”) == 0)
return fromZip(argc, argv);
else if (strcmp(argv[1], “–dex”) == 0)
return fromDex(argc, argv);
else if (strcmp(argv[1], “–preopt”) == 0)
return preopt(argc, argv);
}
fprintf(stderr,
“Usage:\n\n”
“Short version: Don’t use this.\n\n”
“Slightly longer version: This system-internal tool is used to\n”
“produce optimized dex files. See the source code for details.\n”);
return 1;
}
这里分别对三种不同类型的文件做不同的处理,跟进fromdex函数看看对dex是如何处理的。
static int fromDex(int argc, char* const argv[])
{
…….
if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {
ALOGE(“VM init failed”);
goto bail;
}
vmStarted = true;
/* do the optimization */
if (!dvmContinueOptimization(fd, offset, length, debugFileName,
modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0))
{
ALOGE(“Optimization failed”);
goto bail;
}
…….
}
首先初始化虚拟机,然后调用dvmContinueOptimization函数,继续跟进:
bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
{
…….
/*
* Rewrite the file. Byte reordering, structure realigning,
* class verification, and bytecode optimization are all performed
* here.
*
* In theory the file could change size and bits could shift around.
* In practice this would be annoying to deal with, so the file
* layout is designed so that it can always be rewritten in place.
*
* This creates the class lookup table as part of doing the processing.
*/
success = rewriteDex(((u1*) mapAddr) + dexOffset, dexLength,
doVerify, doOpt, &pClassLookup, NULL);
if (success) {
DvmDex* pDvmDex = NULL;
u1* dexAddr = ((u1*) mapAddr) + dexOffset;
if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
ALOGE(“Unable to create DexFile”);
success = false;
} else {
/*
* If configured to do so, generate register map output
* for all verified classes. The register maps were
* generated during verification, and will now be serialized.
*/
if (gDvm.generateRegisterMaps) {
pRegMapBuilder = dvmGenerateRegisterMaps(pDvmDex);
if (pRegMapBuilder == NULL) {
ALOGE(“Failed generating register maps”);
success = false;
}
}
DexHeader* pHeader = (DexHeader*)pDvmDex->pHeader;
updateChecksum(dexAddr, dexLength, pHeader);
dvmDexFileFree(pDvmDex);
}
}
…….
}
这个函数对Dex文件做了一些优化(字节重排序,结构对齐,字节优化等),然后重新写入Dex文件,如果优化重写成功就调用dvmDexFileOpenPartial,这个函数的第一个参数就是dex文件的起始地址,第二个参数是dex的长度,继续跟进:
/*
* Create a DexFile structure for a “partial” DEX. This is one that is in
* the process of being optimized. The optimization header isn’t finished
* and we won’t have any of the auxillary data tables, so we have to do
* the initialization slightly differently.
*
* Returns nonzero on error.
*/
int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex)
{
DvmDex* pDvmDex;
DexFile* pDexFile;
int parseFlags = kDexParseDefault;
int result = -1;
/* — file is incomplete, new checksum has not yet been calculated
if (gDvm.verifyDexChecksum)
parseFlags |= kDexParseVerifyChecksum;
*/
pDexFile = dexFileParse((u1*)addr, len, parseFlags);
if (pDexFile == NULL) {
ALOGE(“DEX parse failed”);
goto bail;
}
pDvmDex = allocateAuxStructures(pDexFile);
if (pDvmDex == NULL) {
dexFileFree(pDexFile);
goto bail;
}
pDvmDex->isMappedReadOnly = false;
*ppDvmDex = pDvmDex;
result = 0;
bail:
return result;
}
里面调用了dexFileParse来具体解析Dex文件。
所以断点在这个地方就能获取加载的dex文件。