windows编程的人都知道,在其操作系统下,进程被创建,通常被赋予很多属性,其中一项属性就是用户名,及进程所属的权限。打开任务管理器,可查看到(查看不到,点击查看,选择列即可)
通常桌面系统explorer的权限是User权限,即用户权限的,它可以是你administrator,可以是你PC的名字,可以是Guest等,所以我们开启并运行的所有进程都继承它的权限。
若想运行具备system权限的explorer,则可参考以前的文章
在添加服务后,服务所对应的进程权限是SYSTEM权限,那么由这个SYSTEM调用的所有子进程,在常规下,都将是SYSTEM权限,如果有这样一个需求,需要通过服务调用某个具备User权限的进程,则需要通过CreateProcess
API的扩展即,CreateProcessAsUser.
WINADVAPI BOOL
WINAPI CreateProcessAsUser (
__in_opt HANDLE hToken,
__in_opt LPCSTR lpApplicationName,
__inout_opt LPSTR lpCommandLine,
__in_opt LPSECURITY_ATTRIBUTES lpProcessAttributes,
__in_opt LPSECURITY_ATTRIBUTES lpThreadAttributes,
__in BOOL bInheritHandles,
__in DWORD dwCreationFlags,
__in_opt LPVOID lpEnvironment,
__in_opt LPCSTR lpCurrentDirectory,
__in LPSTARTUPINFOA lpStartupInfo,
__out LPPROCESS_INFORMATION lpProcessInformation
);
其中hToken是最关键的,它表示进程所需要的会话令牌,通俗点就是权限的一个标识,有了它,就可以创建其他权限的进程了。
hToken的获取,网上资料特别多,就不列举了,这里直接贴关键代码
int CreateProcessByToken(LPSTR lpTokenProcessName,LPSTR lpProcess,LPSTR lpCommend)
{
HANDLE hToken = 0;
LPSTR lpName = lpTokenProcessName;
HANDLE hProcessSnap = 0;
PROCESSENTRY32 pe32 = {0};
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
pe32.dwSize = sizeof(PROCESSENTRY32);
for(Process32First(hProcessSnap,&pe32);Process32Next(hProcessSnap,&pe32);)
{
if(strcmp(strupr(pe32.szExeFile),strupr(lpName))) continue;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,pe32.th32ProcessID);
OpenProcessToken(hProcess,TOKEN_ALL_ACCESS,&hToken);
CloseHandle(hProcessSnap);
}
if(hToken == 0) return 0;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\default";
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
return CreateProcessAsUser(hToken,lpProcess,lpCommend,0,0,FALSE,NORMAL_PRIORITY_CLASS,0,0,&si,&pi);
}
调用方式为
char tokenname[64]="explorer.exe";
CreateProcessByToken(tokenname,0,"myservice_userchild.exe");
注意第一参数必须是非常量的,因为使用了strupr。
添加服务并启用服务,可以看到启动的子进程为User用户名了。
添加服务的方法太easy
sc create myservice_service_service binPath= "E:\code\system2user\Debug\myservice.exe" type= own start= auto
完整的示例已分享
http://download.csdn.net/detail/huanglong8/9708203
看过《windows核心编程》的小伙伴们,肯定比较熟悉第四章,在第四章中有讲到获取进程信息的示例和相关技术说明。于是乎,我又做了如下实验,windows进程的用户名很多,还有NETWORK SERVICE,LOCAL SERVICE等,那么SYSTEM是否再获取token后,仍然可以调用出具备此权限的子进程呢?改写代码,将子进程调用加入到循环中。
for(Process32First(hProcessSnap,&pe32);Process32Next(hProcessSnap,&pe32);)
{
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,FALSE,pe32.th32ProcessID);
OpenProcessToken(hProcess,TOKEN_ALL_ACCESS,&hToken);
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si,sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\default";
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
CreateProcessAsUser(hToken,lpProcess,lpCommend,0,0,FALSE,NORMAL_PRIORITY_CLASS,0,0,&si,&pi);
}
启动服务后,发现调用的子进程中并没有SERVICE的权限进程。
在用LookupAccountSid 函数进行遍历获取用户名时,和书籍提供的样例程序是一样的,获取到了SYSTEM,USER,SERVICE等一系列权限token,但使用CreateProcessAsUser时,却针对其他权限调用失败,很是困惑。查阅网上的说法,说事因为主进程权限不够导致。所以,我便切换到SYSTEM用户桌面下。
启动服务,仍然是上面那种情况,失败。
但控制台直接调用,却意外成功了。
惊奇的发现,居然没有User,好吧,我已慌乱。
按照网上的说法,需要提主进程的权限,参考核心编程中的样例,试过了,并未成功,所以就不贴出来了。
由此可以知道,如果SYSTEM启动用户权限进程是可以做到的,但是启动其他权限进程,则无法做到。不知道有没有其他小伙伴有更好的示例和方法,欢迎分享啊。
最后贴出最佳的解决方案,针对Windows桌面应用程序,在系统框架上,我会选择,一个服务对应一个权限进程,一个随用户桌面的自启动程序随用户权限,这样子,分而治之也不会太乱,至少,用这种跨权限调用子进程的方法风险太高。