parameters for LsaICryptUnprotectData - c++

I am trying to call LsaICryptUnprotectData but I get error code 87 unsupported parameter. Has anyone been able to successfully call this function? would like to see an example function call
Here is how I am calling,
typedef int (WINAPI *LPFUN_LSAICRYPTUNPROTECTDATA)
(
LPBYTE encCredData,
DWORD encCredDataSize,
DWORD reserved1,
DWORD reserved2,
DWORD reserved3,
DWORD reserved4,
DWORD dwFlags,
DWORD reserved5,
LPBYTE *decCredData,
LPDWORD decCredDataSize
);
LPFUN_LSAICRYPTUNPROTECTDATA pLsaICryptUnprotectData = (LPFUN_LSAICRYPTUNPROTECTDATA) GetProcAddress (hLsasrv, "LsaICryptUnprotectData");
if(!pLsaICryptUnprotectData)
{return GetLastError();}
HANDLE credfile = NULL;
LPBYTE buffer = NULL;
LPBYTE pDecrypted = NULL;
DWORD dwSize = 0;
DWORD cbsize=0;
credfile = CreateFile(filename,GENERIC_READ,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,NULL);
dwSize = GetFileSize(credfile,NULL);
buffer=(LPBYTE)malloc(dwSize);
SetFilePointer(credfile,0,0,FILE_BEGIN);
DWORD credFileSize=0;
ReadFile(credfile,buffer,dwSize,&credFileSize,NULL)
if(!pLsaICryptUnprotectData( buffer, dwSize, 0,0,0,0, 0, 0, &pDecrypted, &cbsize) != NULL))
{
// do error handling
}

The LsalCryptUnprotectData function is undocumented, but from this example, you might try with similar parameters:
cbSize = 0;
pLsaICryptUnprotectData ( buffer, dwSize, 0,0,0,0, 0x20000041, 0,
&pDecrypted, &cbSize);

Related

How to assign value to LPVOID buffer of ReadFile

I am developing a win32 API hook program.
Accordingly to my understanding, when a program calls ReadFile for a particular file, the content of that file is copied to lpBuffer(see the definition below),
ReadFile definition:
BOOL ReadFile(
HANDLE hFile,
LPVOID lpBuffer,
DWORD nNumberOfBytesToRead,
LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped
);
Now, my target is to alter this lpBuffer and fill it with provided content by me!
I am using EasyHook to hook ReadFile. I am not familiar with LPVOID type. I was able to alter the content for GetCurrentDirectory using the following code.
string b = "C:\\my\\altered\\directory";
DWORD returnLength = b.length();
int i;
for (i = 0; i<b.length(); i++)
{
lpBuffer[i] = b[i];
}
lpBuffer[i++] = '\0';
GetCurrentDirectory definition:
DWORD GetCurrentDirectory(
DWORD nBufferLength,
LPTSTR lpBuffer
);
How to do similar value assignment for ReadFile (LPVOID lpBuffer)?
Here's the LPVOID typedef:
#define far
typedef void far *LPVOID;
The far macro is defined as nothing, I guess it's because of some historical reasons (baggage).
So you can almost directly treat the LPVOID as void*.
And now, suppose you have a std::vector<uint8_t> named FakeData, just:
if (nNumberOfBytesToRead < FakeData.size()) {
SetLastError(ERROR_INSUFFICIENT_BUFFER);
return FALSE;
}
memcpy(lpBuffer, FakeData.data(), FakeData.size());
*lpNumberOfBytesRead = FakeData.size();
SetLastError(ERROR_SUCCESS);
return TRUE;

Anyone has experience on using GetAppContainerNamedObjectPath?

Recently I came across a Windows API called GetAppContainerNamedObjectPath. But I have no idea on how I can use it.
I found a msdn page for this api (https://learn.microsoft.com/en-us/windows/win32/api/securityappcontainer/nf-securityappcontainer-getappcontainernamedobjectpath). But it does not have a right example and remarks, parameters are written poorly.
I am getting ERROR_INVALID_PARAMETER(87) error at the end, which tells me something's wrong with the parameters that I put. Here's what I've tried.
#define TokenIsAppContainer 29
#define TokenAppContainerSid 31
#define TokenAppContainerNumber 32
typedef struct _TOKEN_APPCONTAINER_INFORMATION {
PSID TokenAppContainer;
} TOKEN_APPCONTAINER_INFORMATION, *PTOKEN_APPCONTAINER_INFORMATION;
void GetAppContainerProcessInfo(CString & procName)
{
DWORD dwSize = 0;
DWORD dwResult;
HANDLE hToken;
PTOKEN_APPCONTAINER_INFORMATION pAppCoInfo;
WCHAR wcsDebug[1024] = {0,};
WCHAR * pwSID = NULL;
typedef BOOL (WINAPI *_LPGETAPPCONTAINERNAMEOBJECTPATH)(HANDLE, PSID, ULONG, LPWSTR, PULONG);
static _LPGETAPPCONTAINERNAMEOBJECTPATH lpGetAppContainerNamedObjectPath = NULL;
if (0 == lpGetAppContainerNamedObjectPath)
{
HMODULE hKernel32 = LoadLibraryExW(L"kernel32.dll", NULL, 0);
if (hKernel32)
{
lpGetAppContainerNamedObjectPath = reinterpret_cast<_LPGETAPPCONTAINERNAMEOBJECTPATH>(GetProcAddress(hKernel32, "GetAppContainerNamedObjectPath"));
}
}
if (lpGetAppContainerNamedObjectPath)
{
DWORD processId = (DWORD)_ttoi((LPCTSTR)procName);
//HANDLE hProcess = GetProcessHandleByProcessName(procName);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
if(!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"OpenProcessToken Error(%u) PID(%d)\n", dwResult, processId );
AfxMessageBox(wcsDebug);
return;
}
if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) TokenAppContainerSid, NULL, dwSize, &dwSize))
{
dwResult = GetLastError();
if( dwResult != ERROR_INSUFFICIENT_BUFFER )
{
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetTokenInformation Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
return;
}
}
pAppCoInfo = (PTOKEN_APPCONTAINER_INFORMATION) GlobalAlloc( GPTR, dwSize );
if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) TokenAppContainerSid, pAppCoInfo, dwSize, &dwSize))
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetTokenInformation Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
return;
}
WCHAR wcsNamedObjectPath[MAX_PATH];
ULONG ulRetlen = 0;
BOOL bRet = lpGetAppContainerNamedObjectPath(hToken, pAppCoInfo->TokenAppContainer, _countof(wcsNamedObjectPath), wcsNamedObjectPath, &ulRetlen );
if (bRet)
{
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetAppContainerNamedObjectPath Path(%s)\n", wcsNamedObjectPath );
AfxMessageBox(wcsDebug);
}
else
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetAppContainerNamedObjectPath Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
}
if (pwSID)
LocalFree(pwSID);
CloseHandle(hToken)
CloseHandle(hProcess);
}
}
As a side-note, I have tried using wchar_t * and dynamically allocate the memory buffer by calling GetAppContainerNamedObjectPath twice. But still had no chance. Return length does not return a meaningful value.
if you call RtlGetLastNtStatus(); instead GetLastError(); after GetAppContainerNamedObjectPath you will got
STATUS_INVALID_PARAMETER_MIX - An invalid combination of parameters was specified.
this give you more info compare simply invalid parameter.
then look for function signature
BOOL
WINAPI
GetAppContainerNamedObjectPath(
_In_opt_ HANDLE Token,
_In_opt_ PSID AppContainerSid,
_In_ ULONG ObjectPathLength,
_Out_writes_opt_(ObjectPathLength) LPWSTR ObjectPath,
_Out_ PULONG ReturnLength
);
the Token and AppContainerSid declared with In_opt -- this mean that this parameters is optional, and you can pass 0 in place one of it. then ask your self - for what you query token for TokenAppContainerSid ? are system can not do this for you if you pass this token to api ? obvious can. so you not need do this yourself. really you need pass Token to api and in this case AppContainerSid must be 0. or you can pass AppContainerSid to api and in this case Token must be 0. when both AppContainerSid and Token not zero - you and got STATUS_INVALID_PARAMETER_MIX
also as side note - you not need open process with PROCESS_ALL_ACCESS if you need get it token. the PROCESS_QUERY_LIMITED_INFORMATION is enough
really api not do big magic. it return to you
AppContainerNamedObjects\<Sid>
path, where string form of app container sid.(some like S-1-15-2-...)

