从Win服务启动UI程序

从windows服务启动一个带UI程序的界面,这个需求在xp中是很随意的,从Vista开始似乎没有那么随意了,因为Vista中加入了Session的概念,那么什么是Session,我想这篇文章介绍的应该比我权威的多。Session隔离介绍

明白了Session的概念后,我将通过Win32 API来实现从windows服务启动一个带UI的界面(从Session 0中启动Session *的程序),这个实现过程是我从C++代码翻译过来的。

实现的思路

  1. 找到一个除Session 0之外的活动Session
  2. 通过Session ID获取用户Token
  3. 通过Token来启动UI程序

涉及的Win32 API

  1. WTSGetActiveConsoleSessionId获取活动的Session ID
  2. WTSQueryUserToken根据Session ID获取用户Token
  3. CreateProcessAsUser使用用户Token来启动UI程序
public class ProcessAsUser
{
    public struct SECURITY_ATTRIBUTES
    {
        public uint nLength;
        public uint lpSecurityDescriptor;
        public bool bInheritHandle;
    }

    public struct STARTUPINFO
    {
        public uint cb;
        public string lpReserved;
        public string lpDesktop;
        public string lpTitle;
        public uint dwX;
        public uint dwY;
        public uint dwXSize;
        public uint dwYSize;
        public uint dwXCountChars;
        public uint dwYCountChars;
        public uint dwFillAttribute;
        public uint dwFlags;
        public ushort wShowWindow;
        public ushort cbReserved2;
        public IntPtr lpReserved2;
        public IntPtr hStdInput;
        public IntPtr hStdOutput;
        public IntPtr hStdError;

    }
    public struct PROCESS_INFORMATION
    {
        public IntPtr hProcess;
        public IntPtr hThread;
        public uint dwProcessId;
        public uint dwThreadId;

    }

    [DllImport("kernel32.dll")]
    static extern uint WTSGetActiveConsoleSessionId();

    [DllImport("Wtsapi32.dll")]
    private static extern bool WTSQueryUserToken(uint SessionId, out uint hToken);

    [DllImport("Kernel32.dll")]
    private static extern uint GetLastError();

    [DllImport("kernel32.dll")]
    private static extern bool CloseHandle(IntPtr hSnapshot);

    [DllImport("advapi32.dll")]
    public extern static bool CreateProcessAsUser(IntPtr hToken,
                                            string lpApplicationName,
                                            string lpCommandLine,
                                            ref SECURITY_ATTRIBUTES lpProcessAttributes,
                                            ref SECURITY_ATTRIBUTES lpThreadAttributes,
                                            bool bInheritHandle,
                                            uint dwCreationFlags,
                                            uint lpEnvironment,
                                            string lpCurrentDirectory,
                                            ref STARTUPINFO lpStartupInfo,
                                            out PROCESS_INFORMATION lpProcessInformation);

    public static bool StartUIProcessFromService(string exePath)
    {
        //获取Session ID
        var sId=WTSGetActiveConsoleSessionId();
        if (sId == 0)
        {
            return false;
        }
        uint hToken;
        var isOk=WTSQueryUserToken(sId, out hToken);
        if (!isOk || hToken == 0)
        {
            return false;
        }
        var lpProcessAttr = new SECURITY_ATTRIBUTES();
        lpProcessAttr.nLength = (uint)Marshal.SizeOf(lpProcessAttr);

        var lpThreadAttr = new SECURITY_ATTRIBUTES();
        lpThreadAttr.nLength = (uint)Marshal.SizeOf(lpThreadAttr);

        var lpStratupInfo = new STARTUPINFO();
        lpStratupInfo.cb = (uint)Marshal.SizeOf(lpStratupInfo);
        lpStratupInfo.lpDesktop = @"winsta0\default";

        PROCESS_INFORMATION lpProcessInfo;
        isOk=CreateProcessAsUser((IntPtr)hToken,
                                    exePath,
                                    null,
                                    ref lpProcessAttr,
                                    ref lpThreadAttr,
                                    false,
                                    0,
                                    0,
                                    null,
                                    ref lpStratupInfo,
                                    out lpProcessInfo
                                );
        CloseHandle((IntPtr)hToken);
        return isOk;            
    }    
}
 

枚举活动Session ID

