使用Python中的Security.framework类型
我正在编写一个Python脚本,该脚本通过ctypes从OSX上的Security.framework调用函数 我能够在Python中生成CFDictionaryRef和CFStringRef,并将字符串存储在字典中,但现在我正在添加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
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中定义结构类型,然后只获取所需的函数