服务程序以管理员身份启动一个进程,被启动进程要能与桌面交互

时间:2022-08-29 14:54:18
我有一个程序,直接运行则可以修改桌面,做了一个守护服务(发现进程不在就启动),在服务里面创建进程,这个时候进程是SYSTEM用户.用了CreateProcessAsUser()后,总算是Administrator用户了,可是桌面死活改不了,请大家帮忙!
//下面是服务程序中的代码
HANDLE hExp = GetProcessHandle("EXPLORER.EXE");
if(hExp == NULL)
return FALSE;

OpenProcessToken(hExp,TOKEN_ALL_ACCESS,&hToken);
if(hToken == NULL)
return FALSE;

ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb        = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\default";

TCHAR szParameter[10] = {0};

if(CreateProcessAsUser(hToken,lpAppName,szParameter,NULL,
NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&si,&pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}

18 个解决方案

#1


牛人呢?

#2


牛人还没出现

#3


mark

#4


在你那个改桌面的进程里打断点调试啊!
调用设置桌面的函数后,GetLastError()看下

#5


程序没有错,
原因是服务程序是和登陆用户无关的,先于WinLogon,而桌面是和用户相关的,一个用户对应一个或多个桌面——当然,只有一个是可见的。
由于修改桌面的程序是被服务程序启动的,因此无法得到用户的信息。
看了一些牛人说可以用DACL和ACEs来做,可是改过后还是不行。因为我对DACL和ACEs不熟,所以希望能有人指点一下。

#6


救命啊

#7


程序没有错
由于修改桌面的程序是被服务程序启动的,因此无法得到用户的信息。
----------------------------------------------------------------
既然你硬要这么说,我也没办法

#8


错误信息是什么?

#9


1 CreateService 时 在dwServiceType加上SERVICE_INTERACTIVE_PROCESS标记.
2 http://www.osronline.com/showthread.cfm?link=102869

#10


我的环境是Windows XP,我是用服务程序创建了一个客户程序,这个客户程序使用了IActiveDesktop来设置桌面.我想知道,客户程序里面要加上一些特别的代码吗?

下面是我在创建客户程序的代码

HANDLE              hToken;
HDESK               hdesk;
HWINSTA             hwinsta;
PROCESS_INFORMATION pi;
PSID                psid;
STARTUPINFO         si;

HANDLE hExp = GetProcessHandle("EXPLORER.EXE");
if(hExp == NULL)
return FALSE;

OpenProcessToken(hExp,TOKEN_ALL_ACCESS,&hToken);
if(hToken == NULL)
return FALSE;

HWND hDesk = GetDesktopWindow();
// BOOL bOk = ImpersonateLoggedOnUser(hToken);
// GenericLog(Info,"ImpersonateLoggedOnUser %s",bOk?"Ok":"Failed");
GenericLog(Info,"Desktop HWND %s",(hDesk == GetDesktopWindow())?"Equal":"Not Equal");


// 
// obtain a handle to the interactive windowstation
// 
hwinsta = OpenWindowStation(
"winsta0",
FALSE,
READ_CONTROL | WRITE_DAC
);
if (hwinsta == NULL)
return RTN_ERROR;

HWINSTA hwinstaold = GetProcessWindowStation();
GenericLog(Info,"WindowStation Old = %.8x,Curr = %.8x",hwinstaold,hwinsta);
// 
// set the windowstation to winsta0 so that you obtain the
// correct default desktop
// 
if (!SetProcessWindowStation(hwinsta))
return RTN_ERROR;

// 
// obtain a handle to the "default" desktop
// 
hdesk = OpenDesktop(
"default",
0,
FALSE,
READ_CONTROL | WRITE_DAC |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS
);
if (hdesk == NULL)
return RTN_ERROR;

// 
// obtain the logon sid of the user fester
// 
if (!ObtainSid(hToken, &psid))
return RTN_ERROR;

// 
// add the user to interactive windowstation
// 
if (!AddTheAceWindowStation(hwinsta, psid))
return RTN_ERROR;

// 
// add user to "default" desktop
// 
if (!AddTheAceDesktop(hdesk, psid))
return RTN_ERROR;

// 
// free the buffer for the logon sid
// 
RemoveSid(&psid);

// 
// close the handles to the interactive windowstation and desktop
// 
CloseWindowStation(hwinsta);

CloseDesktop(hdesk);
// 

ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb        = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\default";

TCHAR szParameter[10] = {0};
// ShellExecute(NULL,"open",lpAppName,NULL,NULL,SW_HIDE);
if(CreateProcessAsUser(hToken,lpAppName,szParameter,NULL,
NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&si,&pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
GenericLog(Info,"Running %s ....",lpAppName);
UnregisteTimer(TIMER_CONNECT);
RegisteTimer(TIMER_FEEDDOG,3000);
return 1;
}
else
{
GenericLog(Info,"CreateProcess %s Fails ,reason = %d",lpAppName,GetLastError());
}
SetProcessWindowStation(hwinstaold); 
return RTN_OK;

#11


我要的不是与服务程序进行交互,我的目的只是让服务程序在用户登陆后创建一个新进程,这个新进程能够修改用户的桌面.

#12


这个线程能创建成功吗?

#13


线程创建是成功的,我的目的是让服务程序启动一个新进程,而不是要服务程序本身去和桌面交互

#14


我的客户进程里面用的IActiveDesktop来改变桌面,这有关系吗?

#15


应该是不用的,不过你还是在IActiveDesktop输出当前的用户名,看看是不是正确。

#16


那么我是该用"winsta0\\default"桌面呢?还是用其他的什么桌面呢?

#17


按照你所说的,我在客户程序里面调用GetUserName()得到的是当前用户的用户名.我试了一下,如果用服务程序打开客户程序,那么客户程序将不能显示桌面背景,可是如果这时打开IE的属性,点击确定,那么背景就会显示出来.而直接运行客户程序的话,就不会出现问题.
又,我的服务程序是用OpenProcessToken打开EXPLORER.EXE的令牌.在调用CreateProcessAsUser前调用ImpersonateLoggedOnUser,在调用完CreateProcessAsUser()后调用RevertToSelf().

#18


呵呵,问题解决了,在ImpersonateLoggedOnUser之前调用LoadUserProfile(),因为IActiveDesktop在设置桌面的时候会用到一些HKEY_CURRENT_USER键里面的东西,CreateProcessAsUser不负责载入用户配置.

新问题又来了
在XP下测试没问题,怎么在Win2000下又不好使了呢?

#1


牛人呢?

#2


牛人还没出现

#3


mark

#4


在你那个改桌面的进程里打断点调试啊!
调用设置桌面的函数后,GetLastError()看下

#5


程序没有错,
原因是服务程序是和登陆用户无关的,先于WinLogon,而桌面是和用户相关的,一个用户对应一个或多个桌面——当然,只有一个是可见的。
由于修改桌面的程序是被服务程序启动的,因此无法得到用户的信息。
看了一些牛人说可以用DACL和ACEs来做,可是改过后还是不行。因为我对DACL和ACEs不熟,所以希望能有人指点一下。

#6


救命啊

#7


程序没有错
由于修改桌面的程序是被服务程序启动的,因此无法得到用户的信息。
----------------------------------------------------------------
既然你硬要这么说,我也没办法

#8


错误信息是什么?

#9


1 CreateService 时 在dwServiceType加上SERVICE_INTERACTIVE_PROCESS标记.
2 http://www.osronline.com/showthread.cfm?link=102869

#10


我的环境是Windows XP,我是用服务程序创建了一个客户程序,这个客户程序使用了IActiveDesktop来设置桌面.我想知道,客户程序里面要加上一些特别的代码吗?

下面是我在创建客户程序的代码

HANDLE              hToken;
HDESK               hdesk;
HWINSTA             hwinsta;
PROCESS_INFORMATION pi;
PSID                psid;
STARTUPINFO         si;

HANDLE hExp = GetProcessHandle("EXPLORER.EXE");
if(hExp == NULL)
return FALSE;

OpenProcessToken(hExp,TOKEN_ALL_ACCESS,&hToken);
if(hToken == NULL)
return FALSE;

HWND hDesk = GetDesktopWindow();
// BOOL bOk = ImpersonateLoggedOnUser(hToken);
// GenericLog(Info,"ImpersonateLoggedOnUser %s",bOk?"Ok":"Failed");
GenericLog(Info,"Desktop HWND %s",(hDesk == GetDesktopWindow())?"Equal":"Not Equal");


// 
// obtain a handle to the interactive windowstation
// 
hwinsta = OpenWindowStation(
"winsta0",
FALSE,
READ_CONTROL | WRITE_DAC
);
if (hwinsta == NULL)
return RTN_ERROR;

HWINSTA hwinstaold = GetProcessWindowStation();
GenericLog(Info,"WindowStation Old = %.8x,Curr = %.8x",hwinstaold,hwinsta);
// 
// set the windowstation to winsta0 so that you obtain the
// correct default desktop
// 
if (!SetProcessWindowStation(hwinsta))
return RTN_ERROR;

// 
// obtain a handle to the "default" desktop
// 
hdesk = OpenDesktop(
"default",
0,
FALSE,
READ_CONTROL | WRITE_DAC |
DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS
);
if (hdesk == NULL)
return RTN_ERROR;

// 
// obtain the logon sid of the user fester
// 
if (!ObtainSid(hToken, &psid))
return RTN_ERROR;

// 
// add the user to interactive windowstation
// 
if (!AddTheAceWindowStation(hwinsta, psid))
return RTN_ERROR;

// 
// add user to "default" desktop
// 
if (!AddTheAceDesktop(hdesk, psid))
return RTN_ERROR;

// 
// free the buffer for the logon sid
// 
RemoveSid(&psid);

// 
// close the handles to the interactive windowstation and desktop
// 
CloseWindowStation(hwinsta);

CloseDesktop(hdesk);
// 

ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb        = sizeof(STARTUPINFO);
si.lpDesktop = "winsta0\\default";

TCHAR szParameter[10] = {0};
// ShellExecute(NULL,"open",lpAppName,NULL,NULL,SW_HIDE);
if(CreateProcessAsUser(hToken,lpAppName,szParameter,NULL,
NULL,FALSE,CREATE_NO_WINDOW,NULL,NULL,&si,&pi))
{
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
GenericLog(Info,"Running %s ....",lpAppName);
UnregisteTimer(TIMER_CONNECT);
RegisteTimer(TIMER_FEEDDOG,3000);
return 1;
}
else
{
GenericLog(Info,"CreateProcess %s Fails ,reason = %d",lpAppName,GetLastError());
}
SetProcessWindowStation(hwinstaold); 
return RTN_OK;

#11


我要的不是与服务程序进行交互,我的目的只是让服务程序在用户登陆后创建一个新进程,这个新进程能够修改用户的桌面.

#12


这个线程能创建成功吗?

#13


线程创建是成功的,我的目的是让服务程序启动一个新进程,而不是要服务程序本身去和桌面交互

#14


我的客户进程里面用的IActiveDesktop来改变桌面,这有关系吗?

#15


应该是不用的,不过你还是在IActiveDesktop输出当前的用户名,看看是不是正确。

#16


那么我是该用"winsta0\\default"桌面呢?还是用其他的什么桌面呢?

#17


按照你所说的,我在客户程序里面调用GetUserName()得到的是当前用户的用户名.我试了一下,如果用服务程序打开客户程序,那么客户程序将不能显示桌面背景,可是如果这时打开IE的属性,点击确定,那么背景就会显示出来.而直接运行客户程序的话,就不会出现问题.
又,我的服务程序是用OpenProcessToken打开EXPLORER.EXE的令牌.在调用CreateProcessAsUser前调用ImpersonateLoggedOnUser,在调用完CreateProcessAsUser()后调用RevertToSelf().

#18


呵呵,问题解决了,在ImpersonateLoggedOnUser之前调用LoadUserProfile(),因为IActiveDesktop在设置桌面的时候会用到一些HKEY_CURRENT_USER键里面的东西,CreateProcessAsUser不负责载入用户配置.

新问题又来了
在XP下测试没问题,怎么在Win2000下又不好使了呢?