之前我们通过WTSGetActiveConsoleSessionId获取活动Session ID,当有多个用户登录时,Windows提供了WTSEnumerateSessions方法枚举多个Session ID。

主要涉及API

  1. WTSEnumerateSessions 检索在远程桌面会话主机 (RD 会话主机) 服务器上的会话的列表。
  2. WTSFreeMemory 释放由远程桌面服务函数分配的内存。

实现代码

[DllImport("Wtsapi32.dll")]
private static extern void WTSFreeMemory(IntPtr pSessionInfo);

[DllImport("Wtsapi32.dll")]
private extern static bool WTSEnumerateSessions(IntPtr hServer, uint reserved, uint version, out IntPtr ppSessionInfo, out uint pCount);
struct WTS_SESSION_INFO
{
    public uint SessionId;
    public string pWinStationName;
    public WTS_CONNECTSTATE_CLASS State;
}

enum WTS_CONNECTSTATE_CLASS
{
    WTSActive,
    WTSConnected,
    WTSConnectQuery,
    WTSShadow,
    WTSDisconnected,
    WTSIdle,
    WTSListen,
    WTSReset,
    WTSDown,
    WTSInit
}

private static uint EnumerateActiveSession()
{
    uint dwSessionID = 0xFFFFFFFF;
    uint dwCount = 0;
    IntPtr intPtr = IntPtr.Zero;
    try
    {
        IntPtr hServer = IntPtr.Zero;
        if (WTSEnumerateSessions(hServer, 0, 1, out intPtr, out dwCount))
        {
            var tmp = intPtr;
            for (var i = 0; i < dwCount; ++i)
            {
                var pSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(tmp, typeof(WTS_SESSION_INFO));

                if (WTS_CONNECTSTATE_CLASS.WTSActive == pSessionInfo.State)
                {
                    dwSessionID = pSessionInfo.SessionId;
                    break;
                }
                if (WTS_CONNECTSTATE_CLASS.WTSConnected == pSessionInfo.State)
                {
                    dwSessionID = pSessionInfo.SessionId;
                }
                tmp += Marshal.SizeOf(typeof(WTS_SESSION_INFO));
            }
            WTSFreeMemory(intPtr);
        }
        var eCode = GetLastError();
    }
    catch (Exception ex)
    {
        var eCode = GetLastError();
    }
    return dwSessionID;
}

 

 

如何将 Visio 绘图粘贴或插入到其他 Office 程序

简介
本文介绍了多种方法,可用来复制 Microsoft Visio 绘图的对象并将它们粘贴到其他程序中。
要将 Visio 中的对象复制到其他程序,请根据您的环境使用以下方法之一。
方法 1:使用“按类型选择”命令或“特殊选定”命令
在Microsoft Office Visio 2007、Microsoft Office Visio 2003 和 Microsoft Visio 2002 中,可以使用“按类型选择”命令。在 Microsoft Visio 2000 中,可以使用“特殊选定”命令。要使用“按类型选择”命令或者“特殊选定”命令,请按照下列步骤操作:
  1. 启动 Visio,然后打开您的绘图。
  2. 在Visio 2007、Visio 2003 或 Visio 2002 中的“编辑”菜单上单击“按类型选择”。或者,在 Visio 2000 中单击“特殊选定”。
  3. 在“按类型选择”对话框或者“特殊选定”对话框中,执行以下步骤之一:
    • 单击“形状类型”。然后,单击选中或者清除下面的一个或多个复选框:
      • 形状
      • 组合
      • 参考线
      • OLE 对象
      • 图元文件
      • 位图
      此外,Visio 2003 中还提供以下形状类型:
      • 墨迹对象
    • 单击“图层”,然后单击选中所需图层旁边的复选框。
  4. ���击“确定”。
  5. 在“编辑”菜单上,单击“复制”。
  6. 切换到要粘贴 Visio 对象的目标文件。
    例如,如果要将 Visio 对象粘贴到 Microsoft Word 文档,则启动 Word 并打开要粘贴 Visio 对象的文档。
  7. 在“编辑”菜单上单击“粘贴”或“选择性粘贴”插入 Visio 对象。
