Error 234, more data is available, with RegQueryInfoKey and RegEnumValue - c

I am trying to use RegQueryInfoKey to get the longest value and data´s size and then RegEnumValue to show all the values, but I am getting the 234 error value, which means "More data is available" when I run the app.
I am also using malloc to allocate lpValueName and lpData so I can use the sizes that RegQueryInfoKey gave me.
If i set lpcchValueName to 16383, for example, the app works just fine, but it no idea why it doesn't with the lpcMaxSubKeyLen value returned by RegQueryInfoKey.
The registry key has two string values:
What am I doing wrong? Apologize for all the noob errors you might see. Here is my code:
int wmain()
{
//RegOpenKeyEx
HKEY hKey = HKEY_CURRENT_USER;
LPCWSTR subKey = L"WinSide";
DWORD options = 0;
REGSAM samDesired = KEY_QUERY_VALUE;
HKEY hkOpenResult;
//Opening the HKEY_CURRENT_USER\WinSide subkey
LONG openKey = RegOpenKeyEx(hKey, subKey, options,
samDesired, &hkOpenResult);
if (openKey != ERROR_SUCCESS)
wprintf(L"Error code: %li\n", openKey);
else
{
wprintf(L"Key opened!\n");
//RegQueryInfoKey
LPWSTR pClass = NULL;
LPDWORD pcClass = NULL;
LPDWORD reserved = NULL;
DWORD numberOfSubKeys;
LPDWORD pcMaxSubKeyLen = NULL;
LPDWORD pcMaxClassLen = NULL;
DWORD numberOfValues;
DWORD longestValueName;
DWORD longestDataComponent;
LPDWORD securityDescriptor = NULL;
PFILETIME pLastWriteTime = NULL;
//Querying info from HKCU\WinSide subkey
LONG queryInfo = RegQueryInfoKey(hkOpenResult, pClass, pcClass, reserved, &numberOfSubKeys,
pcMaxSubKeyLen, pcMaxClassLen, &numberOfValues,
&longestValueName, &longestDataComponent,
securityDescriptor, pLastWriteTime);
if (queryInfo != ERROR_SUCCESS)
wprintf(L"Error code: %li\n", queryInfo);
else
{
wprintf(L"Key queried!\n");
wprintf(L"Number of values: %u\n", numberOfValues);
//RegEnumValue
DWORD index=0;
DWORD sizedem = sizeof(WCHAR);
LPWSTR nameOfValue = (LPWSTR)malloc(longestValueName * sizeof(WCHAR));
DWORD sizeOfBufffer = longestValueName;
DWORD typeOfDataStored;
LPBYTE pData = (LPBYTE)malloc(longestDataComponent * sizeof(BYTE));
DWORD sizeOfData = longestDataComponent;
if (nameOfValue != NULL && pData != NULL)
{
for (index = 0; index < numberOfValues; index++)
{
sizeOfBufffer = longestValueName;
//Enumerating values from HKCU\WinSide subkey
LONG enuValue = RegEnumValue(hkOpenResult, index, nameOfValue,
&sizeOfBufffer, NULL, &typeOfDataStored,
pData, &sizeOfData);
if (enuValue != ERROR_SUCCESS)
wprintf(L"Error code: %li\n", enuValue);
else
{
wprintf(L"Value: %s\n", (LPWSTR)pData);
}
}
}
else
{
wprintf(L"Memory could not be allocated.\n");
}
free(nameOfValue);
free(pData);
}
RegCloseKey(hkOpenResult);
}
return 0;
}
This is my result:
Thanks a lot!

