WriteFile throws Access Violation when 4th (optional) parameter is NULL - c++

Thought that it may be helpful to someone because it was a kind of surprise for me.
WriteFile function tries to write into its 4th (optional) parameter, and if it is NULL it causes Access Violation exception... But not on Windows 8(.1).
This is the function definition from msdn:
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten, // Optional
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
lpNumberOfBytesWritten [out, optional]
...
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
I created short example that reproduces the error. The code is Win32 console application created in Visual Studio 2008 SP1:
int _tmain(int argc, _TCHAR* argv[])
{
HANDLE hFile = CreateFile(L"N:\\Test\\Test.tmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
if (INVALID_HANDLE_VALUE == hFile) {
return -1;
}
unsigned int testValue = 32;
//-----------------------------------------------
// Next line generates AV exception on Windows 7,
// On Windows 8 it works fine:
//-----------------------------------------------
WriteFile(hFile, &testValue, sizeof(unsigned int), NULL, NULL);
CloseHandle(hFile);
return 0;
}
And, finally, if I change the call to WriteFile() by the following two lines, this solves the problem and works on all platforms:
// Now it does not generate AV:
DWORD written = 0;
WriteFile(hFile, &testValue, sizeof(unsigned int), &written, NULL);
The code generates Access Violation on Windows 7 and on Windows XP SP3 (did not test it on Vista). On Windows 8(.1) it works, even when I pass NULL in 4th parameter (lpNumberOfBytesWritten).
The actual problem was that I developed a module that writes into a temporary file, but I ignored the 4th parameter (I read "optional" but misread the rest and thought that it may be ignored). I developed and tested it on Windows 8.1, so the code worked fine, but the client machine was on Windows 7 and code failed.
The lessons I learned: I should be more attentive (to details) and don't be smug (and test carefully).

The documentation for lpNumberOfBytesWritten says:
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
In other words, the lpNumberOfBytesWritten parameter is only optional when you are using overlapped IO. You are passing NULL for lpOverlapped, and therefore not using overlapped IO, the lpNumberOfBytesWritten is not optional and cannot be NULL.

Related

C++ how to find last (offset - adress) used in processmemory with use readprocessmemory

i use this code to readprocessmemory :
BOOL WINAPI ReadProcessMemory(
_In_ HANDLE hProcess,
_In_ LPCVOID lpBaseAddress,
_Out_ LPVOID lpBuffer,
_In_ SIZE_T nSize,
_Out_ SIZE_T *lpNumberOfBytesRead
);
char value[5];
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, 6500);
{
ReadProcessMemory(hProcess, (LPVOID)105477, value, 5, 0);
}
its work 100%
but i want to know how know last Offset used in processmemory - before i read it
see the picture : enter image description here
the last offset in this processmemory is 7FFE0FFF - but how can i get it before i read the processmemory
Well it MAY work if you are absolutely sure that you CAN read the memory of the other process... anyway it is a quite dangerous method, there are much better IPC APIs to do these things!
Unless you are writing a debugger yourself... in fact ReadProcessMemory is cited here "Process Functions for Debugging" https://msdn.microsoft.com/it-it/library/windows/desktop/ms680549(v=vs.85).aspx

How to copy a file but touch the timestamp on the new copy?