方法 2:使用“全选”命令
要使用“全选”命令,请按照下列步骤操作:
  1. 启动 Visio,然后打开您的绘图。
  2. 在“编辑”菜单上,单击“全选”。
  3. 切换到要粘贴 Visio 对象的目标文件。
    例如,如果要将 Visio 对象粘贴到 Word 文档,则启动 Word 并打开要粘贴 Visio 对象的文档。
  4. 在“编辑”菜单上单击“粘贴”或“选择性粘贴”插入 Visio 对象。
方法 3:使用“复制绘图”命令
要使用“复制绘图”命令,请按照下列步骤操作:
  1. 启动 Visio,然后打开您的绘图。
  2. 确保在 Visio 中未选择任何内容。
  3. 在“编辑”菜单上,单击“复制绘图”。
    此命令将复制您正在查看的绘图页。
  4. 切换到要粘贴 Visio 对象的目标文件。
    例如,如果要将 Visio 对象粘贴到 Word 文档,则启动 Word 并打开要粘贴 Visio 对象的文档。
  5. 在“编辑”菜单上单击“粘贴”或“选择性粘贴”插入 Visio 对象。
方法 4:将 Visio 绘图另存为图形文件
要将 Visio 绘图另存为图形文件,请按照下列步骤操作:
  1. 启动 Visio,然后打开您的绘图。
  2. 选择要复制的对象。
    注意:如果想复制整个绘图页,请确保未选择 Visio 绘图中的任何对象。如果选择绘图中的对象,则只有选择的对象会出现在最终的图形文件中。
  3. 在“文件”菜单上,单击“另存为”。
  4. 在“保存类型”列表中,单击所需的图形文件类型,然后单击“保存”。下面的图形文件类型在Visio 2007、Visio 2003、Visio 2002 和 Visio 2000 中是共有的。这些共有图形文件类型在“保存类型”框中列出:
    • 增强型图元文件 (*.emf)
    • 图形交换格式 (*.gif)
    • JPEG 文件交换格式 (*.jpg)
    • 可移植网络图形 (*.png)
    • Tag 图像文件格式 (*.tif)
    • 压缩的增强型图元文件 (*.emz)
    • Windows 位图 (*.bmp; *.dib)
    • Windows 图元文件 (*.wmf)
    在Visio 2007 和Visio 2003 中,除列出上述共有图形文件类型外,还列出了下列图形文件类型:
    • 可缩放的向量图形 - 已压缩 (*.svgz)
    • 可缩放的向量图形 (*.svg)
    在 Visio 2002 和 Visio 2000 中,除列出上述共有图形文件类型外,还列出了下列图形文件类型:
    • Macintosh PICT 格式 (*.pct)
    • Zsoft PC Paintbrush Bitmap (*.pcx)
    • Adobe Illustrator 文件 (*.ai)
    • 计算机图形图元文件 (*.cgm)
    • 封装的 PostScript 文件 (.eps)
    • Postscript 文件 (*.ps)
    • IGES 图形文件格式 (*.igs)
    注意:当您使用“另存为”对话框导出形状或绘图时,可能会显示“输出选项”对话框,您可以在其中为导出文件指定所需的设置。“输出选项”对话框中显示的选项取决于您使用的图形文件格式。
  5. 切换到要粘贴 Visio 对象的目标文件。
    例如,如果要将 Visio 对象粘贴到 Word 文档,则启动 Word 并打开要粘贴 Visio 对象的文档。
  6. 在“插入”菜单上,指向“图片”,然后单击“来自文件”。
  7. 选择在 Visio 中保存的图形文件,然后单击“插入”。
    注意:此方法保留了形状、文本和填充的格式设置。但未保留图层属性。例如,如果某个形状位于隐藏层,则在插入图形文件后该形状不可见。
方法 5:在 Visio 2000 中使用“插入 Visio 绘图”按钮
此方法只适用于 Visio 2000。要安装和使用“插入 Visio 绘图”按钮,请按照下列步骤操作:
  1. 要在 Word、Microsoft Excel 和 Microsoft PowerPoint 中的工具栏上安装“插入 Visio 绘图”按钮,请运行“插入 Visio 按钮”程序。通常此程序位于下面的文件夹中:

    C:\Program Files\Microsoft Visio\System\Custom

  2. 要使用此按钮,请单击“插入 Visio 绘图”,然后单击“选择绘图类型”对话框中的“浏览模板”。
  3. 在“选择绘图模板”对话框中,单击“文件类型”下的“绘图 (*.vsd)”。单击要导入的绘图,然后单击“打开”。
    注意:如果图层处于锁定或隐藏状态,则必须先对图层取消隐藏和取消锁定,以便包括绘图中的所有元素。

