Getting Access Violation Error using GetFileVersionInfo - c++

DWORD dwHandle;
DWORD dwSize = GetFileVersionInfoSizeEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() , &dwHandle );
if( dwSize == 0 )
break;
pVersionInfo = new BYTE[ dwSize ];
bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , &pVersionInfo );
if( bRetVal == false )
break;
UINT uLen;
VS_FIXEDFILEINFO *pFileInfo;
bRetVal = VerQueryValue( &pVersionInfo , L"\\" , (LPVOID *)&pFileInfo , &uLen );
if( bRetVal == false )
break;
DWORD dwFileVersionMS = pFileInfo->dwFileVersionMS;
DWORD dwFileVersionLS = pFileInfo->dwFileVersionLS;
DWORD dwLeftMost = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
DWORD dwRightMost = LOWORD(dwFileVersionLS);
strVersion.sprintf( L"%u.%u.%u.%u", dwLeftMost , dwSecondLeft , dwSecondRight , dwRightMost );
}while(0);
if( pVersionInfo )
delete []pVersionInfo;
return bRetVal;
While debugging this code i am getting access violation error at delete statement . . can anyone tell what i am doing wrong.

The error is that you pass a pointer to the pointer to the allocated data block as the first argument to VerQueryValue, which leads to you passing the wrong address to the function. This leads to undefined behavior as VerQueryValue reads data from, and writes data to, somewhere in memory where it should not be read from/written to.
The solution is to not use the address-of operator here.
Update: you do the same thing with the GetFileVersionInfoEx function call. Don't use the address-of operator for pVersionInfo.

The error is in the line
bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , &pVersionInfo );
The correct call should be
bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath.c_str() ,dwHandle , dwSize , pVersionInfo );
From msdn:
BOOL WINAPI GetFileVersionInfoEx(
_In_ DWORD dwFlags,
_In_ LPCTSTR lptstrFilename,
_Reserved_ DWORD dwHandle,
_In_ DWORD dwLen,
_Out_ LPVOID lpData
);
The function GetFileVersionInfoEx() will fill the buffer pointed to by lpData (or, in the corrected above example, pVersionInfo) with the version info. In your code, it would be changing the value of the pointer, making it point to somewhere else in memory.
When you call delete[], it is giving you the exception because the value of your pointer has changed and it is no longer the value set by the new [] operator. In other words you are trying to free memory that was not dynamically allocated.

Here is the solution yo your issue in another thread with a full code example, but as pointed out the issue is that you are passing the pointer to the buffer for the information the wrong way, no need for the address of opearator.
Here is a snipplet with your code fixed to be working:
#include <Windows.h>
#include <cstdio>
#pragma comment(lib, "version.lib")
void main(int argc, char** argv)
{
const wchar_t* strFilePath = L"C:\\Windows\\System32\\kernel32.dll";
DWORD dwHandle;
BOOL bRetVal;
DWORD dwSize = GetFileVersionInfoSizeEx( FILE_VER_GET_NEUTRAL , strFilePath , &dwHandle );
if( dwSize == 0 )
return;
BYTE* pVersionInfo = new BYTE[dwSize];
bRetVal = GetFileVersionInfoEx( FILE_VER_GET_NEUTRAL , strFilePath , dwHandle , dwSize , pVersionInfo );
if( bRetVal == false )
return;
UINT uLen;
VS_FIXEDFILEINFO *pFileInfo = NULL;
bRetVal = VerQueryValue( pVersionInfo , L"\\" , (LPVOID *)&pFileInfo , &uLen );
if( bRetVal == false )
return;
DWORD dwFileVersionMS = pFileInfo->dwFileVersionMS;
DWORD dwFileVersionLS = pFileInfo->dwFileVersionLS;
DWORD dwLeftMost = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
DWORD dwRightMost = LOWORD(dwFileVersionLS);
char pVersion[1024];
sprintf(pVersion, "%u.%u.%u.%u", dwLeftMost , dwSecondLeft , dwSecondRight , dwRightMost );
if( pVersionInfo )
delete []pVersionInfo;
}

Related

Anyone has experience on using GetAppContainerNamedObjectPath?

