I am retrieving a version string for the current executable using the following code:
// http://stackoverflow.com/questions/13941837/how-to-get-version-info-from-resources
std::string get_version_string()
{
auto hInst = GetModuleHandle(NULL);
// The following functions allocate persistent one-time space in the process's memory - they don't need to have results freed
auto hResInfo = FindResourceA(hInst, MAKEINTRESOURCE(1), RT_VERSION);
auto dwSize = SizeofResource(hInst, hResInfo);
auto hResData = LoadResource(hInst, hResInfo);
char *pRes = static_cast<char *>(LockResource(hResData));
if ( !dwSize || !pRes ) return {};
// Copy is required because VerQueryValue modifies the object, but LoadResource's resource is non-modifiable.
// SizeofResource yielded the size in bytes, according to its documentation.
std::vector<char> ResCopy(dwSize);
std::copy(pRes, pRes + dwSize, ResCopy.begin());
// https://stackoverflow.com/a/1174697/1505939
LPVOID pvFileVersion{};
UINT iFileVersionLen{};
if ( !VerQueryValueA(&ResCopy[0], "\\StringFileInfo\\040904E4\\FileVersion", &pvFileVersion, &iFileVersionLen) )
return "(unknown)"s;
char buf[200];
sprintf(buf, "%p\n%p\n%p", &ResCopy[0], &ResCopy[0] + ResCopy.size(), pvFileVersion);
debug_output ( buf );
auto s = static_cast<char *>(pvFileVersion);
return std::string( s, s + iFileVersionLen );
}
The VerQueryValue documentation, and other SO questions on the topic, indicate that VerQueryValue
is supposed to return a pointer into the resource block. However, the output I get is:
000000000594b460
000000000594b748
000000000594b802
Furthermore, if I change the allocation of ResCopy
to std::vector<char> ResCopy(dwSize + 0x200);
, then I get the output:
000000000594b460
000000000594b948
000000000594b802
and the only thing I can conclude from this is that the VerQueryValueA
function is doing an out-of-bounds write in the original case; it's writing past the end of the resource's size as was given by SizeofResource
; it's writing outside of my vector.
Even though the function seems to work properly I suspect this might actually be a bug.
My question is: am I doing something wrong, or is this a bug in VerQueryValueA
? And how should I fix the problem?
Note: If I use VerQueryValueW
then it does return a pointer inside ResCopy
in the first place.
This answer seems to allude to the issue however I'm not using GetFileVersionInfo
(which requires a filename, there doesn't seem to be any equivalent function that takes the module handle).
The greater purpose of this is to be able to log my application's version string in the log file, and trying to find and open a file based on filename seems like a bunch more possible points of failure when we have obviously already loaded the executable to be running it.