Link to home
Start Free TrialLog in
Avatar of dave_p_r_b
dave_p_r_b

asked on

preventing program execution

Dear genii, (genius - plural??)
I need to write a program to stop programs executing!

I've done research but seem to come accross problems with every idea possible solution i find.

I thought about using PsSetCreateProcessNotifyRoutine, but this seems to be called after the program has been started. if this is the case, then I'd need to terminate the program, which is obviously not a good idea. I need to sneak in somewhere between a request for, say, word.exe and the actual running of word.exe.

Then there's API hooking... system-wide API interceptor that monitors calls made to the CreateProcess function. But, from what I've heard, this doesnt cover all ways that the process can be started.

Then there's IAT (Import Address Table) Patching. Which is way beyond me! I'm just an MFC programmer who has been dropped into the world of system programming.

If anyone could tell me if there is an accepted method for doing this, it would be greatly appreciated. I'm already grey haired and I'm fast approaching baldnes...

cheers,
d.
Avatar of Salte
Salte

One way you can do it is to do this:

Create a DLL and implement functions that are called foo() for EVERY Win32 system function exported by kernel32.exe. Same arguments and same name - EXACTLY.

Upon initialization, load the real kernel32.exe and map pointers to all the functions in it. Afraid you have to do this dynamically since you otherwise would get name clash between your foo() and kernel32.exe's foo() function.

Have your DLL named kernel32.exe and place it in the windows system directory and have the real kernel32.exe stored some place where your kernel32.exe can reach it. For example rename it to 'realk32.exe' or 'kernel32.dll' or some such and place it where your kernel32.exe can reach it. Note, even though the file is named 'kernel32.exe' it is a DLL and you must build a DLL.

Also, I doubt that the system will call any DllMain for this DLL, it is a DLL but a very special DLL so don't count on it calling any DllMain. rather have a global bool init_done variable which is initialized to false and have every exported function test it and do the initialization before they continue if init_done is false. The initialization will set the variable to true.

Then for every call foo you simply call the function through the pointer since you've loaded realk32.exe and have it available.

One more note, you have to be careful with the LoadLibrary function. If I am not mistaken it is defined in kernel32.exe and so you get a slight problem how you can load that library since you need realk32.exe in order to be able to load any DLL, including realk32.exe!

Well, afriad you have to do some black magic there. All the functions in kernel32.exe are implemented by first collecting arguments and then they do an INT instruction to generate an interrupt to the windows kernel. I am afraid you have to implement the very first LoadLibrary that you call to load realk32.exe by doing the same thing. Warning! This is UNDOCUMENTED, it will most likely change in next version of windows etc etc etc and might even change in next service pack upgrade.

The point is that since it is not documented by microsoft and the documented interface to windows is the Win32 functions, microsoft essentially do as they please without telling anyone if they change things in the INT interface.

You are hereby warned.

Anyway, granted that you get this to work you can then use the Win32 interface to regular LoadLibrary for any requests from user code.

Then, you want to intercept CreateProcess? Simple: Just implement your version of CreateProcess and CreateProcessEx so that they do not blindly call realk32.exe's CreateProcess and CreateProcessEx functions but instead check if your conditions are met to block the exe. Note, if you make such a change you will make it system wide and it will have effect always, so if you block every CreateProcess you will block any attempt to create new processes using the Win32 interface and people won't be able to create ANY process. Your system will most likely need to be reinstalled from CD-ROM if you screw up in this. Since you can't create any process you can't run any command or any application to repair the system even, so the only possible way out is to reboot the system and reinstall it from CD-ROM. Therefore you MUST be very careful when doing things like this.

Also, note that Windows also have a Posix subsystem and the fork() function there might still work, if you want to block that too you probably have to do similar black magic to block the posix subsystem also.

Alf
Avatar of dave_p_r_b

ASKER

Thank you for your extensive answer!

Intercepting createProcess was one way i thought i could solve the problem, it wasnt a second question. I guess I'm confused.

I cannot afford to have to change the code with possibly each service pack renewal- it just not appropriate i'm afraid!

Do you happen to know if there's a simpler way? Or the answer to psSetcreateNotify...?

Anyway, thanks for your help...
d.
Simple, obvious ways to prevent a program from running are:

a.  Delete the program file from the disk.

b.  Use access control:  as the all-powerful Administrator, don't allow the user the privilege of running the program.

I suspect you have considered and rejected these for some reasons, but I thought I'd throw them in, since they seem to answer the question as written, and you are looking for an "accepted method" and "simpler way."
I guess his problem is that

1. He can't delete the program since he want to allow it to run, just not at this moment.

2. He can't set the security for program X since he doesn't know which programs he want to disallow. My guess is that he wants to within a certain start time and end time prohibit ANY program or process from being created but when end_time or some event occur, he wants to set the system back to 'normal' situation where any program can start.

This is probably best done through some notification.

However, I believe that attempting to stop ANY CreateProcess is potentially dangerous and not a good thing. Users do want to create a process from time to time while running your program and for perfectly legitimate reasons.

I guess you are running some kind of application and you want to prevent users from running 'dangerous' applications to spy on your application or 'debug' your application while it runs.

I think there are games that has run into that exact problems. A game such as Everquest checks your currently running processes and tries to identify if any of them are on their 'no no' list and if so exit their game. They also scan the hard disk to see if they find any such 'no no' applications.

The problems here are several and it is on the whole utterly futile:

a. Users can rename the application and using a hex editor change other parameters of the executable so that it will avoid detection.

b. Users can simply run such spy programs on another computer. Everquest runs it main communication as TCP/IP packets (both TCP and UDP) and if a user has two computers it is fairly easy for him to set up a snooping program on a unix machine that forward the packets to the PC. Everquest running on the PC has no way of knowing that the snooping software is running.

