首页 > 解决方案 > Android:从应用程序执行二进制文件

问题描述

正如标题所示,我想从我的 android 应用程序中执行一个二进制文件。我使用 NDK 创建了一个二进制文件,并且可以使用 adb shell 运行它。然后我尝试使用 Runtime exec 运行它,但权限被拒绝。我尝试了不同的目录并更改了文件权限。

我调查了这个问题,发现很多堆栈溢出问题/答案大多已经过时了。似乎 Android 安全性在不同版本上发生了很大变化。

我发现了什么: 操作系统阻止应用程序执行自己编写的代码。这称为Write xor execute并且是有意义的。.apk 和 .dex 文件除外。这应该意味着我想要的东西是不可能的。

我还发现了一些能够执行此类二进制文件的应用程序,例如Android 离线 C 编译器,它编译并执行 C 代码。另一个可以执行二进制文件的著名应用程序是终端仿真器Termux。另外,有趣的是,在执行二进制文件时,它们都具有与 adb shell 相同的性能。因此,我假设他们在 shell 上运行二进制文件。

我最终想知道的是这些应用程序如何执行这些二进制文件,以及我是否可以实现相同的目标。

我进一步研究了这两个应用程序的代码,它们使用本机代码来创建一个执行 shell 命令的进程。相反,我总是使用可以从 Java 访问的 Runtime 对象。此外,他们使用本机代码来更改文件权限。这让我想知道使用本机代码是否会给开发人员更多关于这些限制的自由。

我的问题:在尝试执行二进制文件时使用 Java 或本机代码会有所不同吗?如果不是,他们可以执行二进制文件的原因是什么?这可以用 Java 实现吗?

这是来自 Termux 的本机代码,它创建了一个执行 shell 命令的子进程:


static int create_subprocess(JNIEnv *env, const char *cmd, char *const argv[], char *const envp[], int masterFd)
{
    // same size as Android 1.6 libc/unistd/ptsname_r.c
    char devname[64];
    pid_t pid;

    fcntl(masterFd, F_SETFD, FD_CLOEXEC);

    // grantpt is unnecessary, because we already assume devpts by using /dev/ptmx
    if(unlockpt(masterFd)){
        throwIOException(env, errno, "trouble with /dev/ptmx");
        return -1;
    }
    memset(devname, 0, sizeof(devname));
    // Early (Android 1.6) bionic versions of ptsname_r had a bug where they returned the buffer
    // instead of 0 on success.  A compatible way of telling whether ptsname_r
    // succeeded is to zero out errno and check it after the call
    errno = 0;
    int ptsResult = ptsname_r(masterFd, devname, sizeof(devname));
    if (ptsResult && errno) {
        throwIOException(env, errno, "ptsname_r returned error");
        return -1;
    }

    pid = fork();
    if(pid < 0) {
        throwIOException(env, errno, "fork failed");
        return -1;
    }

    if(pid == 0){
        int pts;

        setsid();

        pts = open(devname, O_RDWR);
        if(pts < 0) exit(-1);

        ioctl(pts, TIOCSCTTY, 0);

        dup2(pts, 0);
        dup2(pts, 1);
        dup2(pts, 2);

        closeNonstandardFileDescriptors();

        if (envp) {
            for (; *envp; ++envp) {
                putenv(*envp);
            }
        }

        execv(cmd, argv);
        exit(-1);
    } else {
        return (int) pid;
    }
}

如果我遗漏了某些东西并且还有其他一些技巧可以执行二进制文件,我也想听听。

非常感谢任何帮助和/或见解!

PS:可能也很重要,我不想在 .apk 中包含二进制文件,而是在我的应用程序运行时下载或编写它。此外,二进制文件并不复杂。我目前只是尝试执行“Hello world”-二进制文件。

标签: javaandroidandroid-ndkandroid-shell

解决方案


我发现了不同之处,它与本机代码无关......

这些应用程序使用targetSdkVersion 28或更低,仍然允许执行二进制文件。这意味着二进制文件可以与Runtime对象以及此 SDK 版本中的本机代码一起执行。

这些应用程序仍然可以安装在较新的 Android 版本上。

targetSdkVersion所以我通过将 设置为 28来解决我的问题。


推荐阅读