asp.net中穿透Session 0 隔离(二)
程序员文章站
2024-03-06 16:00:08
对于简单的交互,服务可以通过wtssendmessage 函数,在用户session 上显示消息窗口。对于一些复杂的ui 交互,必须调用createprocessasuse...
对于简单的交互,服务可以通过wtssendmessage 函数,在用户session 上显示消息窗口。对于一些复杂的ui 交互,必须调用createprocessasuser 或其他方法(wcf、.net远程处理等)进行跨session 通信,在桌面用户上创建一个应用程序界面。
wtssendmessage 函数
如果服务只是简单的向桌面用户session 发送消息窗口,则可以使用wtssendmessage 函数实现。首先,在上一篇下载的代码中加入一个interop.cs 类,并在类中加入如下代码:
public static intptr wts_current_server_handle = intptr.zero;
public static void showmessagebox(string message, string title)
{
int resp = 0;
wtssendmessage(
wts_current_server_handle,
wtsgetactiveconsolesessionid(),
title, title.length,
message, message.length,
0, 0, out resp, false);
}
[dllimport("kernel32.dll", setlasterror = true)]
public static extern int wtsgetactiveconsolesessionid();
[dllimport("wtsapi32.dll", setlasterror = true)]
public static extern bool wtssendmessage(
intptr hserver,
int sessionid,
string ptitle,
int titlelength,
string pmessage,
int messagelength,
int style,
int timeout,
out int presponse,
bool bwait);
在showmessagebox 函数中调用了wtssendmessage 来发送信息窗口,这样我们就可以在service 的onstart 函数中使用,打开service1.cs 加入下面代码:
protected override void onstart(string[] args)
{
interop.showmessagebox("this a message from alertservice.", "alertservice message");
}
编译程序后在服务管理器中重新启动alertservice 服务,从下图中可以看到消息窗口是在当前用户桌面显示的,而不是session 0 中。
createprocessasuser 函数
public static void createprocess(string app, string path)
{
bool result;
intptr htoken = windowsidentity.getcurrent().token;
intptr hdupedtoken = intptr.zero;
process_information pi = new process_information();
security_attributes sa = new security_attributes();
sa.length = marshal.sizeof(sa);
startupinfo si = new startupinfo();
si.cb = marshal.sizeof(si);
int dwsessionid = wtsgetactiveconsolesessionid();
result = wtsqueryusertoken(dwsessionid, out htoken);
if (!result)
{
showmessagebox("wtsqueryusertoken failed", "alertservice message");
}
result = duplicatetokenex(
htoken,
generic_all_access,
ref sa,
(int)security_impersonation_level.securityidentification,
(int)token_type.tokenprimary,
ref hdupedtoken
);
if (!result)
{
showmessagebox("duplicatetokenex failed" ,"alertservice message");
}
intptr lpenvironment = intptr.zero;
result = createenvironmentblock(out lpenvironment, hdupedtoken, false);
if (!result)
{
showmessagebox("createenvironmentblock failed", "alertservice message");
}
result = createprocessasuser(
hdupedtoken,
app,
string.empty,
ref sa, ref sa,
false, 0, intptr.zero,
path, ref si, ref pi);
if (!result)
{
int error = marshal.getlastwin32error();
string message = string.format("createprocessasuser error: {0}", error);
showmessagebox(message, "alertservice message");
}
if (pi.hprocess != intptr.zero)
closehandle(pi.hprocess);
if (pi.hthread != intptr.zero)
closehandle(pi.hthread);
if (hdupedtoken != intptr.zero)
closehandle(hdupedtoken);
}
[structlayout(layoutkind.sequential)]
public struct startupinfo
{
public int32 cb;
public string lpreserved;
public string lpdesktop;
public string lptitle;
public int32 dwx;
public int32 dwy;
public int32 dwxsize;
public int32 dwxcountchars;
public int32 dwycountchars;
public int32 dwfillattribute;
public int32 dwflags;
public int16 wshowwindow;
public int16 cbreserved2;
public intptr lpreserved2;
public intptr hstdinput;
public intptr hstdoutput;
public intptr hstderror;
}
[structlayout(layoutkind.sequential)]
public struct process_information
{
public intptr hprocess;
public intptr hthread;
public int32 dwprocessid;
public int32 dwthreadid;
}
[structlayout(layoutkind.sequential)]
public struct security_attributes
{
public int32 length;
public intptr lpsecuritydescriptor;
public bool binherithandle;
}
public enum security_impersonation_level
{
securityanonymous,
securityidentification,
securityimpersonation,
securitydelegation
}
public enum token_type
{
tokenprimary = 1,
tokenimpersonation
}
public const int generic_all_access = 0x10000000;
[dllimport("kernel32.dll", setlasterror = true,
charset = charset.auto, callingconvention = callingconvention.stdcall)]
public static extern bool closehandle(intptr handle);
[dllimport("advapi32.dll", setlasterror = true,
charset = charset.ansi, callingconvention = callingconvention.stdcall)]
public static extern bool createprocessasuser(
intptr htoken,
string lpapplicationname,
string lpcommandline,
ref security_attributes lpprocessattributes,
ref security_attributes lpthreadattributes,
bool binherithandle,
int32 dwcreationflags,
intptr lpenvrionment,
string lpcurrentdirectory,
ref startupinfo lpstartupinfo,
ref process_information lpprocessinformation);
[dllimport("advapi32.dll", setlasterror = true)]
public static extern bool duplicatetokenex(
intptr hexistingtoken,
int32 dwdesiredaccess,
ref security_attributes lpthreadattributes,
int32 impersonationlevel,
int32 dwtokentype,
ref intptr phnewtoken);
[dllimport("wtsapi32.dll", setlasterror=true)]
public static extern bool wtsqueryusertoken(
int32 sessionid,
out intptr token);
[dllimport("userenv.dll", setlasterror = true)]
static extern bool createenvironmentblock(
out intptr lpenvironment,
intptr htoken,
bool binherit);
在createprocess 函数中同时也涉及到duplicatetokenex、wtsqueryusertoken、createenvironmentblock 函数的使用,有兴趣的朋友可通过msdn 进行学习。完成createprocess 函数创建后,就可以真正的通过它来调用应用程序了,回到service1.cs 修改一下onstart 我们来打开一个cmd 窗口。如下代码:
protected override void onstart(string[] args)
{
interop.createprocess("cmd.exe",@"c:\windows\system32\");
}
重新编译程序,启动alertservice 服务便可看到下图界面。至此,我们已经可以通过一些简单的方法对session 0 隔离问题进行解决。大家也可以通过wcf 等技术完成一些更复杂的跨session 通信方式,实现在windows 7 及vista 系统中服务与桌面用户的交互操作。
wtssendmessage 函数
如果服务只是简单的向桌面用户session 发送消息窗口,则可以使用wtssendmessage 函数实现。首先,在上一篇下载的代码中加入一个interop.cs 类,并在类中加入如下代码:
复制代码 代码如下:
public static intptr wts_current_server_handle = intptr.zero;
public static void showmessagebox(string message, string title)
{
int resp = 0;
wtssendmessage(
wts_current_server_handle,
wtsgetactiveconsolesessionid(),
title, title.length,
message, message.length,
0, 0, out resp, false);
}
[dllimport("kernel32.dll", setlasterror = true)]
public static extern int wtsgetactiveconsolesessionid();
[dllimport("wtsapi32.dll", setlasterror = true)]
public static extern bool wtssendmessage(
intptr hserver,
int sessionid,
string ptitle,
int titlelength,
string pmessage,
int messagelength,
int style,
int timeout,
out int presponse,
bool bwait);
在showmessagebox 函数中调用了wtssendmessage 来发送信息窗口,这样我们就可以在service 的onstart 函数中使用,打开service1.cs 加入下面代码:
复制代码 代码如下:
protected override void onstart(string[] args)
{
interop.showmessagebox("this a message from alertservice.", "alertservice message");
}
编译程序后在服务管理器中重新启动alertservice 服务,从下图中可以看到消息窗口是在当前用户桌面显示的,而不是session 0 中。
createprocessasuser 函数
如果想通过服务向桌面用户session 创建一个复杂ui 程序界面,则需要使用createprocessasuser 函数为用户创建一个新进程用来运行相应的程序。打开interop 类继续添加下面代码:
复制代码 代码如下:
public static void createprocess(string app, string path)
{
bool result;
intptr htoken = windowsidentity.getcurrent().token;
intptr hdupedtoken = intptr.zero;
process_information pi = new process_information();
security_attributes sa = new security_attributes();
sa.length = marshal.sizeof(sa);
startupinfo si = new startupinfo();
si.cb = marshal.sizeof(si);
int dwsessionid = wtsgetactiveconsolesessionid();
result = wtsqueryusertoken(dwsessionid, out htoken);
if (!result)
{
showmessagebox("wtsqueryusertoken failed", "alertservice message");
}
result = duplicatetokenex(
htoken,
generic_all_access,
ref sa,
(int)security_impersonation_level.securityidentification,
(int)token_type.tokenprimary,
ref hdupedtoken
);
if (!result)
{
showmessagebox("duplicatetokenex failed" ,"alertservice message");
}
intptr lpenvironment = intptr.zero;
result = createenvironmentblock(out lpenvironment, hdupedtoken, false);
if (!result)
{
showmessagebox("createenvironmentblock failed", "alertservice message");
}
result = createprocessasuser(
hdupedtoken,
app,
string.empty,
ref sa, ref sa,
false, 0, intptr.zero,
path, ref si, ref pi);
if (!result)
{
int error = marshal.getlastwin32error();
string message = string.format("createprocessasuser error: {0}", error);
showmessagebox(message, "alertservice message");
}
if (pi.hprocess != intptr.zero)
closehandle(pi.hprocess);
if (pi.hthread != intptr.zero)
closehandle(pi.hthread);
if (hdupedtoken != intptr.zero)
closehandle(hdupedtoken);
}
[structlayout(layoutkind.sequential)]
public struct startupinfo
{
public int32 cb;
public string lpreserved;
public string lpdesktop;
public string lptitle;
public int32 dwx;
public int32 dwy;
public int32 dwxsize;
public int32 dwxcountchars;
public int32 dwycountchars;
public int32 dwfillattribute;
public int32 dwflags;
public int16 wshowwindow;
public int16 cbreserved2;
public intptr lpreserved2;
public intptr hstdinput;
public intptr hstdoutput;
public intptr hstderror;
}
[structlayout(layoutkind.sequential)]
public struct process_information
{
public intptr hprocess;
public intptr hthread;
public int32 dwprocessid;
public int32 dwthreadid;
}
[structlayout(layoutkind.sequential)]
public struct security_attributes
{
public int32 length;
public intptr lpsecuritydescriptor;
public bool binherithandle;
}
public enum security_impersonation_level
{
securityanonymous,
securityidentification,
securityimpersonation,
securitydelegation
}
public enum token_type
{
tokenprimary = 1,
tokenimpersonation
}
public const int generic_all_access = 0x10000000;
[dllimport("kernel32.dll", setlasterror = true,
charset = charset.auto, callingconvention = callingconvention.stdcall)]
public static extern bool closehandle(intptr handle);
[dllimport("advapi32.dll", setlasterror = true,
charset = charset.ansi, callingconvention = callingconvention.stdcall)]
public static extern bool createprocessasuser(
intptr htoken,
string lpapplicationname,
string lpcommandline,
ref security_attributes lpprocessattributes,
ref security_attributes lpthreadattributes,
bool binherithandle,
int32 dwcreationflags,
intptr lpenvrionment,
string lpcurrentdirectory,
ref startupinfo lpstartupinfo,
ref process_information lpprocessinformation);
[dllimport("advapi32.dll", setlasterror = true)]
public static extern bool duplicatetokenex(
intptr hexistingtoken,
int32 dwdesiredaccess,
ref security_attributes lpthreadattributes,
int32 impersonationlevel,
int32 dwtokentype,
ref intptr phnewtoken);
[dllimport("wtsapi32.dll", setlasterror=true)]
public static extern bool wtsqueryusertoken(
int32 sessionid,
out intptr token);
[dllimport("userenv.dll", setlasterror = true)]
static extern bool createenvironmentblock(
out intptr lpenvironment,
intptr htoken,
bool binherit);
在createprocess 函数中同时也涉及到duplicatetokenex、wtsqueryusertoken、createenvironmentblock 函数的使用,有兴趣的朋友可通过msdn 进行学习。完成createprocess 函数创建后,就可以真正的通过它来调用应用程序了,回到service1.cs 修改一下onstart 我们来打开一个cmd 窗口。如下代码:
复制代码 代码如下:
protected override void onstart(string[] args)
{
interop.createprocess("cmd.exe",@"c:\windows\system32\");
}
重新编译程序,启动alertservice 服务便可看到下图界面。至此,我们已经可以通过一些简单的方法对session 0 隔离问题进行解决。大家也可以通过wcf 等技术完成一些更复杂的跨session 通信方式,实现在windows 7 及vista 系统中服务与桌面用户的交互操作。
参考资料
1. wtssendmessage function
http://msdn.microsoft.com/en-us/library/aa383842(vs.85).aspx
2. createprocessasuser function
http://msdn.microsoft.com/en-us/library/ms682429(v=vs.85).aspx
3. wtssendmessage (wtsapi32)
http://www.pinvoke.net/default.aspx/wtsapi32/wtssendmessage.html
4. wtsqueryusertoken function
http://msdn.microsoft.com/en-us/library/aa383840(vs.85).aspx
5.
代码下载 alertservice2_jb51.rar
作者:李敬然(gnie)
出处:{gnietech} (http://www.cnblogs.com/gnielee/)