Windows调试之安全测试

本文深入探讨Windows操作系统中的安全机制,包括安全对象、访问控制列表、安全标识符等核心概念,并介绍如何通过调试扩展功能来诊断和修复软件中的安全问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

      几乎在很短的时间里,人们对安全的态度发生了巨大的转变,无论是开发人员还是终端用户。几年前,大多数计算机都是未联网的设备,计算机安全问题的主要来源也只是一些离线媒介,例如软盘。在当时,最大的安全问题就是病毒。现在,随着网络连接率日益增加,几乎所有计算机的安全问题都可以被远程攻击。

      在一些老的操作系统中,例如 Windows 95 ,并不支持本地计算机上的安全对象。 Windows NT 的出现为用户带来了符合 C2 级安全标准的内核。今天, Windows 操作系统的客户端版本——即 Windows XP 家庭版和 Windows Vista 家庭版——能够控制对每个对象的访问,因此发生拒绝访问故障( Access Denied Failure )的概率也就越大。另一种推动力是来自安全社群,他们在运行进程时通常使用最低的用户权限。这样可以将主机和程序中的安全漏洞分离开来。那么,如果以非管理员权限来运行程序,那么在实际情况中会有多大的可行性?可能只有一些在设计时考虑了安全因素的程序才能运行,而大多数程序将无法运行,因为它们仍然需要访问一些只有管理员才可以访问的注册表位置或者文件系统位置。

      对象安全性是开发一流软件的基础要素。本章将介绍如何分析和修复软件中的安全问题。本章将重点介绍当合法操作遇到一系列故障时所应采取的步骤,而并不会介绍由于代码缺陷所导致的一些未预期行为(例如缓冲区溢出,整数溢出等),这些缺陷通常会被病毒利用,在其他的参考书中已经给出了详尽的介绍。在本章中,我们将讨论以下内容:

■Windows 安全的基本知识以及工作机制。我们将给出在分析与安全相关的问题时需要具备的基础知识。

■ 如何通过调试扩展功能来分析各种安全组件。本节将介绍一些对调试安全性问题来说非常重要的扩展命令。

■ 如何将一些现有的技术与本书给出的信息结合起来,以解决由于未预期的安全限制所导致的问题。


Windows 中的安全

    任何一个 Windows 安全对象都可以用句柄来表示,在这些安全对象中包含了一些安全信息,并且受到 Windows 安全机制的保护。在 Windows 安全模型中使用了三个安全概念:

■ 自主访问控制列表( DACL , Discretionary Access Control List ):描述的是哪些主体( Principal )可以使用这个对象以及如何使用。

■ 用户的标识:也被称之为主体。

■ 安全访问监督( Security Reference Monitor , SRM ):通过一些的信息来限制对它所保护的对象进行访问。

    与 Windows 安全对象相关的 DACL 是由对象创建者本身来管理的。 DACL 是另一个结构——安全描述符( Security Descriptor )中的成员,安全描述符是一组与对象相关的信息,保存在安全的存储位置中。每当一个新的主体访问对象时,都会从这个安全的存储位置中抽取出对象的安全描述符。例如,文件的安全描述符是保存在 NTFS 文件系统中,注册键的安全描述符是保存在注册表中,而内核对象的安全描述符则是保存在内核地址空间中。

    Windows SRM 运行在内核地址空间中,它与用户态代码是分离的。大多数安全对象都是由内核组件创建的,内核组件通过地址的独立性来保护与用户态组件相关的安全描述符。由于用户态组件不能通过内核来实现自己的安全对象代理( Object Broker ),因此 Windows 中的一些组件是通过类似于 Windows 安全机制的思想来实现定制的安全模型。

    定制的安全对象代理必须增强对象的访问机制。换句话说,在设计安全对象代理时,你必须确保这个对象不能通过其他任何机制来访问。在这些情况中,对象代理将扮演 SRM 角色,并且按照它自己的方式来管理对象安全描述符。为了确保与操作系统保持兼容,并且在安全设置中使用相同的用户接口,对象代理很可能使用与 Windows SRM 一样的数据结构。

    在访问控制中的另一个重要组件就是安全主体,它是由操作系统来创建和验证的。安全主体保存在访问令牌( Access Token )中。在这个访问令牌中包含了安全主体所在的用户组,一组由操作系统赋予的特殊权限,以及由系统其他组件使用的一些信息。

    对象访问权限是通过一组位表示的,每一位表示一项能否被赋予某个主体的权限(特定于对象的属性)。

    在下一节中将介绍与调试 Windows 程序相关的所有安全结构,以及用于查看这些结构的各种方法。熟悉这些概念的读者可以跳过这一节。在本章的示例中使用了三个新的扩展命令: !sd , !token 以及 !sid ,这三个命令是在调试器默认加载的扩展模块中实现的。本章将使用 07sample.exe 程序,这个程序的源代码文件和二进制文件分别位于以下文件夹中:

