我連接使用-sectcreate __TEXT
連接標誌一個的plist一個可執行文件的可執行文件。原因主要是使用SMJobBless()方法。但我需要閱讀從另一個應用程序鏈接的plist。這只是因爲我需要在10.5系統上安裝相同的特權應用程序,並且我無法在10.5上使用SMJobBless()。讀取數據(嵌入的plist)鏈接通過-sectcreate __TEXT
如何閱讀使用Objective-C這樣我就可以把它複製到/庫/ LaunchDaemons /自己這個鏈接的plist?
我連接使用-sectcreate __TEXT
連接標誌一個的plist一個可執行文件的可執行文件。原因主要是使用SMJobBless()方法。但我需要閱讀從另一個應用程序鏈接的plist。這只是因爲我需要在10.5系統上安裝相同的特權應用程序,並且我無法在10.5上使用SMJobBless()。讀取數據(嵌入的plist)鏈接通過-sectcreate __TEXT
如何閱讀使用Objective-C這樣我就可以把它複製到/庫/ LaunchDaemons /自己這個鏈接的plist?
可以使用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。
對於其中一個程序需要讀取它自己的嵌入式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'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一起使用。
爲可執行文件創建一個NSBundle會發生什麼(而不是爲自己的可執行文件獲取主「捆綁」)? –
@Peter'+ [NSBundle bundleWith ...:]'返回'nil'作爲獨立的可執行文件。 – 2011-10-17 23:52:29
我更新了你的帖子,當管道到xxd時添加-X選項,因爲沒有刪除頭文件,你會得到損壞的數據,你可能沒有馬上注意到(即像'<?xml ve.0「encoding =」UTF -8「?>')。 –
有應該是一個功能的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];
不幸的是,這在10.11.5中對我不起作用,上面的embeddedPlist()函數(未修改) – kainjow
一個更簡單的方法:
#include <mach-o/getsect.h>
unsigned long *len;
char *data = getsectdata("__TEXT", "__info_plist");
人getsectdata。有很多關於如何訪問各種組件(當前可執行文件,任意可執行文件,框架等)的示例。
'getsectdata()'在最近的系統上看起來並不能很好地工作,或者根本就沒有工作 - 顯然,它沒有考慮ASLR或其他東西。 ackoverflow.com/q/28978788/291280)使用'getsectiondata()'來解釋它。 – Isaac
如果你還沒有看到更新的答案,我已經發布了[BVPlistExtractor](https://github.com/bavarious/BVPlistExtractor)。 – 2011-10-18 20:50:14
@Bavarious謝謝! BVPlistExtractor是完美的。 – ETroll