C++ application crash when trying to read registry subkey - c++

I'm writing a programme that should return the Value of a registry subkey. I tried this code:
LPCTSTR sk = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\");
HKEY regkey;
char out[255];
RegOpenKeyEx(HKEY_CURRENT_USER, sk, 0, KEY_SET_VALUE, &regkey);
RegGetValue(regkey, L"test", NULL, RRF_RT_ANY, NULL, (PVOID)&out, (LPDWORD) strlen(out) +1);
RegCloseKey(regkey);
MessageBox(NULL, (LP) out, L"Output", MB_OK);
I wrote this in Visual Studio 2017 and it doesn't show any errors. But when I run it, it crashes on line 5.
Crash reason:
Exception Error on 0x7511C481 (KernelBase.dll) in reader.exe: 0xC0000005: Access Violation While Reading at Location 0x00000005. (Translated by Google Translate)
I have already checked if RegOpenKeyEx() works and yes it does work.
What am I doing wrong and how to fix it?

You should use sizeof(out) and not strlen(out)+1. That variable is uninitizlied and depending on how you build this can either be filled with zeros (in which case you're telling RegGetValue() it can write 1 bytes into it) or it can have random data (in which case you're telling RegGetValue() it can write a random number of bytes).
The second issue is that RegOpenKeyEx() is called with KEY_SET_VALUE so you don't even have permission to read. You need KEY_QUERY_VALUE.
The third issue, and the one probably causing the crash, is that you cast the result of strlen(out)+1 to a pointer. It's a number, not a pointer. The function is expecting a pointer so it can write the number of bytes it actually read. Use:
DWORD len = sizeof(out);
RegGetValue(regkey, L"test", NULL, RRF_RT_ANY, NULL, (PVOID)&out, &len);
And finally, as all the comments mention, you should check for errors on all functions and handle all of them.

Related

Writing a DWORD value to registry in C++

I am trying to write a DWORD value to the registry programmatically in C++.
I've done a bit of searching and I have found that this question has been asked before. I've tried to follow their solution but have come up with a really frustrating issue which, as far as I know, have not been addressed by their solution.
This is my code:
HKEY hKey;
LPCWSTR sKeyPath;
int iResult;
sKeyPath = L"Software\\ABI\\";
iResult = RegOpenKeyEx(HKEY_CURRENT_USER, sKeyPath, NULL, KEY_ALL_ACCESS, &hKey);
DWORD value = 0x00000003;
iResult = RegSetValueEx(hKey, L"Test", NULL, REG_DWORD, (const BYTE*)value, sizeof(value));
RegCloseKey(hKey);
I've done some basic debugging and found that the value of iResult is 998 after I call RegSetValueEx. I am sure that this key is present in the windows registry because I created it manually with regedit.exe for testing purposes. The value of the DWORD "Test" is initially 0x00000009 and is unchanged after I run my program.
I am not sure where I am wrong.
Any help would be appreciated.
P.S. I've not managed to find any helpful site on the net for error 998. The only reference I found mentions that that's the worst error you can get when handling registry.
P.P.S. By the way, I'm running this program on Windows 8. I don't think that changes anything but I've had experiences with Windows 8 having some weird security issues before.
You need to pass the address of value:
iResult = RegSetValueEx(hKey,
L"Test",
NULL,
REG_DWORD,
(const BYTE*)&value, // Change made here.
sizeof(value));
The error code 998 means:
Invalid access to memory location.
When the address of value is not passed its actual value (3) is being used as a memory address, causing the failure.

ERROR_INSUFFICIENT_BUFFER returned from GetAdaptersAddresses