源代码文件: C:/AWD/Chapter7

二进制文件: C:/AWDBIN/WinXP.x86.chk/07sample.exe

     由于在分布式程序中经常会发生安全性错误,因此本章还将使用第 8 章“进程间通信”的一些示例,包括一个客户端程序 08cli.exe ,一个包含代理存根( Proxy Stub )的动态库 08coms.dll ,以及一个服务器端程序 08comsrv.exe 。我们必须通过命令行 08comsrv.exe /RegServer 来注册 08comsrv.exe ,并且通过命令行 regsvr32 08comps.dll 来注册 08comps.dll 。这些程序的源代码文件和二进制文件位于以下文件夹中:

 
源代码文件: C:/AWD/Chapter8

二进制文件: C:/AWDBIN/WinXP.x86.chk/08cli.exe, 08comps.dll 以及 08comsrv.exe

 
安全标识符

    安全标识符,也被称之为 SID ,是在 Windows 安全机制中使用的基本概念之一。 SID 表示一个主体或者一个属性,并且这个主体或者属性在 SID 所在的操作系统中是唯一的。 SID 通过一个简单的结构来表示,这个结构定义在头文件 winnt.h 中 。

    SID 结构是变长的,其中包含了变长数量的 SubAuthority 项,可以表示任何主体。 SID 是根据 IdentifierAuthority 来分组的。 SID 的内存布局是非常简单的,计算机很容易理解,但对于人来说却是很难理解的。在一些技术文档中, SID 被表示为一个字符串,形如 S-R-I-S-S-S- ¼ -S ,其中 R 表示修订级别( Revison Level ), I 表示控制这个 SID 的授权( A uthority ) , S 是由这个授权所管理的子授权( Subauthority )。

    Windows SID 的 Revision 域被设置为 1 ,并且可以拥有多达 6 个子授权。在 Windows 中, IdentifierAuthority 等于 5 : {0 , 0 , 0 , 0 , 0 , 5} 。例如,本地系统( Local System )在内存中被表示为一系列的字节, S-1-5-18 ,如果下面的清单所示(这些字节被分散在多行,每行对应一个 SID 组件):

访问控制列表

    在调试 Windows 安全性问题时,另一个重要的结构就是访问控制项( Access Control Entry , ACE )。 ACE 表示,在由这个 ACE 保护的对象上,有哪些权限可以被赋予由 SID 表示的主体。一组有序的 ACE 就构成了一个访问控制列表( ACL ),它将控制所有主体在它所保护对象上的权限。

    从结构上来看,每个 ACE 都有一个 ACE_HEADER ,随后是特定于 ACE 的数据,这是实现对象多态性的一种古老的“ C ”技术。在 MSDN 以及 winnt.h 中对所有的 ACE 类型都给出了非常详尽的描述。本节将只介绍 ACCESS_ALLOWED_ACE ,因为这是最常使用的结构。其他类型的 ACE 都是类似的,都可以在头文件 winnt.h 中找到。

    AceType 域表示在 ACE_HEADER 后面的结构类型。通常的做法是,根据 AceType 域中的值将 ACE_HEADER 结构转换为具体的 ACE 类型,例如 ACCESS_ALLOWED_ACE 。 Mask 域是一个 DWORD 类型的值,其中包含了这个 ACE 允许的所有权限。在表 7.1 中给出了每一位的含义。

 

访问令牌

 

    只有当主体请求访问由这个安全描述符保护的安全对象时,安全描述符才是有用的。主体的标识,以及被赋予的权限,都被封装到一个内核结构中,这个结构被称之为访问令牌( Access Token )。用户态的组件可以通过句柄来使用访问令牌。我们可以通过扩展命令 !token 来查看这些访问令牌,这个命令的参数既可以是访问令牌的地址(例如在内核态调试器中),也可以是一个指向令牌的句柄(例如在用户态调试器中使用)。如果在使用这个扩展命令时没有指定参数,那么当存在线程模拟访问令牌( Thread Impersonation Access Token )时,它将显示这个令牌;否则,它将显示进程令牌。在清单 7.5 中,我们使用了在清单 7.3 中传递给 advapi32!AccessCheck 函数的令牌。由于使用了 -n 选项,因此这个扩展命令将解析与每个 SID 相关的名字(显示在 SID 后面的括号中)。

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值