AccessData AD1镜像格式完全剖析

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: 流行的数字取证工具FTK Imager创造了一种逻辑镜像格式,在取证界广泛使用,但鲜少有人对其格式进行研究。

原作者:Mariri(@AstrumMairi),即文中的“我”

译者:Rock4N6

前言

本文将涵盖我个人对 AccessData 专有镜像格式的探索和剖析,这种格式称为“AccessData 逻辑镜像”,扩展名为“AD1”,由流行的数字取证工具 FTK Imager生成。对这种镜像文件格式进行的研究包括对整体数据结构的观察,这些观察是基于对多个样本进行的实验结果,仅为本文目的而整理。因此,此处披露的发现不应被视为对 AD1 文件格式的详尽研究,也不是结论性研究,而是对AD1格式进行研究要建立的基础。

介绍

我首次探索AD1 文件格式是通过数字取证挑战开始 。这种挑战在 DFIR 的世界中并不少见,我发现它们是教分析师如何使用取证软件调查磁盘镜像时的得力助手。为此,我开始解决CyberDefenders 的一些取证挑战,特别是名为HireMe 的挑战。此挑战提供了一个 AD1 文件,参加者需要使用该文件进行分析以回答一系列问题。

现在,由于我是一个基于 Linux 的用户,我的第一反应是确定是否有一种预先存在的方法可以在不使用 Windows 操作系统的情况下提取 AD1 文件的数据。有趣的是,我发现许多在线论坛都在讨论这是否确实可行; 1, 2, 3, 4。但是,他们都建议使用基于 Windows 的工具来导出数据。在 Windows 上,审查员有多种提取 AD1 文件的选择,其中包括:

  • 将 AD1 镜像加载到 FTK Imager 中并手动导出文件
  • 为7-Zip使用Forensic7z 插件
  • 将Autopsy与自定义 AD1 模块结合使用
  • 使用另一个基于Windows的取证工具(如 Paladin)来装载和提取数据

有趣的是,即使在网上广泛搜索后,我也找不到从 Linux 命令行中提取 AD1 数据的可靠方法。如果任何阅读本文的人知道可以执行这些提取的命令行工具或方法,请告诉

AD1文件格式

AD1 文件是一种 AccessData 专有格式,在其官方博客中被描述为“取证镜像容器” [^1],这意味着它们在网上没有很好的文档记录,这是意料之中的。现在,关于“取证镜像容器”在这种情况下的确切含义是我下一阶段研究的目标。传统的取证镜像文件,例如DDAFFE01文件,通常包含整个文件系统结构,包括分区数据、残留空间、未分配数据、完整文件元数据等。但是,从表面上看,AD1 文件似乎不一定是这种情况。

有趣的是,根据官方的 FTK Imager 用户指南,AD1 镜像格式有两个版本,特别是较新的AD1v4,和旧版本的AD1v3。这很重要,因为旧版本的 AccessData 软件无法识别新AD1v4格式,但可以使用FTK Imager 3.4.0将它们转换为旧格式。此外,该文档还规定,从版本3.4.2之后的 FTK Imager都只会生成AD1v4格式镜像[^2]。

免责声明:本文将只讨论与较新AD1v4格式相关的数据结构,请假设从现在开始提到或用作示例的所有 AD1 文件都是该AD1v4格式。

在此阶段要注意的主要一点是 AD1 文件格式不是传统的取证镜像,而是包含逻辑文件数据的容器。AD1 文件中不包含磁盘几何结构或卷信息,这意味着它无法被 Sleuth Kit 的mmls命令等工具读取。使用 Brian Carriers [^3] 臭名昭著的文件系统抽象模型,这类似于说 AD1 文件仅包含驻留在“文件系统”层及更高层的数据,没有较低级别的数据概念。而传统的取证镜像(例如原始DD格式)通常会包含来自该模型每一层的数据。

实验研究

AD1样本生成

在接下来的实验过程中,我需要各种各样的 AD1 文件来进行测试,这些文件的数据内容是我控制的。为此,我使用了QEMU 中一个现有的 Windows 10(版本 20H2)虚拟机,这是我各种测试都在用的机器,并安装了 FTK Imager 4.2.1——这是当前最应景的版本。需要重点指出的是在 FTK Imager 中,有两种生成 AD1 镜像的方式:

  • 将数据导出到AD1逻辑镜像
  • 将数据添加到自定义内容AD1镜像

这可能会令人困惑,因为上面暗示有两种不同类型的 AD1 文件,但是,它们在功能上是相同的。二者主要区别在于,自定义内容AD1支持添加多个数据源,而在标准 AD1逻辑镜像导出选项中通常只会对单个数据源(例如根目录)执行此操作。不管选择哪种方式,接下来都会看到“证据项目信息”框,会提示输入与案件和操作人员相关的信息。

输入到此框中的数据与生成的 AD1 文件在很大程度上无关,因为此数据将存储在另外的.txt文件中。每次创建 AD1 文件时,FTK Imager 都会自动生成这些文本文件,它们包含在上述框中填写的信息,以及:

  • 用于创建AD1文件的FTK Imager版本
  • AD1文件版本
  • AD1数据源
  • MD5和SHA-1哈希值
  • 镜像获取过程开始与结束的时间戳
  • AD1保存的文件路径

选择 AD1 文件保存路径及及指定文件名称后,有三个附加选项可选:镜像片段大小、压缩和 AD 加密。镜像片段大小只是一种机制,以便将非常大的镜像拆分为更易于管理的块。默认片段大小为 1500 MB,该值存储在 AD1 文件头中,稍后我们也能看到。

免责声明:在实验过程中,我使用各种片段大小生成了多个 AD1 文件。但是,拆分 AD1 文件被认为超出了本文的范围,从这里开始的研究假设片段大小足以覆盖整个镜像。

为了确保我有足够的对照样本,除了随机样本(从线上挑战/其他资源中获取的 AD1 文件)之外,我创建了两个单独的文件夹,并使用我在 Windows 机器上的随机文件为每个文件夹提供了一个独特的结构:

Folder 1/
├── Random.sl2
├── TestD1
│   └── JPG_File.jpg
├── TestD2
│   ├── TestD3
│   │   └── Web_File.html
│   └── Text_File.txt
└── TestD4
    └── PNG_File.png

Folder 2/
├── _ctypes_test.pyd
├── TestD1
│   ├── One_Note_File.one
│   ├── TestD3
│   │   └── DLL_File.dll
│   └── TestD4
│       └── Config_File.cfg
└── TestD2
    ├── Log_File.log
    └── TestD5
        └── Python_File.py

然后我使用 FTK Imager 创建了五组不同的 AD1 数据:

注意:下面括号中的数据表示本文中使用的相关 AD1 文件名。

  1. AD1 文件夹 1 的逻辑镜像 ( Logical_F1)
  2. AD1 文件夹 2 的逻辑镜像 ( Logical_F2)
  3. AD1 文件夹 1 的自定义内容镜像 ( F1)
  4. AD1 文件夹 2 的自定义内容镜像 ( F2)
  5. AD1 文件夹 1 和文件夹 2 的自定义内容镜像 ( Combined)

对于每一组数据,我都选择每个压缩级别重复获取过程,结果为每个数据集生成了10个AD1文件。我还以非默认的片段大小跨数据集创建了大量AD1文件,但选择很小的镜像片段大小以致于AD1文件被分割的情况没进行测试。

AD1 压缩和加密

压缩级别有10个级别可选,从0级(无压缩)到9级(最高压缩级别)。根据上述的用户指南,所需的压缩级别取决于两个因素:时间和文件大小。如果想要相对快速地完成镜像获取,选择较低的压缩级别,因此将得到体积更大的镜像文件;反之,如果空间比时间更重要,最好使用更高级别的压缩。

创建AD1文件的最后一个选项是启用AD加密。根据用户指南,AD加密可以使用密码,也可以使用公钥加密。经过加密的AD1文件可以通过其唯一的文件签名来识别,其特征如下:

# xxd Combined_ENC_C0_1500F.ad1 | head -1
00000000: 4144 4352 5950 5400 0100 0000 0002 0000  ADCRYPT.........

由此我们可以推断,如果AD1文件的签名为0x41444352595054,那么该文件已经被加密。还要注意的一点是,根据我的示例,实际加密的数据从偏移量 0x200 开始,即AD1文件的512字节。本文将不涵盖任何对AD加密的进一步调查,因为这超出我的研究范围。

AD1文件头部分

现在我手上有了相当数量的AD1对照样本,可以开始分析了。我想重申一下,对于这种文件格式,没有详细的在线文档,因为它是AccessData专有的。因此,我将根据我所拥有的样本对我所处理的数据做出很多假设。此外,我很可能会得出误导的模型或曲解数据,但请记住,这都是研究过程中正常的一部分。

按照正常套路,我将联合使用Linux工具xxddd,从AD1的十六进制数据来开始我的分析。首先关注到,每个AD1文件似乎包含一个512字节的头部,非常类似于磁盘镜像的引导扇区。因此,我决定将这个初始512字节的数据称为第一个“AD1 头部段”。在这个头部段中,第一个数据显然是AD1签名,由15字节组成:

# dd if=F1_C7_1500F.ad1 bs=1 count=15 status=none | xxd
00000000: 4144 5345 474d 454e 5445 4446 494c 45    ADSEGMENTEDFILE

与任何文件签名一样,这部分数据将文件类型标识为.ad1,旨在使解析它的程序可以将其识别为合法文件。之后对我的样本进行的测试表明,头部段0x22的偏移量处也有一个 5 字节的值,这似乎与检查员设置的片段大小相关:

# dd if=F2_C0_1500F.ad1 bs=1 count=5 skip=34 status=none | xxd -ps -e | awk '{print $2}'
00005dc0
# dd if=F2_C7_1500F.ad1 bs=1 count=5 skip=34 status=none | xxd -ps -e | awk '{print $2}'
00005dc0
# dd if=F1_C0_2000F.ad1 bs=1 count=5 skip=34 status=none | xxd -ps -e | awk '{print $2}'
00007d00
# dd if=F2_C0_2000F.ad1 bs=1 count=5 skip=34 status=none | xxd -ps -e | awk '{print $2}'
00007d00
# dd if=F2_C9_3000F.ad1 bs=1 count=5 skip=34 status=none | xxd -ps -e | awk '{print $2}'
0000bb80
# dd if=F2_C9_4000F.ad1 bs=1 count=5 skip=34 status=none | xxd -ps -e | awk '{print $2}'
0000fa00

正如所看到的,这些字节的值根据片段大小而变化,正如文件名中所示,例如2000F对应的片段大小为2000MB。那么如何解释这些十六进制值呢?首先以低字节序的方式读取它们,转换为等价的十进制,然后除以16得到分段大小。下表提供了我使用过的数值:

十六进制(LITTLE-ENDIAN) 十进制 分片大小
00002b10 11024 689MB
00005dc0 24000 1500MB
00007d00 32000 2000MB
0000bb80 48000 3000MB
0000fa00 64000 4000MB

因此,我们可以说默认情况下AD1 文件头中的这些特定字节是c05d,即片段大小的默认值为 1500 MB 。另外需要提及一点,片段大小是必填项,如果留空的话FTK Imager 将不会创建 AD1 文件。通过进一步的测试发现,这 5 个字节可以指定的最大值是0x07fffffff0,这相当于片段大小为 2147483647 MB。指定更大数值的尝试都只会恢复至该最大值。

越过 AD1 文件的 512 字节文件头,文件的下一部分本质上是另一个签名,它由偏移量0x200的 14 字节组成,如下所示:

# dd if=Combined_C3_1500F.ad1 bs=1 skip=512 count=14 status=none | xxd
00000000: 4144 4c4f 4749 4341 4c49 4d41 4745       ADLOGICALIMAGE

这个二级签名在我测试的所有样本中也是一致的。从这里开始,我决定使用 16 字节的块来尝试在数据中找到模式,我发现下一段有形数据从偏移量0x210开始,通常如下所示:

# dd if=F1_C7_1500F.ad1 bs=1 skip=528 count=16 status=none | xxd -ps
04000000010000000000010000000000

不幸的是,我不知道这个数据代表什么,这个值的唯一区别出现在作为逻辑镜像生成的 AD1 样本中:

# dd if=Logical_F2_C0_1500F.ad1 bs=1 skip=528 count=16 status=none | xxd -ps
04000000010000000000010070000000

由此可以推断出的唯一结论是,如果偏移0x21c处的单个字节为0x70,则 AD1 文件是逻辑镜像容器,而此偏移处的值为0x00意味着它是自定义内容容器:

# dd if=F2_C5_1500F.ad1 bs=1 skip=540 count=1 status=none | xxd
00000000: 00                                       .
# dd if=Logical_F2_C5_1500F.ad1 bs=1 skip=540 count=1 status=none | xxd
00000000: 70                                       p

