在Android上使用qemu-user运行可执行文件

在Android上使用qemu-user运行可执行文件

@(QEMU)[QEMU]


[TOC]


不歪博客:http://my.oschina.net/ibuwai/blog

本文公开首发于阿里聚安全博客:https://jaq.alibaba.com/community/index.htm?spm=0.0.0.0.ycEUXK

前言

QEMU简要介绍:

QEMU可以解释执行可执行程序。既然QEMU可以解释执行可执行程序,那么QEMU就能够知道执行了哪些指令,从而可以跟踪指令的执行。QEMU编译出来的结果分为系统模式和用户模式,QEMU用户模式编译出来的可执行文件名为:qemu-user。关于QEMU更多的介绍请浏览官方网站:QEMU

关于如何编译QEMU用户模式可执行文件,请参考这篇文章:编译可在Android上运行的qemu user mode

qemu-user的main函数源码在文件"linux-user/main.c"中。

设置前提

本文研究的QEMU用户模式的可执行文件运行在(Android & arm cpu)上,下文中说的“设备”一词指的就是Android arm设备,设备的系统是CyanogenMod12.1 ROM,该ROM基于Android5.1.1。

运行qemu-user

将qemu-user拷贝到设备中,运行该可执行程序时会提示无法找到libglib-2.0.so.0和libgthread-2.0.so.0这两个库,如果读者按照上文中引用的文章《编译可在Android上运行的qemu user mode》编译成功qemu-user,那么这两个库就会存在于Android NDK目录下,将这两个目录拷贝到设备的"/system/lib/"目录下,然后就可以成功运行qemu-user程序。

运行错误解决:FATAL: kernel did not supply AT_SECURE

我在设备上运行qemu-user的时候出现了标题上显示的错误"FATAL: kernel did not supply AT_SECURE"。

解决办法一