PHP官网遭黑客入侵植入恶意程序

  PHP 语言官方网站被入侵植入了JavaScript 恶意代码,悄悄在浏览者电脑上安装恶意程序。但攻击者是通过哪个安全漏洞入侵系统 PHP.net 尚无头绪。

  PHP.net 已经连续发表了两个声明解释这次事故,称调查发现两台服务器被入侵,它们分别托管 www.php.net、static.php.net 和 git.php.net 域名,以及托管 bugs.php.net 域名,所有服务已经迁移到新的服务器。Git 源码库验证之后没发现问题。它怀疑攻击者可能访问了 php.net SSL 证书的私钥,因此撤销了证书,在新证书发布前 SSL 加密连接不可用。 php.net 宣布,未来几天所有用户将需要重置密码。根据 Alexa 排名,php.net 的排名排在第 228 位。

英文报道原文:

http://www.pcworld.com/article/2057980/phpnet-compromised-and-used-to-attack-visitors.html

设置应用程序中嵌入IE的版本

有些时候会用到,如Live Writer设置成11000(即IE11)的话,便可以让其编辑器支持HTML5的标签

如以下的效果:

具体设置如下:

打开注册表,找到并编辑以下选项:

livewriterHtml5

32bit Configuration on 64 bit machine:

HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION

Key: WindowsLiveWriter.exe
Value: 9000 or 10000  (IE 9 or 10 respectively) (DWORD value)

On a 32 bit only machine:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION

Key: WindowsLiveWriter.exe
Value: 9000 or 10000  (IE 9 or 10 respectively) (DWORD value)

Use decimal values of 9000, 10000 or 11000 to specify specific versions of Internet Explorer.

.NET程序在windows操作系统上独立运行的技术要点

最让.NET程序员苦恼的是,辛辛苦苦写出来的.NET程序,需要客户机上安装了.NET才能运行。仅为一个小小的应用程序去下载上百兆的.NET安装包,还得把它老老实实安装到客户机上,并占掉数百兆磁盘空间,这无疑是一件得不偿失的事情。.NET程序的这个弱点,也是影响.NET应用程序普及和价值的一个重要因素。
所谓“独立运行”,是指.NET应用程序脱离完整的.NET运行环境,像c语言编译的程序那样,在操作系统上直接运行。简单地说就是:客户电脑无需安装任何版本的.NET框架,你的.NET程序照样可以在他的电脑或服务器上运行。
.NET程序独立运行的基础是mono运行时以及它的程序集。mono是什么呢,mono是一款开源、免费、可定制的跨平台.NET运行环境,同时,它还包含了一系列具有重要意义的实用工具,当前最新的版本号是3.0.10,本文所采用的mono,即是这个版本号的windows版。

那么,到底怎么才能让你的.NET程序无障碍地在没有安装.NET平台的客户机“独立运行”呢,下面直奔主题。

一,建立跨平台的.NET环境与编译环境:
1、下载并安装mono的windows版,建议将它安装到c:\mono文件夹中。
2、安装cygwin。
A、建议将它安装到c:\cygwin文件夹中。
B、安装时,请将mingw-gcc、mingw-zlib、pkg-config、libiconv这几个组件选上,这是将.NET程序转化为本地程序的必要的编译环境。

二,启动cgywin并设置环境变量:
1、点击开始菜单或桌面上的cygwin图标,启动且进入cygwin环境。
2、输入下面的命令,设置或修改必要的环境变量:
export PKG_CONFIG_PATH=/cygdrive/c/mono/lib/pkgconfig
export PATH=$PATH:/cygdrive/c/mono/bin

三,将你的.NET程序转化为“独立程序”

请注意,这是本文的关键所在,很多地方的操作都有别于其它网文和mono官网所介绍的操作技术。

