起因

应ccadmin邀请,一起分析研究某厂商的虚拟机产品的注册逻辑和加固措施。

以下内容纯属做梦梦到,涉及到的名称如与现实世界雷同,纯属巧合。

下载完成后是个ova文件,使用7zip打开如下:

PixPin_2026-09-05_15-59-21.png

初见端倪

使用7zip继续打开vmdk文件,可以看到Properties中的Comment信息如下:

PixPin_2026-09-05_16-53-25.png

其中ddb.virtualHWVersion = "7"信息表示这是一个传统的MBR引导类型镜像。
具体文件如下:
PixPin_2026-09-05_17-04-36.png

很明显0.img为系统启动的boot分区,大小为190Mb,符合boot分区的大小。
其他分区文件直接打不开,使用010Editor查看,发现为LUKS加密分区。

那么就从boot分区进行检查吧。

加密的boot分区?

之前遇到的LUKS分区加密都在vmlinuz或initrd.img中加载解密密钥,解密挂载硬盘,而这个却和常规做法不同。
分区文件:

PixPin_2026-09-05_17-17-14.png

脱出vmlinuz和initrd.img文件进行分析,使用010Editor发现其都为高熵特征,无法识别原有的文件结构类型。
PixPin_2026-09-05_17-19-42.png

PixPin_2026-09-05_17-22-06.png

怀疑这些文件进行了某种加密/混淆处理,解密一定在系统进入BOOT启动阶段前(不然boot引导加密了,系统就无法执行下去了)。 正常系统加载流程如下:
flowchart TD 
    A[VMware虚拟机上电<br/>虚拟BIOS初始化硬件] --> B[BIOS读取vmdk磁盘0扇区 MBR 0x7C00]
    B --> C[MBR引导代码:查找活动分区<br/>读取活动分区PBR扇区] 
    C --> D["GRUB stage1(PBR 512字节)"]
    D --> E[加载MBR‑gap中的stage1.5<br/>获得ext4文件系统能力] 
    E --> F[读取/boot/grub/core.img] 
    F --> G[core.img加载grub.cfg,弹出GRUB菜单] 
    G --> H[准备读取 /boot/vmlinuz + initramfs]

这里就要去提取、分析vmdk中的引导代码了,但是这里有个取巧的方法。

数据取证?no,just the recovery key !

直接脱出0.img这个boot分区文件,使用autospy开源的数据取证软件进行加载。why? 因为要尝试恢复可能被删除的secret file。

Pasted_image_20260905175309.png

发现autospy部分文件显示0字节,无法有效进行提取。
使用命令sudo losetup -f -P --show 0.img 挂载该分区镜像,使用命令sudo extundelete /dev/loop0 --restore-all来尝试恢复所有的文件,其中/dev/loop0为分区镜像文件挂载后的路径。
PixPin_2026-09-05_19-05-46.png

这里只需要提取*.mod文件,使用Ghidra对其进行分析。
在linux.mod和linux16.mod文件中找到了解密的办法。
存在rc4_setkey、rc4_encrypt_stream函数,大概可知是RC4 KSA相关加密。
PixPin_2026-09-05_20-05-38.png

可知,RC4的密钥为5位,在DAT_0001131c中。
PixPin_2026-09-05_20-08-45.png

最终得到的key为61 8a 63 d2 fb。
解密脚本如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sys
from pathlib import Path


# linux.mod / linux16.mod 中发现的 RC4 Key
KEY = bytes.fromhex("61 8A 63 D2 FB")

def rc4_init(key: bytes) -> list[int]:
    """
    RC4 KSA
    对应目标程序中的 rc4_setkey()
    """
    if not key:
        raise ValueError("RC4 key cannot be empty")

    S = list(range(256))
    j = 0
    key_len = len(key)

    for i in range(256):
        j = (j + S[i] + key[i % key_len]) & 0xFF
        S[i], S[j] = S[j], S[i]

    return S

def rc4_crypt(data: bytes, key: bytes) -> bytes:
    """
    RC4 PRGA + XOR
    RC4 加密和解密使用完全相同的操作。
    """
    S = rc4_init(key)
    i = 0
    j = 0
    output = bytearray(len(data))

    for n, byte in enumerate(data):
        i = (i + 1) & 0xFF
        j = (j + S[i]) & 0xFF

        S[i], S[j] = S[j], S[i]

        k = S[(S[i] + S[j]) & 0xFF]

        output[n] = byte ^ k
    return bytes(output)

def decrypt_file(input_file: str, output_file: str):
    input_path = Path(input_file)
    output_path = Path(output_file)

    if not input_path.is_file():
        raise FileNotFoundError(f"输入文件不存在: {input_path}")
    print(f"[+] Input : {input_path}")
    print(f"[+] Output: {output_path}")
    print(f"[+] Key   : {KEY.hex(' ').upper()}")
    print(f"[+] Size  : {input_path.stat().st_size} bytes")

    with input_path.open("rb") as f:
        encrypted = f.read()

    print("[+] RC4 decrypting...")

    decrypted = rc4_crypt(encrypted, KEY)

    with output_path.open("wb") as f:
        f.write(decrypted)
    print("[+] Done.")
    print(f"[+] Written: {len(decrypted)} bytes")

def main():
    if len(sys.argv) != 3:
        print(
            f"Usage:\n"
            f"  {sys.argv[0]} <input_file> <output_file>\n\n"
            f"Example:\n"
            f"  {sys.argv[0]} encrypted.bin decrypted.bin"
        )
        sys.exit(1)
    input_file = sys.argv[1]
    output_file = sys.argv[2]
    try:
        decrypt_file(input_file, output_file)
    except Exception as e:
        print(f"[-] Error: {e}", file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    main()

PixPin_2026-09-05_20-15-04.png

文章的部分内容被密码保护: