从Swift调用getsectiondata

8
这个问题和答案描述了如何在现代OS X / macOS版本上使用Objective-C从Mach-O部分读取数据:Crash reading bytes from getsectbyname 所述的答案有效。我正在尝试使用Swift实现相同的内容,但无法使其正常工作。
我在“其他链接器标志”中有以下内容:-Wl,-sectcreate,__LOCALIZATIONS,__base,en.lproj/Localizable.strings,-segprot,__LOCALIZATIONS,r,r
这段Swift代码可以让我得到指向嵌入式数据的指针,但一旦我尝试在Xcode之外运行该代码并且ASLR破坏了它:
var size: UInt = 0
let _localizationSection = getsectdata(
    "__LOCALIZATIONS",
    "__base",
    &size)

为了解决ASLR问题,根据上述问题和答案以及自己的测试,我应该使用getsectiondata。在Objective-C中它运行得很好,但是在Swift中我没有成功。以下是我唯一通过编译器的代码,但它返回空值:
var size: UInt = 0
var header = _mh_execute_header
let localizationSection = getsectiondata(
    &header,
    "__LOCALIZATIONS",
    "__base",
    &size)

是拿 _mh_execute_header 的一份副本造成的问题,有没有什么方法可以避免这个问题?我需要一个 UnsafePointer<mach_header_64>,但是使用 &_mh_execute_header 作为传递给 getsectiondata 的第一个参数会导致编译错误。

我正在使用 Swift 3.0,在 macOS 10.12 上运行代码。

1个回答

5

链接到的Objective-C代码与其它代码之间的区别。

void *ptr = getsectiondata(&_mh_execute_header, ...);

而你的Swift翻译
var header = _mh_execute_header
let localizationSection = getsectiondata(&header, ...)

问题在于后者将全局变量_mh_execute_header副本地址传递给函数,显然这是不被接受的。如果您要修改Objective-C代码,则需要:

struct mach_header_64 header = _mh_execute_header;
void *ptr = getsectiondata(&header, ...);

然后它也失败了(在我的测试中实际上崩溃了)。

现在的问题在于_mh_execute_header被暴露给Swift作为一个常量:

public let _mh_execute_header: mach_header_64

在Swift中,不能获取常量的地址。一种可能的解决方法是定义

#import <mach-o/ldsyms.h>
static const struct mach_header_64 *mhExecHeaderPtr = &_mh_execute_header;

在桥接头文件中导入该文件,然后将其用作代码中的引用。
let localizationSection = getsectiondata(mhExecHeaderPtr, ...)

使用Swift编写。


另一个选项是通过dlopen/dlsym查找符号。

import MachO

if let handle = dlopen(nil, RTLD_LAZY) {
    defer { dlclose(handle) }

    if let ptr = dlsym(handle, MH_EXECUTE_SYM) {
        let mhExecHeaderPtr = ptr.assumingMemoryBound(to: mach_header_64.self)

        var size: UInt = 0
        let localizationSection = getsectiondata(
            mhExecHeaderPtr,
            "__LOCALIZATIONS",
            "__base",
            &size)

        // ...
    }
}

这样可以减少我需要编写的Objective-C代码量,如果项目中已经有桥接头文件,这是一个相当不错的解决方案,但在纯Swift项目中仍然有些烦人。 - Juri Pakaste
2
@JuriPakaste:我已经添加了另一个(纯Swift)的解决方案。 - Martin R
@MartinR:“在Swift中无法获取常量的地址”...我们可以使用withUnsafePointer(to: _mh_execute_header),对吧? - fumoboy007
@fumoboy007:是的,这在Swift 4.x中是新功能 - 但我尝试了一下,由于某种原因它在这里不起作用。它可以编译,但无法返回部分数据。 - Martin R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接