So you end up going through all sorts of troubles and those who really want to break your scan can easily do so. Those who suffer from the scan are those who run perfectly legitimate software.

They even tried to block the computer from switching tasks. This caused all sorts of problems when firewall and other programs popped up a dialog box and you couldn't switch to them or you could but then the computer would hang when you tried to switch back to EverQuest. Trust me, I have played that game and know all to well that headache.

Fortunately they have come to their senses and you can now switch task to/from everquest - they must have realized that it was an exercize in futility.

So my advice to you if this is your situation or similar to it:  Forget it, just live with it. If users want to run an application while your program is active, let them do it, it is very hard to stop them and you will most likely block and cause troubles for those who just want to do innocent stuff while those who really want to break your code can easily do so anyway.

Alf
Hi,
I didnt bore you with the details of the background of needing this functionality, perhaps i should have been a little more open.

Its not an issue of people changing executeables... they are just everyday users. If they are going to go to so much effort, I'm not even going to try and stop them.

The application is to run over a network and is to limit the number of times a program can be run concurrently on different machines...

hope this clears it up a bit.


D.
Do you have the source code to the program that is to be controlled?

If so, then it's not too hard to do,
except you're likely to get left with too high a running program count if your program crashes before it gets a chance to decrement some running-program counter.

If you want to limit programs whose .exe files live on the server, you could just move the programs to some other directory, lets call it "hidden_Bins".  Then make batch files named after each program, say "FreeCell.Bat".
Then from that batch file increment and check your counters and allow or disallow usage.

If you make the batch files "Execute only", then your clients wont be able to see where the binaries are hidden.  This is dangerously close to "security thru obscurity", but is probably good enough for many purposes.



Regards,


grg99

Yes, those details matter.  With that information, I will offer a couple more simple, possibly useless ideas, leaving the heavy duty black magic voodoo system programming to Alf.

This now sounds like a license management kind of problem.  If you have control of the application that is supposed to run or not, the usual approach is to have it check with a server.  If the server says a license is available, the program proceeds to run.  If the server says the limit has been reached, the program tells the user, "Have your cheap company buy some more licenses for our fine software" and exits.  There are commercial software components that can do this for you.

If you don't have control of the application, perhaps you can wrap it in another program that checks whether it can run.  That is, instead of running regulated program X directly, the user runs gateway program Y.  Y checks with the server and starts X if it is allowed.

If you can't do either of these and you really need to have some monitor sitting there all the time watching everything the user tries to run and deciding whether it's OK depending on what's going on elsewhere in the network, then I think Alf's detailed advice applies.
ah....

do you have the code of the program? If so, do it this way:

at program start up, check how many concurrent users there are that are using the program (check below for how to check this). If the number is too many, exit the program and refuse to run.

If you do not have the source code available, 'hide' the program some obscure place, possibly not even store it on the hard disk for the users but instead have the program stored in a central server which also count how many concurrent users.

Then replace the program on the user's hard disk with a small application which first connects to that server and then say "I want to run XXXX.exe". THe server check if the number of allowed users are too high, if so it answer "no" and if not too high it sends over the executable.

The application will then exit if it gets a no and will do a CreateProcess() on the received application if "yes". Then the application will sit and wait for the application XXXX.exe to finish and when it is done it deletes the file from the hard disk.

To check for how many concurrent users, you can in a network solution just use such a server in any case, and just have your application contact the server and say "I am application XXX and the user wants to run me now". The server checks how many concurrent and if too many he will say "no" and the application terminates, if "yes" the application continues.

I believe this is safe and simple way to do it. If you want to avoid the copying of the exe file you cna let the user have the exe file but hidden in some obscure place and perhaps encrypted so that he cannot execute it (it doesn't show up as an exe file even). Then if he is allowed to run the application, instead of having the server send over the whole application .exe file it just send over the decryption key, your application will then decrypt the file and place the decrypted .exe file some place and run it and then delete it when you're done as above.

Of course, this scheme isn't foolproof. If the user go to task manager and recognizes the name of your application and terminates it, the file will stay on his hard disk and he can run it as often as he likes. However, provided that users aren't that smart you should be able to stop 99% of those who's trying to just start the icon to run the application if the count is too high.

One word of advice: You must have the ability for a privileged user (that is you) to reset the count from time to time. If user start the program and then his computer hangs up he will reboot and the server will think he is running the application while he isn't. In this case you must somehow be able to understand that.

When the application terminates and you remove the .exe file or whatever you of course also tell the server that the user is no longer using the application so someone else can use it.

Alf
No code... it will be commercial programs such as word.

Thanks for all your input people... appreciated...
If i were to attempt the system programmers method... what would it be? ( incidentily, i'm not bright enough to be a systems programmer! - but I'm going to ask so that I could at least try! )

I'm ok with the network bit... that's someone else's task... it's purely controlling program execution..

d.
I think that it is more clear talking about processes and not programs ...
It seems that you want to prevent programs from executing more then N times at the same time etc (creating N processes or more).
You need to read the processes currently running like Windows Task Manager does, and count the occurences of a specific process, then if there are too many kill the latest ones.
This should be a program that runs all the time and checks the tasks every M minutes/seconds.

I dont want to kill a program after it has started. Surely, this is not safe? To kill a program when it is has hung, is one matter, but to kill a program after it has started or while it is still running could cause data loss- right?

I know it seems impossible to stop a program starting before it starts but i was hoping their would be a some way of sneaking in between the operating system being told that program X should run and the operating system actually starting X.

ok... now i am bald!

D.
ASKER CERTIFIED SOLUTION
Avatar of Salte
Salte

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial