Access Violation Writing Location

Category: visual studio vclanguage

Question

Gopichand_Thangavel on Thu, 22 Aug 2019 13:09:57


Hi,

I am writing a code to identify and display the dll from the registry.

And my code is..

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include<string>
#include<iostream>
#include<vector>
#include<winerror.h>
#include <filesystem>
namespace fs = std::experimental::filesystem;
//using namespace default;
#define BUFFER 8192
#define BUFSIZE 4096
fs::path dir("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application");
fs::path full_path;
#define MAX_KEY_LENGTH 255
#define MAX_VALUE_NAME 16383
char path[255];
void QueryKey(HKEY hKey)
{
TCHAR    achKey[MAX_KEY_LENGTH];   // buffer for subkey name
DWORD    cbName;                   // size of name string 
TCHAR    achClass[MAX_PATH] = TEXT("");  // buffer for class name 
DWORD    cchClassName = MAX_PATH;  // size of class string 
DWORD    cSubKeys = 0;               // number of subkeys 
DWORD    cbMaxSubKey;              // longest subkey size 
DWORD    cchMaxClass;              // longest class string 
DWORD    cValues;              // number of values for key 
DWORD    cchMaxValue;          // longest value name 
DWORD    cbMaxValueData;       // longest value data 
DWORD    cbSecurityDescriptor; // size of security descriptor 
FILETIME ftLastWriteTime;      // last write time 

DWORD i, retCode;
//LONG lResult;
//TCHAR value[255];
DWORD BufferSize = BUFFER;

TCHAR  achValue[MAX_VALUE_NAME];
DWORD cchValue = MAX_VALUE_NAME;
//char value[225];


// Get the class name and the value count. 
retCode = RegQueryInfoKey(
hKey,                    // key handle 
achClass,                // buffer for class name 
&cchClassName,           // size of class string 
NULL,                    // reserved 
&cSubKeys,               // number of subkeys 
&cbMaxSubKey,            // longest subkey size 
&cchMaxClass,            // longest class string 
&cValues,                // number of values for this key 
&cchMaxValue,            // longest value name 
&cbMaxValueData,         // longest value data 
&cbSecurityDescriptor,   // security descriptor 
&ftLastWriteTime);       // last write time 

// Enumerate the subkeys, until RegEnumKeyEx fails.

if (cSubKeys)
{
printf("\nNumber of subkeys: %d\n", cSubKeys);

for (i = 0; i < cSubKeys; i++)
{
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKey, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime);
if (retCode == ERROR_SUCCESS)
{
//_tprintf(TEXT("(%d)\t\t %s\n"), i + 1, achKey);
for (i = 0; i < cSubKeys; i++)
{
cbName = MAX_KEY_LENGTH;
retCode = RegEnumKeyEx(hKey, i, achKey, &cbName, NULL, NULL, NULL, &ftLastWriteTime);

if (retCode == ERROR_SUCCESS)
{
_tprintf(TEXT("\n\n\n\n(%d) %s\n"), i + 1, achKey);

//concatenating the path

fs::path file(achKey);
full_path = dir / file;
std::cout << full_path << std::endl;

HKEY hTestKey1;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, full_path.c_str(),
0, KEY_READ, &hTestKey1) == ERROR_SUCCESS)
{
QueryKey(hTestKey1);

}
RegCloseKey(hTestKey1);
}
}
}
}
}
else
{
printf("Number of subkeys:%d\n", cSubKeys);
printf("Number of Values:%d   %d\n", cValues,cbMaxValueData);
for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++)
{
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL);
fs::path file1(achValue);
file1 = full_path / file1;
char value[255];
//std::cout << full_path << std::endl;
std::cout << file1 << std::endl;
if (retCode == ERROR_SUCCESS)
{
_tprintf(TEXT("(%d) %s\t"), i + 1, achValue);

if (RegGetValue(HKEY_LOCAL_MACHINE,full_path.c_str(), achValue,RRF_RT_REG_EXPAND_SZ,(LPDWORD)REG_EXPAND_SZ , &value, &BufferSize))
{
_tprintf(TEXT("%s\n"),value);
}
//TCHAR szEnvPath[MAX_PATH];
//RegQueryValueEx(HKEY_LOCAL_MACHINE, file1.c_str(), NULL,(LPDWORD)RRF_RT_ANY,(LPBYTE) value, &BufferSize);
/*if (RegQueryValueEx(HKEY_LOCAL_MACHINE, file1.c_str(), NULL, (LPDWORD)RRF_RT_ANY, (LPBYTE)value, &BufferSize)==ERROR_SUCCESS)
{
// ExpandEnvironmentStrings((LPCWSTR)value, szEnvPath, MAX_PATH);
_tprintf(TEXT("%s\n"),value);
}*/
}
}

}
// Enumerate the key values. 
/*if (cValues)
{
printf("\nNumber of values: %d\n", cValues);

for (i = 0, retCode = ERROR_SUCCESS; i < cValues; i++)
{
cchValue = MAX_VALUE_NAME;
achValue[0] = '\0';
retCode = RegEnumValue(hKey, i, achValue, &cchValue, NULL, NULL, NULL, NULL);
fs::path file1(achValue);
full_path = dir / file1;
char value[255];
std::cout << full_path << std::endl;
if (retCode == ERROR_SUCCESS)
{
_tprintf(TEXT("(%d) %s\n"), i + 1, achValue);

if (RegGetValue(HKEY_LOCAL_MACHINE, full_path.c_str(), NULL, RRF_RT_ANY, NULL, &value, &BufferSize))
{
//_tprintf(TEXT("%\n"), value);
//printf("HI");

}
}
}
}*/
}


void __cdecl _tmain(void)
{
HKEY hTestKey;
//HKEY key;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, dir.c_str(),
0, KEY_READ, &hTestKey) == ERROR_SUCCESS)
{
QueryKey(hTestKey);
}
RegCloseKey(hTestKey);
}

During compilation I get a error message stating that "Unhandled exception at 0x74DAA05F (KernelBase.dll) in trail.exe: 0xC0000005: Access violation writing location 0x00000002." Can anyone please resolve it.

Replies

Guido Franzke on Thu, 22 Aug 2019 13:58:29


During compilation I get a error message stating that "Unhandled exception at 0x74DAA05F (KernelBase.dll) in trail.exe: 0xC0000005: Access violation writing location 0x00000002." Can anyone please resolve it.

Hello,

you say "during compilation"? So it should not be a problem in your code, and I don't see where the compiler should through an exception.

Nevertheless, I was able to compile your code. So my compiler is ok.

Which compiler/VS do you use, on which system?

Have you tried to reinstall your VS?

Regards, Guido

RLWA32 on Thu, 22 Aug 2019 14:07:33


During compilation I get a error message stating that "Unhandled exception at 0x74DAA05F (KernelBase.dll) in trail.exe: 0xC0000005: Access violation writing location 0x00000002." Can anyone please resolve it.

Hello,

you say "during compilation"? So it should not be a problem in your code, and I don't see where the compiler should through an exception.

Nevertheless, I was able to compile your code. So my compiler is ok.

Which compiler/VS do you use, on which system?

Have you tried to reinstall your VS?

Regards, Guido

Just from a quick look it appears that the OP has misspoken.  The access violation occurs in trail.exe.  So it seems to me the problem is in the executing program, not the compilation process.

Guido Franzke on Thu, 22 Aug 2019 14:14:13


During compilation I get a error message stating that "Unhandled exception at 0x74DAA05F (KernelBase.dll) in trail.exe: 0xC0000005: Access violation writing location 0x00000002." Can anyone please resolve it.

