I am designing a little tray tool to warn users to remove floppies / CDs from drives, but how do I stop windows from shutting down or logging off? I believe windows sends a message when a shutdown/logoff is going to happen. What is the easiest way to tell windows to not shutdown/logoff? I would like this program to work for a classroom network, or in a corporate environment.

TIA
Posted on 2004-01-20 00:16:21 by bitRAKE
from msdn

The WM_QUERYENDSESSION message is sent when the user chooses to end the session or when an application calls the ExitWindows function. If any application returns zero, the session is not ended. The system stops sending WM_QUERYENDSESSION messages as soon as one application returns zero.



There is an EWX_FORCE Flag wich will kill all applications so I think there is no guaranteed way to stop a shutdown.
Posted on 2004-01-20 01:22:49 by ENF
If you want to trap EWX_FORCE, you'll probably end up having to do a driver?
Posted on 2004-01-20 01:38:50 by f0dder

If you want to trap EWX_FORCE, you'll probably end up having to do a driver?
Thanks, I was afraid of that. :)
Posted on 2004-01-20 09:15:04 by bitRAKE
Don't think it'll be the worst possible driver though... something along turning off Copy-On-Write temporarily, overwrite ShutdownWindowsEx with a RET.

Of course things get more complicated if your intention is to disallow logoff until floppies/CD's are removed, that suddenly requires more complicated patching. The really bad thing is that there's no "global memory" on NT - systemwide API hooks are a bitch to implement. I guess I could ask around if you really need this...
Posted on 2004-01-20 10:18:39 by f0dder
f0dder, you have explained my fears well. Yes, I do want to continue once floppies/CDs/ZIP/etc are removed. I really wondered why this didn't already exist - such a good tool for schools - so many students leave their floppies in the drives. Any help is appreciated. I really wanted to get a little experience with driver programming, but thought this program would be easier to implement.
Posted on 2004-01-20 10:36:24 by bitRAKE
Well, if you find out you're going to do API hook and need add extra code, you'll need to allocate some system-wide global memory - say, to mask off the EWX_FORCE flag. I can try asking whether some persons want to share info/code how to do this, but it sounded pretty complex when they explained it to me, and I'm not sure whether they want this knowledge to spread around too much... but I can try asking :)
Posted on 2004-01-20 12:43:05 by f0dder
f0dder, if you could ask I would be very grateful. I don't really need source code, but some gentle steering as to how to make it work. It might even be obvious once I begin researching in more detail.
Posted on 2004-01-20 13:26:13 by bitRAKE
Obvious is a thing I don't think it will be ^_^
Posted on 2004-01-20 13:27:38 by f0dder

Obvious is a thing I don't think it will be ^_^
Knowing my twisted mind - who knows what I'll come up with. ;)
Posted on 2004-01-20 13:36:45 by bitRAKE
Humm, first guy I talked to didn't really know how to do it, another friend of mine might know - but if you figure out a way of doing globally visible memory, please do tell ^_^

However, I got this here idea...

It should be possible to patch the NT service/system call table (dunno the exact work). Then, you could temporarily turn off copy-on-write, patch the API address to do your new syscall, and then turn back on COW.

The advantage of doing this (if it's possible - just a crazy idea of mine :P) is that you use a well-defined r3->r0 transition, and can end up in your driver code (from where you could use PoolAlloc or whatever if you needed dynamic code addition).

When calling the original API, you need to patch back the original bytes. In the case of ExitWindowsEx, this shouldn't be a problem... for generic API hooking though, it coulde be troublesome - you could miss some API calls.

To handle this, something like the following approach could be taken: disassemble opcodes until you have bytesize>=size_of_syscall - reconstruct those opcodes, possible relocating them, to... somewhere else. Probably wouldn't do any good to have it in driver code, since you really do need to call the code from ring3... and then we have the problem of global memory alloc again :)
Posted on 2004-01-20 14:04:27 by f0dder
f0dder, that sounds crazy. I'm going to look for a way to do it without globally visible memory, but will fall back on your advice as needed, thank you again.
Posted on 2004-01-20 15:22:13 by bitRAKE
Why don't you just hook this API in explorer.exe? Why global?
Posted on 2004-01-20 16:00:44 by comrade
comrade, that might work pretty well... however...
there can be multiple explorer processes - just hook the first one? What if the shell crashes and is restarted?

That could be worked around, though, if you just want to trap "start menu -> shutdown".
Posted on 2004-01-20 16:03:52 by f0dder
There is usually one explorer.exe process, and even if there are multiple, first one is most likely the taskbar. If explorer crashes, I think something restarts automatically - hook CreateProcess in that something :)
Posted on 2004-01-20 16:57:20 by comrade
There is also the possibility that something like a installer may need to restart the system meaning it wouldn't be caught.

Perhpas the user32.dll file could be patched on disk? The patched api code could be placed in a new section or added to the spare space at the end of a section.
Posted on 2004-01-20 16:57:22 by ENF
causes problems with WFP
EDIT: besides it's probably illegal to patch those files, *sigh*
EDIT2: not to mention that you can't do this while the system is running - memory patch is probably the best.
Posted on 2004-01-20 16:59:25 by f0dder
Hi All

>but if you figure out a way of doing globally visible memory, please do tell ^_^

>It should be possible to patch the NT service/system call table


Might this not be a more or less 'accepted' (term used loosely) way now of hooking Int2E-directed API calls globally, by patching the System Service Dispatch Table? 'Tis the way Regmon does it (see Regmon source), I've also seen it in Strace (monitors all Int2E calls). Sure, it requires a driver, and some checking of specific OS/service pack ServiceId numbers, but at some point "undocumented" becomes "semi-documented", becomes "hey, this has been in the literature for some time now, let's pretend M$ isn't going to close this door" (I did say "pretend", so don't bash me f0dder ;-))

I did a quick check of ExitWindowsEx, it's a user32.dll API which eventually calls Int2E with ServiceId of 1139h (Win2k sp3). If you were to hook this service for example, or as a start, I'm sure it could be an effective strategy. Might not be what bitRAKE is looking for in a tray tool, but depending on your application of it...


Just wanted to mention also, regarding globally visible memory, not sure if this meets the definition but...

Recently I posted a small example of adding new Int2E Services to the aforementioned System Service Dispatch Table, this was simply my own implementation of the idea put forth by Prasad Dabak. These new user defined service addresses are simply added to the end of a copy of the dispatch table, and as far as I can tell are valid globally from either user mode or kernel mode, as long as the original driver which installed them is still active of course.


For example, Win2K has 0F8h NTOSKRNL services (0-indexed, ServiceId's < 1000). My example app adds two blank ones with new ServiceId's of F8h and F9h. I can call either one of these services from user mode from a completely different application with the following code:
[size=12]

; Test new user defined Int2E service created in another app

push 2 ; param 2
push 1 ; param 1
mov eax, 0F8h ; service ID of the requested system service in EAX
mov edx, esp ; stack frame of the parameters in EDX
int 2eh

add esp, 4*2 ; balance stack for number of parameter dwords pushed

; use the return value from the new service
lea eax, [eax]
...
[/size]


Since you can create the service with as many parameters as you wish, and write anything you want within this driver memory, I would think one could tailor it to be somewhat multi-use. There might be some limitations to this idea, for example the 'external' app which calls the new service must have a GUI component (or call some user32 API), due to the fact the "Shadow" ServiceDescriptorTable is the one being rewritten, but it might be a strategy for interprocess communication.

One might be able to extend the IPC idea a little further through this potential Int2E conduit. I'm just surmising at the moment, if I had a few minutes I'd test it, but if for example a block of usermode data in App1 was mapped into kernel mode as an MDL (shared block of memory), and this non-paged memory was part of a new Int2E function, then this memory should also be available from App2 (at least indirectly).

For the example and further explanation of adding new NT services, see the following thread if interested, including Four-F's comments and attachment,

http://www.asmcommunity.net/board/showthread.php?threadid=16393

Kayaker
Posted on 2004-01-20 21:48:48 by Kayaker

I did say "pretend", so don't bash me f0dder ;-)

;-) - I'm not going to, since you acknowledge the potential problems of using stuff that's not officially documented.

Requiring a driver isn't bad, imo. And using the dispatch table does seem like an efficient way of handling things - thing is, afaik, there's not a 1:1 correspondence between API calls and the system calls. This shouldn't be a problem in bitRAKE's case, but you can't use this approach for generic API hooking...


and as far as I can tell are valid globally from either user mode or kernel mode

Thanks for confirming my wild guess :). Problem is that while it can give you (useful) global access to executing code, it's still not "globally accessible memory" in the sense that you have an address you could call/jmp from any process - which would be a very nice feature to have.


but if for example a block of usermode data in App1 was mapped into kernel mode as an MDL (shared block of memory), and this non-paged memory was part of a new Int2E function, then this memory should also be available from App2 (at least indirectly).

Well, that's where things start to sound interesting. All processes share the same view of the upper 2GB (or 1GB, depending on boot flags on adv. server) of memory, the "kernel region", right? And memory allocated by a driver would go in this region too? If that's true, couldn't one allocate some kernel memory, and mark it as user accessible?
Posted on 2004-01-21 08:10:28 by f0dder
an ugly but may be doable sulotion without the aid of any driver or time wasting code :P
if u 'log off' / restatr ur computer u see this little window with 3 buttons + cancle button.
this is prolly just a stand-alone dialog with a thin border & bitmaps.
each button show have an id which can be found, the window has an handle too,
u can make a tray prog which monitors when ever the buttons has been pressed and do whatever u want if a floppy is in or not..
it may work :P
Posted on 2004-01-21 14:26:44 by wizzra