How to receive data send with DeviceIoControl at the Driver.c controlFunction? IOCTL,Driver

Let's say I have following code. Loading,unloading,driver entry etc works.
Driver.c
#define IO_INCREMENT_VALUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0001, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#define IO_RECEIVE_RANDOM_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0002, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
ULONG BytesIO = 0;
const IO_STACK_LOCATION stack = *IoGetCurrentIrpStackLocation(Irp);
const ULONG ControlCode = stack.Parameters.DeviceIoControl.IoControlCode;
if (ControlCode == IO_INCREMENT_VALUE)
{
//How to receive LPVOID lpInBuffer,
// DWORD nInBufferSize,
// LPVOID lpOutBuffer,
// DWORD nOutBufferSize,
//send from DeviceIoControl
}
else if (ControlCode == IO_RECEIVE_RANDOM_BUFFER)
{
//How to receive LPVOID lpInBuffer,
// DWORD nInBufferSize,
// LPVOID lpOutBuffer,
// DWORD nOutBufferSize,
// /send from DeviceIoControl
/*
DWORD nOutBufferSize = ;
for(DWORD i = 0; i< nOutBufferSize; ++i)
{
}
*/
}
// Complete the request
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesIO;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
and following UserMode.cpp
constexpr auto IO_INCREMENT_VALUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0001, METHOD_BUFFERED, FILE_SPECIAL_ACCESS);
constexpr auto IO_RECEIVE_RANDOM_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0002, METHOD_BUFFERED, FILE_SPECIAL_ACCESS);
int main()
{
//Find our Driver we want to Communicate with
//https://learn.microsoft.com/de-de/windows/win32/api/fileapi/nf-fileapi-createfilea
const LPCSTR lpFileName = R"(\\.\test)"; //Equals the Name we specified at DriverEntry
const DWORD dwDesiredAccess = GENERIC_ALL;
const DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
const LPSECURITY_ATTRIBUTES lpSecurityAttributes = nullptr;
const DWORD dwCreationDisposition = OPEN_EXISTING;
const DWORD dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
const HANDLE hTemplateFile = nullptr;
const HANDLE driver = CreateFile(
lpFileName,
dwDesiredAccess,
dwShareMode,
lpSecurityAttributes,
dwCreationDisposition,
dwFlagsAndAttributes,
hTemplateFile
);
if (driver == INVALID_HANDLE_VALUE)
{
return GetLastError();
}
//Example 1: Send an uint64_t and receive the value + 1.
uint64_t in_example1 = 1;
uint64_t out_example1 = 0;
LPDWORD lpBytesReturned = nullptr;
DeviceIoControl(driver, IO_INCREMENT_VALUE, &in_example1,
sizeof(in_example1), &out_example1, sizeof(out_example1), lpBytesReturned, nullptr);
std::cout << out_example1 << "\n"; //should return 2
//Example 2: Get a buffer with random values. Should be later the readMemory()
const UINT_PTR bytes_to_be_read = 357096;
//Any Buffer should be possible
char* data = new char[bytes_to_be_read];
uint64_t* data2 = new uint64_t[bytes_to_be_read];
DeviceIoControl(driver, IO_RECEIVE_RANDOM_BUFFER, nullptr,
0, data, bytes_to_be_read, lpBytesReturned, nullptr);
//should return data or data2 with some random values
}
"The DeviceIoControl function provides a device input and output control (IOCTL) interface through which an application can communicate directly with a device driver."
But How do i receive
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
send from DeviceIoControl inside the Driver.c I/O function?
For completness:
Links used:
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_irp
https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_io_stack_location
The IO_STACK_LOCATION just provides access to
Parameters.DeviceIoControl
Parameters.DeviceIoControl.OutputBufferLength
Parameters.DeviceIoControl.InputBufferLength
Parameters.DeviceIoControl.IoControlCode
Parameters.DeviceIoControl.Type3InputBuffer
By using Buffer I/O method, the I/O Manager allocates the input buffer to non-paged pool and stores a pointer to that memory inside Irp->AssociatedIrp.SystemBuffer, Only then IoContorl will start.
Later, when the request completes, the I/O Manager takes that SystemBuffer and copies the amount of bytes (according to Irp->IoStatus.Information) to the output buffer.
With that said, here's the solution:
#define IO_INCREMENT_VALUE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0001, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
#define IO_RECEIVE_RANDOM_BUFFER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x0002, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
NTSTATUS IoControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
NTSTATUS Status = STATUS_INVALID_PARAMETER;
ULONG BytesIO = 0;
const IO_STACK_LOCATION stack = *IoGetCurrentIrpStackLocation(Irp);
const ULONG ControlCode = stack.Parameters.DeviceIoControl.IoControlCode;
if (ControlCode == IO_INCREMENT_VALUE)
{
// Check input buffer size
ULONG bytes = stack.Parameters.DeviceIoControl.InputBufferLength;
if (bytes < sizeof(long long)) {
// Error - should complete the request
Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// Must return the same value as Irp.IoStatus.Status
return STATUS_INVALID_BUFFER_SIZE;
}
long long* input = (long long*)Irp->AssociatedIrp.SystemBuffer;
InterlockedAdd64(input, 1);
// Same SystemBuffer is used for input and output so we just need
// to complete the request with the appropriate bytes written.
Status = STATUS_SUCCESS;
BytesIO = sizeof(*input);
}
else if (ControlCode == IO_RECEIVE_RANDOM_BUFFER)
{
// Check input buffer size
ULONG bytes = stack.Parameters.DeviceIoControl.InputBufferLength;
if (bytes == 0) {
// Error - should complete the request
Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// Must return the same value as Irp.IoStatus.Status
return STATUS_INVALID_BUFFER_SIZE;
}
PVOID buffer = Irp->AssociatedIrp.SystemBuffer;
memset(buffer, 0, bytes);
Status = STATUS_SUCCESS;
BytesIO = bytes;
}
// Complete the request
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = BytesIO;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}

