Is a Program Running in Compatibility Mode - c++

Is there a C++ .NET function that I can call that will detect if my program is running in compatibility mode? If there is not one, could someone show me the code for one? Thanks.
For example:
Program loads up
Compatibility Mode check
if true then exit
else run

From another forum
After a few google searches went in
vain, I decided to experiment myself.
I found that the compatibility
settings for each executable are
stored - as I thought it would be - in
the windows registry.
The key where the settings are stored
is
HKEY_CURRENT_USER\Software\Microsoft\Windows
NT\CurrentVersion\AppCompatFlags\Layers
For each application that has its
compatibility settings specified,
there exists a value under that key
whose name is the path to the
executable and the data is a string
consisting of the compatibility
settings.
The keywords in the string that
specify the compatibility settings
are: WIN95 WIN98 NT4SP5
WIN2000 256COLOR 640X480
DISABLETHEMES DISABLECICERO
If multiple settings are specified (or
are to be specified), the data
consists of the settings above
separated by a space each. The first
four settings are mutually exclusive,
i.e. only one of them is to be
specified (if at all). I haven't
tested the consequences of specifying
multiple operating systems.
So, back to addressing your problem.
To check if an executable (let's say,
"C:\path\executable.exe") is set to
run in 256 color mode, there would be
a value named "C:\path\executable.exe"
(without the quotes, even if the path
contains spaces) under the key
[HKEY_CURRENT_USER\Software\Microsoft\Windows
NT\CurrentVersion\AppCompatFlags\Layers],
and the data associated with the value
would contain the string "256COLOR".
If it is also set to run in
compatibility mode under Windows
98/ME, the data would be "WIN98
256COLOR".
So, the approach is simple. Test if
there is a value with the full path of
the executable under the key I
mentioned above. If there isn't, the
executable has not been specified any
compatibility settings. If the value
exists, retrieve its data and check
for the presence of "256COLOR" in the
data. Accordingly, the presence of
"WIN95" or "WIN98" or "NT4SP5" or
"WIN2000" would mean that the
executable is set to run in
compatibility mode for that particular
operating system.

Get the version of the operation system that is returned from GetVersionEx and compare it to the file version on kernel32.dll. When in application compatibility mode GetVersionEx will always return the version of the operating system that is being 'emulated'. If both versions are different then you are in application compatibility mode.

The answer above helped me to get a "solution" for the question at hand. It is probably not the most elegant, but seems to work. Obviously you can get a bit more creative on the return type. Booleon does not suffice here. I think a native API would be good.
typedef VOID (NTAPI* TRtlGetNtVersionNumbers)(LPDWORD pdwMajorVersion, LPDWORD pdwMinorVersion, LPDWORD pdwBuildNumber);
bool IsRunningCompatMode()
{
TRtlGetNtVersionNumbers RtlGetNtVersionNumbers = (TRtlGetNtVersionNumbers)GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlGetNtVersionNumbers");
assert(RtlGetNtVersionNumbers);
if(RtlGetNtVersionNumbers)
{
OSVERSIONINFO osInfo = {0};
osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osInfo);
DWORD dwMajorVersion;
DWORD dwMinorVersion;
DWORD dwBuildNumber;
RtlGetNtVersionNumbers(&dwMajorVersion, &dwMinorVersion, &dwBuildNumber);
dwBuildNumber &= 0x0000FFFF;
if(osInfo.dwBuildNumber != dwBuildNumber)
{
return true;
}
}
return false;
};

Related

Is it good to use ntdll.dll in a win32 console application?

