.NET在数字取证中的技术优势与实践

本文深入探讨了.NET框架在数字取证领域的应用优势,包括运行时环境兼容性、性能优化、跨平台挑战以及取证工具开发的专业建议,为取证编程提供了实用的技术见解。

与Eric Zimmerman畅谈.NET技术

我认为数字取证领域没有人会否认Python是当今取证编程中最常用的语言。事实上,它的许多狂热追随者经常向我们炫耀它表面上冗长的优越特性列表。以至于有时人们可能会忘记还有其他编程语言存在。认识到这一点,我知道我想写一篇讨论我最喜欢的技术——C#和整个.NET框架——但我想不出比Eric Zimmerman更好的特邀撰稿人来参与这场对话,他是取证编码中最家喻户晓的名字之一,也是该技术的坚定支持者。

Eric是KAPE、Registry Explorer、JumpList Explorer、AmCacheParser等众多工具的背后策划者。和许多读者一样,我在取证生涯早期就接触到了Eric的工作——事实上,就在开始的时候,作为我在加拿大警察学院的"取证101"课程课程的一部分。我很荣幸能与他讨论我最喜欢的话题之一!

forensicmike1: 非常感谢Eric参与这次对话!我很好听是什么最初将您带入.NET世界,又是什么让您在这些年里一直留在这里?

Eric Zimmerman: 我最初在Access中开始了我的开发生涯。当我超越它后,我转向了VB6(在.NET之前的日子)。一旦.NET出现,我慢慢转向了VB.NET,因为我已经懂VB。我一直想用C#,但不想重新学习东西,所以我坚持了很久。事实上,osTriage v1和v2都是用VB写的!osTriage v2发布后不久,我决定强迫自己在几个项目中使用C#,从那时起我就再也没有回头。

所以对我来说,这是希望在我最常处理的平台(即Windows)上使用一流语言的问题。我坚信在Windows上做Windows取证,在Mac上做Mac取证等等概念。当你不这样做时,你就是在自找麻烦。例如,一种非常流行的访问Windows卷影副本的方法,至少在某些情况下,呈现数据供访问的方式与Windows中的原生方法不同。这导致导出损坏的文件,显然,在处理它们时这是个问题。这总是发生吗?不,但即使一次也足以让我在任何重要的案件中犹豫是否信任该方法,除非我也通过Windows原生方式以完全相同的方式验证获取数据。然而,在这一点上,你现在的工作量加倍了,那么为什么还要麻烦使用非Windows方法呢?

我坚持使用.NET,因为它是我所知道的,并且能满足广泛需求的东西。我知道它不会消失,并且它有伟大的IDE和其他资源用于高效开发、调试、日志记录等等。

另一个巨大优势是它的第三方控件范围,这些控件在创建惊人的图形用户界面(GUI)方面其他地方根本没有。像网格、树形视图以及我在GUI中使用的许多其他控件这样的东西是无法获得的,所以我无法用Python编写像RegistryExplorer这样的东西——而且即使我写了,它也无法做到在Windows端能做到的事情。

forensicmike1: 我完全同意!我已经看到这种情况在人们转向C#的过程中一次又一次地发生。从取证的角度来说,您能想到用.NET编写代码的其他优势吗?

Eric Zimmerman: 使用.NET,我知道我需要的运行时环境将默认就位——或者在绝大多数情况下会是这样。我不必担心制作自包含的可执行文件,或者没有正确处理Unicode,或者无法在需要的地方安装某些东西。

回到我之前说的,我觉得你应该在Windows机器上做Windows取证,这使得我的软件最终用户的事情变得容易得多。使用我的东西,你可以在任何机器上下载并解压我的程序,它很可能第一次就能正常工作,没有问题。这可以是在进行"死盒"工作的取证箱上,也可以是在现场对运行系统进行实时响应。

