Search code examples
cwinapifirefoxnss

What could cause nss3.dll loading return code 126, even though it is in the hardcoded path?


I'm trying to use nss3.dll decryption in C. Code:

#include <stdio.h>
#include <windows.h>


typedef int SECStatus;
typedef struct {
    unsigned char *data;
    unsigned int len;
} SECItem;

typedef struct {
} PK11SlotInfo;
typedef SECStatus (*PK11SDR_Decrypt_p)(SECItem*, SECItem*, void*);
typedef PK11SlotInfo* (*PK11_GetInternalKeySlot_p)(void);
typedef void (*PK11_FreeSlot_p)(PK11SlotInfo*);
typedef SECStatus (*NSS_Init_p)(const char*);
typedef void (*NSS_Shutdown_p)(void);
typedef void (*PL_ArenaFinish_p)(void);
typedef SECStatus (*PR_Cleanup_p)(void);

PK11_GetInternalKeySlot_p fpPK11_GetInternalKeySlot = NULL;
PK11_FreeSlot_p fpPK11_FreeSlot = NULL;
PK11SDR_Decrypt_p fpPK11SDR_Decrypt = NULL;
NSS_Init_p fpNSS_Init = NULL;
NSS_Shutdown_p fpNSS_Shutdown = NULL;
PL_ArenaFinish_p fpPL_ArenaFinish = NULL;
PR_Cleanup_p fpPR_Cleanup = NULL;

int Base64Decode(const char* input, char** output, DWORD* outputSize) {
    DWORD cryptFlags = CRYPT_STRING_BASE64;
    HMODULE hCrypt32 = LoadLibrary("crypt32.dll");
    if (!hCrypt32) {
        return -2;
    }
    typedef BOOL(WINAPI* CryptStringToBinaryFunc)(LPCSTR, DWORD, DWORD, BYTE*, DWORD*, DWORD*, DWORD*);
    CryptStringToBinaryFunc cryptStringToBinary = (CryptStringToBinaryFunc)GetProcAddress(hCrypt32, "CryptStringToBinaryA");
    if (!cryptStringToBinary) {
        FreeLibrary(hCrypt32);
        return -3;
    }
    if (!cryptStringToBinary(input, 0, cryptFlags, NULL, outputSize, NULL, NULL)) {
        FreeLibrary(hCrypt32);
        return -4;
    }
    *output = (char*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *outputSize);
    if (!*output) {
        FreeLibrary(hCrypt32);
        return -5;
    }
    if (!cryptStringToBinary(input, 0, cryptFlags, (BYTE*)*output, outputSize, NULL, NULL)) {
        HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, *output);
        FreeLibrary(hCrypt32);
        return -6;
    }
    FreeLibrary(hCrypt32);
    return 0;
}

BOOL initNSS() {
    HMODULE moduleNSS = LoadLibrary("C:\\Program Files\\Mozilla Firefox\\nss3.dll");
    if (moduleNSS == NULL) {
        printf("Error loading nss3.dll: %d\n", GetLastError());
        return FALSE;
    }
    fpNSS_Init = (NSS_Init_p)GetProcAddress(moduleNSS, "NSS_Init");
    fpNSS_Shutdown = (NSS_Shutdown_p)GetProcAddress(moduleNSS, "NSS_Shutdown");
    fpPL_ArenaFinish = (PL_ArenaFinish_p)GetProcAddress(moduleNSS, "PL_ArenaFinish");
    fpPR_Cleanup = (PR_Cleanup_p)GetProcAddress(moduleNSS, "PR_Cleanup");
    fpPK11_GetInternalKeySlot = (PK11_GetInternalKeySlot_p)GetProcAddress(moduleNSS, "PK11_GetInternalKeySlot");
    fpPK11_FreeSlot = (PK11_FreeSlot_p)GetProcAddress(moduleNSS, "PK11_FreeSlot");
    fpPK11SDR_Decrypt = (PK11SDR_Decrypt_p)GetProcAddress(moduleNSS, "PK11SDR_Decrypt");

    if (!fpNSS_Init || !fpNSS_Shutdown || !fpPL_ArenaFinish || !fpPR_Cleanup || !fpPK11_GetInternalKeySlot || !fpPK11_FreeSlot || !fpPK11SDR_Decrypt) {
        printf("Error getting function pointers from nss3.dll\n");
        FreeLibrary(moduleNSS);
        return FALSE;
    }
    return 0;
}

