I am working on a task in a C++ project to upgrade some components from building with VS2010 to build with VS2015 and noticed a strange behavior that I could not find any discussions online. Simplified code is as follows:
#include "stdafx.h"
int main()
{
HCRYPTPROV hCryptProv = NULL;
LPCTSTR UserName = L"MyKeyContainer";
HCRYPTKEY hKey = NULL;
bool result = CryptAcquireContext(&hCryptProv, UserName, NULL, PROV_RSA_FULL, 0);
result = CryptGenKey(hCryptProv, CALG_RC4, 25 << 16, &hKey); // this line is meant to produce an invalid hKey.
result = CryptDestroyKey(hKey);
result = CryptReleaseContext(hCryptProv, 0);
return 0;
}
and precompiled header:
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <Wincrypt.h>
If I try to build and run this code snippet with VS2010, CryptGenKey returns a false result and hKey value of 0.
Passing hKey to the CryptDestroyKey returns false, but does not throw an exception.
If I try to build and run this code snippet with VS2015, CryptGenKey returns a false result and hKey value of 0.
Passing hKey to the CryptDestroyKey throws an access violation exception.
Could someone explain the reason behind this implementation and why Windows won't handle 0 in the more up to date VS version? This could be a potential problem for other projects if they do not manage the 0 themselves.
Related
I am trying to get another process' command-line parameters (on WinXP 32bit).
I do the following:
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ | PROCESS_TERMINATE, FALSE, ProcList.proc_id_as_numbers[i]);
BytesNeeded = sizeof(PROCESS_BASIC_INFORMATION);
ZwQueryInformationProcess(hProcess, ProcessBasicInformation, UserPool, sizeof(PROCESS_BASIC_INFORMATION), &BytesNeeded);
pbi = (PPROCESS_BASIC_INFORMATION)UserPool;
BytesNeeded = sizeof(PEB);
res = ZwReadVirtualMemory(hProcess, pbi->PebBaseAddress, UserPool, sizeof(PEB), &BytesNeeded);
/* zero value returned */
peb = (PPEB)UserPool;
BytesNeeded = sizeof(RTL_USER_PROCESS_PARAMETERS);
res = ZwReadVirtualMemory(hProcess, peb->ProcessParameters, UserPool, sizeof(RTL_USER_PROCESS_PARAMETERS), &BytesNeeded);
ProcParam = (PRTL_USER_PROCESS_PARAMETERS)UserPool;
After the first call, pbi.UniqueProcessID is correct.
But, after calling ZwReadVirtualMemory(), I get the command-line for my process, not the requested one.
I also used ReadProcessMemory() & NtQueryInformationProcess(), but get the same result.
Can anybody help?
On this forum thread, it is said that this code works. Unfortunately, I do not have access to post on that forum to ask them.
It looks like ZwReadVirtualMemory is called only once. That is not enough. It has to be called for each level of pointer indirection. In other words when you retrieve a pointer it points to other process' address space. You cannot read it directly. You have to call ZwReadVirtualMemory again. For the case of those data structures ZwReadVirtualMemory has to be called 3 times: once to read PEB (that is what the code above does), once to read RTL_USER_PROCESS_PARAMETERS and once to read UNICODE_STRING's buffer.
The following code fragment worked for me (error handling omitted for clarity and I used documented ReadProcessMemory API instead of ZwReadVirtualMemory):
LONG status = NtQueryInformationProcess(hProcess,
0,
pinfo,
sizeof(PVOID)*6,
NULL);
PPEB ppeb = (PPEB)((PVOID*)pinfo)[1];
PPEB ppebCopy = (PPEB)malloc(sizeof(PEB));
BOOL result = ReadProcessMemory(hProcess,
ppeb,
ppebCopy,
sizeof(PEB),
NULL);
PRTL_USER_PROCESS_PARAMETERS pRtlProcParam = ppebCopy->ProcessParameters;
PRTL_USER_PROCESS_PARAMETERS pRtlProcParamCopy =
(PRTL_USER_PROCESS_PARAMETERS)malloc(sizeof(RTL_USER_PROCESS_PARAMETERS));
result = ReadProcessMemory(hProcess,
pRtlProcParam,
pRtlProcParamCopy,
sizeof(RTL_USER_PROCESS_PARAMETERS),
NULL);
PWSTR wBuffer = pRtlProcParamCopy->CommandLine.Buffer;
USHORT len = pRtlProcParamCopy->CommandLine.Length;
PWSTR wBufferCopy = (PWSTR)malloc(len);
result = ReadProcessMemory(hProcess,
wBuffer,
wBufferCopy, // command line goes here
len,
NULL);
Why we see see the command line of our own process? That is because processes are laid out in a similar way. Command line and PEB-related structures are likely to have the same addresses. So if you missed ReadProcessMemory you end up exactly with local process' command line.
I was trying to do this same thing using mingw & Qt. I ran into a problem with "undefined reference to CLSID_WbemLocator". After some research, it seems that the version of libwbemuuid.a which was included with my version of mingw only defined IID_IWbemLocator but not CLSID_WbemLocator.
I found that manually defining CLSID_WbemLocator works (although its probably not the "correct" way of doing things).
The final working code:
#include <QDebug>
#include <QString>
#include <QDir>
#include <QProcess>
#define _WIN32_DCOM
#include <windows.h>
#include "TlHelp32.h"
#include <stdio.h>
#include <tchar.h>
#include <wbemidl.h>
#include <comutil.h>
const GUID CLSID_WbemLocator = { 0x4590F811,0x1D3A,0x11D0,{ 0x89,0x1F,0x00,0xAA,0x00,0x4B,0x2E,0x24 } }; //for some reason CLSID_WbemLocator isn't declared in libwbemuuid.a (although it probably should be).
int getProcessInfo(DWORD pid, QString *commandLine, QString *executable)
{
HRESULT hr = 0;
IWbemLocator *WbemLocator = NULL;
IWbemServices *WbemServices = NULL;
IEnumWbemClassObject *EnumWbem = NULL;
//initializate the Windows security
hr = CoInitializeEx(0, COINIT_MULTITHREADED);
hr = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
hr = CoCreateInstance(CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &WbemLocator);
//connect to the WMI
hr = WbemLocator->ConnectServer(L"ROOT\\CIMV2", NULL, NULL, NULL, 0, NULL, NULL, &WbemServices);
//Run the WQL Query
hr = WbemServices->ExecQuery(L"WQL", L"SELECT ProcessId,CommandLine,ExecutablePath FROM Win32_Process", WBEM_FLAG_FORWARD_ONLY, NULL, &EnumWbem);
qDebug() << "Got here." << (void*)hr;
// Iterate over the enumerator
if (EnumWbem != NULL) {
IWbemClassObject *result = NULL;
ULONG returnedCount = 0;
while((hr = EnumWbem->Next(WBEM_INFINITE, 1, &result, &returnedCount)) == S_OK) {
VARIANT ProcessId;
VARIANT CommandLine;
VARIANT ExecutablePath;
// access the properties
hr = result->Get(L"ProcessId", 0, &ProcessId, 0, 0);
hr = result->Get(L"CommandLine", 0, &CommandLine, 0, 0);
hr = result->Get(L"ExecutablePath", 0, &ExecutablePath, 0, 0);
if (ProcessId.uintVal == pid)
{
*commandLine = QString::fromUtf16((ushort*)(long)CommandLine.bstrVal);// + sizeof(int)); //bstrs have their length as an integer.
*executable = QString::fromUtf16((ushort*)(long)ExecutablePath.bstrVal);// + sizeof(int)); //bstrs have their length as an integer.
qDebug() << *commandLine << *executable;
}
result->Release();
}
}
// Release the resources
EnumWbem->Release();
WbemServices->Release();
WbemLocator->Release();
CoUninitialize();
//getchar();
return(0);
}
and in my Qt project file (.pro) I link to the following libraries:
LIBS += -lole32 -lwbemuuid
Duplicate of How to query a running process for it's parameters list? (windows, C++) , so I'll just copy my answer from there over here:
You can't reliably get that information. There are various tricks to try and retrieve it, but there's no guarantee that the target process hasn't already mangled that section of memory. Raymond Chen discussed this awhile back on The Old New Thing.
You need to be more disciplined with checking return codes. It may be that any of your ZwReadVirtualMemory calls yield an error code which points you into the right direction.
In particular, the ProcList.proc_id_as_numbers[i] part suggests that you're executing this code in a loop. Chances are that the procPeb.ProcessParameters structure is still filled with the values of an earlier loop iteration - and since the ZwReadVirtualMemory call fails on your target process, you get to see the command line of whatever process was previously queried.
You don't have to read the VM of the target process to do this. Just make sure you have the correct Process ID for the target process.
Once you have the process handle via OpenProcess, you can then use NtQueryInformationProcess to get detailed process info. Use the ProcessBasicInformation option to get the PEB of the process - this contains another structure pointer RTL_USER_PROCESS_PARAMETERS, through which you can get the command line.
I am trying to write to my Windows 10 registry, to include a program in Startup.
At the moment I have written the following code, which is not wroking:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winnt.h>
#include <winreg.h>
int main()
{
const TCHAR* path = TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run");
LPDWORD holdResult;
PHKEY hKey;
int lResult;
//lResult = RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_READ, &hKey);
lResult = RegCreateKeyExA(HKEY_CURRENT_USER, "myprogram", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &holdResult);
if (lResult != ERROR_SUCCESS)
{
if (lResult == ERROR_FILE_NOT_FOUND) {
printf("Key not found.\n");
return TRUE;
}
else {
printf("Error opening key.\n");
return FALSE;
}
}
printf("Key already existed or not: %p\n", holdResult);
char* szPath = "C:\\Users\\Myname\\Documents\\coolprogram.exe";
lResult = RegSetValueExA(hKey, "program", 0, REG_SZ,(LPBYTE)szPath, sizeof(wchar_t)*(wcslen(szPath)+1));
printf("Key successfully set or not: %d\n", lResult);
RegCloseKey(hKey);
return 0;
}
The strange thing is, although the code does not write anything to the registry, I get no error message, and the program executes as successful!
This is what gets printed to the terminal when I run the code:
Key already existed or not: 0000000000000002
Key successfully set or not: 0
So, the key had already been previously created, and was succesfully set, which did not happen, there is nothing in my registry.
I believe this is a permissions problem, because for some reason I cannot alter my registry permissions manually, even after setting myself as owner, it is impossible for me to allow "Full Control" to myself.
But I expected some sort of error, such as "ACCESS DENIED: INSUFFICIENT PERMISSIONS", but I am getting a success. Strange.
You are passing the wrong key path to RegCreateKeyEx(). You are trying to write your program value to HKCU\myprogram rather than to HKCU\SOFTWARE\Microsoft\...\Run.
You are also passing invalid pointers to RegCreateKeyEx(). Its last 2 parameters expect pointers to HKEY and DWORD variables, but you are passing in pointers to HKEY* and DWORD* variables instead.
You are also passing an incorrect parameter to RegSetValueExA(), too. You are giving it an ANSI string (OK, since it is an ANSI function), but are passing in a Unicode string length that is 2x the byte size of the actual ANSI string (bad).
In fact, your code shouldn't even compile as shown.
Try this instead:
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winnt.h>
#include <winreg.h>
int main()
{
const char* szKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";
const char* szPath = "C:\\Users\\Myname\\Documents\\coolprogram.exe";
DWORD dwDisposition;
HKEY hKey;
LSTATUS lResult;
//lResult = RegOpenKeyExA(HKEY_CURRENT_USER, szKey, 0, KEY_QUERY_VALUE, &hKey);
lResult = RegCreateKeyExA(HKEY_CURRENT_USER, szKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_SET_VALUE, NULL, &hKey, &dwDisposition);
if (lResult != ERROR_SUCCESS)
{
printf("Error creating key: %ld\n", lResult);
return 0;
}
printf("Key already existed or not: %lu\n", dwDisposition);
lResult = RegSetValueExA(hKey, "program", 0, REG_SZ, (LPBYTE)szPath, sizeof(TCHAR)*(strlen(szPath)+1));
printf("Key successfully set or not: %ld\n", lResult);
RegCloseKey(hKey);
return 0;
}
The updates involved are: KB4532938 and KB4528760
This is the code:
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
HMODULE hInst;
HANDLE hImg = NULL;
hInst = LoadLibrary(L"C:\\Users\\asd\\Desktop\\asd\\test.exe");
hImg = LoadImageW(hInst, MAKEINTRESOURCEW(5234), 2, 0, 0, 0);
if (!hImg)
cout << GetLastError() << endl;
cout << hImg;
}
This is the .exe containing the cursor (it's a blank ahk script)
Before the updates:
Output: NOT-null handle and error-code 1813
It works!
After the updates:
Output: NULL handle and error-code 1813
It doesn't work!
The only difference is the installed updates.
The questions are:
Is it a bug?
How is it possible that the resource exists, the name is correct, the format is correct and it fails?
What changed that made it break, was it a bug that made it work in the first place?
How can I report this to Microsoft?
Since it is not easy to clear in comments, I post it as an answer.
I did tests to reproduce this problem and found that it was only related to "KB4528760 update"(you don't need uninstall both of them).
I use EnumResourceTypes, EnumResourceNames to get that the resource does exist:
name = MAKEINTRESOURCE(5234), type = RT_ANICURSOR.
Use FindResource and specify the resource type to RT_ANICURSOR did work.
#include "pch.h"
#include <iostream>
#include <Windows.h>
using namespace std;
int main()
{
HMODULE hInst;
HANDLE hImg = NULL;
hInst = LoadLibrary(L"C:\\Users\\asd\\Desktop\\asd\\test.exe");
HRSRC hResInfo = FindResource(hInst, MAKEINTRESOURCE(5234), RT_ANICURSOR);
hImg = LoadResource(hInst, hResInfo);
if (!hImg)
cout << GetLastError() << endl;
cout << hImg;
}
I'm trying to write code which can add some software to registry. Here is my code :
int main()
{
HKEY hkey;
LONG RegOpenResult;
const char path[] = "C:\\Users\\Adrian\\Documents\\Visual Studio 2015\\Projects\\TcpServer\\x64\\Debug\\TcpServer.exe";
RegOpenResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", 0, KEY_ALL_ACCESS, &hkey);
RegSetValue(hkey,L"Server",REG_SZ, L"C:\\Users\\Adrian\\Documents\\Visual Studio 2015\\Projects\\TcpServer\\x64\\Debug\\TcpServer.exe",strlen(path)+1);
RegCloseKey(hkey);
return 0;
}
I can compile and run it, but it dosen't create a new key in SOFTWARE\Microsoft\Windows\CurrentVersion\Run
I also tried what i found here:
Add Application to Startup (Registry). But i have the same problem. I can compile and run it but no key is added.
Has anyone an idea?
I've got a problem about RegOpenKeyEx, the code:
#include <tchar.h>
#include <stdio.h>
#include <windows.h>
#pragma comment (lib, "Advapi32.lib")
int main () {
TCHAR *keyName = _T("SOFTWARE\\foobar2000\\capabilities");
HKEY key = NULL;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_ALL_ACCESS, &key) != ERROR_SUCCESS) {
printf("open key failed!\n");
return -1;
} else {
printf("open key success!\n");
}
TCHAR *value = _T("123");
if (RegSetValueEx(key, _T("xxx"), 0, REG_SZ,
(const BYTE *)value, sizeof(TCHAR) * (_tcslen(value) + 1)) != ERROR_SUCCESS) {
printf("set value failed!\n");
}
RegCloseKey(key);
return 0;
}
Save the code in such as reg.cpp, and in command mode:
cl reg.cpp
and I got reg.exe, run it:
D:\tmp>reg.exe
open key success!
But the value hasn't been written in the registry.
Another strange thing is that if I use the visual studio to create a CLI project, and paste the code into main(), the RegOpenKeyEx() will return false.
The platform is windows 7, and UAC is enabled.
Sounds like you're running into virtualization. IF the app has no manifest, when you try to write to HKLM\Software it actually writes to HKEY_USERS\<User SID>_Classes\VirtualStore\Machine\Software. To prevent this, you can run the app elevated. You might want to add a manifest forcing it to run elevated every time. Alternatively, stop writing to HKLM and use HKCU instead.
As for the C++/CLI part, my guess would be you are given an asInvoker manifest for that one, which suppresses virtualization and results in the attempt to get to HKLM failing.