接下来从偏移量 0x220开始的16字节数据与之前的数据存在类似的区别:

# dd if=F1_C5_1500F.ad1 bs=1 skip=544 count=16 status=none | xxd -ps
0000000079000000000000001d000000
# dd if=Logical_F2_C4_1500F.ad1 bs=1 skip=544 count=16 status=none | xxd -ps
000000008f0000000000000014000000

从我拥有的样本中只能推断,该数据指的是另一种标识 AD1 文件创建方式(自定义内容或逻辑镜像)的签名。从偏移量0x230开始的下一个 16 字节数据更有趣:

# dd if=F1_C7_1500F.ad1 bs=1 skip=560 count=16 status=none | xxd -ps
414400005c000000000000001a7f4600
# dd if=F1_C7_1500F.ad1 bs=1 skip=560 count=16 status=none | xxd
00000000: 4144 0000 5c00 0000 0000 0000 1a7f 4600  AD..\.........F.

在这个时候,我快速地写了个 BASH 脚本,以遍历每个样本文件。运行这个脚本,我发现上述数据块的前 5 个字节在每个样本中都是相同的,这是有意义的,因为AD表示了一个可能意味着 AccessData 的签名。但是,该行中的最后几个字节对于每个 AD1 文件都是唯一的。例如,以下是我的每个组合文件夹自定义内容 AD1 文件中的唯一十六进制值:

Combined_C0_1500F.ad1: 414400005c0000000000000057dd4900
Combined_C1_1500F.ad1: 414400005c0000000000000091404700
Combined_C2_1500F.ad1: 414400005c00000000000000f12b4700
Combined_C3_1500F.ad1: 414400005c00000000000000191e4700
Combined_C4_1500F.ad1: 414400005c00000000000000fb144700
Combined_C5_1500F.ad1: 414400005c00000000000000bd074700
Combined_C6_1500F.ad1: 414400005c000000000000000a054700
Combined_C7_1500F.ad1: 414400005c00000000000000a9044700
Combined_C8_1500F.ad1: 414400005c0000000000000065044700
Combined_C9_1500F.ad1: 414400005c000000000000005d044700

正如所看到的,上述十六进制数据的最后 4 个字节在 AD1 文件中是唯一的,但是你可能会注意到,对于文件 C1-C9,最后 2 个字节是相同的。意味着这个值可能指的是 AD1 文件之间常见但略有不同的信息。因此我的两个假设是,这个值要么是时间戳,要么是文件大小,因为每个应该 小于最后一个。我通过以小字节序从 AD1 文件中读取这个值,然后将其转换为十进制来验证这个假设。

# dd if=F2_C4_1500F.ad1 bs=1 skip=572 count=4 status=none | xxd -ps -e | awk '{print $2}'
000088d8
# dd if=Logical_F1_C4_1500F.ad1 bs=1 skip=572 count=4 status=none | xxd -ps -e | awk '{print $2}'
00468c32

# hexconv -d 000088d8
DECIMAL:    35032
# hexconv -d 00468c32
DECIMAL:    4623410

# du -b F2_C4_1500F.ad1
35936    F2_C4_1500F.ad1
# du -b Logical_F1_C4_1500F.ad1
4624294    Logical_F1_C4_1500F.ad1

交叉检查上面的“磁盘使用情况” (du ) 命令的输出可以看出,这些十进制值实际上与 AD1 文件的字节大小密切相关。虽然它们看起来并不完全匹配,而且我测试的样本也没有匹配,但我会假设这个值可能是指整个 AD1 文件中包含的压缩数据的大小。这些值很可能不包括 AD1 文件的文件头或文件尾部分,因此 AD1 文件在磁盘上的实际大小略大于 AD1 文件本身报告的大小。

在开始文件结构分析之前,这段数据的最后一部分似乎随操作者生成的 AD1 文件的方式(逻辑镜像或自定义内容)而变化。为了概念化这一点,从 Folder 1 文件夹下每种类型的代表性AD1 文件中截取一段十六进制数值进行输出比较:

# dd if=F1_C3_1500F.ad1 bs=1 count=1000 status=none | xxd
[ . . . ]
00000200: 4144 4c4f 4749 4341 4c49 4d41 4745 0000  ADLOGICALIMAGE..
00000210: 0400 0000 0100 0000 0000 0100 0000 0000  ................
00000220: 0000 0000 7900 0000 0000 0000 1d00 0000  ....y...........
00000230: 4144 0000 5c00 0000 0000 0000 7c90 4600  AD..\.......|.F.
00000240: 0000 0000 0000 0000 0000 0000 b891 4600  ..............F.
00000250: 0000 0000 0000 0000 0000 0000 4375 7374  ............Cust
00000260: 6f6d 2043 6f6e 7465 6e74 2049 6d61 6765  om Content Image
00000270: 285b 4d75 6c74 695d 2900 0000 0000 0000  ([Multi]).......
00000280: 00f9 0000 0000 0000 00c5 0000 0000 0000  ................
00000290: 0000 0000 0000 0000 0000 0000 0000 0000  ................
000002a0: 0005 0000 0014 0000 0046 6f6c 6465 7220  .........Folder 
000002b0: 313a 443a 5c46 6f6c 6465 7220 3100 0000  1:D:\Folder 1
[ . . . ]

# dd if=Logical_F1_C3_1500F.ad1 bs=1 count=1000 status=none | xxd
[ . . . ]
00000200: 4144 4c4f 4749 4341 4c49 4d41 4745 0000  ADLOGICALIMAGE..
00000210: 0400 0000 0100 0000 0000 0100 7000 0000  ............p...
00000220: 0000 0000 8f00 0000 0000 0000 1400 0000  ................
00000230: 4144 0000 5c00 0000 0000 0000 1290 4600  AD..\.........F.
00000240: 0000 0000 0000 0000 0000 0000 4e91 4600  ............N.F.
00000250: 0000 0000 0000 0000 0000 0000 466f 6c64  ............Fold
00000260: 6572 2031 5c44 3a5c 466f 6c64 6572 2031  er 1\D:\Folder 1
[ . . . ]

上面给出的输出中,第一个 AD1 文件的数据似乎包含另一个签名,从偏移量0x25c开始,长度为 30 字节。更仔细深入地研究此签名,可以提取到一个字符串,用于与其他自定义内容 AD1 样本进行比较:

