html5/css教程

javascript教程

asp教程

php教程

jsp教程

C#/.NET教程

Python教程

网络营销

建站经验

点击排行

您现在的位置:首页 > 网络教程 > php技巧

Windows 10安装开启Linux子系统的方法

来源:中文源码网    浏览: 次    日期:2017年6月5日

Windows 10众多新特征中,Linux环境子系统(WSL)无疑是最具开创性的一个。

启用WSL

Windows 10系统运行WSL,要满足两个基本要求:64位和Build号不低于14393.0(如14393.1198和14393.479)。

在满足上述条件的Windows 10中,WSL也不是默认安装的,而是需要通过以下两个步骤来启用。

第一步是通过Settings -> Update and Security -> For developers打开开发者模式(参见图1)。

图1 打开开发者模式

第二步是通过“Turn Windows features on or off”打开WSL功能(图2)。

图2 打开WSL功能

点击图2所示的确定按钮后,Windows 10会安装WSL的组件,需要一点时间。安装完成后,要重启系统。重启后,在开始菜单区输入bash,如果看到图3所示的菜单项就代表WSL启用成功了。Bash是GNU旗下的命令处理器和外壳(shell)程序,包括Ubuntu在内的很多Linux发行版本和苹果macOS都使用它作为默认的控制台外壳和命令处理器。Windows 10中使用的就是Ubuntu版本的Bash。因此,WSL有时也被称为Bash on Ubuntu on Windows。

图3 Bash on Ubuntu on Windows

启用WSL成功代表着在Windows系统中搭建好了运行Linux应用的基本环境,这个环境就是所谓的Windows Subsystem for Linux(WSL)。环境子系统是NT内核固有的机制,目的是可以在一个NT内核运行不同类型的应用程序。在支持WSL之前,有三种子系统:Windows子系统、OS/2子系统和POSIX子系统。

每个子系统通常都有一个子系统服务进程和一个内核态驱动,对于Windows子系统,分别是著名的CSRSS.exe和Win32K.sys。对于WSL,它的组成主要有以下几个部分:

以系统服务形式运行的子系统服务进程LxssManager。在服务管理器里,可以看到这个服务。服务的描述信息很详实,不妨引用一下:LXSS Manager服务支持运行本机ELF二进制文件。该服务提供在Windows上运行ELF二进制文件所需的基础结构。如果停止或禁用该服务,这些二进制文件将不再运行。LxssManager的核心代码是一个DLL,位于system32\lxss子目录下。它使用svchost.exe作为宿主运行。

图4 WSL的子系统服务DLL

运行在内核空间的Linux子系统驱动,有两个,一个文件名叫lxss.sys,另一个叫LxCore.sys,都位于system32\drivers目录中,图5是lxss驱动在注册表中的安装选项。

图5 Linux子系统驱动的注册表表项

用于与Windows环境接口的Bash启动(Bash Launcher)程序bash.exe,位于system32目录下,图3中的菜单项指向的就是这个程序。

一个用于管理和维护WSL的工具程序,名为LxRun.exe。

安装Ubuntu

有了上面的基本运行环境就可以运行Linux应用程序了么?不是的,还需要安装Linux系统,包括系统程序、库文件和必要的工具程序。不过不用担心,微软已经和Canonical(Ubuntu背后的公司)合作准备好了一个特殊版本的Ubuntu,称为Ubuntu On Windows(以下简称UoW)。第一次启动Bash Launcher时,它就会提示安装UoW,如图6所示。

图6 安装Ubuntu On Windows

安装UoW后,便可以在当前用户的AppData\Local\lxss下看到Ubuntu的各个子目录和文件了,图7所示的便是根文件系统下的子目录和文件,可以看到很多熟悉的名字:tmp、boot、etc、home、sbin、bin、usr、var等。

图7 磁盘上的Ubuntu根目录

安装其它应用

UoW里已经包含了很多常用的命令和工具,包括著名的软件包管理工具apt-get。所以很容易在UoW里安装其它软件包,只要使用以下这些命令就可以了。

代码

sudoapt-getupdate

sudoapt-getinstallpackagename

sudoapt-getremovepackagename

sudoapt-cachesearchword

对老雷来说,最想安装的当然就是GDB,这只要执行sudo apt-get install gdb就可以了,安装过程如图8所示。

图8 安装GDB

观察Linux实例的创建过程

做好以上准备工作后,我们的下一个目标就是在调试器里理解WSL的工作原理。首先我们要观察的是在WSL中启动Linux实例的过程。