速度对我来说也是件大事。我倾向于做很多工作来调整我的代码,使其首先尽可能准确。一旦完成,我就为性能进行调整。正如老话所说,速度很好,但准确才是最终目标。当你查看用其他语言编写的取证程序(想到的例外是Rust)时,性能通常很糟糕,并且需要大量工作来准备环境甚至运行应用程序。当然,开发人员可以做些工作将Perl或Python程序打包成自包含的Windows可执行文件,但这个过程可能很痛苦,并且仍然无法解决性能问题。能用Python编写高性能代码吗?也许,但这涉及用Cython重写部分代码,或者用C++编写关键部分等等。所以虽然可能,但对我来说这不值得,尤其考虑到我上面提到的问题。获取准确的数据当然是至关重要的,所以即使只有一次可能无法获得准确数据,也足以让人不愿冒险。

当编写针对Windows工件的取证工具时,Windows的行为和说法应该是我们瞄准的目标。如果你能超越Windows让你看到和做的事情,那就更好了。以不同的方式揭示数据总是件好事,但不能以排除或遗漏东西(或这样做的风险)为代价。

归根结底,我宁愿我的代码在一个平台上运行得非常好,也不愿在五个平台上运行得很差。

forensicmike1: 除了取证领域没有多少人熟悉之外,您能谈谈任何缺点吗?

Eric Zimmerman: 有趣的是,如果人们使用Windows机器,大多数人每天都在各处使用.NET。仅仅因为他们可能没有意识到,并不意味着它不存在。

在我设计和使用的工具链中,我并没有真正看到任何缺点,但显然过去在非Windows平台上运行.NET代码一直是个问题。随着微软更多地参与开源世界——记住.NET Core现在是开源的——并且能够在Linux上运行PowerShell也进一步推动了这一点,这正变得越来越不是问题。

所以在不远的将来的某个时候,我编写的代码将是跨平台的(至少是CLI ones)。在某些情况下,代码已经可以在.NET Core和Standard上运行。我个人在这方面最大的障碍是.NET Core和Standard没有无缝的方式为每个平台制作单个可执行文件。我讨厌分发38个DLL和程序的可执行文件,所以直到我能在Linux或Mac上以与在Windows上相同的方式做到这一点(即给你一个可执行文件来运行),我不会全职做跨平台的东西。

对许多人来说,使用.NET的最大障碍不是技术性的,而是出于某种原因对微软或Windows的偏见。考虑到如今搭建虚拟机如此容易,像"我无法运行X,因为它仅限Windows"这样的借口再也不应该是有效的借口了。

forensicmike1: 您认为编程是数字取证领域内一个合法的专业方向——还是每个检验员此时至少应该涉足的东西?

Eric Zimmerman: 嗯,我不知道是取证编程本身是一个专业,还是以我们取证工作中必要的方式进行编程的能力更重要。换句话说,你不需要身处取证领域就能以我所说的方式看待编程。这在实际中是什么样子?对我来说,它意味着尽早且经常地失败(即绝不、绝不容忍错误消息或其他"未知"条件),防御性编程(即在某种程度上保护最终用户免受自身影响),清理输入,提供查看诊断和跟踪消息以进行调试的能力,强大的输出选项等等。(Forensicmike1: 这是很棒的建议,我希望一些供应商正在阅读!)

不是每个人都具备进行更高级别编程的资质,我当然不是该领域的专家。事实上,不到10年前,我开始寻找一种在我的一个实时响应程序中本地处理LNK文件的方法。在十六进制编辑器中查看LNK文件时,我对自己说"我永远无法编写读取这些东西的程序",但现在我拥有几乎所有关键Windows工件的本地解析器——所有这些我都是用C#完成的。我学习如何编码和解析东西部分是由于必要性(在我的工作之前它们不存在),或者因为现有工具无法完成工作(不完整、不准确、速度慢等),并且我认为我可以做得更好。当然,好奇心和想要解决问题也参与其中(我甚至不愿去想我花了多少时间研究shellbags)。