# dd if=F1_C3_1500F.ad1 bs=1 skip=604 count=30 status=none | xxd -ps
437573746f6d20436f6e74656e7420496d616765285b4d756c74695d297d

结果显示,这个十六进制值在我拥有的所有自定义内容样本中都是一致的。然而,在逻辑镜像样本中,似乎完全省略了该数据。从我用xxd 收集的一些测试信息来看,逻辑镜像容器似乎省略了自定义内容容器签名所在的大约 80 字节的数据(由于填充)。有趣的是,之后的数据继续正常显示根文件夹名称,如上所示,根文件夹名称的开头是“Folder 1”。

从这个实验中可以看到:在自定义内容样本中,实际文件数据从偏移量0x2a9开始;而在逻辑镜像样本中,数据从偏移量0x25c开始。从上述位置可以看到根文件夹和目录数据结构的开始,由压缩的逻辑文件夹及文件组成。

AD1数据结构

至此,我们已经到了AD1文件最重要的部分:包含文件名、原始压缩数据以及相关元数据的主要数据结构。通过用 xxddd 进行的一些初步实验,我发现文件/文件夹几乎按顺序存储在AD1 文件中。乍一看,该结构似乎只是在文件树中列出的文件/文件夹列表中自上而下排列,但没有分支。例如,在“Folder 1”AD1 样本中,文件和目录的排列如下:

Folder 1/
Random.sl2
TestD1
JPG_File.jpg
TestD2
TestD3
Web_File.html
Text_File.txt
TestD4
PNG_File.png

对 AD1 样本的进一步探究显示,对于给定 AD1 文件中存在的每个文件和目录,数据结构似乎遵循相对简单的顺序。下表提供了结构序列的粗略表示,显示了数据类型以及文件和/或文件夹数据是否存在所述类型。

顺序 数据 文件 目录
1 名称 Yes Yes
2 ? 结构化数据 ? Yes Yes
3 压缩数据 Yes No
4 原始大小 Yes No
5 MAC 时间戳 Yes Yes
6 ? 属性 ? Yes Yes
7 哈希值 Yes No

在 AD1 文件中,目录似乎更类似于合理的文件而不是索引,因为它们不包含压缩数据,也不包含哈希值。例如,如果查看包含在“Folder 2”(F2_C0_1500F.ad1)结构中的 TestD1 文件夹的十六进制数据,可以更清楚地看到这一点:

00000320: 0005 0000 0006 0000 0054 6573 7444 3179  .........TestD1y
00000330: 0000 0000 0000 004c 0100 0000 0000 0002  .......L........
00000340: 0000 0002 0000 0001 0000 0033 6101 0000  ...........3a...
00000350: 0000 0000 0300 0000 0300 0000 0100 0000  ................
00000360: 308b 0100 0000 0000 0005 0000 0007 0000  0...............
00000370: 0016 0000 0032 3032 3130 3630 3254 3138  .....20210602T18
00000380: 3338 3031 2e38 3834 3731 34b5 0100 0000  3801.884714.....
00000390: 0000 0005 0000 0008 0000 0016 0000 0032  ...............2
000003a0: 3032 3130 3630 3254 3138 3134 3236 2e33  0210602T181426.3
000003b0: 3030 3030 37df 0100 0000 0000 0005 0000  00007...........
000003c0: 0009 0000 0016 0000 0032 3032 3130 3630  .........2021060
000003d0: 3254 3138 3138 3239 2e34 3430 3533 38f8  2T181829.440538.
000003e0: 0100 0000 0000 0004 0000 000d 0000 0005  ................
000003f0: 0000 0066 616c 7365 1102 0000 0000 0000  ...false........
00000400: 0400 0000 0e00 0000 0500 0000 6661 6c73  ............fals
00000410: 6529 0200 0000 0000 0004 0000 001e 0000  e)..............
00000420: 0004 0000 0074 7275 6542 0200 0000 0000  .....trueB......
00000430: 0004 0000 0002 1000 0005 0000 0066 616c  .............fal
00000440: 7365 5b02 0000 0000 0000 0400 0000 0310  se[.............
00000450: 0000 0500 0000 6661 6c73 6574 0200 0000  ......falset....
00000460: 0000 0004 0000 0004 1000 0005 0000 0066  ...............f
00000470: 616c 7365 0000 0000 0000 0000 0400 0000  alse............
00000480: 0510 0000 0500 0000 6661 6c73 6529 1600  ........false)..
00000490: 0000 0000 0000 0000 0000 0000 0061 1400  .............a..
000004a0: 0000 0000 00d6 0200 0000 0000 0068 1100  .............h..
000004b0: 0000 0000 0000 0000 0011 0000            ............

将这个输出按照前面给出的的表进行分解,可以看到在偏移量0x329处出现了目录名称。有趣的是,在此偏移量之前的 4 个字节,即十六进制值0x06,与文件/目录名称的长度(字符数)相关。由于 0x06 只是十进制的 6,我们可以确定目录名称是 6 个字符长。在我测试的 AD1 样本中包含的所有文件/文件夹中,此文件名长度字节的存在是统一的。

在文件名之后,可见一些数据散布着空字节。我不确定这些数据究竟指的是什么,因为它在我拥有的样本之间似乎差异很大。不过我猜测AD1提取软件肯定有一个机制来理解结构,比如哪个文件属于哪个目录等等,所以我推测这个数据可能和整体的文件结构有关,根据我读过的文献来看[^4]可能是一个B -树.

取证行业的任何人都应该熟悉接下来的数据,正如我们熟知的 MAC(修改、访问、更新)时间戳。有趣的是,我花了一些时间来确定这些时间戳在 AD1 文件中的存储顺序,以及它在所有样本中是否一致。在与原始文件进行一些时间戳比较后(特别注意不要意外更新其中任何一个),我最终得出结论,AD1 格式按以下顺序存储每个文件/文件夹的三个时间戳:

  1. (A) 访问时间
  2. (C) 更新时间
  3. (M) 修改时间

继时间戳之后,我们来到另一组看起来很奇怪的数据。乍一看,它们似乎是一系列标志,即“真”和“假”字符串。因此,我推测这些可能是指单个文件和目录属性,例如文件是隐藏的、只读的还是受保护的。然而,与结构数据一样,这是我所做的一个合乎逻辑的假设,因为这些标志在文件和文件夹之间似乎也不一致,尽管原始文件都没有使用特殊属性。