char* DecryptString(char* strCryptData) {
    if (strCryptData[0] == 0x0) {
        return NULL;
    }

    DWORD dwOut;
    char* strClearData = NULL;
    char* lpBuffer;
    DWORD outputSize;

    int result = Base64Decode(strCryptData, &lpBuffer, &outputSize);
    if (result != 0) {
        printf("Error decoding Base64: %d\n", result);
        return NULL;
    }

    if (!initNSS() == 0) {
        printf("Error initializing NSS.\n");
        return NULL;
    }

    PK11SlotInfo* pK11Slot = fpPK11_GetInternalKeySlot();
    if (pK11Slot) {
        SECItem pInSecItem, pOutSecItem;

        pInSecItem.data = (unsigned char*)lpBuffer;
        pInSecItem.len = outputSize;

        pOutSecItem.data = NULL;
        pOutSecItem.len = 0;

        if (fpPK11SDR_Decrypt(&pInSecItem, &pOutSecItem, NULL) == 0) {
            strClearData = (char*)malloc(pOutSecItem.len + 1);
            if (strClearData != NULL) {
                memcpy(strClearData, pOutSecItem.data, pOutSecItem.len);
                strClearData[pOutSecItem.len] = '\0';
            }
        }

        fpPK11_FreeSlot(pK11Slot);
    }

    fpNSS_Shutdown();
    fpPL_ArenaFinish();
    fpPR_Cleanup();
    HeapFree(GetProcessHeap(), HEAP_NO_SERIALIZE, lpBuffer);

    return strClearData;
}

int main() {
    char* encryptedData = "MDoEEPgAAAAAAAAAAAAAAAAAAAEwFAYIKoZIhvcNAwcECGBlfa+Zvyb2BBBCU5Y9bU8rUwoDfW2dn7yO";
    char* decryptedData = DecryptString(encryptedData);
    if (decryptedData != NULL) {
        printf("Decrypted string: %s\n", decryptedData);
        free(decryptedData);
    } else {
        printf("Decryption failed.\n");
    }

    return 0;
}

The problem is I keep getting the same error, which is:

Error loading nss3.dll: 126

This would tell me this:

ERROR_MOD_NOT_FOUND 126 (0x7E) The specified module could not be found.

But I've made sure it exists. The error may also underlay in the init() function, but really would appreciate any help.

References to pages I've tried to read:


Solution

  • The issue is nss3.dll is a library developed by Mozilla, and is a part of multiple Mozilla applications like Firefox. However, it relies on other Mozilla developed libraries to work correctly. This means that nss3.dll cannot operate independently, and that it requires additional DLL files to be present in the system.

    To resolve this issue, you can ensure that your program knows where to find nss3.dll and its associated dependencies. One way to achieve this is by changing the current working directory of your program to the directory containing nss3.dll, and then loading the library without specifying an absolute path.

    #include <unistd.h>
    #include <windows.h>
    
    int main() {
        chdir("C:\\Program Files\\Mozilla Firefox"); 
        HMODULE moduleNSS = LoadLibrary("nss3.dll");
        return 0;
    }
    

    Second way is to simply add the Firefox directory to the PATH environment variable. This allows accessing nss3.dll from any directory without changing the working directory. Here is a PowerShell one-liner to add the directory to PATH.

    Local:

    [Environment]::SetEnvironmentVariable('Path', $env:Path + ";C:\Program Files\Mozilla Firefox", [EnvironmentVariableTarget]::User)
    

    Machine:

    [Environment]::SetEnvironmentVariable('Path', $env:Path + ";C:\Program Files\Mozilla Firefox", [EnvironmentVariableTarget]::Machine)