Using the following code, more or less copy-pasted from the MSDN example of
GetAdaptersAddresses, I get the return value 122, which means ERROR_INSUFFICIENT_BUFFER (according to this system error code list).
ULONG outBufLen = 150000; // Tried for different (large) values here...
PIP_ADAPTER_ADDRESSES pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
DWORD dwRetVal = GetAdaptersAddresses(AF_INET, 0, NULL, pAddresses, &outBufLen);
// ....
free(pAddresses);
The documentation of GetAdaptersAddresses does not list ERROR_INSUFFICIENT_BUFFER as one of the expected return values. (It lists ERROR_BUFFER_OVERFLOW, which should adjust outBufLen to the needed value, but that remains unchanged).
Using GetAdaptersInfo instead leads to the same symptoms.
This error does not occur on my development machine, but on one virtual and one real clean Windows 7 x86 SP1 installation (added the VC++ redistributables).
As a c++ newbie, am I doing something wrong? What could cause this error and how to fix it? =)
First of all, you can - as others suggested - do two calls, to find out required buffer size, and then do the query itself. Especially if you are seeing the error, your first try would be to ask API what size it expected.
Second, you need to know that this API is not quite safe in 32-bit processes consuming high amounts of memory, so that buffers span into higher 2GB of address space. API might start acting in a weird way, either due to its own bug, or a bug in an underlying layer. See details on this on MS Connect here: GetAdaptersAddresses API incorrectly returns no adapters for a process with high memory consumption.
The fact that error code is not "one of the expected return values" tells for the versions that the error comes from an underlying layer and this API just passes it up on internal failure. As a clue, having disabled some network adapter on the system, you might get rid of the error.
Visual Studio deployed a library named "IPHLPAPI.dll" together with my project which caused the problem. Deleting this file solved it.
Why this was the case is subject to further research =)
First, a buffer is a block of memory.
So insufficient could mean that you haven't given it enough memory somehow. Our could be a block of memory which you don't have access to. Maybe the address doesn't even exist.
Look at this:
ERROR_INSUFFICIENT_BUFFER
122 (0x7A)
The data area passed to a system call is too small.
This sounds really like the buffer hasn't got enough allocated memory. Or similar.
Maybe the
outBufLen
has to be a specific length, maybe the size of the memory block. Because sometimes it doesn't check for the 'name' but tries to compare for each of the variables size. This idea came from the High Level Shader Language.
So i would try to look a bit more on the:
ULONG outBufLen = 150000; // Tried for different (large) values here...
PIP_ADAPTER_ADDRESSES pAddresses = (IP_ADAPTER_ADDRESSES *) malloc(outBufLen);
Good luck!
To know the exact buffer size required, you can just pass NULL into pAddresses and size will be set to the required size. You may want to rewrite your code slightly to make that work;
DWORD rv, size = 0;
PIP_ADAPTER_ADDRESSES adapter_addresses;
rv = GetAdaptersAddresses(AF_INET, 0, NULL, NULL, &size);
if (rv != ERROR_BUFFER_OVERFLOW)
return false; // ERROR
adapter_addresses = (PIP_ADAPTER_ADDRESSES)malloc(size);
rv = GetAdaptersAddresses(AF_INET, 0, NULL, adapter_addresses, &size);
if (rv != ERROR_SUCCESS) {
free(adapter_addresses);
return false; // ERROR
}

Remote thread is failing on call to LoadLibrary with error 87

I am tring to create a Remote thread that will load a DLL I wrote, and run a function from it.
The DLL is working fine (Checked) but from some reason, the Remote thread fails and the proccess in which it was created stop responding.
I used ollyDebug to try and see what is going wrong and I noticed two things...
My strings (dll name and function name) are passed to the remote thread correctly
The thread fails on LoadLibrary with lasterror code 87 "ERROR_INVALID_PARAMETER"
My best guess is that somehow, The remote thread can't find LoadLibrary (Is this because the linker is done with repspect to my proccess???, Just a guess...)
What am I doing wrong?
This is the code to the remote function:
static DWORD WINAPI SetRemoteHook (DATA *data)
{
HINSTANCE dll;
HHOOK WINAPI hook;
HOOK_PROC hookAdress;
dll = LoadLibrary(data->dll);
hookAdress = (HOOK_PROC) GetProcAddress(dll,data->func);
if (hookAdress != NULL)
{
(hookAdress)();
}
return 1;
}
Edit:
This is the part in which I allocate the memory to the remote proccess:
typedef struct
{
char* dll;
char* func;
} DATA;
char* dllName = "C:\\Windows\\System32\\cptnhook.dll";
char* funcName = "SetHook";
char* targetPrgm = "mspaint.exe";
Data lData;
lData.dll = (char*) VirtualAllocEx( explorer, 0, sizeof(char)*strlen(dllName), MEM_COMMIT, PAGE_READWRITE );
lData.func = (char*) VirtualAllocEx( explorer, 0, sizeof(char)*strlen(funcName), MEM_COMMIT, PAGE_READWRITE );
WriteProcessMemory( explorer, lData.func, funcName, sizeof(char)*strlen(funcName), &v );
WriteProcessMemory( explorer, lData.dll, dllName, sizeof(char)*strlen(dllName), &v );
rDataP = (DATA*) VirtualAllocEx( explorer, 0, sizeof(DATA), MEM_COMMIT, PAGE_READWRITE );
WriteProcessMemory( explorer, rDataP, &lData, sizeof(DATA), NULL );
Edit:
It looks like the problem is that the remote thread is calling a "garbage" address
instead of LoadLibrary base address. Is there a possibily Visual studio linked
the remote proccess LoadLibrary address wrong?
Edit:
when I try to run the same exact code as a local thread (I use a handle to the current procces in CreateRemoteThread) the entire thing works just fine. What can cause this?
Should I add the calling function code? It seems to be doing its job as
the code is being executed in the remote thread with the correct parameters...
The code is compiled under VS2010.
data is a simple struct with char* 's to the names. (As explicetly writing the strings in code would lead to pointers to my original proccess).
What am I doing wrong?
Failing with ERROR_INVALID_PARAMETER indicates that there is a problem with the parameters passed.
So one should look at data->dll which represents the only parameter in question.
It is initialised here:
lData.dll = VirtualAllocEx(explorer, 0, sizeof(char) * (strlen(dllName) + 1), MEM_COMMIT, PAGE_READWRITE);
So let's add a check whether the allocation of the memory which's reference should be store into lData.dll really succeded.
if (!lData.dll) {
// do some error logging/handling/whatsoever
}
Having done so, you might have detected that the call as implemented failed because (verbatim from MSDN for VirtualAllocEx()):
The function fails if you attempt to commit a page that has not been
reserved. The resulting error code is ERROR_INVALID_ADDRESS.
So you might like to modifiy the fourth parameter of the call in question as recommended (again verbatim from MSDN):
To reserve and commit pages in one step, call VirtualAllocEx with
MEM_COMMIT | MEM_RESERVE.
PS: Repeat this exercise for the call to allocate lData.func. ;-)
It's possible that LoadLibrary is actually aliasing LoadLibraryW (depending on project settings), which is the Unicode version. Whenever you use the Windows API with "char" strings instead of "TCHAR", you should explicitly use ANSI version names. This will prevent debugging hassles when the code is written, and also in the future for you or somebody else in case the project ever flips to Unicode.
So, in addition to fixing that horrible unterminated string problem, make sure to use:
LoadLibraryA(data->dll);

Using RegQueryInfoKey

I am new to programming, I would like to know the number of entries in a registry key. I think entries are called subkeys but I am not sure. I am trying to use RegQueryInfoKey() but I don't fully understand the MSDN webpage since I am beginner.
HKEY hKey = HKEY_LOCAL_MACHINE;
char regpath[] = "SOFTWARE\\MyApplication\\"
LPDWORD numberofEntries;
RegOpenKeyEx(hKey, regpath, 0, KEY_READ, &hKey);
RegQueryInfoKey(hKey, NULL, NULL, NULL, numberofEntries, NULL);
then I would like to printf the number of entries in this key. The code above doesn't work, the app crash.
How is it done?
Thank you
RegQueryInfoKey has 12 parameters. You are only passing 6. I can't understand how that even compiles—perhaps you are providing your own definition of RegQueryInfoKey rather than the one from the windows header files.
Perhaps you are getting confused by the fact that many of the parameters to RegQueryInfoKey are marked as optional. This only means that you can pass NULL into the function and not that you can omit the parameters altogether.

WIN32_FIND_DATA Problems - cFileName

i have a problem with my code ;)
hFind = FindFirstFileEx( szPath, FindExInfoMaxInfoLevel, &FindData, FindExSearchNameMatch, NULL , 0);
strncpy_s( pszFileName, 280, FindData.cFileName, strlen(FindData.cFileName));
everything seems fine but when i copy the executable to another computer (windows 2003) i get
But for pszFileName i get really strange output
Specifying FindExInfoMaxInfoLevel is incorrect. The MSDN Library says:
FindExInfoMaxInfoLevel
This value is used for validation. Supported values are less than this value.
In addition, from your usage of FindFirstFileEx, I cannot see why you do not use the simpler FindFirstFile function.
There's not enough code to diagnose the problem, especially without any evidence of error checking. However, there is something really smelly in what you posted. Your call to strncpy_s() says that pszFileName is a pointer to an array with 280 elements. Where did that number come from? Is it just a guess? It can never be more than 260 on Windows, why is it more? I suspect that when you make this a real number, like an argument passed to your function, instead of a guess that you'll fix the problem as well.
You shuold not use the output fields in FindData without first checking that hFind is valid. From the MSDN docs:
If the function fails or fails to
locate files from the search string in
the lpFileName parameter, the return
value is INVALID_HANDLE_VALUE and the
contents of lpFindFileData are
indeterminate.
Thus you should have (after fixing other problems in your API call described in the answers here):
hFind = FindFirstFileEx( szPath, /* replace FindExInfoMaxInfoLevel here */,
&FindData, FindExSearchNameMatch, NULL , 0);
if (hFind != INVALID_HANDLE_VALUE)
{
strncpy_s( pszFileName, 280, FindData.cFileName, strlen(FindData.cFileName));
}