日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )

發(fā)布時(shí)間:2025/6/17 Android 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 ) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 前言
  • 一、DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析
  • 二、/bin/dexopt 源碼分析

前言


上一篇博客 【Android 逆向】整體加固脫殼 ( DexClassLoader 加載 dex 流程分析 | RawDexFile.cpp 分析 | dvmRawDexFileOpen函數(shù)讀取 DEX 文件 ) 中 , 在 RawDexFile.cpp 中的 dvmRawDexFileOpen() 方法中 , 調(diào)用了 DexPrepare.cppdvmOptimizeDexFile() 函數(shù) , 對(duì) DEX 文件進(jìn)行了優(yōu)化 ;





一、DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析



dvmOptimizeDexFile 函數(shù)的參數(shù)說(shuō)明 : int fd 是打開(kāi)的 dex 文件標(biāo)識(shí)符 , long dexLength 是打開(kāi)的 dex 文件大小 ;

在該函數(shù)中 , 調(diào)用 /bin/dexopt 程序 , 優(yōu)化 dex 文件 , 最終產(chǎn)生 odex 文件 ;


/** 給定包含DEX數(shù)據(jù)的文件的描述符,生成* 優(yōu)化版本。* * “fd”指向的文件應(yīng)為鎖定的共享資源* (或私人);我們不努力實(shí)施多進(jìn)程正確性* 在這里。* * “文件名”僅用于調(diào)試輸出。存儲(chǔ)“modWhen”和“crc”* 在依賴項(xiàng)集中。* * “isBootstrap”標(biāo)志確定優(yōu)化器和驗(yàn)證器如何處理* 包范圍訪問(wèn)檢查。優(yōu)化時(shí),我們只加載引導(dǎo)* 類DEX文件和目標(biāo)DEX,因此該標(biāo)志確定* 給目標(biāo)DEX類一個(gè)(合成的)非空類加載器指針。* 只有當(dāng)目標(biāo)DEX包含聲明* 與引導(dǎo)類位于同一個(gè)包中。* * 優(yōu)化器需要加載目標(biāo)DEX文件中的每個(gè)類。* 這通常是不可取的,因此我們啟動(dòng)一個(gè)子流程來(lái)執(zhí)行* 工作并等待它完成。* * 成功時(shí)返回“true”。所有數(shù)據(jù)均已寫(xiě)入“fd”。*/ bool dvmOptimizeDexFile(int fd, off_t dexOffset, long dexLength,const char* fileName, u4 modWhen, u4 crc, bool isBootstrap) {const char* lastPart = strrchr(fileName, '/');if (lastPart != NULL)lastPart++;elselastPart = fileName;ALOGD("DexOpt: --- BEGIN '%s' (bootstrap=%d) ---", lastPart, isBootstrap);pid_t pid;/** 如果我們的bootclasspath中出現(xiàn)了我們認(rèn)為* 都優(yōu)化了,被拒絕了。*/if (gDvm.optimizing) {ALOGW("Rejecting recursive optimization attempt on '%s'", fileName);return false;}pid = fork();if (pid == 0) {static const int kUseValgrind = 0;// 調(diào)用 /bin/dexopt 程序 , 優(yōu)化 dex 文件 , 最終產(chǎn)生 odex 文件static const char* kDexOptBin = "/bin/dexopt";static const char* kValgrinder = "/usr/bin/valgrind";static const int kFixedArgCount = 10;static const int kValgrindArgCount = 5;static const int kMaxIntLen = 12; // '-'+10dig+'\0' -OR- 0x+8digint bcpSize = dvmGetBootPathSize();int argc = kFixedArgCount + bcpSize+ (kValgrindArgCount * kUseValgrind);const char* argv[argc+1]; // last entry is NULLchar values[argc][kMaxIntLen];char* execFile;const char* androidRoot;int flags;/* change process groups, so we don't clash with ProcessManager */setpgid(0, 0);/* full path to optimizer */androidRoot = getenv("ANDROID_ROOT");if (androidRoot == NULL) {ALOGW("ANDROID_ROOT not set, defaulting to /system");androidRoot = "/system";}execFile = (char*)alloca(strlen(androidRoot) + strlen(kDexOptBin) + 1);strcpy(execFile, androidRoot);strcat(execFile, kDexOptBin);/** Create arg vector.*/int curArg = 0;if (kUseValgrind) {/* probably shouldn't ship the hard-coded path */argv[curArg++] = (char*)kValgrinder;argv[curArg++] = "--tool=memcheck";argv[curArg++] = "--leak-check=yes"; // check for leaks tooargv[curArg++] = "--leak-resolution=med"; // increase from 2 to 4argv[curArg++] = "--num-callers=16"; // default is 12assert(curArg == kValgrindArgCount);}argv[curArg++] = execFile;argv[curArg++] = "--dex";sprintf(values[2], "%d", DALVIK_VM_BUILD);argv[curArg++] = values[2];sprintf(values[3], "%d", fd);argv[curArg++] = values[3];sprintf(values[4], "%d", (int) dexOffset);argv[curArg++] = values[4];sprintf(values[5], "%d", (int) dexLength);argv[curArg++] = values[5];argv[curArg++] = (char*)fileName;sprintf(values[7], "%d", (int) modWhen);argv[curArg++] = values[7];sprintf(values[8], "%d", (int) crc);argv[curArg++] = values[8];flags = 0;if (gDvm.dexOptMode != OPTIMIZE_MODE_NONE) {flags |= DEXOPT_OPT_ENABLED;if (gDvm.dexOptMode == OPTIMIZE_MODE_ALL)flags |= DEXOPT_OPT_ALL;}if (gDvm.classVerifyMode != VERIFY_MODE_NONE) {flags |= DEXOPT_VERIFY_ENABLED;if (gDvm.classVerifyMode == VERIFY_MODE_ALL)flags |= DEXOPT_VERIFY_ALL;}if (isBootstrap)flags |= DEXOPT_IS_BOOTSTRAP;if (gDvm.generateRegisterMaps)flags |= DEXOPT_GEN_REGISTER_MAPS;sprintf(values[9], "%d", flags);argv[curArg++] = values[9];assert(((!kUseValgrind && curArg == kFixedArgCount) ||((kUseValgrind && curArg == kFixedArgCount+kValgrindArgCount))));ClassPathEntry* cpe;for (cpe = gDvm.bootClassPath; cpe->ptr != NULL; cpe++) {argv[curArg++] = cpe->fileName;}assert(curArg == argc);argv[curArg] = NULL;if (kUseValgrind)execv(kValgrinder, const_cast<char**>(argv));elseexecv(execFile, const_cast<char**>(argv));ALOGE("execv '%s'%s failed: %s", execFile,kUseValgrind ? " [valgrind]" : "", strerror(errno));exit(1);} else {ALOGV("DexOpt: waiting for verify+opt, pid=%d", (int) pid);int status;pid_t gotPid;/** 等待優(yōu)化過(guò)程完成。我們進(jìn)入VMI等待* 模式,這樣GC暫停就不必等待我們了。*/ThreadStatus oldStatus = dvmChangeStatus(NULL, THREAD_VMWAIT);while (true) {gotPid = waitpid(pid, &status, 0);if (gotPid == -1 && errno == EINTR) {ALOGD("waitpid interrupted, retrying");} else {break;}}dvmChangeStatus(NULL, oldStatus);if (gotPid != pid) {ALOGE("waitpid failed: wanted %d, got %d: %s",(int) pid, (int) gotPid, strerror(errno));return false;}if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {ALOGD("DexOpt: --- END '%s' (success) ---", lastPart);return true;} else {ALOGW("DexOpt: --- END '%s' --- status=0x%04x, process failed",lastPart, status);return false;}} }



二、/bin/dexopt 源碼分析



dex 文件優(yōu)化 , 主要是調(diào)用 /bin/dexopt 程序 , 最終產(chǎn)生 odex 文件 ;

其源碼路徑是 /dalvik/dexopt/ 路徑 ,

該 OptMain.cpp 源碼是一個(gè)有 main 函數(shù) , 可以獨(dú)立執(zhí)行的 C++ 程序 , 可以在 Android 命令中執(zhí)行 ;

加載 dex 文件時(shí) , 執(zhí)行 fromDex 函數(shù) ;

return fromDex(argc, argv);

在 fromfromDex 函數(shù)中 , 先準(zhǔn)備優(yōu)化環(huán)境 ,

if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {ALOGE("VM init failed");goto bail;}

然后進(jìn)行正式優(yōu)化 ;

/* do the optimization */if (!dvmContinueOptimization(fd, offset, length, debugFileName,modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0)){ALOGE("Optimization failed");goto bail;}

真正的優(yōu)化操作 , 在 dvmContinueOptimization 函數(shù)中執(zhí)行的 ;


核心源碼如下 : 源碼路徑 /dalvik/dexopt/OptMain.cpp

/** Copyright (C) 2008 The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*//** 命令行DEX優(yōu)化和驗(yàn)證入口點(diǎn)。* * 有三種方法可以啟動(dòng)此功能:* (1)來(lái)自虛擬機(jī)。這需要十幾個(gè)參數(shù),其中一個(gè)是文件* 同時(shí)作為輸入和輸出的描述符。這使我們能夠* 仍然不知道DEX數(shù)據(jù)最初來(lái)自何處。* (2)來(lái)自installd或其他本機(jī)應(yīng)用程序。傳入文件* 用于zip文件的描述符、用于輸出的文件描述符,以及* 調(diào)試消息的文件名。關(guān)于這一點(diǎn),人們做了許多假設(shè)* 發(fā)生了什么(驗(yàn)證+優(yōu)化已啟用,啟動(dòng)* 類路徑位于BOOTCLASSPATH中,等等)。* (3)在構(gòu)建過(guò)程中在主機(jī)上進(jìn)行預(yù)優(yōu)化。這種行為* 與(2)幾乎相同,只是它采用文件名而不是* 文件描述符。* * bootclasspath條目存在一些脆弱的方面,原因如下* 很大程度上是由于虛擬機(jī)在它認(rèn)為需要的時(shí)候進(jìn)行工作的歷史* 而不是嚴(yán)格按照要求去做。如果優(yōu)化引導(dǎo)類路徑* 條目,始終按照它們?cè)诼窂街谐霈F(xiàn)的順序執(zhí)行。*/ #include "Dalvik.h" #include "libdex/OptInvocation.h"#include "cutils/log.h" #include "cutils/process_name.h"#include <fcntl.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> #include <string.h>static const char* kClassesDex = "classes.dex";/* *將zipFd中的“classes.dex”提取到“cacheFd”中,留下一點(diǎn)空間 *用于DEX優(yōu)化收割臺(tái)的前端。 */ static int extractAndProcessZip(int zipFd, int cacheFd,const char* debugFileName, bool isBootstrap, const char* bootClassPath,const char* dexoptFlagStr) {ZipArchive zippy;ZipEntry zipEntry;size_t uncompLen;long modWhen, crc32;off_t dexOffset;int err;int result = -1;int dexoptFlags = 0; /* bit flags, from enum DexoptFlags */DexClassVerifyMode verifyMode = VERIFY_MODE_ALL;DexOptimizerMode dexOptMode = OPTIMIZE_MODE_VERIFIED;memset(&zippy, 0, sizeof(zippy));/* make sure we're still at the start of an empty file */if (lseek(cacheFd, 0, SEEK_END) != 0) {ALOGE("DexOptZ: new cache file '%s' is not empty", debugFileName);goto bail;}/**編寫(xiě)骨架索引優(yōu)化標(biāo)頭。我們要上課。指數(shù)*緊跟其后。*/err = dexOptCreateEmptyHeader(cacheFd);if (err != 0)goto bail;/* record the file position so we can get back here later */dexOffset = lseek(cacheFd, 0, SEEK_CUR);if (dexOffset < 0)goto bail;/**打開(kāi)zip存檔,找到DEX條目。*/if (dexZipPrepArchive(zipFd, debugFileName, &zippy) != 0) {ALOGW("DexOptZ: unable to open zip archive '%s'", debugFileName);goto bail;}zipEntry = dexZipFindEntry(&zippy, kClassesDex);if (zipEntry == NULL) {ALOGW("DexOptZ: zip archive '%s' does not include %s",debugFileName, kClassesDex);goto bail;}/**提取一些關(guān)于zip條目的信息。*/if (dexZipGetEntryInfo(&zippy, zipEntry, NULL, &uncompLen, NULL, NULL,&modWhen, &crc32) != 0){ALOGW("DexOptZ: zip archive GetEntryInfo failed on %s", debugFileName);goto bail;}uncompLen = uncompLen;modWhen = modWhen;crc32 = crc32;/**以當(dāng)前偏移量將DEX數(shù)據(jù)提取到緩存文件中。*/if (dexZipExtractEntryToFile(&zippy, zipEntry, cacheFd) != 0) {ALOGW("DexOptZ: extraction of %s from %s failed",kClassesDex, debugFileName);goto bail;}/* Parse the options. */if (dexoptFlagStr[0] != '\0') {const char* opc;const char* val;opc = strstr(dexoptFlagStr, "v="); /* verification */if (opc != NULL) {switch (*(opc+2)) {case 'n': verifyMode = VERIFY_MODE_NONE; break;case 'r': verifyMode = VERIFY_MODE_REMOTE; break;case 'a': verifyMode = VERIFY_MODE_ALL; break;default: break;}}opc = strstr(dexoptFlagStr, "o="); /* optimization */if (opc != NULL) {switch (*(opc+2)) {case 'n': dexOptMode = OPTIMIZE_MODE_NONE; break;case 'v': dexOptMode = OPTIMIZE_MODE_VERIFIED; break;case 'a': dexOptMode = OPTIMIZE_MODE_ALL; break;case 'f': dexOptMode = OPTIMIZE_MODE_FULL; break;default: break;}}opc = strstr(dexoptFlagStr, "m=y"); /* register map */if (opc != NULL) {dexoptFlags |= DEXOPT_GEN_REGISTER_MAPS;}opc = strstr(dexoptFlagStr, "u="); /* uniprocessor target */if (opc != NULL) {switch (*(opc+2)) {case 'y': dexoptFlags |= DEXOPT_UNIPROCESSOR; break;case 'n': dexoptFlags |= DEXOPT_SMP; break;default: break;}}}/**準(zhǔn)備VM并執(zhí)行優(yōu)化。*/if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode,dexoptFlags) != 0){ALOGE("DexOptZ: VM init failed");goto bail;}//vmStarted = 1;/* do the optimization */if (!dvmContinueOptimization(cacheFd, dexOffset, uncompLen, debugFileName,modWhen, crc32, isBootstrap)){ALOGE("Optimization failed");goto bail;}/* we don't shut the VM down -- process is about to exit */result = 0;bail:dexZipCloseArchive(&zippy);return result; }/* *普通設(shè)備端處理的通用功能以及 *預(yù)優(yōu)化。 */ static int processZipFile(int zipFd, int cacheFd, const char* zipName,const char *dexoptFlags) {char* bcpCopy = NULL;/** Check to see if this is a bootstrap class entry. If so, truncate* the path.*/const char* bcp = getenv("BOOTCLASSPATH");if (bcp == NULL) {ALOGE("DexOptZ: BOOTCLASSPATH not set");return -1;}bool isBootstrap = false;const char* match = strstr(bcp, zipName);if (match != NULL) {/**TODO:我們有一個(gè)部分字符串匹配,但這并不意味著*我們已經(jīng)匹配了整個(gè)路徑組件。我們應(yīng)該確保*我們正在匹配完整的zipName,如果不是*應(yīng)從(匹配+1)開(kāi)始重新執(zhí)行strstr。**該場(chǎng)景將是一個(gè)bootclasspath,具有以下內(nèi)容*“/system/framework/core.jar”,而我們正在嘗試優(yōu)化*“/framework/core.jar”。不太可能,因?yàn)樗新窂蕉际?絕對(duì),以“.jar”結(jié)尾,但并非不可能。*/int matchOffset = match - bcp;if (matchOffset > 0 && bcp[matchOffset-1] == ':')matchOffset--;ALOGV("DexOptZ: found '%s' in bootclasspath, cutting off at %d",zipName, matchOffset);bcpCopy = strdup(bcp);bcpCopy[matchOffset] = '\0';bcp = bcpCopy;ALOGD("DexOptZ: truncated BOOTCLASSPATH to '%s'", bcp);isBootstrap = true;}int result = extractAndProcessZip(zipFd, cacheFd, zipName, isBootstrap,bcp, dexoptFlags);free(bcpCopy);return result; }/* advance to the next arg and extract it */ #define GET_ARG(_var, _func, _msg) \{ \char* endp; \(_var) = _func(*++argv, &endp, 0); \if (*endp != '\0') { \ALOGE("%s '%s'", _msg, *argv); \goto bail; \} \--argc; \}/* *解析參數(shù)。我們希望: * 0. (dexopt命令的名稱--已忽略) * 1. “--zip” * 2. zip fd(輸入,只讀) * 3. 緩存fd(輸出、讀寫(xiě)、用群集鎖定) * 4. 正在優(yōu)化的zipfile的文件名(用于調(diào)試消息和 *用于與BOOTCLASSPATH進(jìn)行比較;不需要 *可訪問(wèn)或甚至存在) * 5. dexopt標(biāo)志 * *假定BOOTCLASSPATH環(huán)境變量包含正確的 *引導(dǎo)類路徑。如果提供的文件名出現(xiàn)在引導(dǎo)類中 *路徑,路徑將在該條目之前被截?cái)?#xff08;因此,如果 *如果您選擇dexopt“core.jar”,您的引導(dǎo)類路徑將為空)。 * *這不會(huì)嘗試規(guī)范化引導(dǎo)類路徑名,因此 *如果你有創(chuàng)意,文件名測(cè)試不會(huì)抓住你。 */ static int fromZip(int argc, char* const argv[]) {int result = -1;int zipFd, cacheFd;const char* zipName;char* bcpCopy = NULL;const char* dexoptFlags;if (argc != 6) {ALOGE("Wrong number of args for --zip (found %d)", argc);goto bail;}/* skip "--zip" */argc--;argv++;GET_ARG(zipFd, strtol, "bad zip fd");GET_ARG(cacheFd, strtol, "bad cache fd");zipName = *++argv;--argc;dexoptFlags = *++argv;--argc;result = processZipFile(zipFd, cacheFd, zipName, dexoptFlags);bail:return result; }/* *分析預(yù)優(yōu)化運(yùn)行的參數(shù)。這是dalvikvm運(yùn)行的時(shí)間 *在主機(jī)上優(yōu)化dex文件,以便最終在主機(jī)上運(yùn)行(不同) *裝置。我們希望: * 0. (dexopt命令的名稱--已忽略) * 1. “--preopt” * 2. zipfile名稱 * 3. 輸出文件名 * 4. dexopt標(biāo)志 * *假定BOOTCLASSPATH環(huán)境變量包含正確的 *引導(dǎo)類路徑。如果提供的文件名出現(xiàn)在引導(dǎo)類中 *路徑,路徑將在該條目之前被截?cái)?#xff08;因此,如果 *如果您選擇dexopt“core.jar”,您的引導(dǎo)類路徑將為空)。 * *這不會(huì)嘗試規(guī)范化引導(dǎo)類路徑名,因此 *如果你有創(chuàng)意,文件名測(cè)試不會(huì)抓住你。 */ static int preopt(int argc, char* const argv[]) {int zipFd = -1;int outFd = -1;int result = -1;if (argc != 5) {/** Use stderr here, since this variant is meant to be called on* the host side.*/fprintf(stderr, "Wrong number of args for --preopt (found %d)\n",argc);return -1;}const char* zipName = argv[2];const char* outName = argv[3];const char* dexoptFlags = argv[4];if (strstr(dexoptFlags, "u=y") == NULL &&strstr(dexoptFlags, "u=n") == NULL){fprintf(stderr, "Either 'u=y' or 'u=n' must be specified\n");return -1;}zipFd = open(zipName, O_RDONLY);if (zipFd < 0) {perror(argv[0]);return -1;}outFd = open(outName, O_RDWR | O_EXCL | O_CREAT, 0666);if (outFd < 0) {perror(argv[0]);goto bail;}result = processZipFile(zipFd, outFd, zipName, dexoptFlags);bail:if (zipFd >= 0) {close(zipFd);}if (outFd >= 0) {close(outFd);}return result; }/* *直接從VM解析“舊式”調(diào)用的參數(shù)。 * *以下是我們想要的: * 0. (dexopt命令的名稱--已忽略) * 1. “--dex” * 2. DALVIK_VM_構(gòu)建值,作為一種健全性檢查 * 3. 文件描述符,用flock鎖定,用于正在優(yōu)化的DEX文件 * 4. 文件內(nèi)的索引偏移量 * 5. 指數(shù)長(zhǎng)度 * 6. 正在優(yōu)化的文件的文件名(僅適用于調(diào)試消息) * 7. 源的修改日期(進(jìn)入依賴項(xiàng)部分) * 8. 源的CRC(進(jìn)入依賴項(xiàng)部分) * 9. 標(biāo)志(優(yōu)化級(jí)別,isBootstrap) * 10. bootclasspath條目#1 * 11. bootclasspath條目#2 * ... * *dalvik/vm/analysis/DexOptimize中的dvmOptimizeDexFile()。c構(gòu)建 *參數(shù)列表并調(diào)用此可執(zhí)行文件。 * *bootclasspath條目將成為此DEX文件的依賴項(xiàng)。 * *打開(kāi)的文件描述符不能用于任何bootclasspath文件。 *父項(xiàng)已鎖定描述符,我們將嘗試再次將其鎖定 *處理引導(dǎo)類路徑的一部分。(我們可以抓住這個(gè)然后回來(lái) *比較文件名或打開(kāi)bootclasspath文件時(shí)出錯(cuò) *并統(tǒng)計(jì)它們的索引節(jié)點(diǎn)編號(hào))。 */ static int fromDex(int argc, char* const argv[]) {int result = -1;bool vmStarted = false;char* bootClassPath = NULL;int fd, flags, vmBuildVersion;long offset, length;const char* debugFileName;u4 crc, modWhen;char* endp;bool onlyOptVerifiedDex = false;DexClassVerifyMode verifyMode;DexOptimizerMode dexOptMode;if (argc < 10) {/* don't have all mandatory args */ALOGE("Not enough arguments for --dex (found %d)", argc);goto bail;}/* skip "--dex" */argc--;argv++;/** Extract the args.*/GET_ARG(vmBuildVersion, strtol, "bad vm build");if (vmBuildVersion != DALVIK_VM_BUILD) {ALOGE("DexOpt: build rev does not match VM: %d vs %d",vmBuildVersion, DALVIK_VM_BUILD);goto bail;}GET_ARG(fd, strtol, "bad fd");GET_ARG(offset, strtol, "bad offset");GET_ARG(length, strtol, "bad length");debugFileName = *++argv;--argc;GET_ARG(modWhen, strtoul, "bad modWhen");GET_ARG(crc, strtoul, "bad crc");GET_ARG(flags, strtol, "bad flags");ALOGV("Args: fd=%d off=%ld len=%ld name='%s' mod=%#x crc=%#x flg=%d (argc=%d)",fd, offset, length, debugFileName, modWhen, crc, flags, argc);assert(argc > 0);if (--argc == 0) {bootClassPath = strdup("");} else {int i, bcpLen;char* const* argp;char* cp;bcpLen = 0;for (i = 0, argp = argv; i < argc; i++) {++argp;ALOGV("DEP: '%s'", *argp);bcpLen += strlen(*argp) + 1;}cp = bootClassPath = (char*) malloc(bcpLen +1);for (i = 0, argp = argv; i < argc; i++) {int strLen;++argp;strLen = strlen(*argp);if (i != 0)*cp++ = ':';memcpy(cp, *argp, strLen);cp += strLen;}*cp = '\0';assert((int) strlen(bootClassPath) == bcpLen-1);}ALOGV(" bootclasspath is '%s'", bootClassPath);/* start the VM partway *//* ugh -- upgrade these to a bit field if they get any more complex */if ((flags & DEXOPT_VERIFY_ENABLED) != 0) {if ((flags & DEXOPT_VERIFY_ALL) != 0)verifyMode = VERIFY_MODE_ALL;elseverifyMode = VERIFY_MODE_REMOTE;} else {verifyMode = VERIFY_MODE_NONE;}if ((flags & DEXOPT_OPT_ENABLED) != 0) {if ((flags & DEXOPT_OPT_ALL) != 0)dexOptMode = OPTIMIZE_MODE_ALL;elsedexOptMode = OPTIMIZE_MODE_VERIFIED;} else {dexOptMode = OPTIMIZE_MODE_NONE;}// 準(zhǔn)備優(yōu)化環(huán)境 if (dvmPrepForDexOpt(bootClassPath, dexOptMode, verifyMode, flags) != 0) {ALOGE("VM init failed");goto bail;}vmStarted = true;/* 正式進(jìn)行優(yōu)化 */if (!dvmContinueOptimization(fd, offset, length, debugFileName,modWhen, crc, (flags & DEXOPT_IS_BOOTSTRAP) != 0)){ALOGE("Optimization failed");goto bail;}result = 0;bail:/**理論上,此時(shí)我們應(yīng)該優(yōu)雅地關(guān)閉VM。在里面*只有當(dāng)我們使用檢查內(nèi)存泄漏時(shí),這才有意義*valgrind——簡(jiǎn)單地退出要快得多。**事實(shí)證明,DEX優(yōu)化器有點(diǎn)快,有點(diǎn)松*使用類加載。我們從一個(gè)部分-*形成的DEX文件,完成后將取消映射。如果我們想*在這里進(jìn)行清潔關(guān)機(jī),可能是為了使用valgrind進(jìn)行測(cè)試,我們需要*要跳過(guò)那里的munmap調(diào)用。*/ #if 0if (vmStarted) {ALOGI("DexOpt shutting down, result=%d", result);dvmShutdown();} #endiffree(bootClassPath);ALOGV("DexOpt command complete (result=%d)", result);return result; }/* *主要入口點(diǎn)。決定去哪里。 */ 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)// 加載 dex 文件時(shí) , 執(zhí)行 fromDex 函數(shù)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; }

源碼路徑 : /dalvik/dexopt/OptMain.cpp

總結(jié)

以上是生活随笔為你收集整理的【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。