I am using ::CopyFile() to make a copy of a file. It appears the original file's timestamp is being preserved and I would like the copy to set the current timestamp on the copy, i.e. 'touching' it.
Is there a WinAPI way to do this easily?
If you read the MSDN documentation for CopyFile(), there are comments at the bottom that say the following:
File times semantics
This article should document semantics with respect to file creation/modification/access times.
Creation time: if the target file already exists, its' creation time is preserved, otherwise it is set to the current system time.
Last Modification time: always copied from modification time of the source file.
Last Access time: always set to the current system time.
and
Mod-time not always preserved
The modification time is not guaranteed to be set. CopyFileEx does try to set the modification time, but it does NO error checking on it. This means if setting modification time fails internally in CopyFileEx (e.g. with access denied), latter will still returns successful!
So if modification time is important for your scenario (it is for my synchronization program), you have to explicitly call SetFileTime() and check it's return value to be sure.
You should use SetFileTime() to update the copied file's timestamp(s) yourself to make sure they are set to what you want them to be set to. There is an example on MSDN:
Changing a File Time to the Current Time
#include <windows.h>
// SetFileToCurrentTime - sets last write time to current system time
// Return value - TRUE if successful, FALSE otherwise
// hFile - must be a valid file handle
BOOL SetFileToCurrentTime(HANDLE hFile)
{
FILETIME ft;
SYSTEMTIME st;
BOOL f;
GetSystemTime(&st); // Gets the current system time
SystemTimeToFileTime(&st, &ft); // Converts the current system time to file time format
f = SetFileTime(hFile, // Sets last-write time of the file
(LPFILETIME) NULL, // to the converted current system time
(LPFILETIME) NULL,
&ft);
return f;
}
::CopyFile is actually part of windows:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363851%28v=vs.85%29.aspx
It is a convenience function that does copy metadata. There is another way, though less convenient, to copy files using windows. Check out these functions:
ReadFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx
CreateFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858%28v=vs.85%29.aspx
WriteFile:
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365747%28v=vs.85%29.aspx
HANDLE WINAPI CreateFile(
_In_ LPCTSTR lpFileName,
_In_ DWORD dwDesiredAccess,
_In_ DWORD dwShareMode,
_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
_In_ DWORD dwCreationDisposition,
_In_ DWORD dwFlagsAndAttributes,
_In_opt_ HANDLE hTemplateFile
);
BOOL WINAPI ReadFile(
_In_ HANDLE hFile,
_Out_ LPVOID lpBuffer,
_In_ DWORD nNumberOfBytesToRead,
_Out_opt_ LPDWORD lpNumberOfBytesRead,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
BOOL WINAPI WriteFile(
_In_ HANDLE hFile,
_In_ LPCVOID lpBuffer,
_In_ DWORD nNumberOfBytesToWrite,
_Out_opt_ LPDWORD lpNumberOfBytesWritten,
_Inout_opt_ LPOVERLAPPED lpOverlapped
);
So you would open the file with something like this:
CreateFile(<File>, GENERIC_READ, FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)
Check for a invalid return handle,
Create the new file with something like this:
CreateFile(<File>, GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL)
Check for a invalid return handle,
read the file into a buffer:
ReadFile(handle for file 1, buffer, Buffer size, Destination file,OUT for Bytes Read, NULL)
Then write out the Buffer:
WriteFile(outfile handle,buffer,number of bytes,NULL)
Close your handles.
Make sure to read CreateFiles details, it can be used to open files too.

Visual C++ RegGetValue() fails in program where it shouldn't

I'm making a C++ program using Visual C++ 2008 Express that gets the paths to specific apps from the registry, display a list of those that are installed, allows the user to pick one to configure, then launch the selected app.
This program is supposed to retrieve the paths to (currently) three apps by using RegGetValue (from windows.h).
While it works with Apps n°1 and 3, it fails with app n°2.
The part of the source that handles the registry is available on Pastebin: http://pastebin.com/9X2hjGqh.
I get error n°234 (ERROR_MORE_DATA) when I add a cout to get the function's return.
RegGetValue syntax:
LONG WINAPI RegGetValue(
_In_ HKEY hkey,
_In_opt_ LPCTSTR lpSubKey,
_In_opt_ LPCTSTR lpValue,
_In_opt_ DWORD dwFlags,
_Out_opt_ LPDWORD pdwType,
_Out_opt_ PVOID pvData,
_Inout_opt_ LPDWORD pcbData
);
Full reference here: http://msdn.microsoft.com/en-us/library/ms724875(v=VS.85).aspx
One thing that stands out are all the calls where you do this:
RegGetValue(hKey, NULL, "PATH", RRF_RT_ANY, NULL, (PVOID)&ValueBuffer, &BufferSize);
Notice the last parameter is &BufferSize. This is an [in, out] parameter. You set it to the size of your buffer before going in and it changes the value to the number of characters read into the buffer on the way out. This is what the docs say about RegGetValue (and other similar Reg) functions:
pcbData [in, out, optional]
A pointer to a variable that specifies the size of the buffer pointed to by the pvData parameter, in bytes. When the function returns, this variable contains the size of the data copied to pvData.
So when you call RegGetValue it started at 8192 (BUFFER) but after the first call it was overwritten by the the number of characters read.
Before each RegGetValue call where you pass a &BufferSize you should do this:
BufferSize = BUFFER
As well I notice you have:
#define BUFFER 8192
char ValueBuffer[255];
DWORD BufferSize = BUFFER;
Shouldn't you be setting ValueBuffer to be at least ValueBuffer[BUFFER] instead of ValueBuffer[255]?
As well your code as it is only supports an 8192 byte buffer. If the Value key from the registry is longer than that then it would return ERROR_MORE_DATA. I assume that your code is not anticipating anything beyond 8192. You can determine the size up front for a Value key by using RegQueryInfoKey and dynamically allocating enough space ahead of time.
ERROR_MORE_DATA means that one of the buffers you passed to RegGetValue is not large enough to store the data you asked RegGetValue to give you. You need to loop and reallocate the buffers supplied here when you get this exit code.
For example:
LONG result = ERROR_MORE_DATA;
DWORD dataLength = /* some reasonable default size */ 255;
unique_ptr<char[]> buffer;
while (result == ERROR_MORE_DATA)
{
buffer.reset(new char[dataLength]);
result = RegGetValueW(
hKey,
L"Subkey",
L"Value",
0,
nullptr,
buffer.get(),
&dataLength
);
}
if (result != ERROR_SUCCESS)
{
// Handle the error
}

WriteFile function C++

Im trying to use the WriteFile function. Ive been working off this example
http://msdn.microsoft.com/en-us/library/ms900134.aspx
Here the buffer that is passed to WriteFile is filled from ReadFile. But I dont want to do it that way. I just want to write a string like "Example text testing WriteFile" or something. But im not sure what values the parameters should have. Ive tried looking around on google but couldnt find anything. Anyone know how i do this?
From MSDN:
BOOL WINAPI WriteFile(
__in HANDLE hFile,
__in LPCVOID lpBuffer,
__in DWORD nNumberOfBytesToWrite,
__out_opt LPDWORD lpNumberOfBytesWritten,
__inout_opt LPOVERLAPPED lpOverlapped
);
The first argument is the handle to the file.
The second argument is a pointer to the data you want to write. In your case it's the string.
The third argument is the length of the data you want to write. In your case it will be something like strlen(str).
The fourth argument is a pointer to a DWORD variable that will receive the number of bytes actually written.
The fifth and last parameter can be NULL for now.
You use it like this:
char str[] = "Example text testing WriteFile";
DWORD bytesWritten;
WriteFile(fileHandle, str, strlen(str), &bytesWritten, NULL);
If WriteFile returns FALSE then there was an error. Use the GetLastError function to find out the error code.
A simple example of writing a string:
(hOutFile here is an open file handle from a call to CreateFile):
{
DWORD dwBytesWritten = 0;
char Str[] = "Example text testing WriteFile";
WriteFile( hOutFile, Str, strlen(Str), &dwBytesWritten, NULL );
}
EDIT: Check the MSDN function definition for what each parameter does.

Create a new windows registry key using c++

I'm trying to create a new registry key in the windows registry using C++. Here is the code I have so far:
HKEY hKey;
LPCTSTR sk = TEXT("SOFTWARE\\OtherTestSoftware");
LONG openRes = RegCreateKeyEx(
HKEY_LOCAL_MACHINE,
sk,
0,
NULL,
REG_OPTION_BACKUP_RESTORE,
KEY_ALL_ACCESS,
NULL,
&hKey,
NULL);
if (openRes==ERROR_SUCCESS) {
printf("Success creating key.");
} else {
printf("Error creating key.");
}
LPCTSTR value = TEXT("OtherTestSoftwareKey");
LPCTSTR data = "OtherTestData\0";
LONG setRes = RegSetValueEx (hKey, value, 0, REG_SZ, (LPBYTE)data, strlen(data)+1);
if (setRes == ERROR_SUCCESS) {
printf("Success writing to Registry.");
} else {
printf("Error writing to Registry.");
}
//RegDeleteKey(hKey, sk);
LONG closeOut = RegCloseKey(hKey);
if (closeOut == ERROR_SUCCESS) {
printf("Success closing key.");
} else {
printf("Error closing key.");
}
I'm able to successfully open an existing key using a very similar code snippet (basically replace RegCreateKeyEx with RegOpenKeyEx). I would imagine that one or more of the arguments I'm passing into RegCreateKeyEx is causing the trouble. I'm honestly not sure where things might be getting fouled up since all of the error codes i've trapped show success. For reference, here is the function signature for RegCreateKeyEx:
/*
* LONG WINAPI RegCreateKeyEx(
__in HKEY hKey,
__in LPCTSTR lpSubKey,
__reserved DWORD Reserved,
__in_opt LPTSTR lpClass,
__in DWORD dwOptions,
__in REGSAM samDesired,
__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes,
__out PHKEY phkResult,
__out_opt LPDWORD lpdwDisposition
);
*/
Any thoughts would be great!
thanks,
brian
I've been compiling my own personal Function Library for years. One part of this deals entirely with registry access, see the CreateRegistryKey function the Registry.Cpp file.
If you are interested, you can grab the entire library here.
As already mentioned, you've specified the REG_OPTION_BACKUP_RESTORE option in the call to RegCreateKeyEx, which means that you're opening the key in order to perform a backup or restore. Ordinarily, you would use REG_OPTION_NON_VOLATILE instead.
What operating system are you running? In Windows 2000/XP, the HKEY_LOCAL_MACHINE registry hive is not writeable by non-administrator users, so RegCreateKeyEx will fail with an access denied error (error 5). This also applies to Vista, if your application has a requestedExecutionLevel entry in its manifest. If you're running Vista, and your application doesn't specify a requestedExecutionLevel (or if it doesn't have a manifest at all), access to HKEY_LOCAL_MACHINE will be virtualised, so RegCreateKeyEx should succeed. See Registry Virtualization in Windows Vista in MSDN for more details.
There are some more problems with the code you've posted, which will only become apparent if you compile your project with UNICODE defined. This line:
LPCTSTR data = "OtherTestData\0";
should be
LPCTSTR data = TEXT("OtherTestData\0");
and this line:
LONG setRes = RegSetValueEx(hKey, value, 0, REG_SZ,
(LPBYTE)data, _tcslen(data)+1);
should be:
LONG setRes = RegSetValueEx(hKey, value, 0, REG_SZ,
(LPBYTE)data, (_tcslen(data)+1) * sizeof(TCHAR));
because the cbData parameter in RegSetValueEx is the length of the data in bytes, not characters.
I hope this helps!
The first clue is your use of REG_OPTION_BACKUP_RESTORE. You probably don't want to use that flag, as I believe it requires a special "backup" privilege that you need to enable beforehand. Normal applications won't want to do that.
Probably this is the reason why you can cannot create a new key, with your code.
These links might be of help.
http://www.codeguru.com/forum/archive/index.php/t-378884.html
http://www.codeguru.com/forum/archive/index.php/t-275250.html
As a sidenote, always try GetLastError() to get the error message.
I have not tested either of them.