1,复制文件。把需编译的.NET EXE文件和对应的DLL文件复制到你在cygwin的工作文件夹中,如果你的windows用户名是xyz,那么这个文件夹就是 c:\cygwin\home\xyz\,(这一步不是必须的,如果你不怕麻烦而愿意多打字的话)。

2,转换与打包。通过下面的命令,将.net程序和类库打包并得到一个c程序源码(假设你需要转换的.NET文件是a.exe)。
mkbundle -c -o b.c -oo b.o a.exe -z
或者:
mkbundle -c -o b.c -oo b.o a.exe aa.dll c:\\mono\\lib\\mono\\4.5\\mscorlib.dll -z
或者:
mkbundle -c -o b.c -oo b.o --dept a.exe -z

3,修改得到的c文件:
这是本文的精华所在。
为什么要修改这个c文件,很简单:
A,不希望与exe文件相关的类库全部打包到一个文件中,否则,太浪费,而且影响启动速度。
B,这个c文件是目标程序的关键文件,我希望在中间加上自己的东西,让我的程序如虎添翼。
C,我程序要在中文、日文这样的含有非英文字母的文件夹中运行。

3.1,需要添加和修改的内容:
A,用VS或记事本打开b.c,把下面的代码复制到main函数之前,作一个准备。

#include <dir.h>
#include "/usr/include/iconv.h"
int gbk_utf8(char *inbuf,int inlen,char *outbuf,int outlen){
iconv_t cd;
char **pin = &inbuf;
char **pout = &outbuf;
cd = iconv_open("utf-8","gbk");
if (cd == 0) return -1;
memset(outbuf, 0, outlen);
if (iconv(cd, pin, &inlen, pout, &outlen) == -1) return -1;
iconv_close(cd);
return 0;
    }

 

B、在main函数中,找到下面这两行并注释或删除掉:

if (config_dir != NULL && getenv ("MONO_CFG_DIR") == NULL)
mono_set_dirs (getenv ("MONO_PATH"), config_dir);

 

C、接着,就在这行下边,即“mono_mkbundle_init”一行之前,输入下边的代码:

const char* lib = "\\lib";
const char* etc = "\\etc";

char p[strlen(argv[0])];
wsprintf(p,"%s",argv[0]);

int l = 0;
l = strlen(p);
for(i=l-1; i>0; i--){
 if(p[i] == '\\'){
 p[i] = '\0';
 break;
        }
    }

 l = strlen(p) + strlen(lib);
 char s_lib[l];
 wsprintf(s_lib, "%s%s", p, lib);

 l = strlen(s_lib);
 char* s_lib_utf8 = (char*)malloc(l*2);
 memset(s_lib_utf8, 0, l*2);
 gbk_utf8(s_lib, l, s_lib_utf8, l*2);

 l = strlen(p) + strlen(etc);
 char s_etc[l];
 wsprintf(s_etc, "%s%s", p, etc);

 l = strlen(s_etc);
 char* s_etc_utf8 = (char*)malloc(l*2);
 memset(s_etc_utf8, 0, l*2);
 gbk_utf8(s_etc, l, s_etc_utf8, l*2);

 mono_set_dirs(s_lib_utf8, s_etc_utf8);

 

接着在mono_mkbundle_init一行之后加入一行:

chdir("c:\\");

 

最后,找到下面三行

#ifdef _WIN32
 #include <windows.h>
 #endif

 

并在“#endif”后加入一行:

 #undef _WIN32

 

改完了,存盘退出。
(有人会说“输入这么多,为什么不写个函数以方便我将来复用?”,我说,这不是我的事。)

3.2,编译:
用下面这个命令生成你的目标文件“b.exe”。
gcc -mno-cygwin -o b.exe -Wall b.c `pkg-config --cflags --libs mono-2|dos2unix` b.o -lz -liconv

四,程序、类库、配置文件的组织:
这一步,是为你的程序安一个家,让它真的能跑起来。

1,在某个盘,比如D盘,建个文件夹,比如是“myapp”
把刚才编译得到的目标文件b.exe复制到D:\myapp文件夹中。
同时把c:\mono\bin\文件夹中的mono-2.0.dll、zlib1.dll、iconv.dll复制到d:\myapp中。

2,组织类库
在“d:\myapp”文件夹中,建lib和etc两个子目录。
在lib文件夹中,建名叫“mono”的文件夹。
在d:\myapp\lib\mono文件夹中,根据你.NET程序集版本号建一个文件夹,名字就是版本号,比如“4.5”,当然,你也可以把2.0、4.0也建好。
如果你没有将mscorlib.dll打包到.EXE中,请将c:\mono\lib\mono\4.5\mscorlib.dll,复制到 d:\myapp\lib\mono\4.5这个文件夹中。
在d:\myall\lib\mono文件夹中,建一个名为gac的文件夹,这个文件夹是用来放你的程序需要的mono版.NET类库的。
放些什么?放你的exe、dll文件中引用到的那些程序集的库文件(如果你已经把这些文件打包到了.exe中,那么你就不需要放任何文件)。
比如,你引用了System名字空间,那么,将c:\mono\lib\mono\gac文件夹下的System文件夹复制到D:\myapp\lib\mono\gac中就行了。

3,组织配置文件
把c:\mono\etc文件夹中的“mono”文件夹复制到d:\myapp\etc文件夹中。
用写字版打开config文件,找到并删除下列三行:

 <dllmap dll="gdiplus" target="/tmp/install/lib/libgdiplus.so" />
 <dllmap dll="gdiplus.dll" target="/tmp/install/lib/libgdiplus.so" />
 <dllmap dll="gtkhtml-3.0" target="libgtkhtml-3.8-15.dll"/>

 

通过上面的几个步骤,你的程序已经变成了可以独立运行的程序了,你把d:\myapp这个文件夹压缩打包,然后解压到没有安装.net的电脑上,试试。
可能有读者会说,对本文某些地方不太理解或者有异议,那么,我欢迎讨论。

补充:

关于中文字符集

mkbundle生成的程序,并没有GB2312等字符集信息,如果有GetEncoding("gb2312")这样的调用,肯定会出错。
解决办法:
1、把mono的I18N.dll、I18N.CJK.dll打包到目标程序中。
2、把mono的lib\mono\gac中的I18N、I18N.CJK文件夹,复制到你应用程序目录的lib\mono\gac中。

常见问题:

gcc有可能提示“cannot find -liconv”,解决这个问题的办法是:在gcc命令行中加入参数 “-LC:/cygwin/lib”,明确指定iconv库的搜索路径。

关于“独立exe”调用dll类库的技巧

exe调用的dll,有三个处理办法:
1、打包到exe中;
2、签名后,放到这个exe所在的文件夹下的lib/mono/gac子文件夹中;
3、直接放到这个exe所在文件夹的lib文件夹中。

如何判别一个.Net程序的目标平台

判别一个.Net程序的目标平台是x86/x64/AnyCpu中的哪个,可以使用以下方法:

1、在VS2010/12/13中的解决方案管理器中,右键你需要使用检测平台的项目

2、选择管理 Nuget 程序包

3、选择 联机 –> Nuget官方程序包源 –> 搜索 LSWFramework

4、点击安装,并等待安装完成

5、在代码中通过以下的代码调用即可

LSW.Common.Runtime.GetAssemblyDetails("D:\WindowsFormsApplication1.exe").CPUVersion.ToString

Windows RT越狱工具已发布 可运行未经签名的桌面程序

前两天我们就报道称安全研究人员clrokr已经研究出了Windows RT的暂时越狱方法,让微软的ARM操作系统运行未经签名的、基于ARM的桌面程序。现在,另一位程序员也发布了他的Windows RT自动越狱工具。

该工具的创作者名为"netham45″,于今天早些时候在XDA Developers网站发布这个工具。这一工具主要是通过修改Windows RT系统内核里的一个特定部分,让用户更改系统的最低签名等级从而在Windows RT上运行未签名的桌面程序。

微软之前表示其虽然“为这种聪明的做法而鼓掌”,但是他们指出这个越狱需要在Windows RT每次启动时进行,重启后将不复存在。这是因为该操作系统的UEFI安全引导过程目前把持着最低签名等级在一个永久基础上。微软还表示这个模式“…其实算不上一个安全漏洞,而且并不会对Windows RT构成威胁。”

更重要的是微软可能正在想办法关闭Windows RT的这个漏洞,即便它不是一个高危漏洞。

下载地址:

http://qiannao.com/file/lishewen/c4877ef1/