Getting Access Violation Error using GetFileVersionInfo

DWORD dwHandle;
DWORD dwSize = GetFileVersionInfoSizeEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() , &dwHandle );
if( dwSize == 0 )
break;
pVersionInfo = new BYTE[ dwSize ];
bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , &pVersionInfo );
if( bRetVal == false )
break;
UINT uLen;
VS_FIXEDFILEINFO *pFileInfo;
bRetVal = VerQueryValue( &pVersionInfo , L"\\" , (LPVOID *)&pFileInfo , &uLen );
if( bRetVal == false )
break;
DWORD dwFileVersionMS = pFileInfo->dwFileVersionMS;
DWORD dwFileVersionLS = pFileInfo->dwFileVersionLS;
DWORD dwLeftMost = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
DWORD dwRightMost = LOWORD(dwFileVersionLS);
strVersion.sprintf( L"%u.%u.%u.%u", dwLeftMost , dwSecondLeft , dwSecondRight , dwRightMost );
}while(0);
if( pVersionInfo )
delete []pVersionInfo;
return bRetVal;
While debugging this code i am getting access violation error at delete statement . . can anyone tell what i am doing wrong.
The error is that you pass a pointer to the pointer to the allocated data block as the first argument to VerQueryValue, which leads to you passing the wrong address to the function. This leads to undefined behavior as VerQueryValue reads data from, and writes data to, somewhere in memory where it should not be read from/written to.
The solution is to not use the address-of operator here.
Update: you do the same thing with the GetFileVersionInfoEx function call. Don't use the address-of operator for pVersionInfo.
The error is in the line
bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , &pVersionInfo );
The correct call should be
bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , pVersionInfo );
From msdn:
BOOL WINAPI GetFileVersionInfoEx(
_In_ DWORD dwFlags,
_In_ LPCTSTR lptstrFilename,
_Reserved_ DWORD dwHandle,
_In_ DWORD dwLen,
_Out_ LPVOID lpData
);
The function GetFileVersionInfoEx() will fill the buffer pointed to by lpData (or, in the corrected above example, pVersionInfo) with the version info. In your code, it would be changing the value of the pointer, making it point to somewhere else in memory.
When you call delete[], it is giving you the exception because the value of your pointer has changed and it is no longer the value set by the new [] operator. In other words you are trying to free memory that was not dynamically allocated.
Here is the solution yo your issue in another thread with a full code example, but as pointed out the issue is that you are passing the pointer to the buffer for the information the wrong way, no need for the address of opearator.
Here is a snipplet with your code fixed to be working:
#include <Windows.h>
#include <cstdio>
#pragma comment(lib, "version.lib")
void main(int argc, char** argv)
{
const wchar_t* strFilePath = L"C:\\Windows\\System32\\kernel32.dll";
DWORD dwHandle;
BOOL bRetVal;
DWORD dwSize = GetFileVersionInfoSizeEx( FILE_VER_GET_NEUTRAL , strFilePath , &dwHandle );
if( dwSize == 0 )
return;
BYTE* pVersionInfo = new BYTE[dwSize];
bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath , dwHandle , dwSize , pVersionInfo );
if( bRetVal == false )
return;
UINT uLen;
VS_FIXEDFILEINFO *pFileInfo = NULL;
bRetVal = VerQueryValue( pVersionInfo , L"\\" , (LPVOID *)&pFileInfo , &uLen );
if( bRetVal == false )
return;
DWORD dwFileVersionMS = pFileInfo->dwFileVersionMS;
DWORD dwFileVersionLS = pFileInfo->dwFileVersionLS;
DWORD dwLeftMost = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
DWORD dwRightMost = LOWORD(dwFileVersionLS);
char pVersion[1024];
sprintf(pVersion, "%u.%u.%u.%u", dwLeftMost , dwSecondLeft , dwSecondRight , dwRightMost );
if( pVersionInfo )
delete []pVersionInfo;
}

