2011-10-15 8 views
12

リンカーフラグ-sectcreate __TEXTを使用して実行可能ファイルをplistにリンクしています。この理由は、主にSMJobBless()メソッドを使用することです。しかし、私は別のアプリケーションからリンクされたplistを読む必要があります。これは、同じ特権アプリケーションを10.5システムにインストールする必要があり、10.5でSMJobBless()を使用できないためです。-sectcreate __TEXTによって実行可能ファイルにリンクされたデータ(埋め込みplist)を読み取る

Objective-Cを使用してリンクされたplistをどのように読むことができるので、/ Library/LaunchDaemons/myselfにコピーできますか?

+1

は、私は[BVPlistExtractor](https://github.com/bavarious/BVPlistExtractor)をリリースしました。 –

+0

@Bavariousありがとう! BVPlistExtractorは完璧です。 – ETroll

答えて

18

コマンドotool

あなたは(1)埋め込みplistの収容部の内容をダンプするコマンドotool使用できる:

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を使用することができるプログラムは、独自の埋め込みプロパティリストを読み取る必要がある場合、について

NSBundle

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

マッハO

プログラムをする必要がある場合についてotoolに依存せずに任意のファイルの埋め込みplistを読み込むと、プログラムはファイル内の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; 
} 

と:それは、ファイルが薄いマッハ-Oファイルであることを期待(すなわち、それは非マッハ-Oファイルでクラッシュすると、それはないでしょう:embeddedPlist()はいくつかの制限があることを

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

注意たとえば、i386とx86_64の両方のMach-Oデータを含むfatファイルで作業します。 x86_64ファイルでのみ動作します。エラーを報告しません。

私はMITライセンスでBVPlistExtractorをリリースしました。ファイルが本当に薄いMach-Oファイルかfat/universalファイルかを検出し、i386とx86_64の両方で動作します。

+0

実行可能ファイル用のNSBundleを作成すると(メインの「バンドル」を独自の実行可能ファイルにするのとは対照的に)何が起こりますか? –

+0

@Peter '+ [NSBundle bundleWith ...:]'は、スタンドアロンの実行可能ファイルに対して 'nil'を返します。 –

+0

ヘッダを削除せずに、あなたはすぐにすなわち( '<?xmlのve.0" エンコード=" UTFのようなものを気づかないかもしれません破損したデータを得ることができますので、私はxxdのためにパイプする際に-Xオプションを追加するためにあなたのポストを更新しました-8" ?> ')。 –

12

CoreFoundationの機能は、CFBundleCopyInfoDictionaryForURL()です。ドキュメントから:

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か何かを考慮していません[この質問](のhttp:// ST ackoverflow.com/q/28978788/291280)は 'getsectiondata()'を使用しています。 – Isaac

関連する問題