在上一篇博客 【Android 逆向】ART 脱壳 ( DexClassLoader 脱壳 | oat_file_assistant.cc 中涉及的 oat 文件生成流程 ) 中分析到 将 Dex 文件编译为 Oat 文件 , 最终在 oat_file_assistant.cc#Dex2Oat 函数中 , 调用了 exec_utils.cc#Exec 函数 , 在该函数中执行最后的转换操作 ;
在 exec_utils.cc#Exec 函数 中 , 调用了 ExecAndReturnCode 方法 ;
bool Exec(std::vector<std::string>& arg_vector, std::string* error_msg) {
// ★ 核心跳转
int status = ExecAndReturnCode(arg_vector, error_msg);
if (status != 0) {
const std::string command_line(android::base::Join(arg_vector, ' '));
*error_msg = StringPrintf("Failed execv(%s) because non-0 exit status",
command_line.c_str());
return false;
}
return true;
}
源码路径 : http://aospxref.com/android-8.0.0_r36/xref/art/runtime/exec_utils.cc#Exec
在该函数中 , 先 fork 一个进程 ,
pid_t pid = fork();
使用 execve 函数 , 执行 Dex 文件编译为 Oat 文件操作 ;
execve(program, &args[0], envp);
exec_utils.cc#ExecAndReturnCode 函数源码 :
int ExecAndReturnCode(std::vector<std::string>& arg_vector, std::string* error_msg) {
const std::string command_line(android::base::Join(arg_vector, ' '));
CHECK_GE(arg_vector.size(), 1U) << command_line;
// 将参数转换为字符指针。
const char* program = arg_vector[0].c_str();
std::vector<char*> args;
for (size_t i = 0; i < arg_vector.size(); ++i) {
const std::string& arg = arg_vector[i];
char* arg_str = const_cast<char*>(arg.c_str());
CHECK(arg_str != nullptr) << i;
args.push_back(arg_str);
}
args.push_back(nullptr);
// fork and exec
pid_t pid = fork();
if (pid == 0) {
// fork和exec之间不允许分配
// 更改流程组,这样我们就不会被ProcessManager收获
setpgid(0, 0);
// (b/30160149): 保护子进程不受对LD_LIBRARY_路径等的修改的影响。
// 使用从创建运行时开始的环境快照。
char** envp = (Runtime::Current() == nullptr) ? nullptr : Runtime::Current()->GetEnvSnapshot();
if (envp == nullptr) {
execv(program, &args[0]);
} else {
execve(program, &args[0], envp);
}
PLOG(ERROR) << "Failed to execve(" << command_line << ")";
// _exit to avoid atexit handlers in child.
_exit(1);
} else {
if (pid == -1) {
*error_msg = StringPrintf("Failed to execv(%s) because fork failed: %s",
command_line.c_str(), strerror(errno));
return -1;
}
// 等待子进程完成
int status = -1;
pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
if (got_pid != pid) {
*error_msg = StringPrintf("Failed after fork for execv(%s) because waitpid failed: "
"wanted %d, got %d: %s",
command_line.c_str(), pid, got_pid, strerror(errno));
return -1;
}
if (WIFEXITED(status)) {
return WEXITSTATUS(status);
}
return -1;
}
}