C++ How to execute a binary from Memory? - c++

Hi i want execute binary code of a exe / dll file from memory and i found this code:
#include <iostream> // Standard C++ library for console I/O
#include <string> // Standard C++ Library for string manip
#include <Windows.h> // WinAPI Header
#include <TlHelp32.h> //WinAPI Process API
int RunPortableExecutable(void* Image)
{
IMAGE_DOS_HEADER* DOSHeader; // For Nt DOS Header symbols
IMAGE_NT_HEADERS* NtHeader; // For Nt PE Header objects & symbols
IMAGE_SECTION_HEADER* SectionHeader;
PROCESS_INFORMATION PI;
STARTUPINFOA SI;
CONTEXT* CTX;
DWORD* ImageBase; //Base address of the image
void* pImageBase; // Pointer to the image base
int count;
char CurrentFilePath[1024];
DOSHeader = PIMAGE_DOS_HEADER(Image); // Initialize Variable
NtHeader = PIMAGE_NT_HEADERS(DWORD(Image) + DOSHeader->e_lfanew); // Initialize
GetModuleFileNameA(0, CurrentFilePath, 1024); // path to current executable
if (NtHeader->Signature == IMAGE_NT_SIGNATURE) // Check if image is a PE File.
{
ZeroMemory(&PI, sizeof(PI)); // Null the memory
ZeroMemory(&SI, sizeof(SI)); // Null the memory
if (CreateProcessA(CurrentFilePath, NULL, NULL, NULL, FALSE,
CREATE_SUSPENDED, NULL, NULL, &SI, &PI)) // Create a new instance of current
//process in suspended state, for the new image.
{
// Allocate memory for the context.
CTX = LPCONTEXT(VirtualAlloc(NULL, sizeof(CTX), MEM_COMMIT, PAGE_READWRITE));
CTX->ContextFlags = CONTEXT_FULL; // Context is allocated
if (GetThreadContext(PI.hThread, LPCONTEXT(CTX))) //if context is in thread
{
// Read instructions
ReadProcessMemory(PI.hProcess, LPCVOID(CTX->Ebx + 8), LPVOID(&ImageBase), 4, 0);
pImageBase = VirtualAllocEx(PI.hProcess, LPVOID(NtHeader->OptionalHeader.ImageBase),
NtHeader->OptionalHeader.SizeOfImage, 0x3000, PAGE_EXECUTE_READWRITE);
// Write the image to the process
WriteProcessMemory(PI.hProcess, pImageBase, Image, NtHeader->OptionalHeader.SizeOfHeaders, NULL);
for (count = 0; count < NtHeader->FileHeader.NumberOfSections; count++)
{
SectionHeader = PIMAGE_SECTION_HEADER(DWORD(Image) + DOSHeader->e_lfanew + 248 + (count * 40));
WriteProcessMemory(PI.hProcess, LPVOID(DWORD(pImageBase) + SectionHeader->VirtualAddress),
LPVOID(DWORD(Image) + SectionHeader->PointerToRawData), SectionHeader->SizeOfRawData, 0);
}
WriteProcessMemory(PI.hProcess, LPVOID(CTX->Ebx + 8),
LPVOID(&NtHeader->OptionalHeader.ImageBase), 4, 0);
// Move address of entry point to the eax register
CTX->Eax = DWORD(pImageBase) + NtHeader->OptionalHeader.AddressOfEntryPoint;
SetThreadContext(PI.hThread, LPCONTEXT(CTX)); // Set the context
ResumeThread(PI.hThread); //´Start the process/call main()
return 0; // Operation was successful.
}
}
}
}
// enter valid bytes of a program here.
unsigned char rawData[37376] = {
0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0x00, 0x00, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
int main()
{
RunPortableExecutable(rawData); // run executable from the array
getchar();
}
This code i found on github when i start it it just waits does nothing:
Than i replaced my own binary codes to project like this:
Its too long so im sharing a picture.
When i debug it i see this error:
But also sometimes works?!
What is problem? and how to solve? thats really weird :/
this is what i use on visual studio (sorry im new and extremelly noob :D)

Remember that you're forking the same process and rewriting the process memory with your custom PE file, so when the Process starts it will start as a child of the stub executable, and seems that you're not waiting for the object to return
WaitForSingleObject(
PI.hProcess,
INFINITE
);
GetExitCodeProcess(
PI.hProcess,
&dwRet
);
CloseHandle(PI.hThread);
CloseHandle(PI.hProcess);
Also you might be interested in attaching the child process to some debugger (i.e x64dbg) and check if it's raising any exception itself.

Related

I'm injecting a dll into the program, after the injection I'm trying to get ntdll.dll ZqQueryInformationProcess, but the application crashes

Here is my code:
inline DWORD RestoreZwQueryInformationProcess() {
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
DWORD ZwQueryInformationProcessAddr = reinterpret_cast<DWORD>(
GetProcAddress(ntdll, "ZwQueryInformationProcess"));
BYTE ZwQIP[] = {
0xB8, 0x19, 0x00, 0x00, 0x00
};
BYTE* originalBytes = (BYTE*)ZwQueryInformationProcessAddr;
int i = 0;
for (BYTE _byte : ZwQIP) {
*(BYTE*)(ZwQueryInformationProcessAddr + i) = _byte;
i++;
}
return ZwQueryInformationProcessAddr;
}
In dllmain.cpp
RestoreZwQueryInformationProcess();
When calling that function, injected application is crashing.
Is it something about ntdll.dll permissions? I couldn't get it work.
Edit: My friend is using the same dll and the same injection method, and his application isn't crashing.

AES-CBC encrypted output in CNG is not matching with online tools

I am new to CNG. I am playing with the basic program from msdn site.
I have modified the input plain string and testing the output using other websites that provides the aes cbc encrypted output.
Unfortunately only first half matches and the next half is not matching.
It would be great if someone can point me where the mistake lies,
original code from msdn is here.
Here is the output generated from my code (below). Please note that there is no difference in my code apart from modifying the input plain string.
Here is the output from the online website (http://aes.online-domain-tools.com/ and anothersite)
The first half ends at "B0 C4 29 18".. after that the 2nd half doesn't match.
Here is the code snippet
#include <windows.h>
#include <stdio.h>
#include <bcrypt.h>
#pragma comment(lib, "bcrypt.lib")
#ifndef STATUS_UNSUCCESSFUL
#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L)
#endif // !STATUS_UNSUCCESSFUL
#ifndef NT_SUCCESS
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
#endif
void
print_inhex(char *buf, int len) {
for (int i = 0; i < len; i++)
printf(" %02x", buf[i]);
printf("\n");
}
const BYTE rgbPlaintext[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
static const BYTE rgbIV[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
static const BYTE rgbAES128Key[] =
{
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
void
CNG_aes_cbc()
{
BCRYPT_ALG_HANDLE hAesAlg = NULL;
BCRYPT_KEY_HANDLE hKey = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
DWORD cbCipherText = 0,
cbPlainText = 0,
cbData = 0,
cbKeyObject = 0,
cbBlockLen = 0,
cbBlob = 0;
PBYTE pbCipherText = NULL,
pbPlainText = NULL,
pbKeyObject = NULL,
pbIV = NULL,
pbBlob = NULL;
// Open an algorithm handle.
if (!NT_SUCCESS(status = BCryptOpenAlgorithmProvider(&hAesAlg, BCRYPT_AES_ALGORITHM, NULL, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptOpenAlgorithmProvider\n", status);
goto Cleanup;
}
// Calculate the size of the buffer to hold the KeyObject.
if (!NT_SUCCESS(status = BCryptGetProperty(hAesAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbKeyObject, sizeof(DWORD), &cbData, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
// Allocate the key object on the heap.
pbKeyObject = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbKeyObject);
if (NULL == pbKeyObject) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
// Calculate the block length for the IV.
if (!NT_SUCCESS(status = BCryptGetProperty(hAesAlg, BCRYPT_BLOCK_LENGTH, (PBYTE)&cbBlockLen, sizeof(DWORD), &cbData, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGetProperty\n", status);
goto Cleanup;
}
// Determine whether the cbBlockLen is not longer than the IV length.
if (cbBlockLen > sizeof(rgbIV)) {
wprintf(L"**** block length is longer than the provided IV length\n");
goto Cleanup;
}
// Allocate a buffer for the IV. The buffer is consumed during the
// encrypt/decrypt process.
pbIV = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlockLen);
if (NULL == pbIV) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
memcpy(pbIV, rgbIV, cbBlockLen);
if (!NT_SUCCESS(status = BCryptSetProperty(hAesAlg, BCRYPT_CHAINING_MODE, (PBYTE)BCRYPT_CHAIN_MODE_CBC, sizeof(BCRYPT_CHAIN_MODE_CBC), 0))) {
wprintf(L"**** Error 0x%x returned by BCryptSetProperty\n", status);
goto Cleanup;
}
// Generate the key from supplied input key bytes.
if (!NT_SUCCESS(status = BCryptGenerateSymmetricKey(hAesAlg, &hKey, pbKeyObject, cbKeyObject, (PBYTE)rgbAES128Key, sizeof(rgbAES128Key), 0))) {
wprintf(L"**** Error 0x%x returned by BCryptGenerateSymmetricKey\n", status);
goto Cleanup;
}
// Save another copy of the key for later.
if (!NT_SUCCESS(status = BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, NULL, 0, &cbBlob, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptExportKey\n", status);
goto Cleanup;
}
// Allocate the buffer to hold the BLOB.
PUCHAR pbBlob_1 = (PUCHAR)malloc(sizeof(PUCHAR) * cbBlob);
//pbBlob = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbBlob);
if (NULL == pbBlob_1) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
if (!NT_SUCCESS(status = BCryptExportKey(hKey, NULL, BCRYPT_KEY_DATA_BLOB, pbBlob_1, cbBlob, &cbBlob, 0))) {
wprintf(L"**** Error 0x%x returned by BCryptExportKey\n", status);
goto Cleanup;
}
PUCHAR blob = pbBlob_1 + sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
int len = cbBlob - sizeof(BCRYPT_KEY_DATA_BLOB_HEADER);
printf("key:");
print_inhex(blob, len);
cbPlainText = sizeof(rgbPlaintext);
pbPlainText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbPlainText);
if (NULL == pbPlainText) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
/*memcpy(pbPlainText, rgbPlaintext, sizeof(rgbPlaintext));*/
char *test_msg = "This is my test msg";
cbPlainText = strlen(test_msg) + 1;
memcpy(pbPlainText, test_msg, cbPlainText);
printf("plain text:");
print_inhex(test_msg, strlen(test_msg));
// Get the output buffer size.
if (!NT_SUCCESS(status = BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV, cbBlockLen, NULL, 0, &cbCipherText, BCRYPT_BLOCK_PADDING))) {
wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status);
goto Cleanup;
}
pbCipherText = (PBYTE)HeapAlloc(GetProcessHeap(), 0, cbCipherText);
if (NULL == pbCipherText) {
wprintf(L"**** memory allocation failed\n");
goto Cleanup;
}
// Use the key to encrypt the plaintext buffer.
// For block sized messages, block padding will add an extra block.
if (!NT_SUCCESS(status = BCryptEncrypt(hKey, pbPlainText, cbPlainText, NULL, pbIV,
cbBlockLen, pbCipherText, cbCipherText, &cbData, BCRYPT_BLOCK_PADDING))){
wprintf(L"**** Error 0x%x returned by BCryptEncrypt\n", status);
goto Cleanup;
}
printf("cipher text:");
for (int i = 0; i < cbCipherText; i++)
printf(" %02x", pbCipherText[i]);
wprintf(L"\nSuccess!\n");
Cleanup:
if (hAesAlg)
BCryptCloseAlgorithmProvider(hAesAlg, 0);
if (hKey)
BCryptDestroyKey(hKey);
if (pbCipherText)
HeapFree(GetProcessHeap(), 0, pbCipherText);
if (pbKeyObject)
HeapFree(GetProcessHeap(), 0, pbKeyObject);
if (pbIV)
HeapFree(GetProcessHeap(), 0, pbIV);
}
You aren't consistent with your value for cbPlainText.
Asides:
You also have some very scary copy/realloc code where you write a string over a buffer not guaranteed as big as the string).
You also defined NT_SUCCESS in such a way that it returns whether or not something failed. 0 is success, !0 is failure.
You hex-printed up to strlen of tst_msg. But you set cbPlainText = strlen(tst_msg) + 1. If you set it to strlen(tst_msg) then you get #zaph's answer (46CC2228E81B2A05E8E8EBF2B0C42918EC496128D7C45BD0B19BB2D6452A3936).
You don't match the website because you used CNG with PKCS#7 padding, and the website uses zero-padding. You could identify the padding used in the website by taking your output ciphertext and putting it as the plaintext, then hitting decrypt. It then says your input was 54686973206973206d792074657374206d736700000000000000000000000000. Or, if you add 00 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C 0C on your input to the website you'll get your original answer. Or add 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D 0D and you'll get #zaph's answer.
So, things to do:
Don't re-evaluate the length of things to print, make one variable (cbPlainText) and stick with it.
AES is a block cipher algorithm. All block ciphers require complete blocks, a deficient last block must be padded (and under removable padding schemes a complete final block requires yet another block). Learn what this means before continuing. https://en.wikipedia.org/wiki/Padding_(cryptography)#Symmetric_cryptography
When something seems wrong with encryption, look at the decrypted output.
Very often the decrypted output with "no padding" is revealing.
Learn C, and how memory works. Or switch to C# and have a less steep learning curve.
The length of the data is not an exact multiple of the block size (16-bytes for AES) so padding is added but. That is where the implementation either rejects the data, pads with a default method such as 0x00 (cryptomathic), PKCS#7 (the generally used padding) or whatever junk follews the provided data in memory.
Don't use BCryptEncrypt, use AES Class
SymmetricAlgorithm.Padding Property Note: The default is PaddingMode.PKCS7.
It is best to specify the padding on instantiation of AES.
See PaddingMode Enumeration: PKCS7
The PKCS #7 padding string consists of a sequence of bytes, each of which is equal to the total number of padding bytes added.
Manually adding PKCS#7 padding to:
cryptommathic AES:
produces: 46CC2228E81B2A05E8E8EBF2B0C42918EC496128D7C45BD0B19BB2D6452A3936

Error when hooking a function, "Stack around the variable x was corrupted."? C++

I'm trying to hook a function on x64 application. Here's my code:
int __stdcall nRecv(SOCKET s, char* buf, int len, int flags)
{
Log("Receving!");
return 0;
}
BOOL HookFunction(LPCWSTR moduleName, LPCSTR funcName, LPVOID pDestination)
{
BYTE stub[6] = { 0xe9, 0x00, 0x00, 0x00, 0x00, 0xc3 };
DWORD pProtection;
DWORD pSource = (DWORD)GetProcAddress(GetModuleHandle(moduleName), funcName);
LPVOID pTrampoline = VirtualAlloc(NULL, 6 + sizeof(stub), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
VirtualProtect((LPVOID)pSource, 6, PAGE_EXECUTE_READWRITE, &pProtection);
CopyMemory(stub + 1, &pDestination, 4);
CopyMemory((LPVOID)((DWORD_PTR)pTrampoline), &pSource, 6);
CopyMemory((LPVOID)((DWORD_PTR)pTrampoline + 6), stub, sizeof(stub));
CopyMemory(stub + 1, &pTrampoline, 4);
CopyMemory(&pSource, &stub, sizeof(stub));
VirtualProtect((LPVOID)pSource, 6, pProtection, NULL);
return TRUE;
}
BOOL recvHook = HookFunction(L"ws2_32.dll", "recv", &nRecv);
I've attached a debugger and spot an error:
Stack around the variable pSource was corrupted.
I couldn't really find a definitive reason for this happening, am I doing something wrong? Thanks!
This line here is copying 6 bytes of memory into a 4 byte variable
CopyMemory(&pSource, &stub, sizeof(stub));

CM_Get_Device_Interface_List returns CR_INVALID_POINTER

So, I have little problem with CM_Get_Device_Interface_List function. Function returns with error code 3, which is CR_INVALID_POINTER. But when I call CM_Get_Device_Interface_List_Size function, it returns success.
ULONG lenght = 0;
PWSTR DevicePath = NULL;
CONFIGRET cr = CR_SUCCESS;
cr = CM_Get_Device_Interface_List_Size(&lenght, (LPGUID)&HWN_DEVINTERFACE_NLED, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT);// success
if (cr != CR_SUCCESS)
{
// error handling
}
cr = CM_Get_Device_Interface_List((LPGUID)&HWN_DEVINTERFACE_NLED, NULL, DevicePath, lenght, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); // error
if (cr != CR_SUCCESS)
{
// error handling
}
DEFINE_GUID(HWN_DEVINTERFACE_NLED,
0x6b2a25e2, 0xaaf5, 0x482c, 0x99, 0xa5, 0x62, 0x05, 0xcd, 0xcc, 0x17, 0x6a); // GUID Declaration
So, why the pointer is invalid?
A bit late, probably figured this out but in case someone else comes across this I believe the reason you are getting the invalid pointer is because you are passing in a null pointer as the buffer (DevicePath), it must be allocated with the size returned from your first call.
Example (cleaned up a bit):
ULONG bufferSize = 0;
if (CM_Get_Device_Interface_List_Size(&bufferSize, (LPGUID)&HWN_DEVINTERFACE_NLED, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CR_SUCCESS)
{
PWSTR buffer = (PWSTR)malloc(bufferSize);
if (CM_Get_Device_Interface_List((LPGUID)&HWN_DEVINTERFACE_NLED, NULL, buffer, bufferSize, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CR_SUCCESS)
{
// buffer should now contain a list of NULL-terminated unicode strings
}
if (buffer)
{
free(buffer);
}
}
DEFINE_GUID(HWN_DEVINTERFACE_NLED,
0x6b2a25e2, 0xaaf5, 0x482c, 0x99, 0xa5, 0x62, 0x05, 0xcd, 0xcc, 0x17, 0x6a); // GUID Declaration
Alternate Example (no malloc):
#define BUFFER_SIZE 4096 // 4k buffer should be plenty
WCHAR buffer[BUFFER_SIZE];
if (CM_Get_Device_Interface_List((LPGUID)&HWN_DEVINTERFACE_NLED, NULL, buffer, BUFFER_SIZE, CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CR_SUCCESS)
{
// buffer should now contain a list of NULL-terminated unicode strings
}
DEFINE_GUID(HWN_DEVINTERFACE_NLED,
0x6b2a25e2, 0xaaf5, 0x482c, 0x99, 0xa5, 0x62, 0x05, 0xcd, 0xcc, 0x17, 0x6a); // GUID Declaration

Invalid Algorithm Specified CryptoAPI

I am trying to decrypt something using 128BIT AES Decryption. When i attempt to calling CryptDecrypt i get an Error stating "Invalid Algorithm Specified". I get the same problem when using the library posted here: http://www.codeproject.com/KB/security/WinAES.aspx
What can cause this error?
I am using CryptoAPI along on vista64bit with visual studio 2008. I checked in the registry and the AES library is there...
EDIT
BYTE*& encryptedData /* get data length */
HCRYPTPROV cryptoHandle = NULL;
HCRYPTKEY aesKeyHandle = NULL;
hr = InitWinCrypt(cryptoHandle);
if(FAILED(hr))
{
return hr;
}
AesKeyOffering aesKey = { {PLAINTEXTKEYBLOB, CUR_BLOB_VERSION, 0, CALG_AES_128}, 16, { 0xFF, 0x00, 0xFF, 0x1C, 0x1D, 0x1E, 0x03, 0x04, 0x05, 0x0F, 0x20, 0x21, 0xAD, 0xAF, 0xA4, 0x04 }};
if(CryptImportKey(cryptoHandle, (CONST BYTE*)&aesKey, sizeof(AesKeyOffering), NULL, 0, &aesKeyHandle) == FALSE)
{
// DO error
return HRESULT_FROM_WIN32(GetLastError());
}
if(CryptSetKeyParam(aesKeyHandle, KP_IV, { 0xFF, 0x00, 0xFF, 0x1C, 0x1D, 0x1E, 0x03, 0x04, 0x05, 0x0F, 0x20, 0x21, 0xAD, 0xAF, 0xA4, 0x04 } , 0) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
BYTE blah2 = CRYPT_MODE_CBC;
// set block mode
if(CryptSetKeyParam(aesKeyHandle, KP_MODE, &blah2, 0) == FALSE)
{
//
return HRESULT_FROM_WIN32(GetLastError());
}
DWORD lol = dataLength / 16 + 1;
DWORD lol2 = lol * 16;
if(CryptDecrypt(aesKeyHandle, 0, TRUE, 0, encryptedData, &lol2) == FALSE)
{
return HRESULT_FROM_WIN32(GetLastError());
}
InitWinCrypt function
if(!CryptAcquireContextW(&cryptoHandle, NULL, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, CRYPT_VERIFYCONTEXT))
{
if(!CryptAcquireContextW(&cryptoHandle, NULL, L"Microsoft Enhanced RSA and AES Cryptographic Provider", PROV_RSA_AES, 0))
{
return HRESULT_FROM_WIN32(GetLastError());
}
else
{
return S_OK;
}
}
return S_OK;
AesOffering struct:
struct AesKeyOffering
{
BLOBHEADER m_Header;
DWORD m_KeyLength;
BYTE Key[16];
};
EDIT2
After rebooting my computer, and remvoing the CBC chunk. I am now getting Bad Data Errors. The data decrypts fine in C#. But i need to do this using wincrypt.
Are you passing cryptoHandle by reference to InitWithCrypt? If not, your code
if(!CryptAcquireContextW(&cryptoHandle, ...
would only modify InitWinCrypt's copy of cryptoHandle.
EDIT: Given that it does, try getting rid of the CryptSetKeyParam call which sets CRYPT_MODE_CBC