如何在 64 位窗口中加载 32 位 DLL

How to load a 32bit DLL in a 64bit windows

本文关键字:加载 DLL 窗口      更新时间:2023-10-16

>我在 64 位窗口中安装了Mozilla FireFox x64,现在我想LoadLibrary(mozglue.dll)但我收到错误号 193

LoadLibrary(mozglue.dll)在具有Mozilla FireFox 86的 32 位窗口中运行良好

我使用此代码:

#include <Windows.h>
#include <strsafe.h>
int main()
{
HMODULE hndl;
DWORD dwError = 0;
WCHAR errorBuff[MAX_PATH] = {};
hndl = LoadLibraryW(L"C:\Program Files\Mozilla Firefox\mozglue.dll");
dwError = GetLastError();
StringCbPrintfW(errorBuff, MAX_PATH, L"%d", dwError);
MessageBoxW(NULL, errorBuff, L"GetLastError", MB_OK);
FreeLibrary(hndl);
return 0;
}

这段代码有什么问题?

编辑:

我使用:

LoadLibraryExW(L"C:\Program Files\Mozilla Firefox\mozglue.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);

而不是:

LoadLibraryW(L"C:\Program Files\Mozilla Firefox\mozglue.dll");

现在GetLastError返回 0 但GetProcAddress失败...

#include <Windows.h>
#include <strsafe.h>

typedef enum SECItemType {
siBuffer = 0,
siClearDataBuffer = 1,
siCipherDataBuffer,
siDERCertBuffer,
siEncodedCertBuffer,
siDERNameBuffer,
siEncodedNameBuffer,
siAsciiNameString,
siAsciiString,
siDEROID,
siUnsignedInteger,
siUTCTime,
siGeneralizedTime
};
struct SECItem {
SECItemType type;
unsigned char *data;
size_t len;
};
typedef enum SECStatus {
SECWouldBlock = -2,
SECFailure = -1,
SECSuccess = 0
};

typedef struct PK11SlotInfoStr PK11SlotInfo;
typedef SECStatus(*NSS_Init) (const char *);
typedef SECStatus(*NSS_Shutdown) (void);
typedef PK11SlotInfo * (*PK11_GetInternalKeySlot) (void);
typedef void(*PK11_FreeSlot) (PK11SlotInfo *);
typedef SECStatus(*PK11_Authenticate) (PK11SlotInfo *, int, void *);
typedef SECStatus(*PK11SDR_Decrypt) (SECItem *, SECItem *, void *);
PK11_GetInternalKeySlot PK11GetInternalKeySlot;
PK11_FreeSlot PK11FreeSlot;
PK11_Authenticate PK11Authenticate;
PK11SDR_Decrypt PK11SDRDecrypt;
NSS_Init fpNSS_INIT;
NSS_Shutdown fpNSS_Shutdown;

BOOL loadFunc()
{
HMODULE hndl;
DWORD dwError = 0;
WCHAR errorBuff[MAX_PATH] = {};
BOOL retVal = FALSE;
hndl = LoadLibraryExW(L"C:\Program Files\Mozilla Firefox\mozglue.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
dwError = GetLastError();
StringCbPrintfW(errorBuff, MAX_PATH, L"%d", dwError);
MessageBoxW(NULL, errorBuff, L"GetLastError", MB_OK);

hndl = LoadLibraryExW(L"C:\Program Files\Mozilla Firefox\nss3.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
dwError = GetLastError();
StringCbPrintfW(errorBuff, MAX_PATH, L"%d", dwError);
MessageBoxW(NULL, errorBuff, L"GetLastError", MB_OK);
if (hndl)
{
fpNSS_INIT = (NSS_Init)GetProcAddress(hndl, "NSS_Init");
fpNSS_Shutdown = (NSS_Shutdown)GetProcAddress(hndl, "NSS_Shutdown");
PK11GetInternalKeySlot = (PK11_GetInternalKeySlot)GetProcAddress(hndl, "PK11_GetInternalKeySlot");
PK11FreeSlot = (PK11_FreeSlot)GetProcAddress(hndl, "PK11_FreeSlot");
PK11Authenticate = (PK11_Authenticate)GetProcAddress(hndl, "PK11_Authenticate");
PK11SDRDecrypt = (PK11SDR_Decrypt)GetProcAddress(hndl, "PK11SDR_Decrypt");
}
return !(!fpNSS_INIT || !fpNSS_Shutdown || !PK11GetInternalKeySlot || !PK11Authenticate || !PK11SDRDecrypt || !PK11FreeSlot);
}

int main()
{
if (loadFunc())
{
MessageBoxW(NULL, L"OK", L"", MB_OK);
}
else
{
MessageBoxW(NULL, L"NO", L"", MB_OK);
}
return 0;
}

第一个问题是 64 位程序无法加载 32 位 DLL,32 位程序无法加载 64 位 DLL 以执行代码。MSDN 的进程互操作性信息中对此进行了描述:

可以使用仿真层在 64 位 Windows 上运行基于 Win32 的应用程序。有关详细信息,请参阅运行 32 位应用程序。

在 64 位 Windows 上,64 位进程无法加载 32 位动态链接库 (DLL)。此外,32 位进程无法加载 64 位 DLL。

如果您需要同时支持 32 位程序和 64 位,最简单的方法是安装 32 位版本的 MozillaDLL(通过 32 位 Mozilla 安装),并对 64 位 Mozilla 执行相同的操作。默认情况下,64位Mozilla应放在C:Program FilesMozilla Firefox中,32位Mozilla应放在C:Program Files (x86)Mozilla Firefox中。在生成 64 位应用程序时需要考虑不同的目录,在加载 DLL 时需要考虑 32 位应用程序

,例如mozglue.dll

您不检查hndl是否为 NULL。只需检查返回的句柄是否为 NULL,而不是检查返回的句柄是否为 NULL,GetLastError检查。其次,使用LOAD_LIBRARY_AS_DATAFILE调用LoadLibraryExW允许您加载 DLL 资源,但不允许您使用GetProcAddress检索函数地址。这记录在 LoadLibraryEx 的 MSDN 文档中:

LOAD_LIBRARY_AS_DATAFILE 0x00000002

如果使用此值,系统会将文件映射到调用进程的虚拟地址空间,就像它是数据文件一样。不执行任何操作来执行或准备执行映射文件。因此,不能使用此 DLL 调用 GetModuleFileName、GetModuleHandle 或GetProcAddress等函数。使用此值会导致写入只读内存以引发访问冲突。当您只想加载 DLL 以从中提取消息或资源时,请使用此标志。


牢记上述想法,我使用修订后的loadfunc编译了您的代码,并将其构建为 64 位应用程序。完成后,程序将在消息框中打印OK

BOOL loadFunc()
{
HMODULE hndl;
DWORD dwError = 0;
WCHAR errorBuff[MAX_PATH] = {};
BOOL retVal = FALSE;
hndl = LoadLibraryW(L"C:\Program Files\Mozilla Firefox\mozglue.dll");
// if the handle is NULL then check for an error otherwise proceed
if (!hndl)
{
dwError = GetLastError();
StringCbPrintfW(errorBuff, MAX_PATH, L"%d", dwError);
MessageBoxW(NULL, errorBuff, L"GetLastError", MB_OK);
return TRUE;
}
hndl = LoadLibraryW(L"C:\Program Files\Mozilla Firefox\nss3.dll");
// if the handle is NOT NULL then try to retrieve the method addresses
if (hndl)
{
fpNSS_INIT = (NSS_Init)GetProcAddress(hndl, "NSS_Init");
fpNSS_Shutdown = (NSS_Shutdown)GetProcAddress(hndl, "NSS_Shutdown");
PK11GetInternalKeySlot = (PK11_GetInternalKeySlot)GetProcAddress(hndl, "PK11_GetInternalKeySlot");
PK11FreeSlot = (PK11_FreeSlot)GetProcAddress(hndl, "PK11_FreeSlot");
PK11Authenticate = (PK11_Authenticate)GetProcAddress(hndl, "PK11_Authenticate");
PK11SDRDecrypt = (PK11SDR_Decrypt)GetProcAddress(hndl, "PK11SDR_Decrypt");
}
// the handle was NULL if we get here so show the error
else
{
dwError = GetLastError();
StringCbPrintfW(errorBuff, MAX_PATH, L"%d", dwError);
MessageBoxW(NULL, errorBuff, L"GetLastError", MB_OK);
return TRUE;
}
return !(!fpNSS_INIT || !fpNSS_Shutdown || !PK11GetInternalKeySlot || !PK11Authenticate || !PK11SDRDecrypt || !PK11FreeSlot);
}

对于 32 位程序,您需要将上述代码中的路径更改为前面提到的 32 位 Mozilla 目录,并编译为 x86 32 位应用程序。前面提到的 32 位代码的默认路径为C:Program Files (x86)Mozilla Firefox

我从这个下载链接下载了64 位版本的 Mozilla,从这个链接下载了 32 位 Mozilla 安装。

您尝试将 32 位 DLL 加载到 64 位进程中,或将 64 位 DLL 加载到 32 位进程中。 这是做不到的。

我想如果你有"Mozilla FireFox x64",mozglue.dll是64位的 - 所以你需要编译和链接你的测试程序为64位。