话虽如此,没有人期望走进DFIR就能在第一天为某个工件编写取证解析器。事实上,大多数人根本没有理由这样做。至少具备一定程度的编程能力当然是有益的,这样你可以编写一些代码来自动化繁琐的工作,所以这是一个至少熟悉像PowerShell、C#、Python等的好理由,即使仅限于循环遍历数千个日志文件寻找东西,并节省手动操作的痛苦。

在您看来,主要的取证软件供应商是否做了足够的工作来为以取证为主要工作的成熟开发人员提供集成他们创作的方式?如果没有,对于他们可以做得更好的方面有什么想法吗?

Eric Zimmerman: 这是个难题,因为供应商编写程序使用的语言不同。供应商使用.NET、C++还是Delphi?每一种在编写代码时都有不同的方式让外部用户接入。

我对供应商的建议是提供编写可由供应商产品使用的插件的能力。例如,X-Ways有一个API让你编写这样的东西。我的几个工具也这样做(Registry工具中的插件,事件日志中的映射,KAPE中的目标和模块)。(Forensicmike1: 有趣的是,使用Delphi的供应商也是唯一做过任何.NET插件工作的供应商!)

另一种途径是提出非编程手段(或编程和非编程的平衡)来交互和扩展程序。像EvtxECmd中的映射或RECmd中的批处理文件模式就是很好的例子。两者都允许最终用户利用工具的能力,并按照他们认为合适的方式扩展它们,所有这些都不需要我参与。

我认为对最终用户最大的好处是设计开放和可扩展的工具,然后人们可以将它们带到开发人员以前从未想过的地方。听到一些使用案例和人们使用我的东西的方式是相当酷的。他们找到了各种新的用途和方法,这些是我在设计程序时从未设想过的。

通过这样做,不再是关于程序的作者,而是关于最终用户,使他们的工作更轻松,数据更清晰,工作更高效等等。让最终用户减少噪音以便找到他们想要找到的信号才是重要的。

forensicmike1: 最后的话交给您——对于可能犹豫与世界分享他们工作的新兴取证编码者有什么建议吗?

Eric Zimmerman: 把代码扔出去!记住,凡事总有第一次,你第一次做任何事情时都不擅长(甚至前100次!)。把工作放出去,交到人们手中,让他们试用,提出建议,破坏它等等。

不要让任何人告诉你这个领域的任何事情是"已解决的问题",因为学习一个工件的最好方法就是为它编写一个解析器。而且你永远不知道,你可能会在主要产品中发现长期存在的错误,这些错误人们过去20年一直视为理所当然并认为是正确的。

即使没有人在案件中使用你的代码,你从无到有创造了东西的事实也是一种很棒的感觉。看到你的代码做了你打算让它做的事,第一次看到所有单元测试通过,看到输出从你从头到尾编写的程序中出来,是一件神奇的事情。当我开始一个新项目时,这仍然让我兴奋。

分享那个代码,谈论那个项目,寻求你领域的专家来审查、帮助和提供反馈。我无法告诉你同伴对于碰撞想法、测试事物并将我的想法推向更好境地有多么宝贵。多年来为我做过数百次这类事情的两个人( among many )是David Cowen和Matt Seyer。他们为什么有能力这样做?因为他们也在很久以前抓住了机会放出代码,承担风险,变得脆弱,并探索数据,努力理解它如何工作,为什么工作,以及利用该数据帮助我们讲述计算机上发生故事的最佳方式。正如Matt和我喜欢说的,“每个字节都很重要!"。它们的存在是有原因的。寻求找出它们究竟为什么在那里。

所以,总结一下,我的建议是:

  • 承担经过计算的风险。
  • 从错误中学习。
  • 利用同伴。
  • 推动进展。
  • 让事物比你发现时更好。

在Twitter上关注Eric @EricRZimmerman或访问他的网站 https://ericzimmerman.github.io/

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计