You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

macOS下C++/Objective-C获取.app签名证书信息的替代方案

绝对有办法!在macOS上,你可以直接用系统提供的Security.framework和CodeSigning.framework的原生API来实现这个需求,完全不需要调用终端命令,用Objective-C或者混编C++都能搞定。下面是具体的实现思路和代码示例:

核心依赖框架

macOS的代码签名和证书管理都依赖两个系统框架:

  • Security.framework:提供证书解析、读取证书字段的核心API
  • CodeSigning.framework:用于获取已签名应用的代码签名信息
完整代码示例

下面是一个可以直接运行的Objective-C示例,它会读取指定.app的签名证书,提取主题名称和序列号:

#import <Security/Security.h>
#import <CodeSigning/CodeSigning.h>
#import <Foundation/Foundation.h>

// 定义获取证书信息的函数,兼容C风格调用
BOOL getAppCertificateInfo(const char *appPath, char **outSubjectName, CFStringRef *outSerialNumber) {
    // 初始化输出参数为NULL
    *outSubjectName = NULL;
    *outSerialNumber = NULL;

    // 将C字符串路径转为CFString和CFURL
    CFStringRef pathCFStr = CFStringCreateWithCString(NULL, appPath, kCFStringEncodingUTF8);
    CFURLRef appURL = CFURLCreateWithFileSystemPath(NULL, pathCFStr, kCFURLPOSIXPathStyle, true);
    CFRelease(pathCFStr);

    // 创建静态代码对象(代表已签名的.app)
    SecStaticCodeRef staticCode = NULL;
    OSStatus status = SecStaticCodeCreateWithPath(appURL, kSecCSDefaultFlags, &staticCode);
    CFRelease(appURL);
    if (status != errSecSuccess) {
        fprintf(stderr, "❌ 无法创建静态代码对象,错误码: %d\n", (int)status);
        return NO;
    }

    // 获取代码签名信息字典
    CFDictionaryRef signingInfo = NULL;
    status = SecCodeCopySigningInformation(staticCode, kSecCSRequirementInformation, &signingInfo);
    CFRelease(staticCode);
    if (status != errSecSuccess) {
        fprintf(stderr, "❌ 无法获取签名信息,错误码: %d\n", (int)status);
        return NO;
    }

    // 从签名信息中提取证书链
    CFArrayRef certChain = CFDictionaryGetValue(signingInfo, kSecCodeInfoCertificates);
    if (!certChain || CFArrayGetCount(certChain) == 0) {
        fprintf(stderr, "❌ 签名中未找到证书\n");
        CFRelease(signingInfo);
        return NO;
    }

    // 取出证书链中的第一个证书(叶子证书,即直接给app签名的证书)
    SecCertificateRef leafCert = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, 0);

    // 1. 获取证书主题名称(友好格式)
    CFStringRef subjectSummary = SecCertificateCopySubjectSummary(leafCert);
    if (subjectSummary) {
        // 将CFString转为C字符串输出
        CFIndex maxBufferSize = CFStringGetMaximumSizeForEncoding(CFStringGetLength(subjectSummary), kCFStringEncodingUTF8) + 1;
        *outSubjectName = (char *)malloc(maxBufferSize);
        if (*outSubjectName) {
            CFStringGetCString(subjectSummary, *outSubjectName, maxBufferSize, kCFStringEncodingUTF8);
        }
        CFRelease(subjectSummary);
    }

    // 2. 获取证书序列号(转为十六进制字符串)
    CFDataRef serialData = SecCertificateCopySerialNumber(leafCert);
    if (serialData) {
        NSMutableString *serialHexStr = [NSMutableString stringWithCapacity:CFDataGetLength(serialData) * 2];
        const UInt8 *bytes = CFDataGetBytePtr(serialData);
        for (CFIndex i = 0; i < CFDataGetLength(serialData); i++) {
            [serialHexStr appendFormat:@"%02X", bytes[i]];
        }
        *outSerialNumber = CFStringCreateCopy(NULL, (__bridge CFStringRef)serialHexStr);
        CFRelease(serialData);
    }

    CFRelease(signingInfo);
    return YES;
}

// 测试主函数
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // 替换为你的.app路径
        const char *targetAppPath = "/Applications/YourApp.app";
        
        char *subjectName = NULL;
        CFStringRef serialNumber = NULL;

        if (getAppCertificateInfo(targetAppPath, &subjectName, &serialNumber)) {
            printf("✅ 证书主题名称: %s\n", subjectName);
            printf("✅ 证书序列号: %s\n", CFStringGetCStringPtr(serialNumber, kCFStringEncodingUTF8));
            
            // 记得释放内存
            free(subjectName);
            CFRelease(serialNumber);
        } else {
            fprintf(stderr, "❌ 获取证书信息失败\n");
            return 1;
        }
    }
    return 0;
}
关键细节说明
  1. 证书选择:代码中取的是证书链的第一个证书(叶子证书),这就是直接给你的.app签名的开发者证书,和终端codesign -dv --verbose=4 YourApp.app输出的Authority字段中最顶层的证书一致。
  2. 主题名称:SecCertificateCopySubjectSummary返回的是友好的摘要格式(比如Apple Development: John Doe (ABC123XYZ)),如果需要解析更详细的主题字段(如CN、O、OU等),可以用SecCertificateCopyValues来读取ASN.1结构中的具体字段。
  3. 序列号格式:代码中将二进制序列号转为大写十六进制字符串,和终端命令输出的序列号格式完全一致。
  4. 权限问题:如果你的.app位于系统受保护目录(如/System/Applications),需要以root权限运行程序才能读取签名信息。
编译与运行
  • 在Xcode中:新建Command Line Tool项目,添加Security.framework和CodeSigning.framework到项目依赖,然后粘贴上述代码。
  • 用clang编译:在终端执行以下命令(假设代码文件名为CertInfo.m):
    clang -o CertInfo CertInfo.m -framework Security -framework CodeSigning -framework Foundation
    
    运行时直接执行./CertInfo即可。

内容的提问来源于stack exchange,提问作者Vuwox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:06:55