ETr*_*oll 21 macos linker objective-c
我使用-sectcreate __TEXT链接器标志链接可执行文件和plist .原因主要是使用SMJobBless()方法.但我需要阅读另一个应用程序链接的plist.这只是因为我需要在10.5系统上安装相同的特权应用程序而我不能在10.5上使用SMJobBless().
如何使用Objective-C阅读此链接的plist,以便将其复制到/ Library/LaunchDaemons /我?
小智 28
您可以使用otool(1)转储包含嵌入plist的节的内容:
otool -s __TEXT __info_plist /path/to/executable
Run Code Online (Sandbox Code Playgroud)
然后将其输出传递给xxd(1)以获得相应的ASCII表示:
otool -X -s __TEXT __info_plist /path/to/executable | xxd -r
Run Code Online (Sandbox Code Playgroud)
对于程序需要读取其自己的嵌入式plist的情况,可以使用NSBundle:
id someValue = [[NSBundle mainBundle] objectForInfoDictionaryKey:someKey];
Run Code Online (Sandbox Code Playgroud)
对于程序需要读取任意文件的嵌入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;
}
Run Code Online (Sandbox Code Playgroud)
和:
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];
}
Run Code Online (Sandbox Code Playgroud)
请注意,它embeddedPlist()有一些限制:它期望文件是一个瘦的Mach-O文件(即,它将与非Mach-O文件崩溃,并且它不适用于包含例如i386和x86_64 Mach的胖文件-O数据); 它只适用于x86_64文件; 它不报告错误.
我继续在MIT许可下发布了BVPlistExtractor.它检测文件是否确实是一个瘦的Mach-O文件或胖/通用文件,并且可以同时使用i386和x86_64.
小智 14
有一个CoreFoundation功能:CFBundleCopyInfoDictionaryForURL().从文档:
对于目录URL,这相当于
CFBundleCopyInfoDictionaryInDirectory.对于表示非捆绑应用程序的普通文件URL,此函数将尝试从文件的(__TEXT,__info_plist)部分(对于Mach-O文件)或从plst资源读取信息字典.
它可以在Mac OS X v10.2及更高版本上使用.如果你在Cocoa中使用,你可以这样做(前提是你有一个(NSURL*)url包):
NSDictionary* infoPlist = [ (NSDictionary*) CFBundleCopyInfoDictionaryForURL( (CFURLRef) url ) autorelease];
Run Code Online (Sandbox Code Playgroud)
一种更简单的方法:
#include <mach-o/getsect.h>
unsigned long *len;
char *data = getsectdata("__TEXT", "__info_plist");
Run Code Online (Sandbox Code Playgroud)
男人getsectdata.有很多关于如何访问各种部分的示例(当前可执行文件,任意可执行文件,框架等).
用户的计算机可能没有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.
Run Code Online (Sandbox Code Playgroud)
如果您不指定该部分,则默认打印 __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";
};
Run Code Online (Sandbox Code Playgroud)
它可以在命令行中使用,也可以通过NSTask(Process在 swift 中)类从代码中使用。
| 归档时间: |
|
| 查看次数: |
5749 次 |
| 最近记录: |