So yesterday I took a few hours to throw together this sniblet after reviewing MimiKatz source code. This code takes a Blob that is in DPAPI format (Stright from the registery and decode’s it with the Key given. This key is your SysKey/BootKey.

#pragma comment(lib, "crypt32.lib")
#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <wincrypt.h>
#include <minwindef.h>
#define AES_256_KEY_SIZE    (256/8)
#define LAZY_NT6_IV_SIZE    32
typedef struct _NT6_CLEAR_SECRET {
    DWORD SecretSize;
    DWORD unk0;
    DWORD unk1;
    DWORD unk2;
    BYTE  Secret[ANYSIZE_ARRAY];
} NT6_CLEAR_SECRET, *PNT6_CLEAR_SECRET;
typedef struct _NT6_HARD_SECRET {
    DWORD version;
    GUID KeyId;
    DWORD algorithm;
    DWORD flag;
    BYTE lazyiv[LAZY_NT6_IV_SIZE];
    union {
        NT6_CLEAR_SECRET clearSecret;
        BYTE encryptedSecret[ANYSIZE_ARRAY];
    };
} NT6_HARD_SECRET, *PNT6_HARD_SECRET;
typedef struct _GENERICKEY_BLOB {
    BLOBHEADER Header;
    DWORD dwKeyLen;
} GENERICKEY_BLOB, *PGENERICKEY_BLOB;

BOOL kull_m_crypto_hkey(HCRYPTPROV hProv, ALG_ID calgid, LPCVOID key, DWORD keyLen, DWORD flags, HCRYPTKEY *hKey, HCRYPTPROV *hSessionProv)
{
    BOOL status = FALSE;
    PGENERICKEY_BLOB keyBlob;
    DWORD szBlob = sizeof(GENERICKEY_BLOB) + keyLen;

    if (calgid != CALG_3DES)
    {
        if (keyBlob = (PGENERICKEY_BLOB)LocalAlloc(LPTR, szBlob))
        {
            keyBlob->Header.bType = PLAINTEXTKEYBLOB;
            keyBlob->Header.bVersion = CUR_BLOB_VERSION;
            keyBlob->Header.reserved = 0;
            keyBlob->Header.aiKeyAlg = calgid;
            keyBlob->dwKeyLen = keyLen;
            RtlCopyMemory((PBYTE)keyBlob + sizeof(GENERICKEY_BLOB), key, keyBlob->dwKeyLen);
            status = CryptImportKey(hProv, (LPCBYTE)keyBlob, szBlob, 0, flags, hKey);
            LocalFree(keyBlob);
        }
    }
    else if (hSessionProv)
    {
        return NULL;
        //status = kull_m_crypto_hkey_session(calgid, key, keyLen, flags, hKey, hSessionProv);
    }


    return status;
}

wchar_t * outputBuffer = NULL;
size_t outputBufferElements = 0, outputBufferElementsPosition = 0;

PCWCHAR WPRINTF_TYPES[] =
{
    L"%02x",        // WPRINTF_HEX_SHORT
    L"%02x ",       // WPRINTF_HEX_SPACE
    L"0x%02x, ",    // WPRINTF_HEX_C
    L"\\x%02x",     // WPRINTF_HEX_PYTHON
};

void kprintf(PCWCHAR format, ...)
{
    int varBuf;
    size_t tempSize;
    wchar_t * tmpBuffer;
    va_list args;
    va_start(args, format);
    if (outputBuffer)
    {
        varBuf = _vscwprintf(format, args);
        if (varBuf > 0)
        {
            if ((size_t)varBuf > (outputBufferElements - outputBufferElementsPosition - 1)) // NULL character
            {
                tempSize = (outputBufferElements + varBuf + 1) * 2; // * 2, just to be cool
                if (tmpBuffer = (wchar_t *)LocalAlloc(LPTR, tempSize * sizeof(wchar_t)))
                {
                    RtlCopyMemory(tmpBuffer, outputBuffer, outputBufferElementsPosition * sizeof(wchar_t));
                    LocalFree(outputBuffer);
                    outputBuffer = tmpBuffer;
                    outputBufferElements = tempSize;
                }
                else wprintf(L"Erreur LocalAlloc: %u\n", GetLastError());
                //if(outputBuffer = (wchar_t *) LocalReAlloc(outputBuffer, tempSize * sizeof(wchar_t), LPTR))
                //  outputBufferElements = tempSize;
                //else wprintf(L"Erreur ReAlloc: %u\n", GetLastError());
            }
            varBuf = vswprintf_s(outputBuffer + outputBufferElementsPosition, outputBufferElements - outputBufferElementsPosition, format, args);
            if (varBuf > 0)
                outputBufferElementsPosition += varBuf;
        }
    }
    //vwprintf(format, args);
    va_end(args);
    //
}

void kull_m_string_wprintf_hex2(LPCVOID lpData, DWORD cbData, DWORD flags)
{
    DWORD i, sep = flags >> 16;
    PCWCHAR pType = WPRINTF_TYPES[flags & 0x0000000f];

    if ((flags & 0x0000000f) == 2)
        std::cout << L"\nBYTE data[] = {\n\t";

    for (i = 0; i < cbData; i++)
    {
        std::cout << pType, ((LPCBYTE)lpData)[i];
        if (sep && !((i + 1) % sep))
        {
            std::cout << L"\n";
            if ((flags & 0x0000000f) == 2)
                std::cout << L"\t";
        }
    }
    if ((flags & 0x0000000f) == 2)
        std::cout << L"\n};\n";
}

void kull_m_string_wprintf_hex(LPCVOID lpData, DWORD cbData, DWORD flags)
{
    DWORD i, sep = flags >> 16;
    PCWCHAR pType = WPRINTF_TYPES[flags & 0x0000000f];

    if ((flags & 0x0000000f) == 2)
        printf("\nBYTE data[] = {\n\t");

    for (i = 0; i < cbData; i++)
    {
        //kprintf(pType, ((LPCBYTE)lpData)[i]);
        printf("%02x", ((LPCBYTE)lpData)[i]);
        if (sep && !((i + 1) % sep))
        {
            kprintf(L"\n");
            if ((flags & 0x0000000f) == 2)
                kprintf(L"\t");
        }
    }
    if ((flags & 0x0000000f) == 2)
        kprintf(L"\n};\n");
}




int main()
{
    std::cout << "Hello World!\n";

    BOOL status = FALSE;
    BYTE keyBuffer[AES_256_KEY_SIZE];
    DWORD i, offset, szNeeded;
    HCRYPTPROV hContext;
    HCRYPTHASH hHash;
    HCRYPTKEY hKey;
    PBYTE pKey = NULL;

    PNT6_HARD_SECRET hardSecretBlob = (PNT6_HARD_SECRET)LocalAlloc(LPTR, sizeof(PNT6_HARD_SECRET));
    BYTE key[] = { 0xed, 0xbc, 0x23, 0x26, 0xf8, 0x21, 0xe9, 0x6a, 0xbc, 0x38, 0x34, 0x7a, 0xfa, 0xbd, 0x1c, 0x90, 0x18, 0xf2, 0x24, 0xf5, 0x82, 0xe9, 0x00, 0xac, 0xf8, 0x41, 0x6f, 0xdb, 0x03, 0xe8, 0xac, 0xd4 };
    BYTE FullBlob[] = { 0x00, 0x00, 0x00, 0x01, 0xdd, 0x7b, 0xe8, 0xa2, 0x48, 0xd1, 0x45, 0x0b, 0x29, 0xf7, 0x6f, 0xd2, 0x93, 0x88, 0x16, 0x63, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x2c, 0x25, 0x10, 0x31, 0x73, 0x57, 0xba, 0xb4, 0x86, 0x6f, 0xb4, 0x8c, 0xd7, 0xe2, 0x8a, 0xb8, 0x6d, 0x22, 0xf6, 0x6d, 0xa3, 0x61, 0xb4, 0x3c, 0xa9, 0xec, 0x48, 0x72, 0x96, 0xcf, 0x9a, 0xad, 0xc2, 0xc6, 0x72, 0x26, 0x91, 0xa4, 0x99, 0x51, 0x8a, 0x54, 0xf8, 0xc2, 0xdf, 0x1e, 0x3a, 0x8d, 0xf4, 0x5e, 0xd3, 0xff, 0xad, 0x18, 0x9d, 0xb7, 0x2b, 0x06, 0xc2, 0x75, 0xb1, 0xb5, 0xc7, 0x3d, 0x52, 0xc1, 0x40, 0x17, 0xd0, 0x75, 0x3a, 0x64, 0x9f, 0x99, 0x3e, 0xa4, 0x95, 0xd2, 0x4e };
    memcpy(hardSecretBlob, FullBlob, sizeof(FullBlob));

    DWORD hardSecretBlobSize = sizeof(FullBlob);

    pKey = key;

    szNeeded = 32; //Keysize is always 32

    if (CryptAcquireContext(&hContext, NULL, NULL, PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
    {
        if (CryptCreateHash(hContext, CALG_SHA_256, 0, 0, &hHash))
        {
            CryptHashData(hHash, pKey, szNeeded, 0);
            for (i = 0; i < 1000; i++)
                CryptHashData(hHash, hardSecretBlob->lazyiv, LAZY_NT6_IV_SIZE, 0);

            //kull_m_string_wprintf_hex(hHash, 64, 0);

            szNeeded = sizeof(keyBuffer);
            if (CryptGetHashParam(hHash, HP_HASHVAL, keyBuffer, &szNeeded, 0))
            {
                if (kull_m_crypto_hkey(hContext, CALG_AES_256, keyBuffer, sizeof(keyBuffer), 0, &hKey, NULL))
                {
                    i = CRYPT_MODE_ECB;
                    if (CryptSetKeyParam(hKey, KP_MODE, (LPCBYTE)&i, 0))
                    {
                        szNeeded = hardSecretBlobSize - FIELD_OFFSET(NT6_HARD_SECRET, encryptedSecret);
                        status = CryptDecrypt(hKey, 0, FALSE, 0, hardSecretBlob->encryptedSecret, &szNeeded);
                        kull_m_string_wprintf_hex(hardSecretBlob->encryptedSecret, szNeeded, 0);
                        if (!status)
                            std::cout << "CryptDecrypt";
                    }
                    else std::cout << "CryptSetKeyParam";
                    CryptDestroyKey(hKey);
                }
                else std::cout << "kull_m_crypto_hkey";
            }
            CryptDestroyHash(hHash);
        }
        CryptReleaseContext(hContext, 0);
    }
}

Leave a Reply

Your email address will not be published. Required fields are marked *