使用Python中的Security.framework类型

使用Python中的Security.framework类型,python,macos,cocoa,ctypes,Python,Macos,Cocoa,Ctypes,我正在编写一个Python脚本,该脚本通过ctypes从OSX上的Security.framework调用函数 我能够在Python中生成CFDictionaryRef和CFStringRef,并将字符串存储在字典中,但现在我正在添加Security.framework查询对象(kSecClass,kSecMatchLimit,kSecReturnAttributes,…),我遇到以下崩溃: objc[28201]: Method cache corrupted. This may be a m

我正在编写一个Python脚本,该脚本通过ctypes从OSX上的Security.framework调用函数

我能够在Python中生成CFDictionaryRef和CFStringRef,并将字符串存储在字典中,但现在我正在添加Security.framework查询对象(
kSecClass
kSecMatchLimit
kSecReturnAttributes
,…),我遇到以下崩溃:

objc[28201]: Method cache corrupted. This may be a message to an invalid object, or a memory error somewhere else.
objc[28201]: receiver 0x7fff724fcdf8, SEL 0x7fff8d814fe5, isa 0x7fff724f5f90, cache 0x7fff724f5fa0, buckets 0x7fff8842ffe3, mask 0x5, occupied 0x0, wrap bucket 0x7fff8842ffe3
objc[28201]: receiver 0 bytes, buckets 0 bytes
objc[28201]: selector 'hash'
objc[28201]: isa '(null)'
objc[28201]: Method cache corrupted.
zsh: illegal hardware instruction  python kc.py
我尝试过用包含对象的ctypes数组调用
CFDictionaryCreate()
,也尝试过调用
CFMutableDictionaryCreate()
然后调用
CFDictionarySetValue
。见下文

import ctypes
import ctypes.util
from ctypes import CFUNCTYPE

security = ctypes.CDLL(ctypes.util.find_library('Security'))
foundation = ctypes.CDLL(ctypes.util.find_library('Foundation'))

CFDictionaryRef = ctypes.c_void_p
CFMutableDictionaryRef = ctypes.c_void_p
CFTypeRef = ctypes.c_void_p
CFIndex = ctypes.c_long

CFDictionaryCreate = CFUNCTYPE(CFDictionaryRef, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p, CFIndex, ctypes.c_void_p, ctypes.c_void_p)(('CFDictionaryCreate', foundation))
CFDictionaryCreateMutable = CFUNCTYPE(CFMutableDictionaryRef, CFIndex, ctypes.c_void_p, ctypes.c_void_p)(('CFDictionaryCreateMutable', foundation))
CFDictionarySetValue = CFUNCTYPE(CFMutableDictionaryRef, ctypes.c_void_p, ctypes.c_void_p)(('CFDictionarySetValue', foundation))

def createCFDictionary(items):
    """
    Create a CFDictionaryRef from items = [(CFTypeRef, CFTypeRef), ...]
    """
    # Create C arrays for the keys and values (which are cast as CFTypeRefs).
    keys_array = (CFTypeRef * len(items))(*[ctypes.cast(k, CFTypeRef) for k, v in items])
    values_array = (CFTypeRef * len(items))(*[ctypes.cast(v, CFTypeRef) for k, v in items])

    return CFDictionaryCreate(None,
                              keys_array, values_array, len(items),
                              foundation.kCFTypeDictionaryKeyCallBacks, foundation.kCFTypeDictionaryValueCallBacks)

# 1. Create a CFDictionary with the items in it (crashes).
query = createCFDictionary([(security.kSecClass, security.kSecClassCertificate)])


# 2a. Create a CFMutableDictionary.
query = CFDictionaryCreateMutable(0, foundation.kCFTypeDictionaryKeyCallBacks, foundation.kCFTypeDictionaryValueCallBacks)

# 2b. Add items to it (crashes).
CFDictionarySetValue(query, security.kSecClass, security.kSecClassCertificate)
如果这是一个更简单的解决方案,我很乐意使用PyObjC而不是ctypes;但是,我对它不太熟悉,无法导入Security.framework

OSX10.9.2、Python2.7.5(包括在OSX中)。

我正在研究案例2,因为它看起来更简单

您的CFDictionarySetValue缺少dict参数。修复后,似乎
security.kSecClass
实际上返回了一个函数引用,这是错误的。我认为你需要:

ctypes.c_void_p.in_dll(foundation, 'kSecClass')
这将导致向函数传递正确的值(如lldb中所示)

不知何故,kCFTypeDictionaryKeyCallBacks结构仍然无法使用该机制,可能是因为符号实际上指向一个结构,而不是指向结构的指针。我无法找到任何方法让ctypes返回符号表示的实际地址(这是您想要传递给CFDictionaryCreateMutable的地址),而不是该符号处的值(0,因为这是该结构的第一个成员的值)

您可以自己构造回调,这应该更容易,因为您可以在ctypes中定义结构类型,然后只获取所需的函数