CopyFile2 not getting detoured - c++

I am stuck. For some reason, I need to block Copy feature of the file system on Windows 8.
Till Windows 7, ShFileOperation & CopyFile used to do trick. However, with Windows 8, as I could scan through API monitor, a new API: CopyFile2, has been used to do the job. So I need to detour CopyFile2.
I tried doing this using Detour 2.x & 3.x along windows SDK 6.x, 7.x and Win8 SDK. Following is the code snippet -
HRESULT (WINAPI *Trampoline_CopyFile2)(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters) = CopyFile2;
HRESULT WINAPI Detour_CopyFile2(PCWSTR pwszExistingFileName, PCWSTR pwszNewFileName, COPYFILE2_EXTENDED_PARAMETERS *pExtendedParameters)
{
OutputDebugString(L"Inside TrozenCopyFile...");
return Trampoline_CopyFile2(pwszExistingFileName, pwszNewFileName, pExtendedParameters);
}
//Attaching Detour
DetourAttach( &(PVOID&)Trampoline_CopyFile2, (PVOID)Detour_CopyFile2);
DetourAttach returns 0(Successful), but I do not receive call to my Trampoline function.
I know my dll is getting loaded in Explorer because other APIs are getting detoured - and I have checked it in ProcessExplorer too.
Does microsoft Detour Library support win8 APIs? If yes, am I doing anything wrong? If No, shall I report this as a bug?
--
Further more, I create a sample application calls CopyFile2. My Dll is getting loaded and DetourAttach is returning 0. However, I am still unable to get traces to Detour_CopyFile2

Related

C++ SetupApi SetupDiGetDeviceRegistryProperty SPDRP_DEVTYPE fails

I have C++ code (works well with VS6 up to VS2017) that enumerates USB devices and retrieves several properties. I recently added SPDRP_DEVTYPE:
SetupDiGetDeviceRegistryProperty(hDevInfo, &DevData, SPDRP_DEVTYPE, 0L, (BYTE*) &dwData, 4, 0);
The call returns with 'false' and GetLastError() then returns 13 ("The data is invalid"). The same happens when trying to query for SPDRP_CHARACTERISTICS.
Most other PropertyKey values I have tried work well (for example, SPDRP_CAPABILITIES, SPDRP_PHYSICAL_DEVICE_OBJECT_NAME, SPDRP_FRIENDLYNAME, and so on) but these two keep failing.
Running the EXE as administrator does not change anything. I tested on Windows 7 (32/64) and on Windows 10.
In addition, I tried to open the device with CreateFile (which succeeds) and then use DeviceIoControl(), but every call to DeviceIoControl fails with Error 50 "not supported"
Any idea why these calls are not working?

LoadLibrary() : How to handle invalid DLLs?

