Win 32 Writefile: Access Viloation and Error 1784 - c++

Two problems with the below code. To begin, I have been scouring this and various other forums for answers to my 1784 error code and everything I've tried has failed. Two of the threads I've checked on stackoverflow are WriteFile returning error 1784 and BlockWrite I/O Error 1784. I've checked some others on this forum but I'm not remembering exactly what the are right now.
I'm trying to save an array of structs to an empty binary file. The first problem is that I get an access violation if my size variable (nNumberOfBytesToWrite parameter) is anything less about 99000 bytes. That number jumps around. For awhile when I was testing it would have the access violation if it was 99,999 bytes but not 100,000 bytes. Of course, what I eventually want to do is set the size to the size of the entire array. The original code to handle that is now commented out so I can test with various sizes.
The second thing that happens (if I don't get an access violation) is I get error code 1784 and WriteFile fails every time. As other threads on this topic have stated, this is defined on MSDN as ERROR_INVALID_USER_BUFFER and the description is "The supplied user buffer is not valid for the requested operation." I've looked at MSDN's own example for opening files like this (http://msdn.microsoft.com/en-us/library/windows/desktop/bb540534%28v=vs.85%29.aspx) and have tried some variations based on their code, but nothing seems to work.
This problem is probably massively noob and I'm sure I'm overlooking something ridiculously simple, but if anyone has suggestions they'd be greatly appreciated.
case IDM_SAVE1:
{
HANDLE hFile = CreateFile("MineSave.mss", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
int test_buffer[] = {1,2,3,4,5,6,7,8,9,10};
if(hFile != INVALID_HANDLE_VALUE)
{
BOOL bSuccess;
DWORD size = 100000; //DWORD size = (((sizeof(tile)) * tiles_total));
LPDWORD bytes_written = 0;
bSuccess = WriteFile(hFile, test_buffer, size, bytes_written, NULL);
if(bSuccess)
{
MessageBox(hwnd, "File saved successfully.", "Great Job!", MB_OK);
}
else
{
DWORD error = GetLastError();
MessageBox(hwnd, "Could not write to file.", "Error", MB_OK);
}
CloseHandle(hFile);
}
else
{
MessageBox(hwnd, "Could not create file.", "Error", MB_OK);
}
}
break;

Your buffer is the size of 10 ints, which is 40 bytes on Windows. You are trying to write 100,000 bytes from that buffer. That is undefined behaviour, a buffer overrun. Hence the access violation.
You must not pass a value greater than sizeof(test_buffer), i.e. 40, to the nNumberOfBytesToWrite parameter of WriteFile.
You'll need to write this file in a loop, writing 40 bytes at a time, until you have written as much as you need. Perhaps something like this:
BOOL bSuccess = TRUE;
DWORD bytesRemaining = 100000;
while (bSuccess && bytesRemaining>0)
{
DWORD bytesToWrite = std::min(sizeof(test_buffer), bytesRemaining);
DWORD bytesWritten;
bSuccess = WriteFile(hFile, test_buffer, bytesToWrite, &bytesWritten, NULL);
bytesRemaining -= bytesToWrite;
}
if (!bSuccess)
{
//handle error;
}
Writing 40 bytes at a time is pretty slow. You'll find it more efficient to write a few KB with each call to WriteFile.
Note that you aren't allowed to pass NULL to the lpNumberOfBytesWritten parameter if you also pass NULL to lpOverlapped, as you do here. From the documentation:
lpNumberOfBytesWritten [out, optional]
......
This parameter can be NULL only when the lpOverlapped parameter is not NULL.

You must provide a buffer to receive the number of bytes written, either the lpNumberOfBytesWritten parameter must be non-NULL, or the lpOverlapped parameter must be non-NULL.
You are passing NULL for both, which is illegal and causes the access violation.

Related

C++ Download File WinInet - 0kb written to file

Can someone tell me what is wrong with my code?
I am trying to download a file from the internet using WinInet. The function connects to the target site just fine, I don't understand why this code isn't working. Can anyone help me out?
Here is my code:
HANDLE hFile = CreateFileW(FilePath, GENERIC_WRITE, NULL, NULL, CREATE_ALWAYS, NULL, NULL);
if (hFile != INVALID_HANDLE_VALUE || GetLastError() == ERROR_ALREADY_EXISTS)
{
CHAR Buffer[2048];
DWORD BytesRead=0, BytesToRead=0;
DWORD BytesWritten=0, BytesToWrite=0;
SetFilePointer(hFile, 0, 0, FILE_BEGIN);
do
{
if (BytesRead)
{
WriteFile(hFile, Buffer, BytesWritten, &BytesToWrite, FALSE);
}
}
while
(InternetReadFile(hRequest, (LPVOID)Buffer, BytesToRead, &BytesRead) != FALSE);
}
CloseHandle(hFile);
}
hRequest is passed to the function, it is the HINTERNET handle from HttpOpenRequestA.
Your code has some logic problems.
you are misusing GetLastError() when calling CreateFileW(). Regardless of whether the file already exists or not, CreateFileW() will not return INVALID_HANDLE if it successfully creates/opens the file. That is all you need to check for (call GetLastError() only if CreateFileW() fails and you want to find out why). also, there is no need to call SetFilePointer() at all, as CREATE_ALWAYS ensures the opened file is empty, truncating the file if it already exists and has data in it.
your do..while loop should be a while loop instead, so that InternetReadFile() is called first. There is no point in skipping WriteFile() on the first loop iteration. If you use a do..while loop, InternetReadFile() should not be used as the loop condition.
more importantly, you are breaking the loop only if InternetReadFile() fails with an error. You are expecting it to fail when it reaches the end of the response, but it actually returns TRUE and sets BytesRead to 0. This is documented behavior, which you are not handling at all:
InternetReadFile function
InternetReadFile operates much like the base ReadFile function, with a few exceptions. Typically, InternetReadFile retrieves data from an HINTERNET handle as a sequential stream of bytes. The amount of data to be read for each call to InternetReadFile is specified by the dwNumberOfBytesToRead parameter and the data is returned in the lpBuffer parameter. A normal read retrieves the specified dwNumberOfBytesToRead for each call to InternetReadFile until the end of the file is reached. To ensure all data is retrieved, an application must continue to call the InternetReadFile function until the function returns TRUE and the lpdwNumberOfBytesRead parameter equals zero. This is especially important if the requested data is written to the cache, because otherwise the cache will not be properly updated and the file downloaded will not be committed to the cache. Note that caching happens automatically unless the original request to open the data stream set the INTERNET_FLAG_NO_CACHE_WRITE flag.
ReadFile function
When a synchronous read operation reaches the end of a file, ReadFile returns TRUE and sets *lpNumberOfBytesRead to zero.
when calling WriteFile(), you are passing BytesWritten to the nNumberOfBytesToWrite parameter, but BytesWritten is never set to anything other than 0, so nothing gets written to the file. You need to pass BytesRead instead.
With that said, use something more like this:
HANDLE hFile = CreateFileW(FilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
// handle error as needed...
}
else
{
BYTE Buffer[2048];
DWORD BytesRead, BytesWritten;
do
{
if (!InternetReadFile(hRequest, Buffer, sizeof(Buffer), &BytesRead))
{
// handle error as needed...
break;
}
if (!BytesRead)
break;
if (!WriteFile(hFile, Buffer, BytesRead, &BytesWritten, FALSE))
{
// handle error as needed...
break;
}
}
while (true);
CloseHandle(hFile);
}
MSDN even has a full example of how to use InternetReadFile():
HOWTO: Using InternetReadFile To Get File
BOOL GetFile (HINTERNET IN hOpen, // Handle from InternetOpen()
CHAR *szUrl, // Full URL
CHAR *szFileName) // Local file name
{
DWORD dwSize;
CHAR szHead[] = "Accept: */*\r\n\r\n";
VOID * szTemp[25];
HINTERNET hConnect;
FILE * pFile;
if ( !(hConnect = InternetOpenUrl ( hOpen, szUrl, szHead,
lstrlen (szHead), INTERNET_FLAG_DONT_CACHE, 0)))
{
cerr << "Error !" << endl;
return 0;
}
if ( !(pFile = fopen (szFileName, "wb" ) ) )
{
cerr << "Error !" << endl;
return FALSE;
}
do
{
// Keep coping in 25 bytes chunks, while file has any data left.
// Note: bigger buffer will greatly improve performance.
if (!InternetReadFile (hConnect, szTemp, 50, &dwSize) )
{
fclose (pFile);
cerr << "Error !" << endl;
return FALSE;
}
if (!dwSize)
break; // Condition of dwSize=0 indicate EOF. Stop.
else
fwrite(szTemp, sizeof (char), dwSize , pFile);
} // do
while (TRUE);
fflush (pFile);
fclose (pFile);
return TRUE;
}

Stack Corruption With SetupDiXxx structures

I am having some trouble with the structures used to obtain device information. From what I understand it is somewhat tricky to set the cbSize correctly, and thus the API is writing data beyond where it is supposed to (causing the stack corruption). So far I have the following code:
GUID guid;
HidD_GetHidGuid(&guid);
HDEVINFO info;
info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
SP_DEVINFO_DATA DeviceInfoData;
memset(&DeviceInfoData, 0, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
int deviceIndex = 0;
while (SetupDiEnumDeviceInfo(info, deviceIndex++, &DeviceInfoData))
{
SP_INTERFACE_DEVICE_DATA data;
data.cbSize = sizeof(SP_INTERFACE_DEVICE_DATA);
int interfaceIndex = 0;
while (SetupDiEnumDeviceInterfaces(info, &DeviceInfoData, &guid, interfaceIndex++, &data))
{
//https://msdn.microsoft.com/en-us/library/windows/hardware/ff551120%28v=vs.85%29.aspx
//Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with a NULLDeviceInterfaceDetailData pointer,
//a DeviceInterfaceDetailDataSize of zero, and a valid RequiredSize variable. In response to such a call, this function
//returns the required buffer size at RequiredSize and fails with GetLastError returning ERROR_INSUFFICIENT_BUFFER.
SP_DEVICE_INTERFACE_DETAIL_DATA interfaceData;
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
DWORD bufferSize = 0;
SetupDiGetDeviceInterfaceDetail(info, &data, NULL, 0, &bufferSize, nullptr);
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
//Call the function again
SetupDiGetDeviceInterfaceDetail(info, &data, &interfaceData, bufferSize, NULL, &DeviceInfoData);
DWORD error = GetLastError();
if (error != ERROR_SUCCESS)
{
printf("Could not obtain device interface details. Error: %d \n", error);
}
}
}
The error which I get is:
Run-Time Check Failure #2 - Stack around the variable 'DeviceInfoData' was corrupted.
though I have seen SP_INTERFACE_DEVICE_DATA and SP_DEVICE_INTERFACE_DETAIL_DATA cause the same error
Any help is greatly appreciated!
It looks like your interfaceData buffer is too small.
Check the documentation for the DeviceInterfaceDetailData argument to SetupDiGetDeviceInterfaceDetail again.
If you want to get more info about driver development, I recommend the book USB Complete. I fixed the issue based on their explanation. The issue is as follows:
First, get the buffer size:
SetupDiGetDeviceInterfaceDetail(info, &data, NULL, 0, &bufferSize, nullptr);
Then, allocate the PSP_DEVICE_INTERFACE_DETAIL_DATA structure manually using malloc based on the size that was returned:
PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceData;
interfaceData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
notice the P in front of PSP_DEVICE_INTERFACE_DETAIL_DATA. This is Microsofts semantics for this API. It stands for pointer; something really easy to miss when looking at the documentation (if you also miss the ->)
The SetupDiGetDeviceInterfaceDetail function returns the size of the entire structure, so you need to allocate it to that size. I've seen examples that attempt to increment size until the error goes away. That approach is wrong... for alot of reasons. Obtain the size from SetupDiGetDeviceInterfaceDetail and then allocate the entire PSP_DEVICE_INTERFACE_DETAIL_DATA memory block based on that size. Don't forget to set cbSize to the size of the struct SP_DEVICE_INTERFACE_DETAIL_DATA
Once again, pay attention to the P in the naming conventions because it's easy to get the sizeof(PSP_DEVICE_INTERFACE_DETAIL_DATA) by mistake.

C++ WriteFile only writing 4 bytes

Here's what I'm trying to achieve; I'm hooking onto the HttpSendRequest function (on Xbox it's XHttp) and trying dump the certificate that's in pcszHeaders which has the size of 0x1F0E.
Now the problem; it only seems to write 4 bytes, I've even tried allocating extra memory and setting each bit to 0 to see if it's the size of Headers and it continues to only write 4 bytes. I've been able to dump pcszHeaders remotely because I got the address whilst debugging but I need to dump it at run-time.
Something I notice whilst debugging - The address of pcszHeaders only shows in locals until it reaches;
printf("XHttpSendRequest: %s\n", "Creating Certificate.bin...");
Once it reaches the printf() above the address changes to 0x00000000 (bad ptr) but it still writes the first byte of correct data of pcszHeaders correctly but nothing more.
Here is the entire hook;
BOOL XHTTP_SEND_REQUEST_HOOK(
HINTERNET hRequest,
const CHAR *pcszHeaders,
DWORD dwHeadersLength,
const VOID *lpOptional,
DWORD dwOptionalLength,
DWORD dwTotalLength,
DWORD_PTR dwContext)
{
if(pcszHeaders != XHTTP_NO_ADDITIONAL_HEADERS)
{
printf("XHttpSendRequest: %s\n", "Creating Certificate.bin...");
// Setup expansion
doMountPath("Hdd:", "\\Device\\Harddisk0\\Partition1");
//create our file
HANDLE fileHandle = CreateFile("Hdd:\\Certificate.bin", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
//does file exist?
if(GetLastError()!=ERROR_ALREADY_EXISTS
||fileHandle!=INVALID_HANDLE_VALUE)
{
printf("XHttpSendRequest: %s\n", "Writing to file...");
DWORD wfbr;
//write to our file
if(WriteFile(fileHandle, pcszHeaders, 0x2000, &wfbr, NULL))
{
printf("XHttpSendRequest: %s\n", "File written!");
printf("%s\n", "Request has ended.");
CloseHandle(fileHandle);
return XHttpSendRequest(hRequest, pcszHeaders, dwHeadersLength, lpOptional, dwOptionalLength, dwTotalLength, dwContext);
}
}
}
}
EDIT: I've changed the code slightly and I've copied pcszHeaders data into another section of memory that I've created and my pointers seems to have all the correct data and I've tried Writing it to file and it still only writes 4 bytes. I've even used sizeof() instead of hard-coded 0x2000.
pcszHeaders is a char* pointer. sizeof(pcszHeaders) is 4 in a 32bit app (8 in a 64bit app). You need to use the dwHeadersLength parameter instead, which tells you how many characters are in pcszHeaders.
Also, your GetLastError() check after CreateFile() is wrong. If CreateFile() fails for any reason other than ERROR_ALREADY_EXISTS, you are entering the code block and thus writing data to an invalid file handle. When using CREATE_NEW, CreateFile() returns INVALID_HANDLE_VALUE if the file already exists. You don't need to check GetLastError() for that, checking for INVALID_HANDLE_VALUE by itself is enough. If you want to overwrite the existing file, use CREATE_ALWAYS instead.
You are also leaking the file handle if WriteFile() fails.
And you are calling the original HttpSendRequest() only if you successfully write headers to your file. If there are no headers, or the create/write fails, you are not allowing the request to proceed. Is that what you really want?
Try this instead:
BOOL XHTTP_SEND_REQUEST_HOOK(
HINTERNET hRequest,
const CHAR *pcszHeaders,
DWORD dwHeadersLength,
const VOID *lpOptional,
DWORD dwOptionalLength,
DWORD dwTotalLength,
DWORD_PTR dwContext)
{
if (pcszHeaders != XHTTP_NO_ADDITIONAL_HEADERS)
{
printf("XHttpSendRequest: Creating Certificate.bin...\n");
// Setup expansion
doMountPath("Hdd:", "\\Device\\Harddisk0\\Partition1");
//create our file
HANDLE fileHandle = CreateFile("Hdd:\\Certificate.bin", GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
//is file open?
if (fileHandle != INVALID_HANDLE_VALUE)
{
printf("XHttpSendRequest: Writing to file...\n");
DWORD wfbr;
//write to our file
if (WriteFile(fileHandle, pcszHeaders, dwHeadersLength, &wfbr, NULL))
printf("XHttpSendRequest: File written!\n");
else
printf("XHttpSendRequest: Error writing to file: %u\n", GetLastError());
CloseHandle(fileHandle);
}
else
printf("XHttpSendRequest: Error creating file: %u\n", GetLastError());
}
printf("Request has ended.\n");
return XHttpSendRequest(hRequest, pcszHeaders, dwHeadersLength, lpOptional, dwOptionalLength, dwTotalLength, dwContext);
}
Finally the problem has been solved!
First I created an empty array for the data to be stored.
CHAR xtoken[0x2000];
memset(xtoken, 0, 0x2000);
The first part of the hook is to store the header data.
DWORD bufferLength = dwHeadersLength;
memcpy(xtoken, pcszHeaders, bufferLength);
I then write the data to file
WriteFile(fileHandle, (void*)&xtoken, bufferLength, &wfbr, NULL))
Success! I guess the problem was that parameter 2 of WriteFile() was incorrect.

Creating a file with the same name as registry

I want to create a text file with the same name as a registry.
Say, I get the variable valueName, and I want it's value to be the name of a .txt file in C:\ How can I do that?
Almost final code:
void EnumerateValues(HKEY hKey, DWORD numValues)
{
for (DWORD dwIndex = 0; dwIndex < numValues; dwIndex++)
{BOOL bErrorFlag = FALSE;
char valueName[64];
DWORD valNameLen = sizeof(valueName);
DWORD dataType;
DWORD dataSize = 0;
DWORD retval = RegEnumValue(hKey, dwIndex, valueName, &valNameLen,
NULL, &dataType, NULL, &dataSize);
if (retval == ERROR_SUCCESS)
{//pregatesc calea
char* val = new char[strlen(valueName)];
sprintf(val, "C:\\%s.txt", valueName);
printf("S-a creat fisierul: %s\n", val);
//creez/suprascriu fisierul
HANDLE hFile;
hFile=CreateFile(val,GENERIC_WRITE | GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_ALWAYS , FILE_ATTRIBUTE_NORMAL,NULL);
if (hFile == INVALID_HANDLE_VALUE)
{ printf("Eroare la creat fisierul %s!\n",val);
}
//sciru in fisier
char str[] = "Example text testing WriteFile";
DWORD bytesWritten=0;
DWORD dwBytesToWrite = (DWORD)strlen(str);
bErrorFlag=WriteFile(hFile, str, dwBytesToWrite, &bytesWritten, NULL);
if (FALSE == bErrorFlag)
{
printf("Eroare la scriere in fisier\n");
}
//inchid fisierul
CloseHandle(hFile);
}
//eroare regenumv
else printf("\nError RegEnumValue");
}
}
The fundamental problem is that you seem to want to convert a registry key, HKEY into a path. And there's no API to do that. You will need to keep track of the path and pass it to the function in the question, along with the HKEY.
You are passing uninitialized values to RegEnumValue, specifically dataSize. Since you don't care about the data, don't ask for it. Pass NULL for the data pointer, and zero for data size.
Your call to new is not allocating enough memory. You need space for the directory name, the file extension, and the null-terminator.
These problems are exacerbated by your complete neglect for error checking. That might sound harsh, but frankly you need some shock treatment. In order to be able to fail gracefully you need to check for errors. More pressing for you, in order to be able to debug code, you need to check for errors.
You've tagged the code C++ but write as if it were C. If you really are using C++ then you can use standard containers, std::string, avoid raw memory allocation and the result leaks. Yes, you code leaks as it stands.
first of all your program is more C like than C++, but if you want to solve this in C++ you can use stringstream in the following way:
std::stringstream stream;
stream << "C:\\";
stream << valueName;
stream << ".txt";
std::string filename(stream.str());
HANDLE hFile=CreateFile(filename.c_str() ,GENERIC_READ,FILE_SHARE_READ,
NULL, CREATE_NEW , FILE_ATTRIBUTE_NORMAL,NULL);
Also you need a include:
#include <sstream>

Async call to ReadFile function returns 6 error code

I wrote the c++ code below in order to read a file asynchronously:
#define BUF_SIZE 1024
HANDLE hFile;
DWORD NumberOfBytesRead = 0;
BYTE *buf = (BYTE*)malloc(BUF_SIZE*sizeof(BYTE));
OVERLAPPED overlapped;
overlapped.Offset = overlapped.OffsetHigh = 0;
hFile = CreateFile("C:\\Users\\Desktop\\FOO.cpp",
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
printf("invalid hfile\n");
int i;
i= ReadFile(hFile,
&buf,
BUF_SIZE,
&NumberOfBytesRead,
&overlapped);
if(!i && GetLastError() != ERROR_IO_PENDING)
printf ("ReadFile failed with error %d.\n", GetLastError());
else
{
WaitForSingleObject(&(overlapped.hEvent), 0);
printf("here it is %d",NumberOfBytesRead );
}
CloseHandle(hFile);
But the return value from ReadFile is 0, and the last error equals to 6.
Does anyone have any idea why? and what does 6 error code say?
Thanks!.
Maybe your problem is with OVERLAPPED structure, which you don't initialize properly.
See: "Any unused members of this structure should always be initialized to zero before the structure is used in a function call. Otherwise, the function may fail and return ERROR_INVALID_PARAMETER." in remarks here: here. You can use memset to clear all of it.
Error code 6 means invalid handle.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx
Which seems odd since you check for invalid handle value. Not sure if this helped you but I might try opening the file synchronously first.