Recently I came across a Windows API called GetAppContainerNamedObjectPath. But I have no idea on how I can use it.
I found a msdn page for this api (https://learn.microsoft.com/en-us/windows/win32/api/securityappcontainer/nf-securityappcontainer-getappcontainernamedobjectpath). But it does not have a right example and remarks, parameters are written poorly.
I am getting ERROR_INVALID_PARAMETER(87) error at the end, which tells me something's wrong with the parameters that I put. Here's what I've tried.
#define TokenIsAppContainer 29
#define TokenAppContainerSid 31
#define TokenAppContainerNumber 32
typedef struct _TOKEN_APPCONTAINER_INFORMATION {
PSID TokenAppContainer;
} TOKEN_APPCONTAINER_INFORMATION, *PTOKEN_APPCONTAINER_INFORMATION;
void GetAppContainerProcessInfo(CString & procName)
{
DWORD dwSize = 0;
DWORD dwResult;
HANDLE hToken;
PTOKEN_APPCONTAINER_INFORMATION pAppCoInfo;
WCHAR wcsDebug[1024] = {0,};
WCHAR * pwSID = NULL;
typedef BOOL (WINAPI *_LPGETAPPCONTAINERNAMEOBJECTPATH)(HANDLE, PSID, ULONG, LPWSTR, PULONG);
static _LPGETAPPCONTAINERNAMEOBJECTPATH lpGetAppContainerNamedObjectPath = NULL;
if (0 == lpGetAppContainerNamedObjectPath)
{
HMODULE hKernel32 = LoadLibraryExW(L"kernel32.dll", NULL, 0);
if (hKernel32)
{
lpGetAppContainerNamedObjectPath = reinterpret_cast<_LPGETAPPCONTAINERNAMEOBJECTPATH>(GetProcAddress(hKernel32, "GetAppContainerNamedObjectPath"));
}
}
if (lpGetAppContainerNamedObjectPath)
{
DWORD processId = (DWORD)_ttoi((LPCTSTR)procName);
//HANDLE hProcess = GetProcessHandleByProcessName(procName);
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processId);
if(!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken))
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"OpenProcessToken Error(%u) PID(%d)\n", dwResult, processId );
AfxMessageBox(wcsDebug);
return;
}
if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) TokenAppContainerSid, NULL, dwSize, &dwSize))
{
dwResult = GetLastError();
if( dwResult != ERROR_INSUFFICIENT_BUFFER )
{
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetTokenInformation Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
return;
}
}
pAppCoInfo = (PTOKEN_APPCONTAINER_INFORMATION) GlobalAlloc( GPTR, dwSize );
if (!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS) TokenAppContainerSid, pAppCoInfo, dwSize, &dwSize))
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetTokenInformation Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
return;
}
WCHAR wcsNamedObjectPath[MAX_PATH];
ULONG ulRetlen = 0;
BOOL bRet = lpGetAppContainerNamedObjectPath(hToken, pAppCoInfo->TokenAppContainer, _countof(wcsNamedObjectPath), wcsNamedObjectPath, &ulRetlen );
if (bRet)
{
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetAppContainerNamedObjectPath Path(%s)\n", wcsNamedObjectPath );
AfxMessageBox(wcsDebug);
}
else
{
dwResult = GetLastError();
swprintf_s( wcsDebug, _countof(wcsDebug), L"GetAppContainerNamedObjectPath Error %u\n", dwResult );
AfxMessageBox(wcsDebug);
}
if (pwSID)
LocalFree(pwSID);
CloseHandle(hToken)
CloseHandle(hProcess);
}
}
As a side-note, I have tried using wchar_t * and dynamically allocate the memory buffer by calling GetAppContainerNamedObjectPath twice. But still had no chance. Return length does not return a meaningful value.
if you call RtlGetLastNtStatus(); instead GetLastError(); after GetAppContainerNamedObjectPath you will got
STATUS_INVALID_PARAMETER_MIX - An invalid combination of parameters was specified.
this give you more info compare simply invalid parameter.
then look for function signature
BOOL
WINAPI
GetAppContainerNamedObjectPath(
_In_opt_ HANDLE Token,
_In_opt_ PSID AppContainerSid,
_In_ ULONG ObjectPathLength,
_Out_writes_opt_(ObjectPathLength) LPWSTR ObjectPath,
_Out_ PULONG ReturnLength
);
the Token and AppContainerSid declared with In_opt -- this mean that this parameters is optional, and you can pass 0 in place one of it. then ask your self - for what you query token for TokenAppContainerSid ? are system can not do this for you if you pass this token to api ? obvious can. so you not need do this yourself. really you need pass Token to api and in this case AppContainerSid must be 0. or you can pass AppContainerSid to api and in this case Token must be 0. when both AppContainerSid and Token not zero - you and got STATUS_INVALID_PARAMETER_MIX
also as side note - you not need open process with PROCESS_ALL_ACCESS if you need get it token. the PROCESS_QUERY_LIMITED_INFORMATION is enough
really api not do big magic. it return to you
AppContainerNamedObjects\<Sid>
path, where string form of app container sid.(some like S-1-15-2-...)

CreateDC() method,while setting up a Printer fails for certain PRINTERs as well as in certain Windows Environment