I have an application that relies heavily on plugins.
On startup it scans a directory for DLLs and loads them one by one, looking for ones that implement a certain exported function. However - if someone were to rename a different type of file to *.dll and put it in the directory, that file would then also be loaded by LoadLibrary(). LoadLibrary() doesn't like that and produces an error [dialog].
Is there a way to simply ignore invalid / incompatible .dll files (either detecting them prior to the call or have LoadLibrary() return NULL rather than throwing a fit)?
You need to set the error mode for your process. Do this once and for all at startup:
UINT oldMode = SetErrorMode(0);
SetErrorMode(oldMode | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
After you've set the process error mode, when LoadLibrary fails no dialog box will be displayed and LoadLibrary will return NULL.
The documentation says:
Best practice is that all applications call the process-wide SetErrorMode function with a parameter of SEM_FAILCRITICALERRORS at startup. This is to prevent error mode dialogs from hanging the application.
I also recommend adding SEM_NOOPENFILEERRORBOX for reasons that I guess should be obvious.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms684175%28v=vs.85%29.aspx
Remarks
To enable or disable error messages displayed by the loader during DLL loads, use the SetErrorMode function.
Don't forget to restore the error mode after you are finished.
If you wanted to do this yourself, in a primitive manner you could parse the PE header to identify obvious cases of bad DLL files, however it is not really possible to determine if a DLL is valid and loadable without a full PE loader which requires a lot of work and is already built into the operating system.
Updated answer after feedback in comments from djgandy and Remy Lebeau. Now a complete
function, better preservation of error mode at entry:
// This function will load the DLL named by pszPath if it is a valid library.
// If the function succeeds, it will return a valid HMODULE for the DLL. This
// handle should be passed to FreeLibrary when it is no longer needed.
// If the function fails, it will return NULL and no annoying dialog boxes will
// be displayed. It is therefore up to the caller to notify the user about what
// happened or take any other appropriate action. The reason for failure can
// be obtained from GetLastError(). Common problems:
// ERROR_BAD_EXE_FORMAT - Bad DLL (tested function with text file)
// ERROR_MOD_NOT_FOUND - Missing DLL (tested with file that did not exist)
//
// Module-loading functions can return several other errors, look at winerror.h
// list starting at ERROR_INVALID_MODULETYPE
//
// Obviously, since it's just a wrapper around LoadLibrary this function is not
// safe to call from DllMain.
//
// NB: GetErrorMode() is only available on Vista / Server 2003 or later.
HMODULE LoadLibraryIfValid(LPCTSTR pszPath)
{
HMODULE hModule = NULL;
UINT prevErrorMode = GetErrorMode();
SetErrorMode(prevErrorMode | SEM_FAILCRITICALERRORS);
hModule = LoadLibrary(pszPath);
SetErrorMode(prevErrorMode);
return hModule;
}
If targeting Windows 7 / Server 2008 R2 or later, the Get/SetThreadErrorMode()
functions are available, but might not be worth it or even a good alternative
(discussion in comments, below)
If anyone cared enough to put the time into it (I sure don't), a version of
this function could easily be written using GetModuleHandle for kernel32 and
GetProcAddress to be compatible with earlier versions of Windows as well as
provide a global/per-thread error mode option for platforms that support it
(truly pointless because it's only changed for the duration of one call anyway).
This is the largest commentary-to-code ratio in my life.

Detect emptiness of DVD-RAM media on Windows 7 x64

I'm trying to detect if a DVD-RAM media is empty or not, with C++ on Windows. The simplest choice is to use IMAPI (version 2) - boilerplate code omitted:
IMAPI_FORMAT2_DATA_MEDIA_STATE state;
HRESULT hr;
// ... Initialize an MsftDiscFormat2Data COM object and put recorder
hr = format->get_CurrentMediaStatus( &state );
// ... Verify returned status ...
return (state & IMAPI_FORMAT2_DATA_MEDIA_STATE_BLANK);
This code usually works perfectly. However, with DVD-RAM it gives the wrong results: the only flag enabled in the returned state is IMAPI_FORMAT2_DATA_MEDIA_STATE_OVERWRITE_ONLY ( = 0x1).
On Windows Vista 32 bit it works as expected.
Does anyone knows the reason for this result? Is there any workaround?
You can use the method IDiscFormat2::get_MediaHeuristicallyBlank from IDiscFormat2 interface.
It will attempt to determine if the media is blank using heuristics (mainly for DVD+RW and DVD-RAM media).
VARIANT_BOOL vbBlank;
hr = format->get_MediaHeuristicallyBlank(&vbBlank);
if (VARIANT_TRUE == vbBlank)
Log("The media is blank.");
In order to determine if the current media is reported as physically blank by the drive you can use IDiscFormat2::get_MediaPhysicallyBlank method.
As for the reasons of the different behavior between Windows7 x64 and Windows Vista x86, it could be because IMAPIv2 versions may be different on those systems. You may want to update your Vista machine with the latest Image Mastering API v2.0 update package to get the same results on each system.

How to set the application path to the running program?

I have a program that is executed by another program. The program that is being executed needs files located at its own location [same folder]. If I call myfile.open("xpo.dll") I might get an error because I am not passing the [fullpath + name + extension]. The program that is being executed can vary paths depending on the installation path. Therefore, I was wondering if there is a way to get the application path [where the application is located] and set it so that when another program executes from another path everything might work properly...?
[Using C++ without .NET Framework]
Thanks.
Use GetModuleFileName and pass NULL for hModule.
DWORD GetModuleFileName(
HMODULE hModule, // handle to module
LPTSTR lpFilename, // path buffer
DWORD nSize // size of buffer
);
First off, I run into this problem in other languages a lot, and find Process Monitor (http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx) very useful for finding out what folder it is currently trying to access.
There is no standard function for doing this.
Just a thought, have you tried doing myfile.open "./xpo.dll"?
If it's a console application, you can use the POSIX getcwd function: http://www.dreamincode.net/code/snippet77.htm
If it's a Windows app and you can use the windows API, you can use GetModuleFileName... see the second reply to this question here: How do I get the directory that a program is running from?

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.