[WebKit]遭遇Mac OS私有API

WebKit并不是完全开源的, Apple封装了一部代码在一个静态库(libWebKitSystemInterfaceXXXX.a)中,并没有提供源代码。而且不同版本的OS (包括iOS),会有特定的版本。

这就是我今天从分析中了解到的, 觉得过程比较有趣,记录一下。

1. 在WebKit中有这样一段源代码 (Laguage.mm):

static String httpStyleLanguageCode(NSString *languageCode)
{
    ASSERT(isMainThread());

    // Look up the language code using CFBundle.
    RetainPtr<CFStringRef> preferredLanguageCode(AdoptCF, wkCopyCFLocalizationPreferredName((CFStringRef)languageCode));

其中wkCopyCFLocalizationPreferredName只有如下的定义,找不到实现代码:
extern CFStringRef (*wkCopyCFLocalizationPreferredName)(CFStringRef);

2. 在运行时,查询wkCopyCFLocalizationPreferredName的地址信息:
(lldb) p wkCopyCFLocalizationPreferredName
(CFStringRef (*)(CFStringRef)) $0 = 0x0000000100478a49 
(WebKit2`WKCopyCFLocalizationPreferredName)


(lldb) image lookup -s WKCopyCFLocalizationPreferredName
1 symbols match 'WKCopyCFLocalizationPreferredName' in /Volumes/Data/Project/Webkit/webkitSvn/Build/Products/Debug/WebKit2.framework/Versions/A/WebKit2:
        Address: WebKit2[0x0000000000464a49] (WebKit2.__TEXT.__text + 4600745)
        Summary: WebKit2`WKCopyCFLocalizationPreferredName
1 symbols match 'WKCopyCFLocalizationPreferredName' in /Volumes/Data/Project/Webkit/webkitSvn/Build/Products/Debug/WebKit.framework/Versions/A/WebKit:
        Address: WebKit[0x00000000001b8275] (WebKit.__TEXT.__text + 1795141)
        Summary: WebKit`WKCopyCFLocalizationPreferredName

可以看到代码是位于WebKit2.framework中的, 但没有源代码信息,所以必然是link了一个静态库进来。


3. 查看项目的编译设置,可以发现要链接进来的库:
[WebKit]遭遇Mac OS私有API_第1张图片

还可以在WEBKIT_SYSTEM_INTERFACE_LIBRARY的定义中发现有不同系统的版本。

可以找到一个正在使用的库看看:
  

4. 用IDA(试用版)打开找找里面有没有WKCopyCFLocalizationPreferredName:
[WebKit]遭遇Mac OS私有API_第2张图片

也可以使用nm看看源文件,显然WebKitSystemInterface.o找不到对应的源代码:
nm -a libWebKitSystemInterfaceLion.a
/XXXXXX/Build/Products/Debug/libWebKitSystemInterfaceLion.a(WebKitSystemInterface.o):
0000000000002591 t -[NSWindowGraphicsContext(WebKitSystemInterface) _WebKitSystemInterface_setGraphicsPort:]
0000000000008d98 s -[NSWindowGraphicsContext(WebKitSystemInterface) _WebKitSystemInterface_setGraphicsPort:].eh
00000000000090a8 S _WKCopyBundleURLForExecutableURL.eh
00000000000006c7 T _WKCopyCFLocalizationPreferredName
0000000000008200 S _WKCopyCFLocalizationPreferredName.eh

反汇编可以看到如下的代码:
function _WKCopyCFLocalizationPreferredName {
    CFBundleGetLocalizationInfoForLocalization(arg_0, &var_32, &var_28, &var_24, &var_20);
    rax = CFBundleCopyLocalizationForLocalizationInfo(var_32, var_28, var_24, var_20);
    return rax;
}

很简单,就是涉及到两个函数调用。问题是,这两个函数并没有在开发文档里。


5 继续查找libWebKitSystemInterfaceXXX.a的来历。WebKit的工程都是通过gyp来生成的,打开果然里面提到了这样一段描述:
WebCore.gyp
 ['OS == "mac"', {
      'targets': [
        {
          # On the Mac, libWebKitSystemInterface*.a is used to help WebCore
          # interface with the system.  This library is supplied as a static
          # library in binary format.  At present, it contains many global
          # symbols not marked private_extern.  It should be considered an
          # implementation detail of WebCore, and does not need these symbols
          # to be exposed so widely.
          #
          # This target contains an action that cracks open the existing
          # static library and rebuilds it with these global symbols
          # transformed to private_extern.
          'target_name': 'webkit_system_interface',

它只以二进制形式提供。没问题,有反汇编的结果,写出一个一样的函数也不是问题。


6. 找到两个私有API的来历。
使用 image lookup -s可以很容易确定两个函数是在CoreFundation.framework中的。在Apple Open Source中也可以查得到声明(class-dump对C接口就不灵光了):
   CFBundlePriv.h on opensource.apple.com
    CFBundleGetLocalizationInfoForLocalization
    CFBundleCopyLocalizationForLocalizationInfo

最后添加如下的声明就可以使用了:
extern "C" {
CF_EXPORT Boolean CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName, SInt32 *languageCode, SInt32 *regionCode, SInt32 *scriptCode, CFStringEncoding *stringEncoding);
CF_EXPORT CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SInt32 regionCode, SInt32 scriptCode, CFStringEncoding stringEncoding);
}


你可能感兴趣的:(mac,webkit)