your code containing many errors.
1)
LPWSTR nameOfValue = (LPWSTR)malloc(longestValueName * sizeof(WCHAR));
really longestValueName this is
The size does not include the terminating null character.
so you need
LPWSTR nameOfValue = (LPWSTR)malloc((longestValueName + 1) * sizeof(WCHAR));
or (better)
LPWSTR nameOfValue = (LPWSTR)malloc(++longestValueName * sizeof(WCHAR));
then in loop, if use first variant - sizeOfBufffer = longestValueName + 1;
or as in your code, if use ++longestValueName
2) DWORD sizeOfData = longestDataComponent;
you must do this in Loop, as and sizeOfBufffer = longestValueName; because sizeOfData will be changed after every RegEnumValue
3) and you must be ready, that until you enumerate key, somebody can change key data/values - so Maximum can increase - what you got in call RegQueryInfoKey is only reasonable hint but not 100% guarantee

Related

why doesn't the callback function change a value in a global struct?

I have this struct called String that contains a pointer to a char array and the length of that array, now when the callback function grabOutput is called it does copy the output into the ptr allocated buffer but the len is not change
#define BUF_SIZE 1024
typedef struct String
{
char * ptr;
int len;
} String;
HANDLE Child_IN_R = NULL;
HANDLE Child_IN_W = NULL;
HANDLE Child_OUT_R = NULL;
HANDLE Child_OUT_W = NULL;
HANDLE handle = NULL;
String str;
DWORD grabOutput(LPVOID lpParam )
{
BOOL success = FALSE;
DWORD dwRead, total =0;
char buffer[BUF_SIZE];
while(1)
{
success = ReadFile(Child_OUT_R, buffer, BUF_SIZE, &dwRead, NULL);
if (!success) break;
memcpy(str.ptr+total, buffer, dwRead);
total += dwRead;
str.ptr = realloc(str.ptr, total+BUF_SIZE);
}
str.len = total; // this does not change the value of str.len
return 0;
}
why doesn't this code change the value of str.len in the global String str?

WideCharToMultiByte fails randomly with error 122/ERROR_INSUFFICIENT_BUFFER