I have installed a HP Printer and added it to my list of Printer devices.
I am trying to use the following code:
QString printerName = "HP Designjet 500 24+HPGL2 Card";
DWORD infoSize, numBytes;
HANDLE hPrinter;
bool ok = OpenPrinter( ( LPWSTR )printerName.utf16(), ( LPHANDLE )&hPrinter, 0 );
if ( !ok )
{
qErrnoWarning( "QWin32PrintEngine::initialize: OpenPrinter failed" );
return;
}
GetPrinter( hPrinter, 2, NULL, 0, &infoSize );
HGLOBAL hMem;
hMem = GlobalAlloc( GHND, infoSize );
PRINTER_INFO_2 *pInfo;
pInfo = ( PRINTER_INFO_2* )GlobalLock( hMem );
ok = GetPrinter( hPrinter, 2, ( LPBYTE )pInfo, infoSize, &numBytes );
if ( !ok )
{
qErrnoWarning( "QWin32PrintEngine::initialize: GetPrinter failed" );
}
DEVMODE *devMode;
devMode = pInfo->pDevMode;
HDC hdc = NULL;
hdc = CreateDC( NULL, ( LPCWSTR )printerName.utf16(), 0, devMode );
Now,the CreateDC() method fails.I even tried to return the Error using GetLastError() method, and it returned as "203",which corresponds to "ERROR_ENVVAR_NOT_FOUND".
I am completely clueless as of now.
I would be really glad,if someone can help me regarding this.
Thanks in Advance.

C++ read Registry

i try to read the Registry in my NPAPI-Plugin:
bool ScriptablePluginObject::Invoke(NPObject* obj, NPIdentifier methodName, const NPVariant* args, uint32_t argCount, NPVariant* result) {
ScriptablePluginObject *thisObj = (ScriptablePluginObject*) obj;
char* name = npnfuncs->utf8fromidentifier(methodName);
LPCWSTR game_path = getRegKey(L"SOFTWARE\\World of RPG", L"Path");
MessageBox(NULL, game_path, L"Debugging", MB_TOPMOST);
/* ... */
}
LPCWSTR ScriptablePluginObject::getRegKey(LPCWSTR location, LPCWSTR name) {
HKEY hKey;
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
long registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, location, 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
long entry = RegQueryValueEx(hKey, name, NULL, REG_NONE, folder, &dwSize);
if(registry != ERROR_SUCCESS) {
return L"Error1";
}
if(entry != ERROR_SUCCESS) {
return L"Error2";
}
RegCloseKey(hKey);
folder[dwSize / sizeof(folder[0])] = '\0';
return (LPCWSTR) folder;
}
But it's returned every call Error2. I've tried a lot of changes:
change the Path (with Start and/or Ending \\)
change parameters
I Want to get the Path of HKEY_LOCAL_MACHINE\SOFTWARE\World of RPG\Path:
Anyone can help me? What i'm doing wrong?
Here's the sample I mentioned in the comments above:
#include <stdlib.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, DWORD *pBufferSize );
int _tmain(int argc, _TCHAR* argv[])
{
const int BUFFER_SIZE = 1024;
WCHAR sBuffer[BUFFER_SIZE]; // 2048 bytes
DWORD nBufferSize = BUFFER_SIZE * sizeof ( WCHAR );
ZeroMemory ( sBuffer, nBufferSize );
LSTATUS nResult = ReadRegistry ( L"SOFTWARE\\7-Zip", L"Path64",
sBuffer, &nBufferSize );
// check nResult for ERROR_SUCCESS to know if the call succeeded or not
return 0;
}
LSTATUS ReadRegistry ( LPCWSTR sPath, LPCWSTR sKey, LPWSTR pBuffer, LPDWORD pBufferSize )
{
HKEY hKey;
LSTATUS nResult = ::RegOpenKeyEx ( HKEY_LOCAL_MACHINE, sPath,
0, KEY_READ | KEY_WOW64_64KEY, &hKey );
if ( nResult == ERROR_SUCCESS )
{
nResult = ::RegQueryValueEx ( hKey, sKey, NULL, NULL,
(LPBYTE) pBuffer, pBufferSize );
RegCloseKey ( hKey );
}
return ( nResult );
}
Notice how the ReadRegistry function doesn't allocate memory - it takes a buffer and fills it with data. It's a lot easier to deal with memory if you always have the caller allocate memory. If the callee allocates memory, the caller may not know how memory was allocated and it may not know how to free it. (Of course, you can always assume the use of new and delete but things are simpler if only one side does this consistently. If the caller allocates memory, it'll know how to free it. The callee only needs to put data in the allocated space.
Also, notice how the return value of the API functions is checked before proceeding to the next call - this is important because this tells you if you got a useful registry handle back or not and whether you need to close it or not.
(This sample is really just C, not C++ but it still applies.)
In getRegKey(), your folder variable is a pointer, so sizeof(folder) is 4 (if compiling for 32bit) or 8 (if compiling for 64bit). Thus RegQueryValueEx() fails with an ERROR_MORE_DATA error code.
You are also using the wrong data type for the array. You need to use WCHAR instead of BYTE.
Change this:
LPBYTE folder = new BYTE[MAX_PATH];
DWORD dwSize = sizeof(folder);
To this:
LPWSTR folder = new WCHAR[MAX_PATH];
DWORD dwSize = sizeof(WCHAR) * MAX_PATH;
With that said, you are leaking the memory pointed to by folder, since you never delete[] it.

parameters for LsaICryptUnprotectData

I am trying to call LsaICryptUnprotectData but I get error code 87 unsupported parameter. Has anyone been able to successfully call this function? would like to see an example function call
Here is how I am calling,
typedef int (WINAPI *LPFUN_LSAICRYPTUNPROTECTDATA)
(
LPBYTE encCredData,
DWORD encCredDataSize,
DWORD reserved1,
DWORD reserved2,
DWORD reserved3,
DWORD reserved4,
DWORD dwFlags,
DWORD reserved5,
LPBYTE *decCredData,
LPDWORD decCredDataSize
);
LPFUN_LSAICRYPTUNPROTECTDATA pLsaICryptUnprotectData = (LPFUN_LSAICRYPTUNPROTECTDATA) GetProcAddress (hLsasrv, "LsaICryptUnprotectData");
if(!pLsaICryptUnprotectData)
{return GetLastError();}
HANDLE credfile = NULL;
LPBYTE buffer = NULL;
LPBYTE pDecrypted = NULL;
DWORD dwSize = 0;
DWORD cbsize=0;
credfile = CreateFile(filename,GENERIC_READ,0,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM,NULL);
dwSize = GetFileSize(credfile,NULL);
buffer=(LPBYTE)malloc(dwSize);
SetFilePointer(credfile,0,0,FILE_BEGIN);
DWORD credFileSize=0;
ReadFile(credfile,buffer,dwSize,&credFileSize,NULL)
if(!pLsaICryptUnprotectData( buffer, dwSize, 0,0,0,0, 0, 0, &pDecrypted, &cbsize) != NULL))
{
// do error handling
}
The LsalCryptUnprotectData function is undocumented, but from this example, you might try with similar parameters:
cbSize = 0;
pLsaICryptUnprotectData ( buffer, dwSize, 0,0,0,0, 0x20000041, 0,
&pDecrypted, &cbSize);