Short:
In my c++ project i need to read/write extended file properties. I managed it with using alternate data streams (ADS). My problem is, for opening the ADS i need to use the CreateFile API. But it is not fulfilling my needs. NtCreateFile will fullfill all my needs. (Or alternatively NtSetEaFile and NtQueryEaFile) But NtCreateFile is not directly accessible from a win32 console application.
I know i can use this function easily via GetProcAdress. But i like to know the opinion of you all, if i did miss something? Some other libs are using this pattern already, for example Chromium (https://github.com/chromium-googlesource-mirror/chromium/blob/1c1996b75d3611f56d14e2b30e7ae4eabc101486/src/sandbox/src/win_utils.cc function: ResolveNTFunctionPtr)
But im uncertain, because the c++ project is not a hobby project and i ask myself if it is dangerous or not.
I guess NtCreateFile is maybe the securest way to do, because it is well documented and supported by winternl.h header. Especially because this method is unchanged since windows 2000. But what is with NtSetEaFile, NtQueryEaFile which are fitting my needs perfectly. They are only half documented. A documentation for ZwSetEaFile and ZwQueryEaFile exist (unchanged since windows 2000).
Reason why i want to do that:
I want to write and read extended properties from files via ADS. But in case of writing the extended property of a given file the first time, i need to open the file with OPEN_ALWAYS. In case of file is not existing it will create a new file, even if i only access not the content stream of the file. To avoid this i get first the handle of the original file and check with this HANDLE if the file still exist.
But i dont want to blog any file with reduced access rights, because from my point of view that is a very bad pattern. The user needs to have full access to any file any time. Because of that we open all HANDLES with the flag FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE. And now i have the race.
auto hFile = CreateFileW(originalPath, …, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, …).
// this is the little race: if somebody at least rename originalPath the
// second CreateFileW call will cause the creation of a empty file with the
// path originalPath (the old path).
auto hADS = CreateFileW(originalPath + adsName, …, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_ALWAYS, …).
This is a main issue, especially because this happens from time to time in our tests. NtCreateFile will fix it, because i can create the second HANDLE with the help of the first HANDLE. Because of that no race. Or NtSetEaFile and NtQueryEaFile will help, because i only need one HANDLE.
The thing is, that the application needs not to be save for the future, because ADS works only on NTFS anyway. And who knows when NTFS will be exchanged. But i dont want a flaky behaviour. I want to trust this Methods. I I am fine if the API will change in the future and the software needs to adapt to it. But i want to be sure, that all Windows higher or equal then 7 can deal with it. Somebody some experience to share? I would like to hear them very much.
This question is wrong. Your proposed solution for your problem, is not using NtCreateFile, but use CreateFile with dwCreationDisposition set to the OPEN_EXISTING.
From documentation:
OPEN_EXISTING
Opens a file or device, only if it exists. If the specified file or
device does not exist, the function fails and the last-error code is
set to ERROR_FILE_NOT_FOUND.
Simply open file if exists and set whatever you want. If file is renamed, CreateFile returns ERROR_FILE_NOT_FOUND.
THE PROBLEM
Now, to your proposed solution, what is better method or why is not possible use ntdll.dll in win32 console application (???).
Again, your "better" method - GetProcAddress is "wrong" same as using linking against ntdll.dll. In Windows 11, or Windows 12 or Windows 3030 the function may be removed and both solutions (statical vs. dynamical import) will be fail.
It is not really unsecure to use this kind of APIs if their is a documentation. In case of NtSetEaFile, NtQueryEaFile and NtCreateFile you can find a description inside of Microsoft's Doc. (keep in mind NtXxx == ZwXxx)
But this API can change in the future and Microsoft does not guarantee that it will provides the same methods in the next Windows version. If you can, use the public API, because then you are safe. If not it is a case by case decision. In this case the three methods from the API are unchanged since Windows2000. Plus for example NtSetEaFile and NtQueryEaFile is used by Microsoft for WSL (Windows Subsystem for Linux). And especially NtCreateFile is used by a wide range of OpenSource Projects. So it is very unlikely that this API will change.
In my use case another aspect is important. Because I wanted to use ADS, but ADS is only supported by NTFS. So using ADS does not ensure future compatibility as well. So it was very clear for me using NtSetEaFile and NtQueryEaFile.
But how you can use this kind of APIs? Dynamic or static linking is possible. It depends on your needs what is better. In case of static linking you need to download the last WDK (Windows Driver Kit) and link against the ntdll.lib. In case of dynamic linking you can access the dll directly via GetModuleHandle and finding out the address of the method with GetProcAddress. Under Windows ntdll.dll is accessible from any application. In both cases you don't have directly a header file. You have to define the header file by yourself or use WDK to get them.
In my project dynamic linking was the best choice. The reason was, that on every windows the right implementation will be choosen and in case the method is not available i have the chance to deactivate the feature in my software instead of crash. Microsoft is recommending the dynamic way, because of the last reason.
Simple PseudoCode (dynamic case):
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
typedef struct _IO_STATUS_BLOCK {
union {
NTSTATUS Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
typedef NTSTATUS(WINAPI *NtSetEaFileFunction)(IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK
IoStatusBlock,
IN PVOID Buffer,
IN ULONG Length);
HMODULE ntdll = GetModuleHandle(L"ntdll.dll");
NtSetEaFileFunction function = nullptr;
FARPROC *function_ptr = reinterpret_cast<FARPROC *>(&function);
*function_ptr = GetProcAddress(ntdll, "NtQueryEaFile");
// function could be used normally.
The other answer is incorrect. The reason is that the reason of my problem is, that I need to use OPEN_ALWAYS. Of course, if you don't need this flag, everything is fine. But in my case there is a point where I needed to create the ADS. And it will not be created without the OPEN_ALWAYS flag.

GetDiskFreeSpaceEx with NULL Directory Name failing

I'm trying to use GetDiskFreeSpaceEx in my C++ win32 application to get the total available bytes on the 'current' drive. I'm on Windows 7.
I'm using this sample code: http://support.microsoft.com/kb/231497
And it works! Well, almost. It works if I provide a drive, such as:
...
szDrive[0] = 'C'; // <-- specifying drive
szDrive[1] = ':';
szDrive[2] = '\\';
szDrive[3] = '\0';
pszDrive = szDrive;
...
fResult = pGetDiskFreeSpaceEx ((LPCTSTR)pszDrive,
    (PULARGE_INTEGER)&i64FreeBytesToCaller,
    (PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
fResult becomes true and i can go on to accurately calculate the number of free bytes available.
The problem, however, is that I was hoping to not have to specify the drive, but instead just use the 'current' one. The docs I found online (Here) state:
lpDirectoryName [in, optional]
A directory on the disk. If this parameter is NULL, the function uses the root of the current disk.
But if I pass in NULL for the Directory Name then GetDiskFreeSpaceEx ends up returning false and the data remains as garbage.
fResult = pGetDiskFreeSpaceEx (NULL,
    (PULARGE_INTEGER)&i64FreeBytesToCaller,
    (PULARGE_INTEGER)&i64TotalBytes,
(PULARGE_INTEGER)&i64FreeBytes);
//fResult == false
Is this odd? Surely I'm missing something? Any help is appreciated!
EDIT
As per JosephH's comment, I did a GetLastError() call. It returned the DWORD for:
ERROR_INVALID_NAME 123 (0x7B)
The filename, directory name, or volume label syntax is incorrect.
2nd EDIT
Buried down in the comments I mentioned:
I tried GetCurrentDirectory and it returns the correct absolute path, except it prefixes it with \\?\
it returns the correct absolute path, except it prefixes it with \\?\
That's the key to this mystery. What you got back is the name of the directory with the native api path name. Windows is an operating system that internally looks very different from what you are familiar with winapi programming. The Windows kernel has a completely different api, it resembles the DEC VMS operating system a lot. No coincidence, David Cutler used to work for DEC. On top of that native OS were originally three api layers, Win32, POSIX and OS/2. They made it easy to port programs from other operating systems to Windows NT. Nobody cared much for the POSIX and OS/2 layers, they were dropped at XP time.
One infamous restriction in Win32 is the value of MAX_PATH, 260. It sets the largest permitted size of a C string that stores a file path name. The native api permits much larger names, 32000 characters. You can bypass the Win32 restriction by using the path name using the native api format. Which is simply the same path name as you are familiar with, but prefixed with \\?\.
So surely the reason that you got such a string back from GetCurrentDirectory() is because your current directory name is longer than 259 characters. Extrapolating further, GetDiskFreeSpaceEx() failed because it has a bug, it rejects the long name it sees when you pass NULL. Somewhat understandable, it isn't normally asked to deal with long names. Everybody just passes the drive name.
This is fairly typical for what happens when you create directories with such long names. Stuff just starts falling over randomly. In general there is a lot of C code around that uses MAX_PATH and that code will fail miserably when it has to deal with path names that are longer than that. This is a pretty exploitable problem too for its ability to create stack buffer overflow in a C program, technically a carefully crafted file name could be used to manipulate programs and inject malware.
There is no real cure for this problem, that bug in GetDiskFreeSpaceEx() isn't going to be fixed any time soon. Delete that directory, it can cause lots more trouble, and write this off as a learning experience.
I am pretty sure you will have to retrieve the current drive and directory and pass that to the function. I remember attempting to use GetDiskFreeSpaceEx() with the directory name as ".", but that did not work.

Correctly creating and running a win32 service with file I/O

I've written a very simple service application based on this code example.
The application as part of its normal running assumes there exists a file in the directory it is found, or in its execution path.
When I 'install' the service and then subsequently 'start' the service from the service manager in control panel. The application fails because it can't find the file to open and read from (even though the file is in the same directory as the installed executable).
My question is when a windows service is run, which is the expected running path supposed to be?
When calling 'CreateService' there only seems to be a path parameter for the binary, not for execution. Is there someway to indicate where the binary should be executed from?
I've tried this on windows vista and windows 7. Getting the same issues.
Since Windows services are run from a different context than normal user-mode applications, it's best if you don't make any assumptions about working directories or relative paths. Aside from differences in working directories, a service could run using a completely different set of permissions, etc.
Using an absolute path to the file that your service needs should avoid this problem entirely. Absolute paths will be interpreted the same regardless of the working directory, so this should make the working directory of your service irrelevant. There are several ways to go about this:
Hard-code the absolute path - This is perhaps the easiest way to avoid the problem, however it's also the least flexible. This method is probably fine for basic development and testing work, but you probably want something a bit more sophisticated before other people start using your program.
Store the absolute path in an environment variable - This gives you an extra layer of flexibility since the path can now be set to any arbitrary value and changed as needed. Since a service can run as a different user with a different set of environment variables, there are still some gotchas with this approach.
Store an absolute path in the registry - This is probably the most fool-proof method. Retrieving the path from the registry will give you the same result for all user accounts, plus this is relatively easy to set up at install time.
By default, the current directory for your Windows service is the System32 folder.
A promising solution is creating an environment variable that keeps the full path of your input location and retrieving the path from this variable at runtime.
If you use the same path as binary, you could just read binary path and modify it accordingly. But this is rather quick-fix rather than designed-solution. If I were you, I would either create system-wide environment variable and store value there, or (even better) use windows registry to store service configuration.
Note:
You will need to add Yourself some privileges using AdjustTokenPrivileges function, you can see an example here in ModifyPrivilege function.
Also be sure to use HKEY_LOCAL_MACHINE and not HKEY_CURRENT_USER. Services ar running under different user account so it's HKCU's will be different than what you can see in your registry editor.
Today I solved this problem as it was needed for some software I was developing.
As people above have said; you can hardcode the directory to a specific file - but that would mean whatever config files are needed to load would have to be placed there.
For me, this service was being installed on > 50,000 computers.
We designed it to load from directory in which the service executable is running from.
Now, this is easy enough to set up and achieve as a non-system process (I did most of my testing as a non-system process). But the thing is that the system wrapper that you used (and I used as well) uses Unicode formatting (and depends on it) so traditional ways of doing it doesn't work as well.
Commented parts of the code should explain this. There are some redundancies, I know, but I just wanted a working version when I wrote this.
Fortunately, you can just use GetModuleFileNameA to process it in ASCII format
The code I used is:
char buffer[MAX_PATH]; // create buffer
DWORD size = GetModuleFileNameA(NULL, buffer, MAX_PATH); // Get file path in ASCII
std::string configLoc; // make string
for (int i = 0; i < strlen(buffer); i++) // iterate through characters of buffer
{
if (buffer[i] == '\\') // if buffer has a '\' in it, replace with doubles
{
configLoc = configLoc + "\\\\"; // doubles needed for parsing. 4 = 2(str)
}
else
{
configLoc = configLoc + buffer[i]; // else just add char as normal
}
}
// Complete location
configLoc = configLoc.substr(0, configLoc.length() - 17); //cut the .exe off the end
//(change this to fit needs)
configLoc += "\\\\login.cfg"; // add config file to end of string
From here on, you can simple parse configLoc into a new ifsteam - and then process the contents.
Use this function to adjust the working directory of the service to be the same as the working directory of the exe it's running.
void AdjustCurrentWorkingDir() {
TCHAR szBuff[1024];
DWORD dwRet = 0;
dwRet = GetModuleFileName(NULL, szBuff, 1024); //gets path of exe
if (dwRet != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
*(_tcsrchr(szBuff, '\\') + 1) = 0; //get parent directory of exe
if (SetCurrentDirectory(szBuff) == 0) {
//Error
}
}
}

64 bit windows file opening

I'm trying to use a dialog box to open a file in my program. This works perfectly on a 32 bit system, but when I try to use it on 64 bit it is unable to open the file. I've figured out that if the file trying to be opened is in the same directory as my program, it works fine. Trying to open a file from another folder, however, doesn't work at all.
So, I tried to copy the file to the program folder. This also works fine on 32 bit but doesn't work at all on a 64 system. Any thoughts why?
char cwdl[500];
getcwd(cwdl,500);
string mystring = string(cwdl);
CFileDialog fileDlg(TRUE, NULL, NULL, OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, "All Files (*.*)|*.*||", this);
fileDlg.m_ofn.lpstrTitle = "Select New File";
if( fileDlg.DoModal() == IDOK)
{
CString newFile= fileDlg.GetFileName();
mystring+="\\"+newFile;
const char * newLoc = mystring.c_str();
CopyFile(newFile,newLoc,true);
this is just a snippet of the code.
UAC and file system redirection are related yet different.
User account control is a permissions based security to prevent unauthorized users from changing your file system or executing applications which may affect other users. The prompt allows you to override the security by providing administrator privileges temporarily if that was your intent.
File system redirection is to allow backwards compatibility with 32bit applications by having a mirrored 32bit system folders and registry. In fact if the action causes UAC to kick in redirection does not occur it will always try to use the 64bit version of the file in that case. Unless you specify the redirection directory explicitly or run the 32bit application with administrator privileges to bypass UAC.
Ok that said you are using a relative path so it will look for the file in the current directory for the process. If it's compiled as 32 bit process running it on systems with different architectures may not behave as expected due to aforementioned redirection.
You can use GetCurrentDirectory windows API to see what directory the current process is using and verify it is what you expected. If not you have a few options.
The easiest would be to use fully qualified file paths.
You could also have two builds one targeted for each architecture you intend to deploy on. After all if you're on a 64bit system you might as well deploy 64bit applications.
A more involved option would be to subclass CFileDialog and disable redirection by calling Wow64DisableWow64FsRedirection in the constructor and Wow64RevertWow64FsRedirection in the desctructor. However this is meant to be a system setting so you may get new problems by forcing your 32bit application on 64bit windows.
There are probably plenty of other options as well since there is usually many ways to skin a cat. However the first step is to put some debug code in place and verify or eliminate redirection as a culprit with GetCurrentDirectory
Maybe it's just me, but I'm seeing a strange result: in 64-bit mode, the first four bytes of the buffer used to store the location of the path, are filled with zeros.
char wk[_MAX_PATH];
char *ret = _getcwd(wk, _MAX_PATH); // wk = "\0\0\0\0C:\\MyFolder\\..."
// ret = "C:\\MyFolder\\..."
The return value OTOH is correct. "ret" points to wk + 4;
In 32-bit mode, there are no leading zeros, the path starts at the first byte. Note: this is a Multi-byte app, not Unicode.
I'm using Visual Studio 2010 (10.0.40219.1 SP1Rel).
Anyway, if you're getting the same result, that would explain why your example doesn't work. You would have to say (in 64-bit mode only):
string mystring = string(cwdl + 4); // 64-bit only
Weird or What?
Edit: Seems to be an alignment problem. Works OK if the _getcwd is in a separate function.

How to allow 32 bit apps on 64 bit windows to execute 64 bit apps provided in Windows\System32

Say you have an app, that you want to provide users ability to browse the system32 directory and execute programs in (like telnet).
What is the best method for supporting this when you need to support XP onwards as a client and 2k onwards for server?
Having written all this up I wonder if it's just too much time/effort in providing a browse to do this, where they could just copy it from explorer. Still requires ability to launch.
I have found some discussion on Nynaeve.
So far it seems there are the following options
Create a sysnative folder in windows which will allow you to browse/execute 64 bit. Issues are:
only available in Vista/Longhorn, so no support for XP 64
leads to different path naming, can't use same path on multiple versions.
will be active for whole of windows, not just our app
may not (probably is not) appropriate to do when installing the app
allows to specify explicitly through path only which version of the app to launch if there is a 32 bit and 64 bit version
Use the windows API to temporarily disable the redirection when showing file lists or executing users run commands. Issues are:
Only available on 64 bit - have to mess with GetProcAddress
available only under certain service packs
must individually identify all locations that this should be implemented
user will need to provide seperate information about whether this is a 64 bit app or 32 bit.
If anybody had some example code which displayed a Windows OpenFile dialog (say using MFC CFileDialog) showing nativly for XP/Vista and allowing the viewing of 64 bit system32 directory, that would be awesome.
If anybody had an example of launching the named app, that would also be great!
Edit:
Currently we use CreateProcess for launching the app (which is failing).
err = CreateProcess((wchar_t*)exeName.c_str(), (wchar_t*)cmdLine.c_str(), NULL, NULL, FALSE, CREATE_SEPARATE_WOW_VDM, NULL, workingDir.c_str(), &startupInfo, &processInfo);
I've gone with option 2,
For those who might be interested; here is my quick hack at a scoped version of managing the disabling of Wow64 redirection based on notes from MS. Will redirect if the API is available, expects that kernel32.dll is already available.
class Wow64RedirectOff {
typedef BOOL (WINAPI *FN_Wow64DisableWow64FsRedirection) ( __out PVOID *OldValue );
typedef BOOL (WINAPI *FN_Wow64RevertWow64FsRedirection) ( __in PVOID OldValue );
public:
Wow64RedirectOff() {
LPFN_Disable = (FN_Wow64DisableWow64FsRedirection)GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"Wow64DisableWow64FsRedirection");
if( LPFN_Disable ) {
LPFN_Disable(&OldValue);
}
}
~Wow64RedirectOff() {
if( LPFN_Disable ) {
FN_Wow64RevertWow64FsRedirection LPFN_Revert = (FN_Wow64RevertWow64FsRedirection)GetProcAddress(
GetModuleHandle(TEXT("kernel32")),"Wow64RevertWow64FsRedirection");
if( LPFN_Revert ) {
LPFN_Revert(OldValue);
}
}
}
private:
FN_Wow64DisableWow64FsRedirection LPFN_Disable;
PVOID OldValue;
};
And thus usage would be
Wow64RedirectOff scopedRedirect;
//CFileOpen
//CreateProcess
Are you getting redirected to Windows/SysWoW64? I can launch 64-bit apps from Windows/System32 from an OpenFile in a 32-bit managed executable.