Подтвердить что ты не робот

Чтение данных (встроенный plist), связанных с исполняемым через -sectcreate __TEXT

Я связываю исполняемый файл с plist, используя флаги компоновщика -sectcreate __TEXT. Причиной этого является использование метода SMJobBless(). Но мне нужно прочитать plist, связанный с другим приложением. Это связано только с тем, что мне нужно установить такое же привилегированное приложение в системе 10.5, и я не могу использовать SMJobBless() в 10.5.

Как прочитать этот связанный plist с помощью Objective-C, чтобы я мог его скопировать в/Library/LaunchDaemons/self?

4b9b3361

Ответ 1

otool

Вы можете использовать otool (1), чтобы вывести содержимое раздела, содержащего встроенный список:

otool -s __TEXT __info_plist /path/to/executable

и затем направить свой вывод в xxd (1), чтобы получить соответствующее представление ASCII:

otool -X -s __TEXT __info_plist /path/to/executable | xxd -r

Однако otool доступен только на машинах, где установлен Xcode.

NSBundle

Для случаев, когда программе необходимо прочитать собственный встроенный plist, можно использовать NSBundle:

id someValue = [[NSBundle mainBundle] objectForInfoDictionaryKey:someKey];

Мачо

В тех случаях, когда программе необходимо прочитать внедренный plist произвольного файла, не прибегая к otool, программа может проанализировать информацию Mach-O в файле и извлечь свой встроенный plist следующим образом:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <mach-o/loader.h>
#include <sys/mman.h>
#include <sys/stat.h>
#import <Foundation/Foundation.h>

id embeddedPlist(NSURL *executableURL) {
    id plist = nil;
    int fd;
    struct stat stat_buf;
    size_t size;

    char *addr = NULL;
    char *start_addr = NULL;
    struct mach_header_64 *mh = NULL;
    struct load_command *lc = NULL;
    struct segment_command_64 *sc = NULL;
    struct section_64 *sect = NULL;

    // Open the file and get its size
    fd = open([[executableURL path] UTF8String], O_RDONLY);
    if (fd == -1) goto END_FUNCTION;
    if (fstat(fd, &stat_buf) == -1) goto END_FILE;
    size = stat_buf.st_size;

    // Map the file to memory
    addr = start_addr = mmap(0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
    if (addr == MAP_FAILED) goto END_FILE;

    // The first bytes are the Mach-O header
    mh = (struct mach_header_64 *)addr;

    // Load commands follow the header
    addr += sizeof(struct mach_header_64);

    for (int icmd = 0; icmd < mh->ncmds; icmd++) {
        lc = (struct load_command *)addr;

        if (lc->cmd != LC_SEGMENT_64) {
            addr += lc->cmdsize;
            continue;
        }

        if (lc->cmdsize == 0) continue;

        // It a 64-bit segment
        sc = (struct segment_command_64 *)addr;

        if (strcmp("__TEXT", sc->segname) != 0 || sc->nsects == 0) {
            addr += lc->cmdsize;
            continue;
        }

        // It the __TEXT segment and it has at least one section
        // Section data follows segment data
        addr += sizeof(struct segment_command_64);
        for (int isect = 0; isect < sc->nsects; isect++) {
            sect = (struct section_64 *)addr;
            addr += sizeof(struct section_64);

            if (strcmp("__info_plist", sect->sectname) != 0) continue;

            // It the __TEXT __info_plist section
            NSData *data = [NSData dataWithBytes:(start_addr + sect->offset)
                                          length:sect->size];
            plist = [NSPropertyListSerialization propertyListWithData:data
                                                              options:NSPropertyListImmutable
                                                               format:NULL
                                                                error:NULL];
            goto END_MMAP;
        }
    }

END_MMAP:
    munmap(addr, size);

END_FILE:
    close(fd);

END_FUNCTION:
    return plist;
}

а также:

NSURL *url = [NSURL fileURLWithPath:@"/path/to/some/file"];
id plist = embeddedPlist(url);
if ([plist isKindOfClass:[NSDictionary class]]) {
    NSDictionary *info = plist;
    id someValue = [info objectForKey:someKey];
}

Обратите внимание, что для embeddedPlist() есть некоторые ограничения: он ожидает, что файл будет тонким файлом Mach-O (т.е. Он будет аварийно завершать работу с файлами, не относящимися к Mach-O), и не будет работать с толстыми файлами, содержащими, например, i386 и x86_64. Данные Mach-O); работает только с файлами x86_64; он не сообщает об ошибках.

Я пошел дальше и выпустил BVPlistExtractor под лицензией MIT. Он определяет, является ли файл действительно тонким файлом Mach-O или толстым/универсальным файлом, и работает как с i386, так и с x86_64.

Ответ 2

Для этого существует функция CoreFoundation: CFBundleCopyInfoDictionaryForURL(). Из документации:

Для URL-адреса каталога это эквивалентно CFBundleCopyInfoDictionaryInDirectory. Для простого URL-адреса файла, представляющего несвязанное приложение, эта функция попытается прочитать информационный словарь либо из раздела (__TEXT, __info_plist) файла (для файла Mach-O), либо из ресурса plst.

Он доступен в Mac OS X версии 10.2 и более поздних версиях. Если вы используете в Cocoa, вы можете сделать это (если у вас есть (NSURL*)url для пакета):

NSDictionary* infoPlist = [ (NSDictionary*) CFBundleCopyInfoDictionaryForURL( (CFURLRef) url ) autorelease];

Ответ 3

Более простой подход:

#include <mach-o/getsect.h>

unsigned long *len;
char *data = getsectdata("__TEXT", "__info_plist");

man getsectdata. Там много примеров о том, как обращаться к различным частям (текущий исполняемый файл, произвольный исполняемый файл, фреймворк и т.д.).

Ответ 4

На компьютере пользователя, вероятно, не otool установлен otool, и у меня была такая же проблема. Решением было использовать launchctl, который гарантированно присутствует на любом современном Mac.

У него есть подкоманда plist которая выполняет следующие действия:

Prints the the property list embedded in the __TEXT,__info_plist segment/section
of the target Mach-O or the specified segment/section.

Если вы не укажете этот раздел, он по умолчанию печатает __TEXT. Единственный аргумент, который нужно указать - это путь к исполняемому файлу:

launchctl plist/Library/PrivilegedHelperTools/com.sparklabs.ViscosityHelper

Если вы указали путь, вывод может выглядеть примерно так:

{
    "CFBundleIdentifier" = "com.sparklabs.ViscosityHelper";
    "SMAuthorizedClients" = (
        "anchor apple generic and identifier "com.viscosityvpn.Viscosity" and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = "34XR7GXFPX")";
    );
    "CFBundleName" = "ViscosityHelper";
    "CFBundleVersion" = "548";
    "CFBundleInfoDictionaryVersion" = "6.0";
};

Его можно использовать как в командной строке, так и из кода через NSTask (Process in swift).