I have created a small application in C that encrypts and decrypts a string using the caesar cipher. After a string (unicode) has been decrypted, it gets converted to UTF8 using WideCharToMultiByte. It works around 90% of times, but sometimes the the WideCharToMultiByte seems to fail and the GetLastError function prints 122 which means ERROR_INSUFFICIENT_BUFFER.
My function for converting the unicode strings to UTF8 looks like this:
LPSTR convert(LPWSTR wideStringToDecryptAndConvertUTF) {
LPWSTR res = shift(wideStringToDecryptAndConvertUTF, -6); //Decrypting the string by shifting -6 letters.
MessageBoxW(NULL, res, L"Decrypted output", MB_OK); //Check if the string was successfully decrypted - judging by the output of the messagebox this is always the case, the decrypted string looks as expected.
LPSTR retVal = 0;
ULONG cb = 0, cch = (ULONG)strl(res);
cb = WideCharToMultiByte(CP_UTF8, 0, res, cch * sizeof(WCHAR), retVal, cb, 0, 0);
retVal = GlobalAlloc(GMEM_FIXED, cb);
WideCharToMultiByte(CP_UTF8, 0, res, cch * sizeof(WCHAR), retVal, cb, 0, 0);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { //Check for debugging purposes. At random times (even with the same string) this specific error occurs.
MessageBoxW(NULL, L"Error", L"Debug", MB_OK);
}
GlobalFree(res);
return retVal;
}
My shift function to decrypt/encrypt strings looks like this (in this case it gets decrypted):
LPWSTR shift(LPWSTR shift, int param) {
LPWSTR allc = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[]<>()[]";
LPWSTR encrypted = (LPWSTR)GlobalAlloc(GMEM_FIXED, strl(shift) * sizeof(WCHAR) + 1);
int r = 0;
if (encrypted != NULL) {
for (size_t i = 0; i < strl(shift); i++) {
r++;
if (strchr42a((LPWSTR)allc, shift[i]) != NULL) {
LPWSTR e = strchr42a((LPWSTR)allc, shift[i]);
int index = (int)(e - allc);
encrypted[i] = allc[index + param];
}
else {
encrypted[i] = shift[i];
}
}
}
if (encrypted != NULL) {
encrypted[r] = 0;
}
return encrypted;
}
Although this is quite simple, here's the strl function used in both functions above:
size_t strl(LPWSTR s) {
size_t i = 0;
while (s && *s != '\0') {
s++;
i++;
}
return i;
}
All strings I try to encrypt have been encrypted using the same program and only consist of letters.
I know that the encryption itself has limitations (for example you can't shift more than 8 letters when encrypting), but that's not my problem.
I don't understand why the WideCharToMultiByte function seems to work unstable in my case. Any suggestions are appreciated!
You are calling WideCharToMultiByte incorrectly. The 4th parameter is a character count, not a byte count. You are also not null-terminating the retVal buffer, and not doing any error handling at all.
Also, shift() is calculating the wrong byte size for its encrypted buffer. And worse, if the input shift string contains any character A..F, the found index being offset by -6 will go out of bounds of allc.
Try something more like this:
LPCWSTR strchr42a(LPCWSTR str, int ch)
{
do {
if (*str == ch) return str;
} while (*str++);
return NULL;
}
LPWSTR shift(LPCWSTR shift, int param) {
LPCWSTR allc = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz[]<>()[]";
ULONG shift_len = strl(shift);
LPWSTR encrypted = (LPWSTR) GlobalAlloc(GMEM_FIXED, (shift_len + 1) * sizeof(WCHAR));
if (!encrypted) return NULL;
int r = 0;
for (size_t i = 0; i < shift_len; ++i) {
++r;
LPCWSTR e = strchr42a(allc, shift[i]);
if (e != NULL) {
int index = (int)(e - allc) + param;
if (index < 0) {
// OUT OF BOUNDS! Need to wrap the index, or fail the function...
}
encrypted[i] = allc[index];
}
else {
encrypted[i] = shift[i];
}
}
encrypted[r] = 0;
return encrypted;
}
LPSTR convert(LPWSTR wideStringToDecryptAndConvertUTF) {
LPWSTR res = shift(wideStringToDecryptAndConvertUTF, -6); //Decrypting the string by shifting -6 letters.
if (!res) {
MessageBoxW(NULL, L"Error", L"Debug", MB_OK);
return NULL;
}
MessageBoxW(NULL, res, L"Decrypted output", MB_OK); //Check if the string was successfully decrypted - judging by the output of the messagebox this is always the case, the decrypted string looks as expected.
ULONG cch = (ULONG) strl(res);
ULONG cb = WideCharToMultiByte(CP_UTF8, 0, res, cch, retVal, 0, NULL, NULL);
if (cb == 0) {
DWORD errCode = GetLastError();
MessageBoxW(NULL, L"Error", L"Debug", MB_OK);
return NULL;
}
LPSTR retVal = GlobalAlloc(GMEM_FIXED, cb + 1);
if (!retVal) {
DWORD errCode = GetLastError();
MessageBoxW(NULL, L"Error", L"Debug", MB_OK);
return NULL;
}
WideCharToMultiByte(CP_UTF8, 0, res, cch, retVal, cb, NULL, NULL);
retVal[cb] = 0;
GlobalFree(res);
return retVal;
}

Crypt32 function CryptProtectData always returning "\x1"

Trying to use the Crypt32 functions CryptProtectData and CryptUnprotectData to encrypt and decrypt strings from a C program. The encrypt claims to be successful, but the pbData in the output DATA_BLOB always contains just "\x1". Below is what I am currently using for encryption. Any suggestions on what I may be doing wrong?
This is on Windows 7 using crypt32.dll v6.1.7601.
EXPORT short CALLBACK ASEncryptDPApiValue (char *pszEntropy, char *pszValue, char *pszEncryptValue, int iValueLen)
{
short sRetCd = 0;
char szDecryptValue [MAX_INI_VALUE] = "";
DWORD dwLastErrorRC = 0;
DWORD dwFlags = CRYPTPROTECT_LOCAL_MACHINE;
CHAR szMsgBuffer[200] = "";
DATA_BLOB encrBlob;
DATA_BLOB decrBlob = {0, 0};
DATA_BLOB entropyBlob = {0, 0};
LPWSTR pDescrOut = NULL;
if (pszValue[0] != '\0')
{
decrBlob.pbData = (BYTE *)pszValue;
decrBlob.cbData = strlen((char *)decrBlob.pbData)+1;
}
// else return an error
if (pszEntropy[0] != '\0')
{
entropyBlob.pbData = (BYTE *)pszEntropy;
entropyBlob.cbData = strlen((char *)entropyBlob.pbData)+1;
}
if (CryptProtectData(&decrBlob,
pDescrOut,
&entropyBlob,
NULL,
NULL,
dwFlags,
&encrBlob))
{
strcpy_s(pszEncryptValue, iValueLen, (char *) encrBlob.pbData);
dwLastErrorRC = GetLastError();
LocalFree(encrBlob.pbData);
sprintf(szMsgBuffer,
_T("ASEncryptDPApiValue - Decrypting value - successful = %d [%s]\r\n"), dwLastErrorRC, pszEncryptValue);
OutputDebugString(szMsgBuffer);
}
else
{
sRetCd = TRUE;
dwLastErrorRC = GetLastError();
sprintf(szMsgBuffer,
_T("ASEncryptDPApiValue - error decrypting value - last OS error = %d\r\n"), dwLastErrorRC);
OutputDebugString(szMsgBuffer);
LocalFree(encrBlob.pbData);
}
return sRetCd;
}

Error code 87 with RegEnumValue

I am trying to show a single value's name using RegEnumValue (I can use RegGetValue, but i'm trying to learn how to use the RegEnumValue function), but I'm getting the error code 87, "The parameter is incorrect".
Here's my code:
int wmain()
{
//RegOpenKeyEx
HKEY hKey = HKEY_CURRENT_USER;
LPCWSTR subKey = L"WinSide";
DWORD options = 0;
REGSAM samDesired = KEY_QUERY_VALUE;
HKEY pkOpenResult;
//RegEnumValue
DWORD index = 0;
WCHAR valueName[16383];
LPWSTR pValueName = valueName;
DWORD size=sizeof(valueName);
DWORD reserved = NULL;
DWORD type;
WCHAR data[255];
LPWSTR pData=data;
DWORD sizeData = sizeof(data);
LONG openKey = RegOpenKeyEx(hKey, subKey, options, samDesired, &pkOpenResult);
if (openKey != ERROR_SUCCESS)
{
wprintf(L"Error opening the key. Code: %li\n");
}
else
{
wprintf(L"Key opened!\n");
LONG enumValue = RegEnumValue(pkOpenResult, index, pValueName, &size,
&reserved, &type, pData, &sizeData);
if (enumValue != ERROR_SUCCESS)
wprintf(L"Error code: %li\n", enumValue);
else
{
wprintf(L"Going to show the value's name here!");
}
RegCloseKey(pkOpenResult);
}
return 0;
}
What am I doing wrong?
So sorry for any mistake.
lpReserved must be NULL as stated in the documentation. You pass a non-null value. That is the reason for the failure. Remove the reserved variable and simply pass NULL for lpReserved.
The lpcchValueName argument specifies characters rather than bytes. You pass the number of bytes in error. That mistake won't necessarily hurt you now but there is a buffer overrun error in the making there so you do need to fix it.

