2011-10-15 26 views
12

Tôi đang liên kết một tệp thực thi với một plist sử dụng -sectcreate __TEXT cờ liên kết. Lý do cho việc này chủ yếu là sử dụng phương thức SMJobBless(). Nhưng tôi cần phải đọc plist liên kết từ một ứng dụng khác. Điều này chỉ vì tôi cần cài đặt cùng một ứng dụng đặc quyền trên một hệ thống 10.5 và tôi không thể sử dụng SMJobBless() trên 10.5.Dữ liệu đọc (plist nhúng) được liên kết với thực thi thông qua -sectcreate __TEXT

Tôi làm cách nào để đọc plist được liên kết này bằng cách sử dụng Objective-C để tôi có thể sao chép nó vào/Library/LaunchDaemons/myself?

+1

Trong trường hợp bạn chưa thấy câu trả lời cập nhật, tôi đã phát hành [BVPlistExtractor] (https://github.com/bavarious/BVPlistExtractor). –

+0

@Bavarious Thanks! BVPlistExtractor là hoàn hảo. – ETroll

Trả lời

18

otool

Bạn có thể sử dụng otool (1) để đổ nội dung của phần này có chứa các plist nhúng:

otool -s __TEXT __info_plist /path/to/executable 

và sau đó ống đầu ra của nó để xxd (1) để có được đại diện ASCII tương ứng:

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

Tuy nhiên, otool is only available in machines where Xcode has been installed.

NSBundle

Đối với trường hợp một chương trình cần phải đọc plist nhúng riêng của mình, NSBundle thể được sử dụng:

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

Mach-O

Đối với trường hợp một chương trình cần đọc plist nhúng của một tập tin tùy ý mà không cần đến otool, chương trình có thể phân tích cú pháp thông tin Mach-O trong tệp và trích xuất plist nhúng của nó như sau:

#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's a 64-bit segment 
     sc = (struct segment_command_64 *)addr; 

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

     // It's 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's 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; 
} 

và:

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]; 
} 

Lưu ý rằng embeddedPlist() có một số hạn chế: nó sẽ yêu cầu tập tin là một tập tin mỏng Mach-O (tức là, nó sẽ sụp đổ với các tập tin không Mach-O và nó sẽ không làm việc với các tệp chất béo có chứa, ví dụ, cả dữ liệu Mach-O i386 và x86_64); nó chỉ hoạt động với các tệp x86_64; nó không báo cáo lỗi.

Tôi đã tiếp tục và phát hành BVPlistExtractor theo giấy phép MIT. Nó phát hiện xem tệp thực sự là một tệp Mach-O mỏng hay một tệp chất béo/phổ dụng và hoạt động với cả i386 và x86_64.

+0

Điều gì sẽ xảy ra khi bạn tạo NSBundle cho một tệp thi hành (trái ngược với việc nhận "gói" chính cho tệp thực thi của riêng bạn)? –

+0

@Peter '+ [Gói NSBundleVới…:]' trả về 'nil' cho các tệp thực thi độc lập. –

+0

Tôi đã cập nhật bài đăng của bạn để thêm tùy chọn -X khi đường ống đến xxd vì không xóa tiêu đề bạn sẽ nhận được dữ liệu bị hỏng mà bạn có thể không nhận thấy ngay lập tức (ví dụ: '') –

12

Có chức năng CoreFoundation cho điều đó: CFBundleCopyInfoDictionaryForURL(). Từ tài liệu:

Đối với URL thư mục, số này tương đương với CFBundleCopyInfoDictionaryInDirectory. Đối với một URL tệp đơn giản thể hiện một ứng dụng chưa được gộp, hàm này sẽ cố đọc một từ điển thông tin từ phần (__TEXT, __info_plist) của tệp (đối với tệp Mach-O) hoặc từ tài nguyên plst.

Tính năng này khả dụng trên Mac OS X v10.2 trở lên.Nếu bạn sử dụng trong Cocoa bạn có thể làm điều này (với điều kiện bạn có một (NSURL*)url cho gói):

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

Đáng buồn thay, điều này không làm việc cho tôi trên 10.11.5. (unmodified) – kainjow

3

Một cách tiếp cận đơn giản hơn nhiều:

#include <mach-o/getsect.h> 

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

người getsectdata. Có rất nhiều ví dụ về cách truy cập các phần khác nhau (thực thi hiện tại, thực thi tùy ý, khung công tác, v.v.).

+0

'getectdata()' dường như không hoạt động tốt hoặc có thể ở tất cả trên các hệ thống gần đây - rõ ràng, nó không tính đến ASLR hay cái gì đó. [Câu hỏi này] (http: // st ackoverflow.com/q/28978788/291280) sử dụng 'getsectiondata()', tính toán cho điều đó. – Isaac

Các vấn đề liên quan