Delete key and subkey from registry:Code throw unhandled exception

I want to delete the Registry key and the all subkey.I am using the code from here.
Code compile fine but when debug the code
"Unhandled exception at 0x00416d14 in deletedemo.exe: 0xC0000005: Access violation writing location 0x0041ff01."
exception occur at the line
// Check for an ending slash and add one if it is missing.
lpEnd = lpSubKey + lstrlen(lpSubKey);
if (*(lpEnd - 1) != TEXT('\\'))
{
*lpEnd = TEXT('\\'); //Here exception occur.
lpEnd++;
*lpEnd = TEXT('\0');
}
I have written a code to delete the Registry Key and its Subkeys recursively some time ago. The code goes like this::
static BOOL RcrsvRegDel( HKEY hKey, LPTSTR lpszSub, DWORD dwOpenFlags )
{
BOOL bRet = TRUE ;
LONG lRet ;
DWORD dwSize = MAX_PATH ;
TCHAR szName[MAX_PATH] ;
HKEY hKeySub = NULL ;
HRESULT hr = NULL ;
HANDLE hProcess = NULL ;
HANDLE hToken = NULL ;
do{
lRet = RegOpenKeyEx( hKey, lpszSub, 0, dwOpenFlags, &hKeySub ) ;
if( lRet != ERROR_SUCCESS )
{
bRet = FALSE ;
break ;
}
while( ERROR_NO_MORE_ITEMS != (lRet = RegEnumKeyEx(hKeySub, 0, szName, &dwSize, NULL,
NULL, NULL, NULL)) )
if( !RcrsvRegDel(hKeySub, szName, dwOpenFlags) )
{
bRet = FALSE ;
break ;
}
lRet = RegDeleteKey( hKey, lpszSub ) ;
printf("RegDelKey:: %S :: lRet = %ld\n", lpszSub, lRet) ;
if( lRet != ERROR_SUCCESS )
{
bRet = FALSE ;
break ;
}
if( hKeySub != NULL )
{
RegCloseKey(hKeySub) ;
hKeySub = NULL ;
}
}while(0) ;
return bRet ;
}
dwOpenFlags = Flags to be passed to RegOpenKeyEx or RegDeleteKey.
EDIT:: If you do not want to delete the whole tree yourself recursively, MSDN have two functions to do this. You can always use them, namely, RegDeleteTree and SHDeleteKey.