Deny Access to Kiosk program process
I have a kiosk app and have to disable task manager always to prevent closing the program by users .
But some users need the TaskManager to close hanging programs. Any help would be appropriated. However, I am sure there is a function in windows to prevent closing a program's process , as when one attempt to kill rundll.exe process. I want to know that function if I can call it withDllImport
Can anyo开发者_StackOverflowne help with a trick?
A hack? A function? Any other solution?EDIT:
At least if there is not a way to prevent the process from being closed, I need a way to hide it from processes list appeared in the task manager.
EDIT 2: I can't find the solution so far
One approach, if you could access the process ID in an administrative context, is to deny the PROCESS_TERMINATE permission on the process to end users. Terminating the process (through task manager or other contexts) is by default granted to the owner, but can be explicitly denied. When it is denied, terminating the process would require the owner to manually change the ACL, and then terminate the process. If the user is neither an administrator nor the owner of the process, he will not be able to forcibly terminate the process (e.g., through Task Manager), although the process will be allowed to exit normally.
The following code puts an explicit deny ACE on the process with the PID processid
for members of the Everyone group.
#include "Aclapi.h"
#include "Sddl.h"
DWORD RestrictTerminateOnProcessId(DWORD processid)
{
PACL dacl = NULL, newdacl = NULL;
HANDLE ph = NULL;
PSECURITY_DESCRIPTOR* desc = NULL;
PSID everyonesid = NULL;
ph = OpenProcess(WRITE_DAC | READ_CONTROL, false, processid);
if (!ph) goto cleanup;
if (ERROR_SUCCESS != GetSecurityInfo(ph,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
&dacl,
NULL,
desc)) goto cleanup;
SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
if (!AllocateAndInitializeSid(
&WorldAuth,1,SECURITY_WORLD_RID,
0,0,0,0,0,0,0,&everyonesid)) goto cleanup;
// begin copy dacl
_ACL_SIZE_INFORMATION si;
GetAclInformation(dacl,
&si,
sizeof(si),
AclSizeInformation);
DWORD dwNewAclSize = si.AclBytesInUse +
(2*sizeof(ACCESS_DENIED_ACE)) + (2*GetLengthSid(everyonesid)) -
(2*sizeof(DWORD));
newdacl = (PACL)HeapAlloc(
GetProcessHeap(),
HEAP_ZERO_MEMORY,
dwNewAclSize);
if (newdacl == NULL) goto cleanup;
if (!InitializeAcl(newdacl, dwNewAclSize, ACL_REVISION_DS))
goto cleanup;
if (!AddAccessDeniedAce(newdacl,
ACL_REVISION_DS,
PROCESS_TERMINATE,
everyonesid)) goto cleanup;
for (int i = 0; i < si.AceCount; i++)
{
LPVOID pace = NULL;
if (!GetAce(dacl, i, &pace)) goto cleanup;
if (!AddAce(newdacl, ACL_REVISION_DS,
MAXDWORD, pace, ((PACE_HEADER)pace)->AceSize))
goto cleanup;
}
// end copy dacl
if (!SetSecurityInfo(ph,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
NULL,
NULL,
newdacl,
NULL)) goto cleanup;
SetLastError(0);
cleanup:
DWORD ret = GetLastError();
if (desc) LocalFree(desc);
if (newdacl) HeapFree(GetProcessHeap(), 0, (LPVOID)newdacl);
if (ph) CloseHandle(ph);
if (everyonesid) FreeSid(everyonesid);
return !ret;
}
You could create a service that runs on boot. It then monitors when the user logs in and starts your program. From there you have two choices:
- Have it wait on the program and revive it for as long as the user's session persists.
- Run it under an administrator account and make sure the users are always running on limited accounts. Windows' privilege enforcement should take care of your program not dying.
If you must allow the users administrative privileges (and they can thus kill your service), make sure to register your service so that the SCM restarts it automatically.
Anything beyond that would require some kernel hacking, as mdm said, or diving into rootkit territory. Which I would suggest you avoid.
If by any chance you're still running Windows XP, instead of a system service, you can register a Winlogon notification package. They're basically unkillable, as they run in the context of winlogon.exe, which is the reason they were removed from Vista and above.
The proper way of doing this is:
Create a user for the Kiosk application. Lets say KioskUser Create other users that do stuff in the computer. Lets say User1 NONE of them should be administrator. They do not need to be admins right? They can have privileges of course.
You are going to use User1 account as usual. Then, you run the Kiosk application as the KioskUser. (use runas command) - add the application to the session and make it visible (see the arguments for more info on this)
While the User1 is loged in and the Kiosk application runs from the KioskUser, the User1 cannot kill the process.
I wouldn't recommend "hacking" the system, nor changing something on the registry. Also, you can make the Kiosk application a service, and run it under the Kiosk user.
It sounds like you can't prevent a process from being killed - see this question and specifically the link posted to an explanation.
You can however prevent the user from opening the task manager from the taskbar (right click -> open task manager), from pressing Ctrl-Shift-Esc, or from typing taskman
at the command prompt using the following registry key:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\System\DisableTaskMgr
Setting it to 1 disables the task manager, 0 enables it again.
From the command prompt, disable it like so:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System /v DisableTaskMgr /t REG_DWORD /d 1 /f
And you can renable with this command:
reg add HKCU\Software\Microsoft\Windows\CurrentVersion\Policies\System /v DisableTaskMgr /t REG_DWORD /d 0 /f
You'll also need to find a way of preventing the user from writing to this key in the registry - although on my Windows 7 64-bit machine I had to open an admin command prompt before I could change the key.
Edit
As suggested in the comments, you could intercept a low level system call to alter the list of processes reported. This answer eludes to it, you will basically have to write a kernel-mode rootkit - probably implemented as a device driver. This will likely only work in Windows XP and below due to kernel changes made in Vista and onwards. It can be done however, a friend of mine created a prototype of this for his BSc final year dissertation.
You'll also have to consider other methods of querying for processes - IIRC NtQuerySystemInformation
isn't the only way that processes can be enumerated.
Short of protecting your Kiosk app with some rootkit/driver you can't... although the methods you would need to use in this context are "malware-like" so beware...
Here http://blogs.msdn.com/b/oldnewthing/archive/2004/02/16/73780.aspx you can see on one side why this is a task not really possible and on the other side the several possibilities you would have to defend against... which would be:
deny PROCESS_TERMINATE
deny PROCESS_CREATE_THREAD
deny PROCESS_VM_WRITE
deny PROCESS_SUSPEND_RESUME
Plus any defense you can get your hands on against debuggers - another very tricky business.
Sorry for not posting this as a comment (not enough reputation). I'm using drfs solution, but it seems to induce a memory leak with the way GetSecurityInfo is used. I changed the code and got rid of the memory leak like this:
Declaration:
PSECURITY_DESCRIPTOR desc = NULL;
Initialisation:
desc = (PSECURITY_DESCRIPTOR)GlobalAlloc(GMEM_FIXED, sizeof(PSECURITY_DESCRIPTOR));
Cleanup:
if (desc) GlobalFree(desc);
Call:
GetSecurityInfo(ph, SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION, NULL, NULL, &dacl, NULL, &desc)
I also found this article on the issue: http://i1.blogs.msdn.com/b/oldnewthing/archive/2012/12/12/10376639.aspx
While you can't prevent an authorized user from killing your process, you can prevent users from having the necessary permissions to kill your process. That said, a local administrator will always have permission to kill any process. Is your hope to prevent closing of your application by any user or just non-admins? If the former, simply running the process under a dedicated user account may be enough to do the trick.
精彩评论