C++ Windows get registry value inconsistent returns

I am writing a simple C++ program to grab a Windows registry value on a 64 bit machine.
The problem is it only works for about 50% of the registry's and for the other half "ret" does not return ERROR_SUCCESS(0).
My question is to why I am getting these inconsistent returns and also when I attempt to make the path longer than two directories it also break.
ex.
keypath = TEXT("SOFTWARE\\Perl\\ASDF");
Here is my code.
LPCTSTR keypath = TEXT("SOFTWARE\\Perl");
HKEY key = NULL;
LONG ret = ERROR_SUCCESS;
DWORD BufferSize = TOTALBYTES;
DWORD cbData;
DWORD dwRet;
DWORD type;
char registry[256] = {'\0'};
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keypath, 0, KEY_QUERY_VALUE, &key);
PPERF_DATA_BLOCK PerfData = (PPERF_DATA_BLOCK) malloc( BufferSize );
cbData = BufferSize;
if (ret == ERROR_SUCCESS)
{
dwRet = RegQueryValueEx( key,
TEXT("BinDir"),
NULL,
&type,
(LPBYTE) PerfData,
&cbData );
RegCloseKey(key);
printf("\nFinal buffer size is %d\n", BufferSize);
int i = 0;
while ((*PerfData).Signature[i] != NULL)
{
registry[i] = (char)(*PerfData).Signature[i];
i++;
}
printf("registery: %s\n", registry);
}
editing in fixes.