moonregf

    纯 MoonBit 实现的 Windows 注册表 hive(REGF)读取与写入库,不依赖 Windows API

    windows
    registry
    regf
    hive
    parser
    forensics
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    13 hours ago
    Downloads
    9

    #moonregf

    纯 MoonBit 实现的 Windows 注册表 hive 文件(REGF 二进制格式)读取与写入库:不依赖 Windows API、C 库或 FFI。

    Windows 把 NTUSER.DAT、SYSTEM、SOFTWARE 等配置单元以 REGF 格式存盘。本项目在纯 MoonBit 中读写该格式, 让工具链在 Windows 之外(Linux CI、wasm-gc、浏览器)也能读取、生成 hive 内容。

    #安装

    moon add Xcsa-ee/moonregf

    moon.pkg 中导入:

    import { "Xcsa-ee/moonregf", }

    #读取

    match @moonregf.parse_header(bytes) { Ok(header) => println(header.file_name) Err(error) => println(error.message()) }

    遍历键树与读取键值:

    for entry in @moonregf.walk_key_tree(bytes, header.root_cell_offset, 3) { println(entry.path) } match @moonregf.list_values(bytes, key) { Ok(values) => for value in values { println(value.name + " = " + value.data_type.label()) } Err(error) => println(error.message()) }

    #写入

    从零生成一个 hive 文件:

    let builder = @moonregf.HiveBuilder::new() let software = builder.add_key(0, "Software") builder.set_string(software, "Install", "Hello") builder.set_dword(software, "Count", 42) match builder.build() { Ok(bytes) => println(bytes.length()) Err(error) => println(error.message()) }

    命令行:

    moon run cmd/main -- <path-to-NTUSER.DAT> moon run cmd/main -- <path-to-NTUSER.DAT> --values moon run cmd/main -- --build demo.hive

    #当前进度

    #已知限制

    • 写入器目前只接受 ASCII 键名与值名;非 ASCII 名称会返回 UnsupportedName。
    • 单个值最大 16344 字节,超过者返回 ValueTooLarge(尚未写 big data 分段)。

    #许可

    Apache-2.0,见 LICENSE。

    BuildValue

    type BuildValue

    A value waiting to be written into a hive.

    HiveBuilder

    pub struct HiveBuilder {
    names : Array[String]
    parents : Array[Int]
    children : Array[Array[Int]]
    values : Array[Array[BuildValue]]
    }

    A tree of keys and values that build() turns into a REGF hive.

    Nodes are addressed by index; node 0 is the root key.

    HiveBuilder::add_key

    fn HiveBuilder::add_key(self : HiveBuilder, parent : Int, name : String) -> Int

    Adds a child key under parent and returns its index.

    HiveBuilder::build

    fn HiveBuilder::build(self : HiveBuilder) -> Result[Bytes, RegfError]

    Serializes the tree into a REGF hive file.

    The layout is the one Windows uses: a 4096-byte base block, then one or more hive bins whose cells carry the nk, vk and lf records. Key names must be ASCII and a value payload must fit in one data cell (16344 bytes).

    HiveBuilder::key_count

    fn HiveBuilder::key_count(self : HiveBuilder) -> Int

    Number of keys in the tree.

    HiveBuilder::new

    Creates a builder holding a single root key called ROOT.

    HiveBuilder::new_named

    fn HiveBuilder::new_named(root_name : String) -> HiveBuilder

    Creates a builder whose root key uses root_name.

    HiveBuilder::set_dword

    fn HiveBuilder::set_dword(self : HiveBuilder, key_index : Int, name : String, value : Int) -> Unit

    Stores a REG_DWORD value.

    HiveBuilder::set_string

    fn HiveBuilder::set_string(self : HiveBuilder, key_index : Int, name : String, text : String) -> Unit

    Stores a REG_SZ value holding text.

    HiveBuilder::set_value

    fn HiveBuilder::set_value(self : HiveBuilder, key_index : Int, name : String, data_type : HiveValueType, data : Bytes) -> Unit

    Stores one value under the key at key_index.

    HiveCell

    pub(all) struct HiveCell {
    offset : UInt
    payload_size : Int
    allocated : Bool
    }

    A cell inside the hive bins region.

    A cell starts with a signed 32-bit size that covers the size field itself: negative sizes mark allocated cells, positive sizes mark free cells.

    HiveFileType

    pub(all) enum HiveFileType {
    Primary
    Log
    External
    Unknown(UInt)
    }

    Kind of file recorded in the base block.

    HiveFileType::label

    fn HiveFileType::label(self : HiveFileType) -> String

    Short label for a hive file type.

    HiveHeader

    pub(all) struct HiveHeader {
    primary_sequence : UInt
    secondary_sequence : UInt
    last_written_high : UInt
    last_written_low : UInt
    major_version : UInt
    minor_version : UInt
    file_type : HiveFileType
    file_format : UInt
    root_cell_offset : UInt
    hive_bins_data_size : UInt
    clustering_factor : UInt
    file_name : String
    checksum : UInt
    }

    Parsed REGF base block (the 4096 bytes at the start of a hive file).

    HiveKeyEntry

    pub(all) struct HiveKeyEntry {
    path : String
    offset : UInt
    subkey_count : Int
    value_count : Int
    }

    One entry of a flattened key tree.

    HiveKeyNode

    pub(all) struct HiveKeyNode {
    offset : UInt
    flags : UInt
    last_written_high : UInt
    last_written_low : UInt
    access_bits : UInt
    parent_offset : UInt
    subkey_count : UInt
    volatile_subkey_count : UInt
    subkey_list_offset : UInt
    volatile_subkey_list_offset : UInt
    value_count : UInt
    value_list_offset : UInt
    security_offset : UInt
    class_name_offset : UInt
    name_length : UInt
    class_name_length : UInt
    name : String
    }

    A key node (nk) record: one registry key and the offsets of its children.

    HiveSubkeyList

    pub(all) struct HiveSubkeyList {
    offset : UInt
    kind : SubkeyListKind
    count : Int
    key_offsets : Array[UInt]
    }

    A subkey list record: the direct children of one key.

    For root index (ri) records the child offsets of the nested lists are flattened, so key_offsets always holds key node offsets in stored order.

    HiveValue

    pub(all) struct HiveValue {
    offset : UInt
    name : String
    data_type : HiveValueType
    data_size : UInt
    data_offset : UInt
    inline_data : Bool
    data : Bytes
    }

    A registry value (vk record) together with its resolved data.

    inline_data is true when the four bytes of data_offset hold the data itself, which Windows does for payloads of at most four bytes.

    HiveValue::as_multi_string

    fn HiveValue::as_multi_string(self : HiveValue) -> Array[String]?

    Splits the data of a REG_MULTI_SZ value into its NUL separated entries.

    HiveValue::as_string

    fn HiveValue::as_string(self : HiveValue) -> String?

    Decodes the data of a string typed value; the trailing NUL is dropped.

    HiveValue::as_u32

    fn HiveValue::as_u32(self : HiveValue) -> UInt?

    Interprets the data as a 32-bit integer when it holds at least four bytes.

    HiveValueType

    pub(all) enum HiveValueType {
    Nil
    Sz
    ExpandSz
    Binary
    Dword
    DwordBigEndian
    Link
    MultiSz
    ResourceList
    FullResourceDescriptor
    ResourceRequirementsList
    Qword
    Unknown(UInt)
    }

    Kind of data stored in a registry value.

    HiveValueType::from_code

    fn HiveValueType::from_code(code : UInt) -> HiveValueType

    Maps the numeric type code stored in a vk record to a value type.

    HiveValueType::label

    fn HiveValueType::label(self : HiveValueType) -> String

    Registry type name such as REG_SZ, as used by regedit and .reg files.

    RegfError

    pub(all) enum RegfError {
    TooShort(Int)
    BadSignature(String)
    BadChecksum(UInt, UInt)
    BadCellOffset(Int)
    BadCellSize(Int)
    BadKeyNode(Int)
    BadSubkeyList(Int)
    BadValue(Int)
    BadValueData(Int)
    UnsupportedName(Int)
    ValueTooLarge(Int)
    }

    Errors reported while parsing or building a REGF hive file.

    RegfError::message

    fn RegfError::message(self : RegfError) -> String

    Human readable message for an error value.

    SubkeyListKind

    pub(all) enum SubkeyListKind {
    FastLeaf
    HashLeaf
    IndexLeaf
    RootIndex
    Unknown(String)
    }

    Kind of subkey list record stored in a hive.

    SubkeyListKind::label

    fn SubkeyListKind::label(self : SubkeyListKind) -> String

    Short label for a subkey list kind.

    decode_single_byte

    fn decode_single_byte(bytes : Bytes, offset : Int, count : Int) -> String

    Decodes count single-byte characters starting at byte offset.

    REGF stores compressed key names as one byte per character. Bytes are decoded as UTF-8 with replacement so ASCII names round-trip exactly and stray high bytes stay readable.

    decode_utf16le

    fn decode_utf16le(bytes : Bytes, offset : Int, unit_count : Int) -> String

    Decodes unit_count UTF-16LE code units starting at byte offset.

    Decoding stops at the first NUL code unit, matching how REGF stores the fixed-width base block file name. Unpaired surrogates become U+FFFD so the result is always valid UTF-8.

    list_subkeys

    fn list_subkeys(bytes : Bytes, key : HiveKeyNode) -> Result[Array[HiveKeyNode], RegfError]

    Reads the direct children of a key.

    This is the strict view: any unreadable child record fails the whole call.

    list_values

    fn list_values(bytes : Bytes, key : HiveKeyNode) -> Result[Array[HiveValue], RegfError]

    Reads the values of a key in stored order.

    This is the strict view: any unreadable value fails the whole call.

    parse_header

    fn parse_header(bytes : Bytes) -> Result[HiveHeader, RegfError]

    Parses the base block of a hive file.

    parse_key_node

    fn parse_key_node(bytes : Bytes, offset : UInt) -> Result[HiveKeyNode, RegfError]

    Parses the key node stored in the cell at offset.

    parse_value

    fn parse_value(bytes : Bytes, offset : UInt) -> Result[HiveValue, RegfError]

    Parses the value record stored in the cell at offset and resolves its data.

    read_cell

    fn read_cell(bytes : Bytes, offset : UInt) -> Result[HiveCell, RegfError]

    Reads the cell header at offset, which is relative to the bins region.

    read_subkey_list

    fn read_subkey_list(bytes : Bytes, offset : UInt) -> Result[HiveSubkeyList, RegfError]

    Reads the subkey list stored at offset, expanding nested ri records.

    read_u16_le

    fn read_u16_le(bytes : Bytes, offset : Int) -> UInt

    Reads a little-endian 16-bit unsigned integer at offset.

    The caller must guarantee that offset + 2 is within bounds.

    read_u32_le

    fn read_u32_le(bytes : Bytes, offset : Int) -> UInt

    Reads a little-endian 32-bit unsigned integer at offset.

    The caller must guarantee that offset + 4 is within bounds.

    read_value_list

    fn read_value_list(bytes : Bytes, offset : UInt) -> Result[Array[UInt], RegfError]

    Reads the value list stored in the cell at offset.

    A value list cell is a plain array of 32-bit vk offsets; it carries no signature of its own.

    value_offsets

    fn value_offsets(bytes : Bytes, key : HiveKeyNode) -> Result[Array[UInt], RegfError]

    Reads the vk offsets listed by a key, without parsing the values.

    The lenient counterpart of list_values: callers that must survive hives referencing volatile or freed cells can parse each offset on their own.

    walk_key_tree

    fn walk_key_tree(bytes : Bytes, root_offset : UInt, max_depth : Int) -> Array[HiveKeyEntry]

    Walks the key tree rooted at root_offset, descending max_depth levels.

    The lenient view used for offline hives: children whose records cannot be parsed are skipped, because hives can reference volatile or freed cells that are absent from the file on disk.