Just from a quick look it appears that the OP has misspoken.  The access violation occurs in trail.exe.  So it seems to me the problem is in the executing program, not the compilation process.

Hello OP,

if you only have misspoken: Where in your code does the exception come? Check the call stack. This could be a NULL-pointer problem, etc.

Regards, Guido

Gopichand_Thangavel on Thu, 22 Aug 2019 14:25:36


I'm using VS 2017 community. I'm getting this exception when i try to debug the Code. Should I try it by reinstalling the vs again?

RLWA32 on Thu, 22 Aug 2019 19:46:18


I'm using VS 2017 community. I'm getting this exception when i try to debug the Code. Should I try it by reinstalling the vs again?

No.

What you should do is step through your code line by line in the debugger.  That should enable you to verify that variables contains correct and expected values, parameters passed to Windows API functions are valid and errors are properly handled.  If you do this you should be able to identify the coding errors that are causing the access violation.

Darran Rowe on Thu, 22 Aug 2019 21:28:21


Visual Studio 2019 pulls up at least one problem with your code. Interestingly, as a spoiler, your real problem is hidden due to you misusing a cast.

char value[255];
//std::cout << full_path << std::endl;
std::cout << file1 << std::endl;
if (retCode == ERROR_SUCCESS)
{
	_tprintf(TEXT("(%d) %s\t"), i + 1, achValue);

	if (RegGetValue(HKEY_LOCAL_MACHINE, full_path.c_str(), achValue, RRF_RT_REG_EXPAND_SZ, (LPDWORD)REG_EXPAND_SZ, &value, &BufferSize))
	{
		_tprintf(TEXT("%s\n"), value);
	}
}

The value variable is type char but since you are using the generic macros, RegGetValue and _tprintf will redirect to RegGetValueW and wprintf when the Unicode character set is used. You need to define this as a TCHAR array to get this to work properly. What's worse, the array is 255 bytes, but BufferSize is originally set to 8192 so value is nowhere near large enough to retrieve the largest amount of data that RegGetValue could return. You also never reset BufferSize back to its original value.

But the clue to figuring this out is the address that it is trying to write to, 0x2. If you substitute the macros for the values in the RegGetValue, there is only one which has this value, REG_EXPAND_SZ and it is the only one which has a cast next to it.

If you look at the documentation for RegGetValue, pdwType is documented as:

"A pointer to a variable that receives a code indicating the type of data stored in the specified value."

Emphasis mine. The receive means that this parameter isn't meant to be used to tell RegGetValue to filter so that it will only get certain types of value, no this is used for RegGetValue to indicate what type the value is. pdwType expects a pointer to a DWORD that tells you what the type of the value is.

Again this is one of those cases where a cast was used to silence the compiler without fully understanding what was being done. As is always the case with casts, especially reinterpret casts, you really need to stop and ask yourself if this is really what you want to do since you are saying to the compiler, "trust me, I know what I'm doing".


This is a signature. Any samples given are not meant to have error checking or show best practices. They are meant to just illustrate a point. I may also give inefficient code or introduce some problems to discourage copy/paste coding. This is because the major point of my posts is to aid in the learning process.

Darran Rowe on Fri, 23 Aug 2019 01:08:56


I forgot to mention, besides the cast, there is one more problem in the same function call. You take the address of value, which is an array.

This time the compiler does work against you because this is not something that the compiler will report due to standard conversions. The first thing to remember here is that the type the parameter expects is void * (it is either PVOID or LPVOID but these are just typedefs for void *). The rule that causes problems is that a pointer to anything will silently convert to a typeless pointer (void *). This means that a char * will convert to void pointer or even a char ** will convert to void *.

The type of an array is type[], but this can degrade to a pointer. So as an example char[] will degrade to char *. This means that passing in value and not taking the address of value is the right answer since it will degrade to char * and then convert to void *.

The reason why &value also worked is the way the types work. &value has the type of char (*)[], this degrades to char **. This will convert to void * silently.