我正在尝试用 python 创建一个密码管理器,但遇到了一个问题,一旦加载了一种类型的 dll,我就无法加载不同的 dll,在这个示例中,我加载了一个 dll,并尝试解密加密的密码数据,它工作正常,直到我加载另一个不同的 nss3.dll 文件,此时它给我一个错误:
“过程入口点 HeapAlloc 无法位于动态链接库 C:\Program Files\Waterfox\nss3.dll 中”
我仅在加载多个 nss3.dll 文件后出现此错误,例如:
def DecryptFirefoxBased(Type,EncryptedPassword):
EncryptedPassword = base64.b64decode(EncryptedPassword)
nss3 = ctypes.CDLL(Paths[Type][1])
nss_init = nss3.NSS_Init
nss_init.argtypes = [ctypes.c_char_p]
nss_init.restype = ctypes.c_int
nss_init(ProfileDirectory.encode())
pk11_sdr_decrypt = nss3.PK11SDR_Decrypt
pk11_sdr_decrypt.argtypes = [ctypes.POINTER(SecItem), ctypes.POINTER(SecItem), ctypes.c_int]
pk11_sdr_decrypt.restype = ctypes.c_int
EncryptedItem = SecItem()
EncryptedItem.data = ctypes.create_string_buffer(EncryptedPassword)
EncryptedItem.len = len(EncryptedPassword)
DecryptedItem = SecItem()
decrypted_buffer = ctypes.create_string_buffer(len(EncryptedPassword))
DecryptedItem.data = ctypes.cast(decrypted_buffer, ctypes.POINTER(ctypes.c_char))
DecryptedItem.len = len(EncryptedPassword)
ret = pk11_sdr_decrypt(ctypes.byref(EncryptedItem), ctypes.byref(DecryptedItem), 0)
if ret != 0:
input("PK11SDR_Decrypt failed")
return ctypes.string_at(DecryptedItem.data, DecryptedItem.len).decode()
Paths[Type][1] = "C:\Users\me\Program Files\nss3.dll"
在参考中上面的内容被多次调用,每次加载不同的 dll,在它破坏的第二个不同的 nss3.dll 库上,这实际上是我能提供的所有信息,如果有人知道我为什么会收到此错误,请帮助我或提示为什么会发生这种情况,因为它真的开始激怒我。
你遇到的问题是,当你多次加载
nss3.dll
时,实际上并没有加载多个副本。Windows DLL 加载机制会确保每个 DLL 只加载一次。当你尝试加载已经加载的 DLL 时,Windows 只是返回了对已加载 DLL 的引用。
问题在于,当
ctypes.CDLL
加载 DLL 时,它会解析 DLL 中的所有函数指针。当你加载第二个
nss3.dll
时,
ctypes.CDLL
会覆盖第一个
nss3.dll
中解析的函数指针,导致函数指针指向错误的地址。这就是你看到“过程入口点 HeapAlloc 无法位于动态链接库...中”错误的原因。
解决这个问题的方法是,为每个
nss3.dll
文件创建一个独立的加载器。你可以使用
ctypes.WinDLL
来实现这一点。
ctypes.WinDLL
不会解析所有函数指针,而是只在需要时才解析。这样,每个
nss3.dll
文件都会有自己的函数指针集,避免了冲突。
以下是修改后的代码:
import ctypes
import base64
def DecryptFirefoxBased(Type, EncryptedPassword):
EncryptedPassword = base64.b64decode(EncryptedPassword)
# 使用 WinDLL 加载 DLL
nss3 = ctypes.WinDLL(Paths[Type][1])
# 使用 GetProcAddress 获取函数指针
nss_init = ctypes.WinDLL(Paths[Type][1]).NSS_Init
nss_init.argtypes = [ctypes.c_char_p]
nss_init.restype = ctypes.c_int
nss_init(ProfileDirectory.encode())
pk11_sdr_decrypt = ctypes.WinDLL(Paths[Type][1]).PK11SDR_Decrypt
pk11_sdr_decrypt.argtypes = [ctypes.POINTER(SecItem), ctypes.POINTER(SecItem), ctypes.c_int]
pk11_sdr_decrypt.restype = ctypes.c_int
EncryptedItem = SecItem()
EncryptedItem.data = ctypes.create_string_buffer(EncryptedPassword)
EncryptedItem.len = len(EncryptedPassword)
DecryptedItem = SecItem()
decrypted_buffer = ctypes.create_string_buffer(len(EncryptedPassword))
DecryptedItem.data = ctypes.cast(decrypted_buffer, ctypes.POINTER(ctypes.c_char))
DecryptedItem.len = len(EncryptedPassword)
ret = pk11_sdr_decrypt(ctypes.byref(EncryptedItem), ctypes.byref(DecryptedItem), 0)
if ret != 0:
input("PK11SDR_Decrypt failed")
return ctypes.string_at(DecryptedItem.data, DecryptedItem.len).decode()
请注意,这段代码假设
SecItem
已经定义。
通过使用
ctypes.WinDLL
,你可以避免多次加载 DLL 时函数指针冲突的问题,从而解决你的问题。