目标C-如何检查可执行文件是否可以启动(例如,终端) [英] Objective C - How to check if Executable can be launched (eg. terminal)

查看:157
本文介绍了目标C-如何检查可执行文件是否可以启动(例如,终端)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在Objective C中构建一个可执行处理应用程序,我只想知道一个简单的代码,它可以确定可执行文件是否可以启动(不启动)或仅是可加载文件.

I am currently building an Executable handling application in Objective C and I just wanna know a simple code that can determine if an executable file can be launched (without launching it) or if it is just a loadable one.

谢谢.

推荐答案

一旦您处理了权限位以及文件是否为Mach-O,则需要考虑三件事:

Once you've taken care of permission bits and whether the file is a Mach-O, there are three things you need to consider:

  • 文件类型
  • CPU兼容性
  • 胖二进制文件

您的Mach-O是否是可执行文件,dylib,kext等,都可以从其标头中的字段中确定.
来自<mach-o/loader.h>:

Whether your Mach-O is an executable, dylib, kext, etc., can be determined from a field in its header.
From <mach-o/loader.h>:

struct mach_header {
    uint32_t magic;
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    uint32_t filetype;  // <---
    uint32_t ncmds;
    uint32_t sizeofcmds;
    uint32_t flags;
};

还从<mach-o/loader.h>中获得该字段的所有可能值:

Also from <mach-o/loader.h> you get all possible values for that field:

#define MH_OBJECT       0x1 /* relocatable object file */
#define MH_EXECUTE      0x2 /* demand paged executable file */
#define MH_FVMLIB       0x3 /* fixed VM shared library file */
#define MH_CORE         0x4 /* core file */
#define MH_PRELOAD      0x5 /* preloaded executable file */
#define MH_DYLIB        0x6 /* dynamically bound shared library */
#define MH_DYLINKER     0x7 /* dynamic link editor */
#define MH_BUNDLE       0x8 /* dynamically bound bundle file */
#define MH_DYLIB_STUB   0x9 /* shared library stub for static linking only, no section contents */
#define MH_DSYM         0xa /* companion file with only debug sections */
#define MH_KEXT_BUNDLE  0xb /* x86_64 kexts */

CPU兼容性

尽管它说可执行",但这并不意味着它可以启动.如果您使用iOS应用程序并尝试在iMac上执行它,则会收到可执行文件中的CPU类型错误"错误消息.
<mach/machine.h>中定义了不同的CPU类型,但是与当前CPU类型进行比较的唯一方法是通过define:

CPU compatibility

Just because it says "executable", doesn't mean it can be launched though. If you take an iOS app and try to execute it on your iMac, you'll get a "Bad CPU type in executable" error message.
The different CPU types are defined in <mach/machine.h>, but the only of comparing against the current CPU type is via defines:

#include <mach/machine.h>

bool is_cpu_compatible(cpu_type_t cputype)
{
    return
#ifdef __i386__
    cputype == CPU_TYPE_X86
#endif
#ifdef __x86_64__
    cputype == CPU_TYPE_X86 || cputype == CPU_TYPE_X86_64
#endif
#ifdef __arm__
    cputype == CPU_TYPE_ARM
#endif
#if defined(__arm64__)
    cputype == CPU_TYPE_ARM || cputype == CPU_TYPE_ARM64
#endif
    ;
}

(这仅在您的应用程序具有64位分片时才有效,因此,它总是尽可能以64位运行.如果您希望能够以32位二进制文​​件运行并检测是否有64位可以运行二进制文件,您必须在"hw.cpu64bit_capable"上使用sysctl并与define一起使用,但是它变得更难看.)

(This will only work if your application has 64-bit slices, so that it always runs as 64-bit when it can. If you want to be able to run as a 32-bit binary and detect whether a 64-bit binary could be run, you'd have to use sysctl on "hw.cpu64bit_capable" together with defined, but then it gets even uglier.)

最后,您的二进制文件可能包含在胖标头中.如果是这样,您只需要遍历所有切片,找到与您当前架构相对应的切片,然后检查上面的两个条件即可.

Lastly, your binaries could be enclosed in fat headers. If so, you'll simply need to iterate over all slices, find the one corresponding to your current architecture, and check the two conditions above for that.

据我所知,没有为此提供的Objective-C API,因此您必须使用C.
给定指向文件内容的指针和上方的is_cpu_compatible函数,您可以像这样进行操作:

There is no Objective-C API for this that I know of, so you'll have to fall back to C.
Given a pointer to the file's contents and the is_cpu_compatible function from above, you could do it like this:

#include <stdbool.h>
#include <stddef.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>

bool macho_is_executable(char *file)
{
    struct fat_header *fat = (struct fat_header*)file;
    // Fat file
    if(fat->magic == FAT_CIGAM) // big endian magic
    {
        struct fat_arch *arch = (struct fat_arch*)(fat + 1);
        for(size_t i = 0; i < fat->nfat_arch; ++i)
        {
            if(is_cpu_compatible(arch->cputype))
            {
                return macho_is_executable(&file[arch->offset]);
            }
        }

        // File is not for this architecture
        return false;
    }

    // Thin file
    struct mach_header *hdr32 = (struct mach_header*)file;
    struct mach_header_64 *hdr64 = (struct mach_header_64*)file;

    if(hdr32->magic == MH_MAGIC) // little endian magic
    {
        return hdr32->filetype == MH_EXECUTE && is_cpu_compatible(hdr32->cputype);
    }
    else if(hdr64->magic == MH_MAGIC_64)
    {
        return hdr64->filetype == MH_EXECUTE && is_cpu_compatible(hdr64->cputype);
    }

    // Not a Mach-O
    return false;
}

请注意,尽管如此,这些仍然是基本检查,例如无法检测到损坏的Mach-O,并且很容易被恶意文件欺骗.如果需要的话,您将不得不模拟一个操作系统并在其中启动二进制文件,或者进入理论IT的研究领域并彻底改变可证明性数学.

Note that these are still rather basic checks though, which will e.g. not detect corrupt Mach-O's, and which could easily be fooled by malicious files. If you wanted that, you would have to either emulate an operating system and launch the binary within, or get into the research field of theoretical IT and revolutionize the mathematics of provability.

这篇关于目标C-如何检查可执行文件是否可以启动(例如,终端)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