2011-10-15 65 views
12

我連接使用-sectcreate __TEXT連接標誌一個的plist一個可執行文件的可執行文件。原因主要是使用SMJobBless()方法。但我需要閱讀從另一個應用程序鏈接的plist。這只是因爲我需要在10.5系統上安裝相同的特權應用程序,並且我無法在10.5上使用SMJobBless()。讀取數據(嵌入的plist)鏈接通過-sectcreate __TEXT

如何閱讀使用Objective-C這樣我就可以把它複製到/庫/ LaunchDaemons /自己這個鏈接的plist?

+1

如果你還沒有看到更新的答案,我已經發布了[BVPlistExtractor](https://github.com/bavarious/BVPlistExtractor)。 – 2011-10-18 20:50:14

+0

@Bavarious謝謝! BVPlistExtractor是完美的。 – ETroll

回答

18

otool

可以使用otool(1)以傾倒部分的包含嵌入的plist的內容:

otool -s __TEXT __info_plist /path/to/executable 

然後通過管道將其輸出到XXD(1),以獲得所述相應的ASCII碼錶示:

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

但是,otool is only available in machines where Xcode has been installed

一個NSBundle

對於其中一個程序需要讀取它自己的嵌入式plist中的情況下,一個NSBundle可以使用:

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

馬赫-O

對於情況下一個程序需要讀取任意文件的嵌入的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'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; 
} 

和:

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數據的fat文件);它只適用於x86_64文件;它不會報告錯誤。

我繼續在MIT許可下發布BVPlistExtractor。它檢測文件是否確實是一個精簡的Mach-O文件或胖/通用文件,並且可以與i386和x86_64一起使用。

+0

爲可執行文件創建一個NSBundle會發生什麼(而不是爲自己的可執行文件獲取主「捆綁」)? –

+0

@Peter'+ [NSBundle bundleWith ...:]'返回'nil'作爲獨立的可執行文件。 – 2011-10-17 23:52:29

+0

我更新了你的帖子,當管道到xxd時添加-X選項,因爲沒有刪除頭文件,你會得到損壞的數據,你可能沒有馬上注意到(即像'<?xml ve.0「encoding =」UTF -8「?>')。 –

12

有應該是一個功能的CoreFoundation:CFBundleCopyInfoDictionaryForURL()。從文檔:

對於目錄URL,這相當於CFBundleCopyInfoDictionaryInDirectory。對於表示非捆綁應用程序的純文件URL,此功能將嘗試從文件的(__TEXT,__info_plist)部分(對於Mach-O文件)或從plst資源讀取信息字典。

它的問世在Mac OS X v10.2及更新版本。如果您在使用可可,你可以這樣做(只要你有捆綁的(NSURL*)url):

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

不幸的是,這在10.11.5中對我不起作用,上面的embeddedPlist()函數(未修改) – kainjow

3

一個更簡單的方法:

#include <mach-o/getsect.h> 

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

人getsectdata。有很多關於如何訪問各種組件(當前可執行文件,任意可執行文件,框架等)的示例。

+0

'getsectdata()'在最近的系統上看起來並不能很好地工作,或者根本就沒有工作 - 顯然,它沒有考慮ASLR或其他東西。 ackoverflow.com/q/28978788/291280)使用'getsectiondata()'來解釋它。 – Isaac