(解决办法来源:https://gist.github.com/jserv/5019475)

找到"bionic/linker/linker_environ.cpp"文件,按照下面的代码修改该文件:

diff --git a/linker/linker_environ.cpp b/linker/linker_environ.cpp
index edc659a..4a6e4a0 100644
--- a/linker/linker_environ.cpp
+++ b/linker/linker_environ.cpp
@@ -42,20 +42,6 @@ bool get_AT_SECURE() {
   return _AT_SECURE_value;
 }

-static void __init_AT_SECURE(KernelArgumentBlock& args) {
-  // Check auxv for AT_SECURE first to see if program is setuid, setgid,
-  // has file caps, or caused a SELinux/AppArmor domain transition.
-  bool kernel_supplied_AT_SECURE;
-  _AT_SECURE_value = args.getauxval(AT_SECURE, &kernel_supplied_AT_SECURE);
-
-  // We don't support ancient kernels.
-  if (!kernel_supplied_AT_SECURE) {
-    const char* msg = "FATAL: kernel did not supply AT_SECURE\n";
-    write(2, msg, strlen(msg));
-    exit(EXIT_FAILURE);
-  }
-}
-
 // Check if the environment variable definition at 'envstr'
 // starts with '<name>=', and if so return the address of the
 // first character after the equal sign. Otherwise return NULL.
@@ -108,44 +94,6 @@ static bool __is_valid_environment_variable(const char* name) {
   return true;
 }

-static bool __is_unsafe_environment_variable(const char* name) {
-  // None of these should be allowed in setuid programs.
-  static const char* const UNSAFE_VARIABLE_NAMES[] = {
-      "GCONV_PATH",
-      "GETCONF_DIR",
-      "HOSTALIASES",
-      "LD_AOUT_LIBRARY_PATH",
-      "LD_AOUT_PRELOAD",
-      "LD_AUDIT",
-      "LD_DEBUG",
-      "LD_DEBUG_OUTPUT",
-      "LD_DYNAMIC_WEAK",
-      "LD_LIBRARY_PATH",
-      "LD_ORIGIN_PATH",
-      "LD_PRELOAD",
-      "LD_PROFILE",
-      "LD_SHOW_AUXV",
-      "LD_USE_LOAD_BIAS",
-      "LOCALDOMAIN",
-      "LOCPATH",
-      "MALLOC_CHECK_",
-      "MALLOC_TRACE",
-      "NIS_PATH",
-      "NLSPATH",
-      "RESOLV_HOST_CONF",
-      "RES_OPTIONS",
-      "TMPDIR",
-      "TZDIR",
-      NULL
-  };
-  for (size_t i = 0; UNSAFE_VARIABLE_NAMES[i] != NULL; ++i) {
-    if (env_match(name, UNSAFE_VARIABLE_NAMES[i]) != NULL) {
-      return true;
-    }
-  }
-  return false;
-}
-
 static void __sanitize_environment_variables() {
   char** src  = _envp;
   char** dst = _envp;
@@ -153,10 +101,6 @@ static void __sanitize_environment_variables() {
     if (!__is_valid_environment_variable(src[0])) {
       continue;
     }
-    // Remove various unsafe environment variables if we're loading a setuid program.
-    if (get_AT_SECURE() && __is_unsafe_environment_variable(src[0])) {
-        continue;
-    }
     dst[0] = src[0];
     ++dst;
   }
@@ -167,7 +111,6 @@ void linker_env_init(KernelArgumentBlock& args) {
   // Store environment pointer - can't be NULL.
   _envp = args.envp;

-  __init_AT_SECURE(args);
   __sanitize_environment_variables();
 }

如果读者用过git再看上面的代码就可以很清楚的知道,上面的代码是运行"git diff"后所显示内容,代码做了哪些修改清楚的显示了出来。

如果读者没有见过"git diff"命令所显示的内容,那么这么做:找到"-static void __init_AT_SECURE(KernelArgumentBlock& args) {"这一行,从这行开始(包括这一行)每一行以减号开头的表示删除该行。

文件修改完成后在Android源码根目录运行下面的命令:

. build/envsetup.sh
breakfast hammerhead
mmm <Android源码根目录>/bionic/linker/

mmm命令用于编译"<Android源码根目录>/bionic/linker/"目录下的源码,这个目录下的源码编译完成后会生成一个名为"linker"的可执行文件,这个可执行文件的生成目录会在终端上显示出来,将这个linker覆盖设备上的"/system/bin/linker"文件。

覆盖设备上的"/system/bin/linker"文件的实际操作中,覆盖需要需要ROOT权限。"/system/bin/linker"文件覆盖完成以后,它的文件权限是这样的:

-rwxr-xr-x root     root       91902 2016-05-01 21:50 linker

即linker属于root用户,并属于root用户组。但是linker原本的权限是下面这样的:

-rwxr-xr-x root     shell       91902 2016-05-01 21:50 linker

即linker属于root用户,并属于shell用户组。

所以linker覆盖完成后需要执行"chgrp shell /system/bin/linker"命令设置linker的用户组。

__init_AT_SECURE函数的被调路径:__linker_init -> __linker_init_post_relocation -> linker_env_init -> __init_AT_SECURE

解决办法二

在qemu源码目录下找到"linux-user/elfload.c"文件,文件中有create_elf_tables函数,在该函数中找到这一行代码:

NEW_AUX_ENT(AT_RANDOM, (abi_ulong) u_rand_bytes);

在这行代码下添加一行代码:

NEW_AUX_ENT(AT_SECURE, 0);

在该文件中找到这一行:

#define DLINFO_ITEMS 14

将这一行改为:

#define DLINFO_ITEMS 15

解决办法思路说明:

[翻译] getauxval() and the auxiliary vector这篇文章中说了,fs/binfmt_elf.c文件中有内核的ELF二进制加载器源码,在该文件中也有一个create_elf_tables函数,fs/binfmt_elf.c文件create_elf_tables函数有下面一行代码:

NEW_AUX_ENT(AT_SECURE, security_bprm_secureexec(bprm));

即在标准的create_elf_tables函数中会添加AT_SECURE这一项。通过阅读“解决办法一”可以推断出,产生"FATAL: kernel did not supply AT_SECURE"错误是因为找不到AT_SECURE这一项,那么“解决办法二”的思路就是在qemu的create_elf_tables函数中添加这一项。

为什么在qemu的create_elf_tables函数中添加的AT_SECURE项对应的值是0呢?这是因为我图方便,标准代码中AT_SECURE项对应的值是函数security_bprm_secureexec(bprm)的返回值,我发现理解security_bprm_secureexec函数比较麻烦。那么为什么是0而不是其他常量值?这是因为在linux系统的终端上输入下面的命令:

LD_SHOW_AUXV=1 ps

最后显示AT_SECURE对应的值是0。上面命令中的"ps"可以是其他命令,如:ls。关于LD_SHOW_AUXV这个环境变量在《[翻译] getauxval() and the auxiliary vector》一文中有介绍。

create_elf_tables函数的被调路径:linux-user/main.c - main -> linux-user/linuxload.c - loader_exec -> linux-user/elfload.c - load_elf_binary -> linux-user/elfload.c - create_elf_tables

转载于:https://my.oschina.net/ibuwai/blog/687342

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值