现在我们可以将目录数据与标准文件的数据进行比较,我将以“Folder 2” ( F2_C3_1500F.ad1) 中的PE可执行文件DLL_File.dll为例:

00000960: 0c00 0000 444c 4c5f 4669 6c65 2e64 6c6c  ....DLL_File.dll
00000970: a005 0000 0000 0000 0100 0000 0000 0000  ................
00000980: 9007 0000 0000 0000 2a39 0000 0000 0000  ........*9......
00000990: 785e ed7d 7b7c 1cc5 917f cfec ecec 6af5  x^.}{|........j.
000009a0: 5c59 b217 b0cd fa05 422f 4b96 2ccb c636  \Y......B/K.,..6
000009b0: 9625 d916 48b6 6249 e68d 3d5a 8dac 8d57  .%..H.bI..=Z...W
000009c0: bbf2 eeca b630 0619 0847 2e98 c005 4820  .....0...G....H 
000009d0: e115 c205 0839 9200 811c 3fc0 3c43 8e24  .....9....?.<C.$
000009e0: 478e f009 b910 4c8e 70e1 b824 845f c811  G.....L.p..$._..
000009f0: f2e3 e0f7 adea 9edd 1959 364e eefe bb93  .........Y6N....
00000a00: 999a aeea aaea eaea eeea c7cc 0e3d e75c  .............=.\
00000a10: 237c 4208 03d7 471f 09f1 30ee f4b7 46dd  #|B...G...0...F.
00000a20: 8f76 9b44 66c9 897f 5f22 1e28 f8c1 bc87  .v.Df..._".(....
[ . . . ]
00003aa0: b4ae b975 7868 6983 d588 05b1 c727 b2b3  ...uxhi......'..
00003ab0: 2e9e d21e 2b17 7b1a 4e36 bd8b e7e3 1b9e  ....+.{.N6......
00003ac0: 07a1 d371 57ee 96ed 89b3 7c7a 1f30 936b  ...qW.....|z.0.k
00003ad0: d2a1 b178 db6e bcee e8e8 1bc9 66c7 562c  ...x.n......f.V,
00003ae0: 5eac c675 7d6e 5cd7 c39c c57d 3d5d 8b97  ^..u}n\....}=]..
00003af0: e09d e2c5 aa77 38da e6af 461f b557 2e76  .....w8...F..W.v
00003b00: 9439 fd78 9a42 a754 14a8 8a35 abf9 83e4  .9.x.B.T...5....
00003b10: fffb f797 7b60 527e abfb 03fe aad8 fffe  ....{`R~........
00003b20: fd4f f3c0 ff07 c697 00f2 3f39 0000 0000  .O........?9....
00003b30: 0000 0200 0000 0200 0000 0100 0000 3158  ..............1X
00003b40: 3900 0000 0000 0003 0000 0003 0000 0005  9...............
00003b50: 0000 0032 3931 3834 8239 0000 0000 0000  ...29184.9......
00003b60: 0500 0000 0700 0000 1600 0000 3230 3231  ............2021
00003b70: 3036 3032 5431 3833 3834 372e 3337 3931  0602T183847.3791
00003b80: 3737 ac39 0000 0000 0000 0500 0000 0800  77.9............
00003b90: 0000 1600 0000 3230 3231 3036 3032 5431  ......20210602T1
00003ba0: 3831 3931 302e 3031 3232 3631 d639 0000  81910.012261.9..
00003bb0: 0000 0000 0500 0000 0900 0000 1600 0000  ................
00003bc0: 3230 3139 3033 3330 5431 3831 3933 342e  20190330T181934.
00003bd0: 3439 3636 3231 ef39 0000 0000 0000 0400  496621.9........
00003be0: 0000 0d00 0000 0500 0000 6661 6c73 6508  ..........false.
00003bf0: 3a00 0000 0000 0004 0000 000e 0000 0005  :...............
00003c00: 0000 0066 616c 7365 203a 0000 0000 0000  ...false :......
00003c10: 0400 0000 1e00 0000 0400 0000 7472 7565  ............true
00003c20: 393a 0000 0000 0000 0400 0000 0210 0000  9:..............
00003c30: 0500 0000 6661 6c73 6552 3a00 0000 0000  ....falseR:.....
00003c40: 0004 0000 0003 1000 0005 0000 0066 616c  .............fal
00003c50: 7365 6b3a 0000 0000 0000 0400 0000 0410  sek:............
00003c60: 0000 0500 0000 6661 6c73 6583 3a00 0000  ......false.:...
00003c70: 0000 0004 0000 0005 1000 0004 0000 0074  ...............t
00003c80: 7275 65b7 3a00 0000 0000 0001 0000 0001  rue.:...........
00003c90: 5000 0020 0000 0030 3861 6235 6537 3831  P.. ...08ab5e781
00003ca0: 6134 3863 3366 3632 3734 6561 6264 3239  a48c3f6274eabd29
00003cb0: 3663 6433 6234 6600 0000 0000 0000 0001  6cd3b4f.........
00003cc0: 0000 0002 5000 0028 0000 0064 3339 3337  ....P..(...d3937
00003cd0: 6565 6363 3361 6261 3830 6137 3537 3166  eecc3aba80a7571f
00003ce0: 3435 6333 3730 6437 6238 3163 6462 6335  45c370d7b81cdbc5
00003cf0: 3237 6100 0000 0000 0000 0087 3c00 0000  27a.........<...
00003d00: 0000 0031 3b00 0000 0000 0000 0000 0000  ...1;...........

正如之前剖析的目录数据所示,可以立即确定文件名的长度为0x0c(12)个字符。之后可见文件名确实是DLL_File.dll,后面还有一些推测的结构数据。然而,之后还看到有几乎随机的数据,对于缺乏经验的人来说,这些数据看起来像是加密或编码过的数据。而实际上,这只是包含 PE 文件的原始内容的压缩数据。

当看到签名是0x785e时,很容易确定压缩使用的算法是哪一种,即正在处理的是zlib压缩。为此,我强烈建议先阅读RFC-1950,它提供了 ZLIB 压缩数据格式的规范。同样重要的是,此zlib签名会根据由其指定的压缩级别而变化。下概述了zlib签名与压缩级别的对应关系:

压缩级别 ZLIB签名
1 78 01
2 78 5E
3 78 5E
4 78 5E
5 78 5E
6 78 9C
7 78 DA
8 78 DA
9 78 DA

事实上,当操作者设置一个 0 到 9 之间的压缩级别时,很可能就为 FTK Imager 确定了压缩级别。压缩级别设置在级别 1 和 9 之间的 AD1 样本,上述签名完美匹配:

# xxd F1_C1_1500F.ad1 | less
004212c0: 4a50 475f 4669 6c65 2e6a 7067 fc0e 4200  JPG_File.jpg..B.
004212d0: 0000 0000 0600 0000 0000 0000 1411 4200  ..............B.
004212e0: 0000 0000 bfd4 4200 0000 0000 9c9a 4300  ......B.......C.
004212f0: 0000 0000 d360 4400 0000 0000 8025 4500  .....`D......%E.
00421300: 0000 0000 26e7 4500 0000 0000 d961 4600  ....&.E......aF.
00421310: 0000 0000 7801 9cbc 7b40 13d7 d6ff 3d31  ....x...{@....=1

# xxd F1_C5_1500F.ad1 | less
00421290: a405 0000 0000 0000 0000 000c 0000 004a  ...............J
004212a0: 5047 5f46 696c 652e 6a70 67db 0e42 0000  PG_File.jpg..B..
004212b0: 0000 0006 0000 0000 0000 00f3 1042 0000  .............B..
004212c0: 0000 0082 ce42 0000 0000 006b 8e43 0000  .....B.....k.C..
004212d0: 0000 00c2 4e44 0000 0000 005a 0d45 0000  ....ND.....Z.E..
004212e0: 0000 00ba c645 0000 0000 0087 3c46 0000  .....E......<F..
004212f0: 0000 0078 5e9c bc7b 5853 d7d6 ffbb 6290  ...x^..{XS....b.

# xxd F1_C6_1500F.ad1 | less
00421290: 0000 0000 0000 0000 0c00 0000 4a50 475f  ............JPG_
004212a0: 4669 6c65 2e6a 7067 d80e 4200 0000 0000  File.jpg..B.....
004212b0: 0600 0000 0000 0000 f010 4200 0000 0000  ..........B.....
004212c0: 3bce 4200 0000 0000 e68d 4300 0000 0000  ;.B.......C.....
004212d0: fb4d 4400 0000 0000 530c 4500 0000 0000  .MD.....S.E.....
004212e0: 47c5 4500 0000 0000 b23a 4600 0000 0000  G.E......:F.....
004212f0: 789c 9cbc 7b58 53d7 d6ff bb62 90a0 45e2  x...{XS....b..E.

# xxd F1_C9_1500F.ad1 | less
00421290: 0000 0000 0000 0000 0c00 0000 4a50 475f  ............JPG_
004212a0: 4669 6c65 2e6a 7067 d80e 4200 0000 0000  File.jpg..B.....
004212b0: 0600 0000 0000 0000 f010 4200 0000 0000  ..........B.....
004212c0: 39ce 4200 0000 0000 e38d 4300 0000 0000  9.B.......C.....
004212d0: f54d 4400 0000 0000 4c0c 4500 0000 0000  .MD.....L.E.....
004212e0: 35c5 4500 0000 0000 933a 4600 0000 0000  5.E......:F.....
004212f0: 78da 9cbc 7b58 53d7 d6ff bb62 90a0 45e2  x...{XS....b..E.

但是,选择压缩级别为 0 的 AD1 文件呢?根据 FTK Imager的提示,这相当于“无”压缩,可以通过仔细查看C0AD1 样本之一来验证这一点:

# xxd F1_C0_1500F.ad1 | less
004211e0: 0000 0000 0000 0000 000c 0000 004a 5047  .............JPG
004211f0: 5f46 696c 652e 6a70 6729 0e42 0000 0000  _File.jpg).B....
00421200: 0006 0000 0000 0000 0041 1042 0000 0000  .........A.B....
00421210: 0051 1043 0000 0000 0061 1044 0000 0000  .Q.C.....a.D....
00421220: 0071 1045 0000 0000 0081 1046 0000 0000  .q.E.......F....
00421230: 0091 1047 0000 0000 00b4 b447 0000 0000  ...G.......G....
00421240: 0078 0100 fbff 0400 ffd8 ffe0 0010 4a46  .x............JF
00421250: 4946 0001 0100 0001 0001 0000 fffe 003b  IF.............;

在上面的输出中,zlib 签名仍然存在于 偏移0x421241,这与 ZLIB 压缩级别 1 相关。但是,仔细观察数据,可以看到 JPG 图像文件的原始内容,这意味着原始文件数据实际上并没有被压缩。查看官方 ZLIB 文档,实际上可以使用 Z_NO_COMPRESSION[^5] 指定压缩级别为 0。因此,我假设 zlib 压缩级别 0 也必须与压缩级别 1 共享相同的签名。

有趣的是,可以使用 dd 命令轻松提取与 AD1 样本中给定文件相关联的原始 zlib 数据。如果我们再次从“Folder 2”结构(F2_C3_1500F.ad1)中取出 PE 文件DLL_File.dll,我们可以轻松地手动计算压缩后的“zlib”数据的开始、结束和长度。例如,我知道 AD1 样本中 PE 文件的 zlib 数据从偏移量 0x990 开始,因此样本中有 2448 字节。我也知道当我们遇到一个 NULL 字节序列时,zlib 数据结束,它发生在偏移量 0x3b2b,这意味着我们可以计算出数据的长度为 12700 字节长(包括一个额外的字节来说明)最后一个省略的字节):

# dd if=F2_C3_1500F.ad1 bs=1 skip=2448 count=12700 status=none > zlib.data
# file zlib.data 
zlib.data: zlib compressed data

将先前计算的值代入 dd 命令,我们可以提取包含 PE 文件的原始 zlib 数据,并使用 file 命令验证其内容。从这里开始,我们可以通过多种方式使用 Linux 命令解压缩 zlib 数据,在这种情况下,openssl 命令就足够了:

# openssl zlib -d -in zlib.data > Extracted_DLL.dll
# file Extracted_DLL.dll 
Extracted_DLL.dll: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows

应该注意的是,这显然是从 AD1 容器分配一个全新的文件,因此,新的 PE 文件将不包含任何原始元数据。作为一个快速的旁注;在 AD1 文件中压缩的 zlib 数据之后的数据中,有一小部分数据报告了原始文件的大小。这可以在偏移量0x3b53处的 PE 文件的 AD1 十六进制数据中看到,其中我们可以看到 ASCII 报告大小为 29184 字节。为了验证这一点,我们可以在 Linux 上使用 du -b 命令来查看我们提取的 PE 文件的大小(以字节为单位):

# du -b Extracted_DLL.dll 
29184    Extracted_DLL.dll

最后,经过时间戳数据和推测的文件属性数据部分,我们达到了哈希值。取证软件(例如 FTK Imager)存储此信息以验证数据完整性是有意义的。最后一次查看PE文件的AD1十六进制数据,我们可以看到偏移量0x3c980x3ccb分别有一个MD5和SHA-1哈希值:

00003c90: 5000 0020 0000 0030 3861 6235 6537 3831  P.. ...08ab5e781
00003ca0: 6134 3863 3366 3632 3734 6561 6264 3239  a48c3f6274eabd29
00003cb0: 3663 6433 6234 6600 0000 0000 0000 0001  6cd3b4f.........
00003cc0: 0000 0002 5000 0028 0000 0064 3339 3337  ....P..(...d3937
00003cd0: 6565 6363 3361 6261 3830 6137 3537 3166  eecc3aba80a7571f
00003ce0: 3435 6333 3730 6437 6238 3163 6462 6335  45c370d7b81cdbc5
00003cf0: 3237 6100 0000 0000 0000 0087 3c00 0000  27a.........<...
  • MD5: 08ab5e781a48c3f6274eabd296cd3b4f
  • SHA-1: d3937eecc3aba80a7571f45c370d7b81cdbc527a

与文件大小一样,通过在 Linux 上使用 md5sumsha1sum 工具针对提取的 PE 文件查看它们是否匹配,很容易验证:

# md5sum Extracted_DLL.dll 
08ab5e781a48c3f6274eabd296cd3b4f  Extracted_DLL.dll
# sha1sum Extracted_DLL.dll 
d3937eecc3aba80a7571f45c370d7b81cdbc527a  Extracted_DLL.dll

因此,我们可以看到哈希值匹配,证明之前使用的 zlib 提取和解压缩方法没有以任何方式改变文件内容。此时,数据只是从下一个文件或目录名称开始重复,直到到达 AD1 文件的末尾,我们将其称为“页脚”部分。

AD1文件尾部

许多文件格式通常在文件数据的末尾包含一个“页脚”(有时称为“尾部签名”),可出于各种原因使用。然而,在大多数情况下,这样的部分只是用来表示文件数据的结尾。这对于文件雕刻工具很有用,它将使用头部和尾部签名值来确定特定文件数据的开始和结束位置。在这方面,AD1 文件没有什么不同,并且在不同大小的容器末尾包含一个部分。

有趣的是,当我通过查看文件末尾的十六进制数据来测试我的 AD1 样本时,我注意到虽然有些样本具有共性,但不是所有 AD1 样本都有一致的尾部签名,尾部数据长度也不尽一致。但是,尾部似乎总是以下列数据开始:

4154545247554944 ATTRGUID

例如,这可以在“文件夹 1”示例中看到F1_C5_1500F.ad1

004682e0: 8046 0000 0000 0004 0000 0005 1000 0004  .F..............
004682f0: 0000 0074 7275 652b 8146 0000 0000 0001  ...true+.F......
00468300: 0000 0001 5000 0020 0000 0036 6166 3461  ....P.. ...6af4a
00468310: 3832 3639 3361 3430 3362 3064 3061 6664  82693a403b0d0afd
00468320: 6531 3639 3732 3436 3666 3500 0000 0000  e16972466f5.....
00468330: 0000 0001 0000 0002 5000 0028 0000 0031  ........P..(...1
00468340: 6162 3861 3364 3063 6632 3263 6465 3233  ab8a3d0cf22cde23
00468350: 3137 3362 3662 3431 3532 3133 3737 6330  173b6b41521377c0
00468360: 6664 6265 6561 3841 5454 5247 5549 4400  fdbeea8ATTRGUID.
00468370: 0000 000f 0000 0002 0000 00f4 73d8 8ab0  ............s...
00468380: c06a 47ba 1a36 81c1 816b 0b03 0000 008a  .jG..6...k......
00468390: 8408 354c 7621 4797 9a87 0e1c 1a33 e007  ..5Lv!G......3..
004683a0: 0000 0037 a6cc e543 0457 4fbe ca80 36e4  ...7...C.WO...6.
004683b0: f785 7408 0000 00fc 0d10 f335 c6ef 40ab  ..t........5..@.
004683c0: 7b2e a4f1 1d89 4709 0000 00c8 a66c adef  {.....G......l..
004683d0: db57 429c 27ad a44e 0fe8 b70d 0000 00b6  .WB.'..N........
004683e0: 8132 8cde c3b0 4ca4 5360 74b6 89b9 090e  .2....L.S`t.....
004683f0: 0000 007e 4a0f 065f eba4 4b81 3f08 8b68  ...~J.._..K.?..h
00468400: 81d6 7f1e 0000 0064 ac64 ce64 3a7e 4f85  .......d.d.d:~O.
00468410: 3281 2896 8558 0c02 1000 0045 5504 429e  2.(..X.....EU.B.
00468420: ad1f 4281 e3f7 89b5 4179 8e03 1000 00f7  ..B.....Ay......
00468430: f66a a13d aa14 4d96 1001 73dc 81a4 3604  .j.=..M...s...6.
00468440: 1000 005e 10cb e935 62ab 45aa 652e 2a60  ...^...5b.E.e.*`
00468450: 5e95 b405 1000 0065 795c 1d07 1462 43bd  ^......ey\...bC.
00468460: edfe 175a 4d71 4001 5000 000a 33e2 6be2  ...ZMq@.P...3.k.
00468470: 15ea 4db6 3e21 98e8 1eab 7502 5000 0018  ..M.>!....u.P...
00468480: ffe8 4027 2324 4c93 58db ea9f a4dd 5c02  ..@'#$L.X.....\.
00468490: 0001 0065 9dab 5ef2 a3a1 44aa dd15 5f55  ...e..^...D..._U
004684a0: 06fd 164c 4f43 5347 5549 4400 0000 0003  ...LOCSGUID.....
004684b0: 0000 0001 0000 003e a0fa a262 498a 44ac  .......>...bI.D.
004684c0: 5889 8368 016f c702 0000 005e 6ac1 6efe  X..h.o.....^j.n.
004684d0: cef8 488f 37dc 2342 d969 db03 0000 0042  ..H.7.#B.i.....B
004684e0: f2cb 6423 6670 4cb5 63af b179 c5c8 36    ..d#fpL.c..y..6

从上面的输出中,可以看到 AD1 结构中最终文件的 SHA-1 值紧接在 ATTRGUID 签名之前,之后它会继续直到到达 AD1 文件的末尾。从这里开始的下一步将是进一步剖析此数据部分,以确定它是否包含任何有意义的信息。

然而,在查看了各种 AD1 样本的数据后,很快发现这些数据在内容和长度上也非常不一致。然而,尾部结构也不适合附加到 AD1 容器的文件,正如 file 命令报告的那样:

# dd if=F2_C9_1500F.ad1 bs=1 skip=34751 status=none > F2_C9_1500F.ad1.footer
# file F2_C9_1500F.ad1.footer 
footer: data

实验结果摘要

AD1文件头数据

下表概述了我测试的样本的 AD1 文件头部分中包含的数据:

偏移 LENGTH 十六进制值 DESCRIPTION "逻辑镜像“ ”自定义内容“
0x0 15字节 41445345474d454e54454446494c 签名: ADSEGMENTEDFILE
0x22 5字节 变量 分段级别
0x200 14字节 41444c4f474943414c494d414745 签名: ADLOGICALIMAGE
0x230 2字节 4144 AD 签名
0x25c 30字节 437573746f6d20436f6e74656e7420496d616765285b4d756c74695d297d 自定义内容签名
0x25c N/A N/A 文件数据开始
0x2a9 N/A N/A 文件数据开始

AD1文件/文件夹数据结构

下表提供了 AD1 文件中包含的单个文件/文件夹结构的高级概述:

序号 数据 文件 目录
1 名称
2 ? 结构数据 ?
3 压缩数据
4 原始大小
5 ACM 时间戳
6 ? 属性数据 ?
7 哈希值

AD1压缩签名

下表提供了zlib与审查员选择的相应 AD1 压缩级别相关联的十六进制签名的概览:

AD1压缩级别 ZLIB签名
0 0x7801
1 0x7801
2 0x785e
3 0x785e
4 0x785e
5 0x785e
6 0x789c
7 0x78Da
8 0x78Da
9 0x78Da

AD1文件尾部数据

下表简单地提供了 AD1 文件中使用的十六进制签名来表示尾部数据的起始:

十六进制值 描述
4154545247554944 尾部起始部分的签名: ATTRGUID

其他数据

除了上表之外,请在下面找到与 AD1 文件格式相关的其他发现列表,这些发现可能有用:

  • 可以使用以下两种方法之一创建 AD1 文件;Logical Image或者Custom Content
  • 这两种方法之间唯一可辨别的数据区别在于 AD1 文件头部分
  • AD1 容器使用zlib压缩存储原始文件内容(选择压缩时)
  • 每个文件/文件夹名称的字符长度存储在每个文件/文件夹名称之前的数据中
  • AD1文件大小存储在header部分(存储值似乎省略了header/footer数据,需要进一步测试)

结语

发表这篇文章的目的是分享我个人对AccessData AD1文件格式的研究和实验结果。在正常情况下,我会将科学方法作为我的主要研究方法,就像我在其他文章中看到的那样,但这一研究在本质上更具思辩性。这有很多原因;最重要的是,我基本上是在试图剖析一种无文件记录的、专有的取证数据格式。第二个原因是,有许多AD1文件的变体可以跨许多不同版本的FTK Imager创建,不幸的是,我没有时间致力于探索所有这些潜在的可能性。

考虑到与AD1文件格式分解相关的变量数量,我决定将实验重点放在从FTK Imager的一个(较新的)版本中创建的变量上。我所有的实验和测试包括从各种在线资源中获取的AD1样本,以及我自己生成的对照样本。在测试过程中,我遇到的最大问题是样本之间存在大量的不匹配数据,这使得交叉引用数据集变得困难。因此,我根据我得到的结果和我能够在我可用的时间框架内执行的测试,对数据做了许多假设。

回顾我从测试中得到的信息,我认为应该假设可以构建一个linux兼容的命令行工具,从AD1容器中提取文件数据(使用原始元数据),并以逻辑结构将其呈现给分析人员。我知道,使用本文前面概述的基于windows的技术,这已经是可能的。

总的来说,我希望我在这里进行的研究结果将为那些希望进一步探索AD1文件格式的人,或那些可能只是想了解AD1容器如何存储和压缩文件数据的人提供有用的基础。出于这个原因,我决定将我的实验得出的主要发现的执行摘要作为那些可能需要它的人的快速参考。

如果您对本文中提到的主题有任何建议或问题,请在Twitter 上与我(@AstrumMairi)联系。

参考文献

[^1]: Lefton, S. (2016). Native Production—Advantages to Producing E-Discovery Natively [Accessed 2021-06-02].
[^2]: AccessData Group, Inc. (2016). Imager User Guide [Accessed 2021-05-28].
[^3]: Carrier, B. (2005). File System Forensic Analysis. Addison-Wesley:Boston, MA.
[^4]: Koruga, P. & Baca, M. (2010). Analysis of B-tree Data Structure and its Usage in Computer Forensics. University of Zagreb:Croatia.
[^5]: Gailly, J. & Adler, M. (2017). zlib 1.2.11 Manual [Accessed 2021-06-01].

目录
相关文章
|
编解码 安全 iOS开发
如何将ISO转换为MP4格式
将 ISO 文件转换为 MP4 格式,可以更方便地保存和在常用设备上播放。这里有 8 款适用于 Windows 和 Mac 的最佳软件程序,可用于将 ISO 文件转换为数字格式,以便在任何设备上欣赏您的视频。
|
数据安全/隐私保护
AD2428W手册解读之其他发现流程示例
AD2428W手册解读之其他发现流程示例
AD2428W手册解读之其他发现流程示例
|
Ubuntu 网络安全 开发工具
Cubic(Custom Ubuntu ISO Creator)创建自定义镜像
Cubic(Custom Ubuntu ISO Creator)创建自定义镜像
1215 0
Cubic(Custom Ubuntu ISO Creator)创建自定义镜像
|
安全
我的压缩软件选择:7zip软件+Zip格式
我的压缩软件选择:7zip软件+Zip格式
78 0
|
弹性计算 JSON 数据格式
aws EC2二代镜像迁移阿里云ecs磁盘user_config.json生成脚本
由于迁移需要,此python脚本自动生成user_config.json包含aws二代镜像磁盘nvme的配置,以方便迁移,目前最多支持10块磁盘和每块磁盘最多10个分区,可以自己修改
527 0