I am working on a project to prevent applications from being launched from removable devices.
Does anyone out there know how i can do this? Preferrably in C++ on the Windows platform.
My aim is to prevent execution of the exe file even if the user double clicks it or even if he tries to launch it from the command line.
Assuming that you wish to stop ANY process launching from a removable drive, this seems to be an application for a shell hook. I wrote the following code over the last half-hour, and it seems to test out OK. Bear in mind that writing a hook is a non-trivial process, and a global hook requires that a DLL be written. This is the relevant guts of the hook DLL:
BOOL __declspec(dllexport) __stdcall InstallShellHook ()
{
lpfnHookProc = (HOOKPROC) ShellFunc ;
BOOL bRetVal = FALSE;
if (hShellHook == NULL)
{
hShellHook = SetWindowsHookEx (WH_SHELL,
lpfnHookProc,
hInstance,
NULL);
return TRUE;
}
return FALSE;
}
LRESULT CALLBACK ShellFunc(int nCode, WPARAM wParam, LPARAM lParam)
{
HWND hWndNew;
char szBuff [_MAX_PATH];
char szDrive [_MAX_DRIVE];
switch (nCode)
{
case HSHELL_WINDOWCREATED:
hWndNew = (HWND)wParam;
GetWindowModuleFileName (hWndNew, szBuff, _MAX_PATH);
_splitpath (szBuff, szDrive, NULL, NULL, NULL);
if (GetDriveType (szDrive) == DRIVE_REMOVABLE)
{
PostMessage (hWndNew, WM_CLOSE, 0, 0);
}
break;
default:
break;
}
return 0;
}
I have tested this code, installed from a simple dialog testbed, and it allows me to launch any windowed application from my hard drive, but immediately closes any I launch from a USB key.
Note that this solution works for all GUI processes (i.e. non-console), but requires that they respond to WM_CLOSE on a top-level window. A more aggressive general solution would probably require you to resolve the hwnd into a hprocess and call TerminateProcess: the solution I have provided is "kinder" (linked DLLs will get unloaded etc), but less general.
If you want to know the basics of writing a system-wide hook, you can find them on my website here. Note that the above isn't production-quality code, I hacked it into an old ANSI dll I had laying around, hence the lack of support for Unicode, or anything approaching decent debug capability. It shows the basic idea though.
Your network admin can take care of that without you needing to write any code. We implemented exactly that same thing here to prevent the possibility of employees copying customers private information to removable devices and the network admin implemented it himself without us here in the dev dept needing to do anything. I don't know if that would work in your situation but it's worth considering.
You can write snippet that returns from Main method if the current disk type is removable device.
Call GetCurrentDirectory split disk name and use WMI(this can help) or even better GetDriveType(this can help here) method to know is it on removable disk or not
Seems to me you are looking for a generic way to stop any app being launched off the device from an application that is already running.
So essentially three issues:
1. Detecting the new application has started
2. Checking what type of device it is running off
3. Forcing the app to die if you don't want it
Part 1: This is the difficult party I think you need to either poll on a regular basis using EnumProcess which isn't great or just check applications which generate a WM_ACTIVATEAPP
Part 2: ArsenMkrt's Solution seems appropriate for this
Part 3: TerminateProcess should do it for you
Related
I'm trying to create a simple application to record and playback a series of keyboard and mouse commands (macros). Read the documentation and concluded that the most suitable implementation (if not the only one) would be to set a Windows journal record hook (WH_JOURNALRECORD) and play it back with a journal playback one (WH_JOURNAL_PLAYBACK).
According to the documentation, these hooks don't need to reside in a DLL, instead they can be in an executable (application). So, I had the Visual Studio creating a simple Win32 application for me. It's a very classic application, registering a window class, creating the window, and running a message-loop. The documentation also mentions that the hook procedures for WH_JOURNALRECORD/WH_JOURNAL_PLAYBACK hooks run in the context of the thread that set them. However, it doesn't specifically mention what this thread should be doing, eg run a message-loop, sleep in an alertable state or what. So I just set the hook and run the message loop - it's the application's main and only thread. It's what some code samples I found also do, albeit they don't seem to work as of now, as they are quite old, and some Windows security updates have made things quite more difficult.
I believe I have taken all the necessary steps I have found in some samples and posts:
Set the Manifest options "UAC Execution Level" to "requireAdministrator (/level='requireAdministrator')" and "UAC Bypass UI Protection" to "Yes (/uiAccess='true')".
Created and installed a certificate - the application is signed with it after built.
The executable is copied to System32 (trusted folder) and run from there "As Administator".
Without the above actions, installation of the hook fails, with an error-code of 5 (Access denied).
I have managed to successfully (?) install the WH_JOURNALRECORD hook (SetWindowsHookEx() returns a non-zero handle), however the hook procedure is not called.
Below is my code (I have omitted the window class registration, window creation, window procedure and About dialog stuff, as there is nothing interesting or special in there - they do just the barebones):
// Not sure if these are needed, found it in some code samples
#pragma comment(linker, "/SECTION:.SHARED,RWS")
#pragma data_seg(".SHARED")
HHOOK hhJournal = NULL;
#pragma data_seg()
// Not sure if the Journal proc needs to be exported
__declspec(dllexport) LRESULT CALLBACK _JournalRProc(_In_ int code, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
Beep(1000, 30); // Clumsy way to trace the JournalRProc calls
return CallNextHookEx(NULL, code, wParam, lParam);
}
void AddKMHooks(HMODULE _hMod)
{
if (hhJournal) return;
MessageBox(NULL, "Adding Hooks", szTitle, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
hhJournal = SetWindowsHookEx(WH_JOURNALRECORD, _JournalRProc, _hMod, 0);
if (!hhJournal)
{
CHAR s[100];
wsprintf(s, "Record Journal Hook Failed!\nThe Error-Code was %d", GetLastError());
MessageBox(NULL, s, szTitle, MB_OK | MB_ICONSTOP | MB_TASKMODAL);
}
}
void RemoveKMHooks()
{
if (!hhJournal) return;
MessageBox(NULL, "Removing Hooks", szTitle, MB_OK | MB_ICONINFORMATION | MB_TASKMODAL);
UnhookWindowsHookEx(hhJournal);
hhJournal = NULL;
}
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
// TODO: Place code here.
// Initialize global strings
LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
LoadString(hInstance, IDC_KMRECORD, szWindowClass, MAX_LOADSTRING);
MyRegisterClass(hInstance);
// Perform application initialization:
if (!InitInstance(hInstance, nCmdShow)) return FALSE;
HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_KMRECORD));
AddKMHooks(hInstance);
// Calling AddKMHooks(GetModuleHandle(NULL)) instead, delivers the same results
MSG msg;
// Main message loop:
while (GetMessage(&msg, nullptr, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
// Once the hook has is set the GetMessage() call above
// always returns a WM_TIMER message with a timer ID of 1,
// posted to the queue with the PostMessage() function,
// as the Spy++ tool reports
RemoveKMHooks();
return (int) msg.wParam;
}
I monitored the application with the Spy++ tool, and found that when the hook is set, the application receives a series of successive WM_TIMER timer messages, with a timer ID of 1, posted to the queue with the PostMessage() function (P in Spy++). The window handle for these messages is reported to belong to the same application and thread as the main window, and its class name is "UserAdapterWindowClass". My code neither creates timers nor explicitly creates any window of this class, so apparently these are created by the system. Also, there is another message, with an ID of 0x0060 (Unknown!), posted to the same window only once, after the 1st or 2nd WM_TIMER one.
The application appears to somehow "lock" the system (recording, waiting for a resource, or what?), until I press Alt+Ctrl+Del, which the documentation says stops recording (I have not yet implemented some mechanism to stop recording/uninstall the hook at will, so this is what I use so far). The hook procedure seems to never be called, and this is the problem I'm facing at this point. I have considered examining the code parameter in the hook procedure and act accordingly, but I'm not even close to this, as the procedure is never called - and therefore it would have no effect - so I just call CallNextHookEx() in there (and assume it would work well).
Notes:
The hook procedure may occasionally be called just once, but it's rather rare (almost non-reproducible) and definitely not consistent, so I think I can't rely on this; the code parameter is 0 (HC_ACTION). Tested it though, and returning either zero or non-zero, either calling CallNextHookEx() or not, makes no difference at all.
I have also tried to set the hook in another thread (created after the main one has started processing messages), which then as well runs a message-loop, but I get exactly the same behavior.
Could someone please explain what may be wrong here? Checked some other posts too, esp these ones: SetWindowsHookEx for WH_JOURNALRECORD fails under Vista/Windows 7 and WH_JOURNALRECORD hook in Windows (C++) - Callback never called. , however couldn't find a solution, and I have to note that the usage conditions differ too. What I'm experiencing is closest to this SetWindowsHookEx(WH_JOURNALRECORD, ..) sometimes hang the system though in my case this happens always, not just "sometimes".
I would greatly appreciate any help.
I have uploaded the solution (sources + VS files, but not the .exe, .obj., .pch, .pdb etc file, so a rebuild is required) here, if anyone would like to take a look.
Thank you in advance
EDIT:
Tested the application under different configurations.
Initially, the application was created in Visual Studio 2017, and tested under a Windows 10 Pro 32-bit version 1803, 2-core AMD processor computer (VS2017 is installed on this machine). Got the results described above.
Then tested under a Windows 10 Pro 64-bit version 1903, 4-core AMD processor computer. This machine had a very old version of Visual Studio installed (although it was not involved in development and testing in any way). Installed the certificate and run the application (both created on the other machine). Initially the result was the same (hook proc never called).
Tried deleting the certificate from the "PrivateCertStore" store location, leaving only the copy under "Trusted Root Certification Authorities" (this is the way the batch file I wrote, calling makecert and certmgr, stores the certificate, ie under both the above locations). Unexpected, but it worked, got multiple beeps as I moved the mouse! Tested it again, adding/removing/moving the certificate and the behaviour was fully reproducible: the certificate needed to be installed under "Trusted Root Certification Authorities" only, for the hook to work.
Then repeated the above test on the 32-bit machine. It didn't work there, the application was "frozen" as before (getting only WM_TIMER messages).
On the 64-bit machine, uninstalled the old VS version and quite a few Windows SDK versions installed there, and installed VS 2019 Community Edition. Rebuilt the application in VS2019 (created and installed the certificate anew, and signed the executable). The application now does not work under either machine (again, hook creation succeeds, but the hook proc is not called). Maybe the VS2019 installation, or some Windows Update has caused this.
Identically, the application/certificate created on the 32-bit machine does not work under either machine now.
So it must be a Windows module or some requirements about the certificates which I don't meet, that cause this. Seacrhed on the internet a lot, but can't find which specs the certificate must conform to. For example, what are the requirement about the format, private key or the purposes (now I have all purposes checked, altough I also tried checking only Code Signing, which made no differnce). The makecert utility is now deprecated (the documentation suggests creating certificates with PowerShell instead) but I don't know if this is somehow related to my problem.
I have only come to two conclusions:
- The certificate must be installed under "PrivateCertStore", for the application to be possible to be built (otherwise signing fails). Possibly because I have the /s PrivateCertStore option set in my script. But,
- The certificate must be installed under "Trusted Root Certification Authorities", for the application to be able to be run (otherwise execution fails, with an access-denied error).
I have tried doing things like...
const char *MessageBoxText = "";
DWORD WINAPI CreateMessageBox(LPVOID lpParam){
MessageBox(NULL, MessageBoxText, "", MB_OK|MB_APPLMODAL);
return TRUE;
}
MessageBoxText = "Blah, Blah, Blah...";
CreateThread(NULL, 0, &CreateMessageBox, NULL, 0, NULL);
However, this does not seem to work correctly for the task I am trying to perform.
What is the best way to create a thread for a message box, without having it glitch up?
Consider passing message text as thread parameter instead of global variable, to make code thread-safe.
DWORD WINAPI CreateMessageBox(LPVOID lpParam) {
MessageBoxA(NULL, (char*)lpParam, "", MB_OK);
return 0;
}
CreateThread(NULL, 0, &CreateMessageBox, "Blah, Blah, Blah...", 0, NULL);
Also, you don't need to specify MB_APPLMODAL as it's default flag (it equals to 0).
If you are targeting modern Windows OS, it's better to have UNICODE defined, because MessageBoxA will convert you strings to UTF-16 and call MessageBoxW
What is the best way to create a thread for a message box, without having it glitch up?
In general, you don't.
Under Windows, all the windows (small 'w', meaning individual GUI elements here) in an application "run" in a single thread. This is generally the "main" thread -- but in particular, it is the thread in which the message pump is running. See my linked post for more details on the message pump.
If what you are truly trying to achieve is a dialog box or some other kind of window that can run concurrently to other windows running, so that it can remain up while other windows are still responsive to user input, then you want a modeless window or dialog box. This is a window that doesn't block other windows from processing updates or accepting user input. See here for a description of how to implement this using MFC, but note that you don't need to use MFC in order to implement a modeless dialog box.
Old question, new answer...
If the thread being invoked is being called into existence by a process that immediately exits (say you're running an executable that uses a VC++ DLL which pops a message box) then the thread will never have a chance to execute.
I had created a VC++ executable for testing that ran a loadlibrary on my DLL and the DLL created various threads with debugging message boxes. Since my testing executable only called the DLL and then exited, it didn't work.
I was informed by a coworker that I needed to add a sleep to the end of the testing executable that is using the DLL file in order for it to work.
Sure enough, it fixed it. This makes sense too, especially in the context of a DLL. Most applications loop until instructed to exit; my test application did not.
Be mindful of how your application is behaving!
If my application crashes, I use an ExceptionFilter to catch the crash, perform some final actions, then show a message box to the user that the application has crashed.
Because the application already crashed, there's not much I can (or I dare) to do, because if I do too much, the executed code might access corrupted memory and crash again.
Some of the things I currently can't do (or I don't dare to do) is to close network connections, Oracle database sessions, ...
Problem is that if an application crashes, and the user is out to lunch while the MessageBox is open, other users might be blocked, because of the open database session. Therefore I want:
Either a MessageBox with a time-out. Problem is that you can't do this with the standard MessageBox Win32 API function, and I don't want to make a specific dialog for it (because I want to minimize the executed logic after the crash)
Or the possibility to close the MessageBox from another thread (the other thread can provide the time-out logic).
Did I overlook something in the Win32 API and is there a possibility to have a MessageBox with a time-out?
Or what is the correct way to close an open MessageBox from another thread (how to get the MessageBox handle, how to close it, ...)?
While I agree that spawning a new process to display a fire-and-forget dialog is probably best, FWIW there is actually a timeoutable messagebox function exported from user32 on XP & above; MessageBoxTimeout (as used by things like WShell.Popup())
Quick copy/paste solution:
int DU_MessageBoxTimeout(HWND hWnd, const WCHAR* sText, const WCHAR* sCaption, UINT uType, DWORD dwMilliseconds)
{
// Displays a message box, and dismisses it after the specified timeout.
typedef int(__stdcall *MSGBOXWAPI)(IN HWND hWnd, IN LPCWSTR lpText, IN LPCWSTR lpCaption, IN UINT uType, IN WORD wLanguageId, IN DWORD dwMilliseconds);
int iResult;
HMODULE hUser32 = LoadLibraryA("user32.dll");
if (hUser32)
{
auto MessageBoxTimeoutW = (MSGBOXWAPI)GetProcAddress(hUser32, "MessageBoxTimeoutW");
iResult = MessageBoxTimeoutW(hWnd, sText, sCaption, uType, 0, dwMilliseconds);
FreeLibrary(hUser32);
}
else
iResult = MessageBox(hWnd, sText, sCaption, uType); // oups, fallback to the standard function!
return iResult;
}
You should ask yourself, why you want a messagebox in the first place. When it is OK that the message box is not seen when noone is sitting in front of the computer, why isn't it OK that the user doesn't see a message when his program disappears?
If you really want it, I think the simplest solution is to spawn a new process displaying the message. It can run as long as it wants and does not interfer with your crashing program.
I noticed that if the main thread simply exits the application while the other thread still has the ::MessageBox open, that the MessageBox is being adopted by a process called CSRSS. This solves my problem, since this only requires a time-out on the Event in the main thread (WaitForSingleObject with timeout).
However, this raised another question: https://stackoverflow.com/questions/3091915/explanation-why-messagebox-of-exited-application-is-adopted-by-winsrv.
This does not justify a thread.
The best solution would be to use a modal dialog box that registers a timer for auto-close.
What about just logging the event to a local file (and record memory dumps or whatever information you might need for later debugging)?
You could close your application, close network connections and do your housekeeping stuff.
As soon as the application is started again, you can inform your user (based on local file information) that the application has crashed during last execution.
A Win32 MessageBox really is a dialog, with a dialog message pump. You can therefore rely on standard Win32 timer messages (WM_TIMER). Send one to your own window, and when you do get it, dismiss the MessageBox by sending a WM_COMMAND/BN_CLICKED message to the ID_OK button.
The messagebox, since it's a dialog, will be class "#32770". Since it's the only dialog box you will have open, it's easy to find amongst your child windows.
I would run your original code from inside a wrapper application that does a CreateProcess and then a MsgWaitForMultipleObjects on the process handle (most process launching code samples use WaitForSingleObject, but you need to guard against messaging deadlock scenarios). Your watching process can then detect the failure of the spawned process, pop up its own timed-out dialog, and exit on user response or timeout.
I think that's the cleanest solution which prevents your unstable program having to execute any code.
I'm trying to find a way to detect when focus is changed to another window (without having to poll every X ms).
I've already figured out a way to detect when focus is switched between applications using WH_SHELL and HSHELL_ACTIVATESHELLWINDOW.
The problem is I want to detect when focus is switched between dialog/windows within the same app.
ie. In Notepad, I can determine when the app switches to Notepad, but I cannot detect when the "Open" or "Save" dialogs appear because the focus is still within the same application.
You can use SetWindowsHookEx with a WH_CBT hook type. If you just want to detect focus changes within an application, pass GetCurrentThreadId() as the last parameter, otherwise the hook will be for all threads on the current desktop.
Note that using windows hooks can have an adverse effect on system performance, so the hook should only be installed when necessary and you should do a minimum amount of work in the hook procedure.
Sorry for the delay, I don't have VS installed on this computer so it's a bit hard to find the code.
Use this to hook your code into the system.
HHOOK oldShellHook = SetWindowsHookEx(WH_SHELL, BCK_WndShellProc, hDll, NULL);
if (!info->oldShellHook) {
MessageBox(m_hwnd, L"Failed to load global hook.", strTitle, MB_OK | MB_ICONERROR);
return;
}
And this your hook. Depending on what you're doing, use nMsg to figure out when you want to apply your custom logic.
LRESULT CALLBACK BCK_WndShellProc(int nMsg, WPARAM wParam, LPARAM lParam) {
...
}
Read the MSDN docs for SetWindowsHookEx() to make sure you return the expected values, otherwise you can lock up the whole system.
I use code similar to this on my Breadcrumb Killer and Spasm (Show all programs on Start menu) programs and it seems to work fine.
How about the "Computer Based Training API"; SetWindowsHookEx with WH_CBT which will enable you to receive HCBT_SETFOCUS (among others)
From the native Win32 API using C++ is there a way to determine whether the window associated with an HWND is still valid?
You could use the Win32 API IsWindow.
It is not recommended to use it though for 2 reasons:
Windows handles can be re-used once the window is destroyed, so you don't know if you have a handle to an entirely different window or not.
The state could change directly after this call and you will think it is valid, but it may really not be valid.
From MSDN (same link as above):
A thread should not use IsWindow for a
window that it did not create because
the window could be destroyed after
this function was called. Further,
because window handles are recycled
the handle could even point to a
different window.
What can be done?
Perhaps your problem can be re-architected so that you do not have the need to check for a valid handle. Maybe for example you can establish a pipe from the client to the server.
You could also create a windows hook to detect when certain messages occur, but this is probably overkill for most needs.
This question is old, but I needed this functionality myself and was a bit disappointed after reading about the caveats. However, after doing a bit more digging it seems that all is well. Unless you're dealing with 16bit programs, IsWindow appears to be the way to go. The problem of handle re-use appears to have been sufficiently addressed according to this:
http://blogs.msdn.com/b/oldnewthing/archive/2007/07/17/3903614.aspx
So, because of the upper 16bit reuse counter, it is highly unlikely that you'll run into a window reuse problem.
You can use IsWindow() or also try to send the window a WM_NULL message with SendMessage(hWnd, WM_NULL) and see if it is successful.
Also, it is true that the window could be destroyed at any time if it isn't under your control. As others have stated the handle could potentially belong to another window as the handles are reused. In reality I don't know how likely that is.
The only solution that I know of the to create a system wide hook that looks for messages indicating a window is destroyed (WM_CLOSE, WM_DESTROY). Then you would compare the message window handle to ones you are holding to see if any of the windows you care about are affected. See here for more information on system wide hooks.
Maybe a combination of IsWindow, FindWindow and GetWindowThreadProcessId will be more accurate
HWND windowHandle = FindWindow(NULL, TEXT("window_title"));
LPDWORD oldpid = 0;
GetWindowThreadProcessId(windowHandle, &oldpid);
//after some time
if (IsWindow(windowHandle))
{
LPDWORD newpid = 0;
GetWindowThreadProcessId(windowHandle, &newpid);
if (newpid == oldpid)
{
//the window is still running
}else
{
//the window exists but has changed
}
}
If the window procedure for the window in question is under your control (or if you can subclass it), then I would suggest registering a custom message that the window responds to with a non-zero result. Sending that message to any other window (or an invalid HWND) will result in 0.
Of course, that only tells you if the HWND refers to one of the windows that you control -- but perhaps given other answers above that might even be advantageous.
Use RegisterWindowMessage to register the message, using a sufficiently unique name.
if(IsWindow(FindWindow(NULL , TEXT("Example Window Name")))){
// do stuff
}
will check if the window exists and has the appropriate name