Error code 87 with RegEnumValue - c

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.

Related

Can't set cbData in RegSetValue

I am trying to create a registry key with type REG_SZ and with a value longer than 4 chars.
But I can't figure out the right way to pass the data as argument :
#include <windows.h>
#include <stdio.h>
HKEY OpenKey(HKEY hRootKey, wchar_t* strKey)
{
HKEY hKey;
LONG nError = RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, &hKey);
if (nError == ERROR_FILE_NOT_FOUND)
{
printf("Debug: Creating registry key\n");
nError = RegCreateKeyEx(hRootKey, strKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
}
if (nError) {
printf("Error: Could not find or create\n");
}
return hKey;
}
void SetValSZ(HKEY hKey, LPCTSTR lpValue, LPCTSTR data)
{
LONG nError = RegSetValueEx(hKey, lpValue, 0, REG_SZ, (const BYTE*) data, sizeof(data));
if (nError)
printf("Error: Could not set registry value\n");
}
int main()
{
HKEY hKey = OpenKey(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Policies\\Microsoft\\FVE");
const wchar_t data[] = L"AAAABBBBCCCC";
SetValSZ(hKey, L"RecoveryKeyMessage", data);
RegCloseKey(hKey);
return 0;
}
When I run it, only the first 4 characters are saved.
I must have a type mistake...
Do you have any idea to help me to fix it ?
Thank you.
PS: I hope my english is clear enoth, feel free to ask me more if it isn't.
void SetValSZ(HKEY hKey, LPCTSTR lpValue, LPCTSTR data)
{
RegSetValueEx(hKey, lpValue, 0, REG_SZ, (const BYTE*) data, sizeof(data));
}
data is being passed as a pointer to a function, so its actual size will be lost. sizeof(data) is translated to the size of a pointer, which is 4 bytes in this case.
You have to either pass in the size as a parameter:
int len = sizeof(data);
SetValSZ(..., data, len);
Or better yet, use wcslen() to calculate the string length, then multiply that by sizeof(wchar_t).
Since you are using those T macros, the function can be written as:
RegSetValueEx(hKey,lpValue,0,REG_SZ,(const BYTE*)data,sizeof(TCHAR)*(lstrlen(data) + 1));
Edit: The size should also include the terminating null character

Copying Bytes from Memory to char array then writing the bytes to a registry key via Driver C

I am having an issue with my project where I am attempting to copy a structure from memory.
Copying the structure into a char array and writing the bytes in the char array to a registry key of type REG_BINARY
Here is the code so far, I am using RtlCopyMemory to achieve copying the bytes from memory:
VOID ReadVirtualMem(ULONG32 address, PVOID buffer, SIZE_T size)
{
PEPROCESS Process;
if (NT_SUCCESS(PsLookupProcessByProcessId((HANDLE)ProcessID, &Process)))
{
KAPC_STATE apc_state;
KeStackAttachProcess(Process, &apc_state);
if (MmIsAddressValid((PVOID)address) && MmIsAddressValid((PVOID)(address + size)))
{
RtlCopyMemory(buffer, (PVOID)address, size);
}
KeUnstackDetachProcess(&apc_state);
}
}
The above code will take in a vew parameters, address of the location I need reading from, buffer aka output the bytes need to be stored in, and the amount of bytes I want copied.
So here is how I am obtaining the bytes from memory:
struct PlayerInformation {
float Position;
int Points;
float Speed;
};
struct PlayerInformation PlayerInfo;
ReadVirtualMem(ReadAddress, &PlayerInfo, size);
I then cast this information to a PVOID data type so I can write this to the registry key like so:
PVOID Buffer;
memcpy(&Buffer, &PlayerInfo, sizeof(struct PlayerInfo));
status = WriteToKey(L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", L"Bytes", REG_BINARY, Buffer, size);
if (!NT_SUCCESS(status))
return STATUS_UNSUCCESSFUL;
The following above code works just fine for 8 bytes only. I believe this is due to PVOID only having a size of 8 bytes.
Here is my code for writing to the registry key:
NTSTATUS WriteToKey(PWSTR registry_path, PWSTR value_name, ULONG type, PVOID data, ULONG length)
{
UNICODE_STRING valname;
UNICODE_STRING keyname;
OBJECT_ATTRIBUTES attribs;
HANDLE handle;
NTSTATUS rc;
ULONG result;
RtlInitUnicodeString(&valname, registry_path);
RtlInitUnicodeString(&keyname, value_name);
InitializeObjectAttributes(&attribs, &valname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
rc = ZwCreateKey(&handle, KEY_ALL_ACCESS, &attribs, 0, NULL, REG_OPTION_VOLATILE, &result);
if (!NT_SUCCESS(rc))
return STATUS_UNSUCCESSFUL;
rc = ZwSetValueKey(handle, &keyname, 0, type, &data, length);
if (!NT_SUCCESS(rc))
STATUS_UNSUCCESSFUL;
return STATUS_SUCCESS;
}
My question is how would I be able to take the data copied from RtlCopyMemory into a structure, turn that structure into a char array and write this data to the registry key path.
In c++ its as easy as this:
unsigned char b[sizeof(PlayerInfo)];
std::cout << "Size of structure: " << sizeof(PlayerInfo) << "\n\n";
memcpy(b, &PlayerInfo, sizeof(PlayerInfo));
HKEY handle;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_WRITE, &handle) == ERROR_SUCCESS)
{
RegSetValueEx(handle, L"Bytes", 0, REG_BINARY, (BYTE*)&b, sizeof(b));
But C has no data type for BYTE* so I am just a bit confused on how I could go on about taking this C++ function, which works perfectly, and implementing it into C code to work the exact same way as the C++ function.
If you need any other details I will be more than gladly to give you the information.
Thanks in advance!
EDIT: So I edited my function to accept the PlayerInfo struct as an argument and now all the data is read correctly.
Here is the updated code:
NTSTATUS WriteToBytes(PWSTR registry_path, PWSTR value_name, ULONG type, struct PlayerInfo data, ULONG length)
{
UNICODE_STRING valname;
UNICODE_STRING keyname;
OBJECT_ATTRIBUTES attribs;
HANDLE handle;
NTSTATUS rc;
ULONG result;
RtlInitUnicodeString(&valname, registry_path);
RtlInitUnicodeString(&keyname, value_name);
InitializeObjectAttributes(&attribs, &valname, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
rc = ZwCreateKey(&handle, KEY_ALL_ACCESS, &attribs, 0, NULL, REG_OPTION_VOLATILE, &result);
if (!NT_SUCCESS(rc))
return STATUS_UNSUCCESSFUL;
rc = ZwSetValueKey(handle, &keyname, 0, type, &data, length);
if (!NT_SUCCESS(rc))
STATUS_UNSUCCESSFUL;
return STATUS_SUCCESS;
}
This works well, no errors from what I can see. does anyone know why this works? And not passing a void* to the original write key function?

Error 234 "More data is available" with GetComputerNameEx

I am getting More data is available error with the GetComputerNameEx function, but no idea how to fix it.
This is my code:
int wmain()
{
COMPUTER_NAME_FORMAT nameType = ComputerNameDnsFullyQualified;
WCHAR computerName[MAX_COMPUTERNAME_LENGTH + 1];
DWORD size = ARRAYSIZE(computerName);
BOOL pcName = GetComputerNameEx(nameType, computerName, &size);
DWORD error = GetLastError();
if (pcName != 0)
{
wprintf("Computer name: %s\n", computerName);
}
else
{
wprintf(L"Error getting the name. Code: %li\n", error);
}
return 0;
}
No idea how to set size variable as output so I can declare the computerName array correctly.
You have to call the function twice; once with a null pointer to get the required size, and again with a buffer of (at least) the specified size. As the docs say:
To ensure that this buffer is large enough, set this parameter to NULL
and use the required buffer size returned in the lpnSize parameter.
This is a common pattern for Win32 functions. And yes, it does lead to a possible race condition, but that's just how it works.
Example
DWORD dwSize = 0;
if (GetComputerNameEx(nameType, nullptr, &dwSize))
{
WCHAR* computerName;
computerName = (WCHAR*)malloc(dwSize * sizeof(WCHAR));
if (GetComputerNameEx(nameType, computerName, &dwSize))
{
// use the name
}
free(computerName); // don't forget to free
}
Per the GetComputerNameEx() documentation:
lpBuffer [out]
A pointer to a buffer that receives the computer name or the cluster virtual server name.
The length of the name may be greater than MAX_COMPUTERNAME_LENGTH characters because DNS allows longer names. To ensure that this buffer is large enough, set this parameter to NULL and use the required buffer size returned in the lpnSize parameter.
lpnSize [in, out]
On input, specifies the size of the buffer, in TCHARs. On output, receives the number of TCHARs copied to the destination buffer, not including the terminating null character.
If the buffer is too small, the function fails and GetLastError returns ERROR_MORE_DATA. This parameter receives the size of the buffer required, including the terminating null character.
If lpBuffer is NULL, this parameter must be zero.
For example:
int wmain()
{
COMPUTER_NAME_FORMAT nameType = ComputerNameDnsFullyQualified;
WCHAR *computerName = NULL, *computerNameNew;
DWORD size = 0;
BOOL pcName;
DWORD error;
do
{
pcName = GetComputerNameExW(nameType, computerName, &size);
if (pcName) break;
error = GetLastError();
if (error != ERROR_MORE_DATA) break;
computerNameNew = (WCHAR*) realloc(computerName, sizeof(WCHAR) * size);
if (!computerNameNew) {
error = ERROR_OUTOFMEMORY;
break;
}
computerName = computerNameNew;
}
while (1);
if (pcName)
{
wprintf("Computer name: %s\n", computerName);
}
else
{
wprintf(L"Error getting the name. Code: %ul\n", error);
}
free(computerName);
return 0;
}
That error means that the GetComputerNameEx function needs a larger buffer to store the returned string.
To avoid the race condition cited in Jonathan Potter's answer, you could do something like this:
LONG error = ERROR_MORE_DATA;
WCHAR* buffer = NULL;
DWORD bufferLength = /* Some initial reasonable length for the string buffer */;
while (error == ERROR_MORE_DATA) {
// Create a buffer with bufferLength size (measured in WCHARs)
buffer = realloc(buffer, bufferLength * sizeof(WCHAR));
if (GetComputerNameEx(nameType, buffer, &bufferLength)) {
error = ERROR_SUCCESS;
} else {
error = GetLastError();
}
}
if (error != ERROR_SUCCESS) {
// Some error occurred
...
}
// Use buffer containing computer name
// Don't forget to free(buffer)

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

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

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