终止进程是通过以下4种方式来实现的:
*主线程入口点函数返回.(推荐)
*进程中线程调用ExitProcess函数(避免)
*另一个进程中线程调用TerminateProcess函数(避免)*
进程,自然死亡(几乎不可能)
一、主线程的入口点函数返回 主程序入口点函数返回之后,这个应用程序的进程才终止.
主线程的入口点函数返回,保证以下操作会被执行.
1.线程创建任何C++对象都将由这些对象的析构函数正确销毁.
2.正确释放线程栈使用内存.
3.将进程的退出代码,设为入口点函数的返回值.
4.递减进程内核对象使用计数.
二.ExitProcess函数:
进程中的线程调用ExitProcess函数时终止:
VOID ExitProcess(UINT fuExitCode);
终止进程,并将进程的退出代码设为fuExitCode。ExitProcess不会返回值当主线程入口点函数返回时,
会返回C/C++运行库启动代码,后者将正确清理进程使用的全部C运行时资源.释放了C运行时资源之后,
C运行时启动代码将显式调用ExitProcess,将入口点函数返回的值传给它.为什么只需要从主线程入口点函数返回,
就会终止整个进程.不管进程中是否还有其他线程在运行,只要应用程序的主线程从它的入口点函数返回,
C/C++运行库就会调用ExitProcess来终止进程.调用是ExitThread,或者入口点函数直接返回,应用程序的主线程将停止执行,
但只要进程中还有其他线程正在运行,进程就不会终止.
调用ExitProcess或ExitThread会导致进程或线程直接运行-再也不会返回当前函数调用.
C/C++应用程序应避免用这些函数,因为C/C++运行库也许不能执行正确清理工作.
#include <windows.h>
#include <stdio.h>
class CSomeObj {
public:
CSomeObj() { printf("Constructor/r/n"); }
~CSomeObj() { printf("Destructor/r/n"); }
};
CSomeObj g_GlobalObj;
void main () {
CSomeObj LocalObj;
ExitProcess(0); // This shouldn't be here
// At the end of this function, the compiler automatically added
// the code necessary to call LocalObj's destructor.
// ExitProcess prevents it from executing.
}
执行上述代码,会显示以下结果:
Constructor
Constructor
ExitProcess造成进程"当场终止运行";C/C++运行时没有机会执行清理工作.
任何时候都不要显式地调用ExitProcess.再运行这个程序就会得到以下结果...
Constructor
Constructor
Destructor
Destructor
三、 TerminateProcess函数
TerminateProcess函数可终止一个进程
Bool TerminateProcess(
HANDLE Process, // 制定终止进程句柄
UINT fuExitCode // 退出代码值,全传给fuExitCode参数
);
任何线程可通过TerminateProcess结束另一个或自己的进程。
只有无法通过其它方法来强制进程退出时,才使用TerminateProcess
另外TerminateProcess函数是异步的,它告诉系统我们希望进程终止,
但函数返回时候,系统并不能保证进程已经被强行终止?
为了确定进程是否已终止应调用WaitForSingleObject或者一个类似的函数
并将进程句柄传给它。
四、进程终止运行时
用过调用GetExitCodeProcess获得已经终止的一个进程退出代码
BOOL GetExitCodeProcess(
HANDLE hProcess,
PDWORD pdwExitCode);
函数会查找进程内核对象,并从内核对象的数据
结构中提取用于标识进程退出代码的成员。
任何时候都可调用此函数,调用GetExitCodeProcess进程还没终止
将用STILL_ACTIVE 标识符,来填充DWORD如果进程已经终止,就返回实际退出代码值。
五、子进程
Windows 提供几种不同进程间传递数据方式
包括动态数据交换(DDE)、OLE、管道、邮件槽等。
共享数据最好方式之一使用内存映射文件。
PROCESS_INFORMATION pi;
DWORD dwExitCode; // 退出代码
// Spawn the child process.
BOOL fSuccess = CreateProcess(..., &pi);
if (fSuccess) {
// Close the thread handle as soon as it is no longer needed!
CloseHandle(pi.hThread); // 关闭主线程内核对象句柄
// Suspend our execution until the child has terminated.
WaitForSingleObject(pi.hProcess, INFINITE);
// 等待hObject参数被触发
// The child process terminated; get its exit code.
GetExitCodeProcess(pi.hProcess, &dwExitCode);
// 获取子进程的退出代码
// Close the process handle as soon as it is no longer needed.
CloseHandle(pi.hProcess);
// 关闭主进程内核对象句柄
}
WaitForSingleObject 函数声明:
DWORD WaitForSingleObject(HANDLE hObject, DWORD dwTimeout);
运行独立子进程
Windows 进程间的关系:
如当Windows资源管理器为用户创建一个新的进程,之后就不再关系这个进程是否继续存在,也
不关心用户是否要终止它。
为断绝与子进程所有联系,Windows资源管理器必须调用 CloseHandle来关闭新进程及其主线程句柄。
五、管理员以标准用户权限运行时(UAC)
为什么UAC,不一定询问,然后把安全数据保存到系统中,并让用户下次可不经过提示直接运行呢?
如果提供这样一个安全数据库。那么数据被入侵了怎么办呢?
任务管理器上的用户提示权限
实际上你注意这任务管理器,在点击后的PID是不一样的,这意味着任务管理器,生成它的另一个实例。
六、自动提升进程权限
如果在应用程序中可执行文件中嵌入一种特殊资源(RT_MANIFEST)
其中系统会检查<trustInfo>段,下面是示例清单文件的<trustInfo>段。
我们可以将清单保存到可知性文件所在目录中,名称和可执行文件相同
且扩展名使用 *.manifest那么效果也是一样的。
不过这个清单须要在注销系统后生效,可知性文件嵌入清单的优先权会比外部清单文件大。
...
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="requireAdministrator"
/>
</requestedPrivileges>
</security>
</trustInfo>
...
可能有3个不同的值
level 属性的值
值 描述
requireAdministrator 程序必须以管理员权限启动;否则不会运行
highestAvailable 使用管理员帐户登入,就会出现一个要求批准提升权限的对话框
使用管理员帐户登入,会出现一个要求批准提升权限的对话框
普通用户帐户登录,应用程序就会用这些标准权限来启动(不会提示用户提升权限)
asInvoker 应用程序使用与主调进程应用程序一样的权限来启动。
七、手动提升进程权限
shellExecutEx函数
BOOL ShellExecuteEx(LPSHELLEXECUTEINFO pExecInfo);
typedef struct _SHELLEXECUTEINFO {
DWORD cbSize;
ULONG fMask;
HWND hwnd;
PCTSTR lpVerb; // 必须设为runas
PCTSTR lpFile; // 提升后的权限启动一个可执行文件路径
PCTSTR lpParameters;
PCTSTR lpDirectory;
int nShow;
HINSTANCE hInstApp;
PVOID lpIDList;
PCTSTR lpClass;
HKEY hkeyClass;
DWORD dwHotKey;
union {
HANDLE hIcon;
HANDLE hMonitor;
} DUMMYUNIONNAME;
HANDLE hProcess;
} SHELLEXECUTEINFO, *LPSHELLEXECUTEINFO;
========================================================================
实用例子:
// Initialize the structure.
SHELLEXECUTEINFO sei = { sizeof(SHELLEXECUTEINFO) };
// Ask for privileges elevation.
sei.lpVerb = TEXT("runas");
// Create a Command Prompt from which you will be able to start
// other elevated applications.
sei.lpFile = TEXT("cmd.exe");
// Don't forget this parameter; otherwise, the window will be hidden.
sei.nShow = SW_SHOWNORMAL;
if (!ShellExecuteEx(&sei)) {
DWORD dwStatus = GetLastError();
if (dwStatus == ERROR_CANCELLED) {
// The user refused to allow privileges elevation.
}
else
if (dwStatus == ERROR_FILE_NOT_FOUND) {
// The file defined by lpFile was not found and
// an error message popped up.
}
}
用户拒绝提升权限,shellExecutEx返回Flase,GetLastError通过使用一个ERROR_CANCELLED值来指出情况
当父进程以已经用shellExecutEx函数取得相关权限时,有继承权的子进程就不要在用CreateProcess函数
去申请同样释放权限,否则调用会失败的,GetLastError会返回 ERROR_ELEVATION_REQUIRED
八、 何为当前权限上下文
我们可以通过GetProcessElevation函数 来返回提升类型和一个指出进程是否正以管理员身份运行的布尔值。
BOOL GetProcessElevation(TOKEN_ELEVATION_TYPE* pElevationType, BOOL* pIsAdmin) {
HANDLE hToken = NULL;
DWORD dwSize;
// Get current process token
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
return(FALSE);
BOOL bResult = FALSE;
// Retrieve elevation type information
if (GetTokenInformation(hToken, TokenElevationType,
pElevationType, sizeof(TOKEN_ELEVATION_TYPE), &dwSize)) {
// Create the SID corresponding to the Administrators group
BYTE adminSID[SECURITY_MAX_SID_SIZE];
dwSize = sizeof(adminSID);
CreateWellKnownSid(WinBuiltinAdministratorsSid, NULL, &adminSID,
&dwSize);
if (*pElevationType == TokenElevationTypeLimited) {
// Get handle to linked token (will have one if we are lua)
HANDLE hUnfilteredToken = NULL;
GetTokenInformation(hToken, TokenLinkedToken, (VOID*)
&hUnfilteredToken, sizeof(HANDLE), &dwSize);
// Check if this original token contains admin SID
if (CheckTokenMembership(hUnfilteredToken, &adminSID, pIsAdmin)) {
bResult = TRUE;
}
// Don't forget to close the unfiltered token
CloseHandle(hUnfilteredToken);
} else {
*pIsAdmin = IsUserAnAdmin();
bResult = TRUE;
}
}
// Don't forget to close the process token
CloseHandle(hToken);
return(bResult);
}
其中GetTokenInformation使用的与进程关联的安全令牌和 TokenElevationType 参数获得提升类型,
提升类型的值由TOKEN_ELEVATION_TYPE 枚举类型来定义。
TOKEN_ELEVATION_TYPE 的值
值 说明
TokenElevationTypeDefault 默认运行用户运行,UAC被禁用
TokenElevationTypeFull 权限被成功提升,而且令牌没有被筛选过
TokenElevationTypeLimited 进程以受限的权限运行,它对应于一个筛选过的令牌
http://hi.baidu.com/csw8923/blog/item/c1f329a98587edf61f17a206.html