How to fix creating a buffer and Writing it directly to disk (WriteFile)

The code:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <Windows.h>
HANDLE creatFile(void);
long WriteBuffer(HANDLE);
char * GetBuffer(void);
void main(void)
{
HANDLE hFile;
printf("CreateFile: ");
hFile = creatFile();
if(hFile != NULL)
{
WriteBuffer(hFile);
FlushFileBuffers(hFile);
}
CloseHandle(hFile);
printf("\n\rDone");
getchar();
}
HANDLE creatFile(void)
{
HANDLE hFile;
LPCWSTR sFileName = L"\\\\.\\E:";
DWORD dwDesiredAccess = GENERIC_WRITE;
DWORD fShareMode = FILE_SHARE_WRITE | FILE_SHARE_WRITE;
DWORD fCreationDisposition = OPEN_EXISTING;
DWORD fFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
hFile = CreateFile(sFileName, dwDesiredAccess,fShareMode,
NULL, fCreationDisposition, fFlagsAndAttributes,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
printf("INVALID_HANDLE_VALUE: ");
switch (GetLastError())
{
case 5:
printf("\n\r Administrative Account required to run this program\n\r");
break;
case 87:
printf("\n\r Invalid Parameter in CreateFile Call \n\r");
break;
default:
printf("Error %d\n",GetLastError());
break;
}
return NULL;
}
else
{
printf("Attached -> %d\n\r",hFile);
return hFile;
}
}
long WriteBuffer(HANDLE hFile)
{
char *str = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ;
DWORD bytesWritten;
long totalBytesWritten = 0;
long idx = 0;
int len = strlen(str);
for(idx = 0; idx < 100000; idx ++)
{
if(WriteFile(hFile, str, 512 * sizeof(char), &bytesWritten, NULL))
{
totalBytesWritten += bytesWritten;
printf("Sectors Written : %d\r",idx+1);
}
else
{
int le = GetLastError();
printf("Last Error : %d\r",GetLastError());
break;
}
}
printf("\n\r");
printf("Bytes Written: %d\n\r", totalBytesWritten);
printf("Handle -> %d\n\r",hFile);
return totalBytesWritten;
}
char * GetBuffer(void)
{
int i = 0, idx = 0;
const char * cstr_init = "ERASED1 ";
char *buffer = (char*)malloc(512);
char word2[512];
for (idx = 0; idx < 512; idx+=8) {
for (i = 0; i < 8; i++) {
buffer[idx+i] = cstr_init[i];
if(strlen(buffer) == 512)
break;
}
}
return buffer;
}
The problems:
char * GetBuffer has extraneous data of 16 bytes in it. I modified WriteFile so that it only write 512 (instead of the 528) chars that the buffer actually holds.
After 16 sectors of writing - WriteFile fails with GetLastError = 5 (Access Denied)
The Questions:
How do I fix WriteFile so that it does NOT fail after 16 sectors and...
How do I fix GetBuffer so it actually produces a 512 buffer and not 528?
Notes
The application is ANSI C and the program is being run as admin.
I can't speak to the error with WriteFile(), however, you've got issues with your string operations.
C strings are null terminated, that is, the string literal "abc" is actually an array of characters like: {'a','b','c','\0'} All str...() operations rely on this fact. There is no information stored anywhere on the length of the string, only the fact that it is expected to end with a '\0'.
Your GetBuffer() function improved:
char * GetBuffer(void)
{
int i = 0, idx = 0;
const char * cstr_init = "ERASED1 ";
char *buffer = malloc(513); // Space for a '\0'
for (idx = 0; idx < 512; idx+=8) {
for (i = 0; i < 8; i++) {
buffer[idx+i] = cstr_init[i];
}
}
}
You were getting weird results for strlen() because it looks for a '\0' and was only finding one at 528 bytes, reading outside of the 512 bytes malloced is invoking undefined behavior, you could have found a '\0' at 513 bytes, or never found one.
Other comments, after calling GetBuffer() you never free() the char * returned, that is a memory leak since it was malloced and lost outside of that context. Also, a better implementation of GetBuffer() would be:
char * GetBuffer(void)
{
const char * cstr_init = "ERASED1 ";
const int cstr_init_len = strlen(cstr_init);
char * buffer = calloc(1,513); // Guaranteed zeroed
int i;
for (i = 0; i < 512; i+=8) {
memcpy(buffer+i, cstr_init, cstr_init_len);
// Or strcpy(buffer+1, cstr_init);
// Or strcat(buffer, cstr_init); // Inefficient because each call runs from buffer[0] to find a '\0' for where to start appending
}
return buffer;
}
the INT type could only be a 2 byte number from 0 - 65536 unsigned. replace all INT types with LONG (long) to start with...Not sure what compiler environment you are in though - as this change may not apply
I was unable to fix question 2 - the way I would have liked. However, by Telling WriteFile to write 512 bytes out of the buffer of 528 bytes - I got the desired results. As for Question 1.
Because The Disk drive has a Filesystem on it - Windows OS recognises that fact and prevents writing to the full drive. All I needed to do was in fact Lock the drive and that would give me exclusive access to the drive.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <Windows.h>
#include <winioctl.h>
HANDLE creatFile(void);
long WriteBuffer(HANDLE);
char * GetBuffer(void);
void main(void)
{
HANDLE hFile;
printf("CreateFile: ");
hFile = creatFile();
if(hFile != NULL)
{
WriteBuffer(hFile);
FlushFileBuffers(hFile);
}
CloseHandle(hFile);
printf("\n\rDone");
getchar();
}
HANDLE creatFile(void)
{
HANDLE hFile;
LPCWSTR sFileName = L"\\\\.\\E:";
DWORD dwDesiredAccess = GENERIC_WRITE;
DWORD fShareMode = FILE_SHARE_WRITE | FILE_SHARE_WRITE;
DWORD fCreationDisposition = OPEN_EXISTING;
DWORD fFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL;
BOOL bResult = FALSE; // results flag
LPDWORD lpBytesReturned = 0;
hFile = CreateFile(sFileName, dwDesiredAccess,fShareMode,
NULL, fCreationDisposition, fFlagsAndAttributes,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
hFile = NULL;
printf("INVALID_HANDLE_VALUE: ");
switch (GetLastError())
{
case 5:
printf("\n\r Administrative Account required to run this program\n\r");
break;
case 87:
printf("\n\r Invalid Parameter in CreateFile Call \n\r");
break;
default:
printf("Error %d\n",GetLastError());
break;
}
return NULL;
}
else
{
printf("Attached -> %d\n\r",hFile);
// HERE I JUST ADD THE FSCTL_LOCK_VOLUME command to stop Windows preventing me from writing to the drive
bResult = DeviceIoControl(hFile, // device to be queried
FSCTL_LOCK_VOLUME, // dwIoControlCode
NULL, 0, // no input buffer
NULL, 0, // output buffer
lpBytesReturned, // # bytes returned
(LPOVERLAPPED) NULL); // synchronous I/O
return hFile;
}
}
long WriteBuffer(HANDLE hFile)
{
char *str = GetBuffer(); // x 64 will give us 512 (sector sized buffer) ;
DWORD bytesWritten;
long totalBytesWritten = 0;
long idx = 0;
int len = strlen(str);
for(idx = 0; idx < 100000; idx ++)
{
if(WriteFile(hFile, str, 512 * sizeof(char), &bytesWritten, NULL))
{
totalBytesWritten += bytesWritten;
printf("Sectors Written : %d\r",idx+1);
}
else
{
int le = GetLastError();
printf("\n\rLast Error : %d\r",GetLastError());
break;
}
}
printf("\n\r");
printf("Bytes Written: %d\n\r", totalBytesWritten);
printf("Handle -> %d\n\r",hFile);
return totalBytesWritten;
}
char * GetBuffer(void)
{
const char * cstr_init = "ERASED2 ";
const int cstr_init_len = strlen(cstr_init);
char *buffer = (char*)malloc(513);
int i;
for (i = 0; i < 512; i+=8) {
memcpy(buffer+i, cstr_init, cstr_init_len);
// Or strcpy(buffer+1, cstr_init);
// Or strcat(buffer, cstr_init); // Inefficient because each call runs from buffer[0] to find a '\0' for where to start appending
}
return buffer;
}
So for future reference, if you wish to write directly to the drive it is important to LOCK the volume first. I know that there are memory leaks within the above code - but as a learning exercise for the Writing of data to a drive I am not bothered. The code will be tidied up and made into a .dll

Resources