Jeffrey Richter
Q: I am developing a Windows NT® service program. There are some small problems like any program. When my service program is wrong, I want to kill this service to restart it. I often use the task manager to kill the process I no longer want to use. However, if I want to kill a service program, it is displayed in front of me is a message box that is rejected. Is there any way to let the task manager to kill a service program? Andrea Demaiopacific Grove, CA
A. Before I answer this question, let us first study why the task manager will display a message box (as shown in Figure 1). When you select a process in the Task Manager and click on the termination process, the task manager will get the ID of the selected process and perform the following pseudo code:
DWORD dwprocessid = (Initialized from the listview
CONTROL);
Handle HProcess = OpenProcess (Process_Terminate, False,
DWProcessID);
IF (hprocess == null) {
// Display Error Message Box (Like in Figure 1).
} else {
TerminateProcess (HProcess, 1);
CloseHandle (HPROCESS);
}
Since the OpenProcess is not able to open the handle of a particular process, the message box pops out. This operation failed because the service program is running under the native system security account, and you even log in as an administrator, there is no sufficient permissions to open the handle of this service program. In fact, after OpenProcess returns empty and receives an error code such as error_access_denied (5), the task manager will immediately call GetLastError. Task Manager will place the text on behalf of this error in the message box.
Figure 1: Error message box
Microsoft allows the process to take this permission check by using privileges. In Windows NT, privilege is an attribute assigned to the user, which allows the user to transcend so-called restrictions on a part of the operating system. Windows NT 4.0 supports 24 privileges Allow some similar backup recovery files, which are usually not granted permissions, and can also change the system time, or run a process on real-time priority, and turn off the system.
One of the privileges called SedebugPrivilege. Typically, the operating system does not allow the user to track the process because the system does not want to make the user (or hacker) capable of changing the ability of a running process. However, some users need this ability to track the process. By default, Windows NT automatically grands administrators track debug privileges. You can verify by running the User Manager management tool. Select the User Rights menu option under Polic, click Show Advanced User Rights Checkbox, then select the power of Debug Program (as shown in Figure 2).
Figure 2: User Rights Strategy
If you are awarded the privilege of tracking programs after logging in, you can track the application. What does that mean? That is to say, I want to track debugging an application. You must be able to successfully call the OpenProcess this function, so you can call a variety of APIs related to the debugger, such as ReadProcessMemory, WriteProcessMemory, VirtualQueryex, VirtualProtectex, Virtualalalk, VirtualFreex , CreateRemoteThread, and more. All of these features require a process's handle to run correctly. Simply put, although you usually can't open a process, if you have debug privileges, you can force OpenProcess to open a process. Read more, you may still be confused. You may be said to yourself: "I am blamed, I am logged in as an administrator, but when I tell the Task Manager, when I want to terminate a service process, I still see a message box that is rejected. Why? "With privilege means that it can exceed normal operation, with unlimited permissions for powerful system functions. However, the system should protect ordinary users, do not allow administrators to deliberately or unintentionally cause the system to crash, affecting other users. We can easily imagine a scene, assume that an administrator logs in into the system, then tells the Task Manager to kill the Winlogon.exe or CSRSS.exe process. These processes are essential conditions for the normal operation of the system, and they must always run in the system, otherwise the entire system will crash will be caused. For this reason, the task manager does not allow an administrator to terminate these processes in unintentional, so that the entire system is paralyzed.
There are three relationships between users and privileges: rejected, authorized and available. "Rejected" thinks that users never have the ability to surpass their restrictions on a component of the system. For example, users do not have tracking debug privileges, such as all administrators you have seen, so an ordinary user will never debug a process. For many users of the system, most privileges are rejected. Administrators can grant privileges to users using the USER Manager tool. However, pay attention: Users must exit the system (if it is currently logging in, re-login with the newly allocated privilege, authorization can take effect.
"Authorized" means that users can utilize privileged operations. However, please remember the privilege to give the user an execution of the power that is often restricted. This is a very dangerous thing, so it should not be easily obtained. So, even if a user may be granted privilege, the system may also understand this privilege before it is understood that the user may still do this permission.
"Can use" means that users have been given privilege and privileged is already open. Then now, when you want to perform a restricted operation, the system will check, see which privilege is given this user (not just authorization), after confirmation, the user can transcend this limit. That is why the task manager does not allow the administrator to terminate a service program, although the administrator has been awarded the debug privilege, the task manager did not open it.
When you log in into the system, Windows NT creates an object called access flag. This object includes a number of information, including those privileges being authorized or available. The access logo is associated with the shell process Explorer.exe. Once you have run a new process, you will give a new process to the new process of access logo. In other words, every process has its own privilege set. That is, if you give a privilege to give a privilege, this right will not open other processes unless you clearly give it. So, if you open the use of the task management process, the task manager will be able to terminate the service process. Figure 3 shows a small program, enabledebugprivandrun, which demonstrates how to run a process with tracking debug privileges. Run Task Manager (its debug privilege open), compile this program to use this command line to run it: c: /> enabledebugprivandrun.exe taskmgr.exe When you perform this command line, EnableDebugprivandrun first calls OpenProcessToken. It returns a handle of the access flag connected to the EnableDebugPrivandRun process. If you successfully get the handle of the access flag, call EnablePrivilege - my own function, the function is just the steps that all the necessary or not assigned privileges.
Figure 3: enabledebugprivandrun.cpp
/ ************************************************** ************
Module Name: enabledebugprivandrun.cpp
Notices: Written 1998 by Jeffrey Richter
Description: Enables the debug privilege before running an app
************************************************************ *********** /
#define strict
#include
//
Bool EnablePrivilege (Handle Htoken, LPCTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSTSR SZPRIVNAME,
Bool fenable) {
Token_Privileges TP;
Tp.privilegectount = 1;
Lookuppprivilerage (NULL, SZPRIVNAME, & TP.PrIVileges [0] .luid);
TP.Privileges [0] .attributes = feNable? SE_PRIVILE_ENABED: 0;
AdjustTokenPrivileges (HToken, False, & TP, SIZEOF (TP), NULL, NULL;
Return ((GetLastError () == Error_Success));
}
//
Int WinApi Winmain (Hinstance Hinstexe, Hinstance Hinstexeprev,
LPSTR PSZCMDLINE, INT NCMDSHOW) {
Handle htokeen;
IF (openprocessToken (GetCurrentProcess (),
Token_adjust_privileges, & htokeen) {
IF (enableprivilege (htoken, se_debug_name, true) {
IF (SHELLECUTE (NULL, NULL, PSZCMDLINE, NULL,
NULL, SW_SHOWNORMAL) <(hinstance) 32) {
MessageBox (Null, Pszcmdline, __ text ("Enabledebugprivandrun: couldn't run",
MB_OK | MB_ICONITIONFORMATION
}
}
CloseHandle (HTOKEN);
}
Return (0);
}
END OF FILE /
EnablePrivilege requires three parameters: including the handle of the access flag of user privilege information, identify the string you want to change, and a Boolean variable identifies whether you want to give this privilege. With these three parameters, EnablePrivilege initializes the Token_Privileges structure. This structure is actually a variable length structure, which allows you to indicate several privileges simultaneously. Since the EnablePrivilege function only allows you to change a privilege once, the code is simpler than the simplicity of the multiple privileges.
The LookUpprivileGeValue function converts the privilege name into a 64-bit equivalent value called Luid (local unique identity). This is very strange to many developers. Typically, developers prefer to use numbers instead of strings; however, when using privileges, it is usually made in a string, and then the lookprivilerage is converted to numbers. LUID, guarantees that the unique identity in the local system. You can't pass a Luid between the machine, or even, you can't keep a Luid after you have been restarted on the same machine. In other words, if you restart the system between twice calls, pass the debug privilege string to lookupprivilegue will result in returning two different Luid.
Once you have a debug privilege, EnablePriviege will call AdjustTokenPrivileges to give or cancel privileges. You should notice that when I call OpenProcessToken, I want to apply token_adjust_privileges permissions, and successfully call AdjustTokenPrivileges permissions.
After the enableprivilege returns, I passed the command line of EnableDebugPrivandrun to the Shellexecute function. Shellexecute will generate a new process internally to CreateProcess internally. Remember that the permission identifier is inherited, so this new process will inherit the permissions identifier of EnableDebugPrivandrun, and now this identifier indicates that the privilege is open. This means that the new process is also an open to call OpenProcess.
I like to run the task manager on my system so I often view the performance of the CPU through the small icon that is always left on the taskbar. This is the following is what I have done in order to confirm that the task manager is always debugging privilege open. First, I built my enabledebugprivandrun program and put it under a directory. Then I create a shortcut to run the task manager at the beginning of the window minimized. I put this shortcut .lnk file in the same directory where the enabledebugprivandrun program is located. Then create another shortcut to run EnableDebugPrivandrun, passed the file name of the task manager shortcut as the parameter to it. This shortcut command line string is as follows:
C: /bin/enabledebugprivandrun.exe "c: / bin / task manager.lnk"
I put the second shortcut in the Startup folder of my start menu, you can activate it when I log in. It is so simple!
Q: In your Advanced Windows (127 page), you mentioned that when Windows 95 or Windows NT runs a executable image file from the floppy disk, the system is actually loaded into the RAM. The system is done to make the disc from the drive from the drive without affecting the application. This looks a good idea, I am very happy Microsoft putting this function into the operating system. I can also imagine a lot of benefits. For example, it is also necessary when the image file is located in a network drive or an optical disk drive. I also want the file to be loaded into the RAM when compressed or encrypted (Windows NT5.0). Is there a way to allow me to force the system to put a specified file image into the RAM? FRANK MERROW A: Windows NT 4.0 is started, Microsoft adds such support in the loader. When you create an executable image, (. EXE or DLL), you can add the following switches in the linker. :
/ Swaprun: net
This switch tells the linker to open a flag. When the loader loads your image file, the load file is to check if this bit has been set to open, and if the image is loaded from the network drive. If so, the loader loads the image of the file into the RAM to prevent frequent exchange of frequent networks.
The linker also supports the Swaprun switch in this format:
/ Swaprun: CD
This switch tells the loader If the file image is running in the optical drive, the image is forced to load the image into the RAM. Note To make these switches, your linker must support this switch and load the program must know this switch to make a correct response. Windows NT 4.0 and later version can be recognized / swaprun: net and / swaprun: CD bit; Windows? 95 cannot.
Now, the loader does not support loading the compressed or encrypted image file into the RAM. But it is very simple to prepare a function that is forcibly loading the entire image file into the RAM. Figure 4 shows a function of RunImageLocally. This function has only one parameter, which is the Hinstance (or HModule) of an executable image. This parameter also passes to your Winmain function, the DLLMAIN function, which is also the value returned from the loadLibrary call function. The function is then cycled to call the VirtualQuery check All memory areas of the executable image.
Figure 4: RunimageLocally.cpp
/ ************************************************** ****************************
Module Name: RunimageLocally.cpp
Notices: Written 1998 by Jeffrey Richter
Description: Forces an Executable Image to Be Run from The Paging File.
*********************************************************** *************************** /
#include
///
Void WinApi RunimageLocally (Hinstance Hinst) {
DWORD CP = 0;
Static DWORD S_DWPAGESIZE = 0;
// Get the system's page size (do this only overce)
IF (s_dwpagesize == 0) {
System_info si;
GetSystemInfo (& S);
s_dwpagesize = si.dwagesize;
}
PBYTE PBADDR = (pbyte) hinst; memory_basic_information MBI;
VirtualQuery (Pbaddr, & MBI, SIZEOF (MBI));
// Perform this loop untric we find a region beyond the end.
While (mbi.allocationbase == hinst) {
// We can Only Force CommTed Pages Into Ram.
// We do Not Want to Trigger Guard Pages and Confuse The Application.
IF ((Mbi.State == MEM_COMMIT && ((Mbi.Protect & Page_guard) == 0)) {
// DETERMINE IF The Pages in this Region Are Nonwriteable
Bool fnonwritablergn =
(Mbi.Protect == Page_noAccess) ||
(Mbi.Protect == Page_Readonly) ||
(Mbi.Protect == Page_execute) ||
(Mbi.Protect == Page_execute_read);
DWORD DWORIGPROTECT = 0;
IF (fnonwritablergn) {
// Nonwriteable Region, Make it whyableable (with the least protection)
VirtualProtect (Mbi.Baseaddress, Mbi.Regionsize,
Page_execute_readwrite, & dworigprotect);
} else {
// this is a writable page, we can Leave the protections alone.
}
// Write to every component.
// this forces the page to be in rum and swapped to the paging file.
For (DWORD CBRGN = 0; CBRGN // Volatile So That The Optimizer Won't Remove this Code Volatile PDWORD PDW = (PDWORD) & PBADDR [CBRGN]; * PDW = * PDW; CP ; } IF (DWORIGPROTECT! = 0) { // if we change the Protection, Change It Back VirtualProtect (Mbi.Baseaddress, Mbi.Regionsize, DWORIGPROTECT, & dworigprotect); } } // Get Next Region VirtualQuery (Pbaddr = Mbi.Regionsize, & MBI, SIZEOF (MBI)); } GetLastError (); } /// Int WinApi Winmain (Hinstance Hinstexe, Hinstance Hinstexeprev, LPSTR LPCMDLINE, INT NCMDSHOW) { RunimageLocally (Hinstexe); Return (0); } / END OF FILE / For each area, check whether the page is submitted and whether it is a protection page. If the page has not been submitted, the contents of the RAM are not written. If the page has a page_guard property, the action will cause a status_guard_page_violation. If you don't want your application to be confusing, it is not possible to write these pages into the RAM. For these all pages, I check whether they are writable. If not, I will change the protection of these pages so that I can write them. I am using Page_Execute_readwrite because it is the most free of the protection. Once I know that the page is writable, I can write a single DWORD in each page of a zone. Execute this writing order system to make a copy of the page in the RAM. After all the pages in the area have been written, I change the protection of the page back to the original way (if necessary). Finally, this operation is repeated until all areas containing the executable image file are completed. It should be noted that this program is not a thread security, and there is no way to make it safe. Other threads in the process may change the protection mode of the file image or the data in the page where the file image is located. It is not a problem just to execute code or touch data. But if other thread changes the protection of the page, this will be a potential problem. I only tested this code on Windows NT, but it should work well as Windows 95. Since Windows 95 does not support writing mechanisms, use this technology on Windows 95 is not suitable. When you load an image on Windows 95, the loader automatically assigns the RAM (and Exchange Document Area) for the image file.