在内核调试会话中对nt!MmInitializeProcessAddressSpace设置断点,然后启动bash.exe,第一次命中后直接放行(bash.exe是普通的Windows进程,不感兴趣),第二次命中时,看到的是services.exe在创建svchost.exe,切换到bash.exe,观察其栈回溯,可以看到它正在构建用以与WSL服务进程通信的SvcComm对象(图9)。此对象的构造函数内部会调用CoCreateInstance创建由WSL服务进程实现的进程外COM对象。这会触发创建COM对象的宿主进程,即svchost.exe。

图9 Bash Launcher进程在与WSL服务进程建立通信

图10是来自WSL团队官方博客的WSL组件协作图,左侧的bash.exe和Linux会话管理服务之间的黑色箭头代表它们之间是通过COM技术交互的。

图10 WSL组件协作图

恢复目标执行后,断点很快又命中,栈回溯如图11所示。

图11 创建Linux实例

从栈帧12-17可以看出,这次命中断点的正是WSL服务进程,它在通过I/O控制(I/O Control)方式与内核空间的LxCore通信。栈帧9-b中的Adss代表的是Android subsystem,是微软放弃了的Astoria项目(用于在Windows上运行Android应用程序)留下的痕迹。

根据笔者的分析和图10、图11所示栈回溯是在创建Linux系统中的init进程。当init进程启动后,会创建真正的bash进程。图12显示了创建bash进程后的WSL有关进程列表。

图12 创建bash进程后的WSL有关进程列表

图12中一共有四个进程,第一个是bash launcher进程,从操作系统的角度看,它是典型的Windows程序。第二个进程是WSL的子系统服务进程,第三个是它发起创建的init进程,第四个是init进程创建的bash进程。通过ParentCid(父进程ID)字段,可以看到后三个进程有父子关系。图13是使用Process Explorer观察的结果。

图13 WSL的进程关系图

最小进程和Pico进程

要深入理解WSL,必须先了解最近几年里NT内核引入的两个新概念:最小进程和Pico进程。最小进程是Windows 8.1引入的,代表一个最小化的进程对象,它具有名字、令牌、保护级别等基本属性,但是进程空间是空的,没有PEB,也没有NTDLL,也没有句柄表。EPROCESS结构体中的Minimal为1代表该进程是最小进程。比如观察图12中的init进程,可以看到它是最小进程。

代码

kd>dt_EPROCESSffffce8d779b9780-yMinimal

nt!_EPROCESS

+0x6c4Minimal:0y1

除了WSL使用最小进程外,Windows 10中的内存压缩进程也是最小进程。

Pico进程是最小进程的一种,它的特点是有一个驱动程序与其关联,当这个进程内发生系统调用时,内核会把系统调用转给这个驱动,这个驱动被称为Pico Provider,这样的进程被称为Pico进程。图14是来自WSL官方博客的插图,用以说明NT系统中的三种进程。

图14 三种进程

Pico的意思是微小,常常出现在容器技术中。从容器技术的角度来看,可以把Pico进程看作一个沙盒。事实上,Pico进程便源于Stony Brook University、Cambridge和微软研究院联合开发的Drawbridge项目。在Channel9上可以找到一个名为Drawbridge: A New Form of Virtualization for Application Sandboxing的录像,介绍了Library OS的思想和Drawbridge项目实现的技术原型。

用于WSL的Pico进程空间中可以执行Linux的原生程序,当发生系统调用时,内核会将这些调用转发给与它关联的驱动(Pico Provider)。比如图15所示的栈回溯显示的便是NT内核将系统调用转发给LxCore的过程。

图15 转发系统调用

文章收尾之际再介绍一个调试小技巧。对于已经有20多年历史的NT内核来说,WSL绝对是新生事物,很多配套设施还不完善,比如在WinDBG中列进程时所有Pico进程的名字都显示为System Process(图12中下面两个),很不方便。如何知道它们的Linux进程名呢?是有办法的。在EPROCESS中有个名为PicoContext的字段(目前偏移0x708),指向的是一个记录Pico属性的结构体,它的详细定义没有公开,笔者通过反汇编了解到在它的偏移0x180处存放的便是进程的可执行文件路径。基于此,便可以使用如下命令来显示了:

代码

kd>dUpoi(poi(ffffce8d779b9780+708)+180)

ffffa782`0e43d960"/init"

kd>dUpoi(poi(ffffce8d78f31080+708)+180)

ffffa782`19840fa0"/bin/bash"

如果有人问执行uname -a会返回什么,试一下便知道了。

代码

gedu@DESKTOP-4NBEECU:/mnt/c/Windows/System32$uname-a

LinuxDESKTOP-4NBEECU3.4.0+#1PREEMPTThuAug117:06:05CST2013x86_64x86_64x86_64GNU/Linux

在LXCORE!LxpSyscall_NEWUNAME设个断点便可以跟踪这个结果的产生过程,有些来自字符串常量,有些是动态拼接的。

亲,试试微信扫码分享本页! *^_^*

精彩推荐

相关内容