This spec allows to parse files used by Microsoft Windows family of operating systems to store parts of its "registry". "Registry" is a hierarchical database that is used to store system settings (global configuration, per-user, per-application configuration, etc).
Typically, registry files are stored in:
%SystemRoot%\System32\Config\
%USERPROFILE%\Ntuser.dat
%USERPROFILE%\Local Settings\Application Data\Microsoft\Windows\Usrclass.dat
(localized, Windows 2000, Server 2003 and Windows XP)%USERPROFILE%\AppData\Local\Microsoft\Windows\Usrclass.dat
(non-localized, Windows Vista and later)Note that one typically can't access files directly on a mounted filesystem with a running Windows OS.
This page hosts a formal specification of Windows registry database using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.
All parsing code for JavaScript generated by Kaitai Struct depends on the JavaScript runtime library. You have to install it before you can parse data.
The JavaScript runtime library is available at npm:
npm install kaitai-struct
See the usage examples in the JavaScript notes.
Parse structure from an ArrayBuffer:
var arrayBuffer = ...;
var data = new Regf(new KaitaiStream(arrayBuffer));
After that, one can get various attributes from the structure by accessing fields or properties like:
data.header // => get header
// This is a generated file! Please edit source .ksy file and use kaitai-struct-compiler to rebuild
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
define(['exports', 'kaitai-struct/KaitaiStream'], factory);
} else if (typeof exports === 'object' && exports !== null && typeof exports.nodeType !== 'number') {
factory(exports, require('kaitai-struct/KaitaiStream'));
} else {
factory(root.Regf || (root.Regf = {}), root.KaitaiStream);
}
})(typeof self !== 'undefined' ? self : this, function (Regf_, KaitaiStream) {
/**
* This spec allows to parse files used by Microsoft Windows family of
* operating systems to store parts of its "registry". "Registry" is a
* hierarchical database that is used to store system settings (global
* configuration, per-user, per-application configuration, etc).
*
* Typically, registry files are stored in:
*
* * System-wide: several files in `%SystemRoot%\System32\Config\`
* * User-wide:
* * `%USERPROFILE%\Ntuser.dat`
* * `%USERPROFILE%\Local Settings\Application Data\Microsoft\Windows\Usrclass.dat` (localized, Windows 2000, Server 2003 and Windows XP)
* * `%USERPROFILE%\AppData\Local\Microsoft\Windows\Usrclass.dat` (non-localized, Windows Vista and later)
*
* Note that one typically can't access files directly on a mounted
* filesystem with a running Windows OS.
* @see {@link https://github.com/libyal/libregf/blob/main/documentation/Windows%20NT%20Registry%20File%20(REGF)%20format.asciidoc|Source}
*/
var Regf = (function() {
function Regf(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root || this;
this._read();
}
Regf.prototype._read = function() {
this.header = new FileHeader(this._io, this, this._root);
this._raw_hiveBins = [];
this.hiveBins = [];
var i = 0;
while (!this._io.isEof()) {
this._raw_hiveBins.push(this._io.readBytes(4096));
var _io__raw_hiveBins = new KaitaiStream(this._raw_hiveBins[this._raw_hiveBins.length - 1]);
this.hiveBins.push(new HiveBin(_io__raw_hiveBins, this, this._root));
i++;
}
}
var FileHeader = Regf.FileHeader = (function() {
FileHeader.FileFormat = Object.freeze({
DIRECT_MEMORY_LOAD: 1,
1: "DIRECT_MEMORY_LOAD",
});
FileHeader.FileType = Object.freeze({
NORMAL: 0,
TRANSACTION_LOG: 1,
0: "NORMAL",
1: "TRANSACTION_LOG",
});
function FileHeader(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
FileHeader.prototype._read = function() {
this.signature = this._io.readBytes(4);
if (!((KaitaiStream.byteArrayCompare(this.signature, new Uint8Array([114, 101, 103, 102])) == 0))) {
throw new KaitaiStream.ValidationNotEqualError(new Uint8Array([114, 101, 103, 102]), this.signature, this._io, "/types/file_header/seq/0");
}
this.primarySequenceNumber = this._io.readU4le();
this.secondarySequenceNumber = this._io.readU4le();
this.lastModificationDateAndTime = new Filetime(this._io, this, this._root);
this.majorVersion = this._io.readU4le();
this.minorVersion = this._io.readU4le();
this.type = this._io.readU4le();
this.format = this._io.readU4le();
this.rootKeyOffset = this._io.readU4le();
this.hiveBinsDataSize = this._io.readU4le();
this.clusteringFactor = this._io.readU4le();
this.unknown1 = this._io.readBytes(64);
this.unknown2 = this._io.readBytes(396);
this.checksum = this._io.readU4le();
this.reserved = this._io.readBytes(3576);
this.bootType = this._io.readU4le();
this.bootRecover = this._io.readU4le();
}
return FileHeader;
})();
var Filetime = Regf.Filetime = (function() {
function Filetime(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
Filetime.prototype._read = function() {
this.value = this._io.readU8le();
}
return Filetime;
})();
var HiveBin = Regf.HiveBin = (function() {
function HiveBin(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
HiveBin.prototype._read = function() {
this.header = new HiveBinHeader(this._io, this, this._root);
this.cells = [];
var i = 0;
while (!this._io.isEof()) {
this.cells.push(new HiveBinCell(this._io, this, this._root));
i++;
}
}
return HiveBin;
})();
var HiveBinCell = Regf.HiveBinCell = (function() {
function HiveBinCell(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
HiveBinCell.prototype._read = function() {
this.cellSizeRaw = this._io.readS4le();
this.identifier = KaitaiStream.bytesToStr(this._io.readBytes(2), "ASCII");
switch (this.identifier) {
case "lf":
this._raw_data = this._io.readBytes((this.cellSize - 2) - 4);
var _io__raw_data = new KaitaiStream(this._raw_data);
this.data = new SubKeyListLhLf(_io__raw_data, this, this._root);
break;
case "lh":
this._raw_data = this._io.readBytes((this.cellSize - 2) - 4);
var _io__raw_data = new KaitaiStream(this._raw_data);
this.data = new SubKeyListLhLf(_io__raw_data, this, this._root);
break;
case "li":
this._raw_data = this._io.readBytes((this.cellSize - 2) - 4);
var _io__raw_data = new KaitaiStream(this._raw_data);
this.data = new SubKeyListLi(_io__raw_data, this, this._root);
break;
case "nk":
this._raw_data = this._io.readBytes((this.cellSize - 2) - 4);
var _io__raw_data = new KaitaiStream(this._raw_data);
this.data = new NamedKey(_io__raw_data, this, this._root);
break;
case "ri":
this._raw_data = this._io.readBytes((this.cellSize - 2) - 4);
var _io__raw_data = new KaitaiStream(this._raw_data);
this.data = new SubKeyListRi(_io__raw_data, this, this._root);
break;
case "sk":
this._raw_data = this._io.readBytes((this.cellSize - 2) - 4);
var _io__raw_data = new KaitaiStream(this._raw_data);
this.data = new SubKeyListSk(_io__raw_data, this, this._root);
break;
case "vk":
this._raw_data = this._io.readBytes((this.cellSize - 2) - 4);
var _io__raw_data = new KaitaiStream(this._raw_data);
this.data = new SubKeyListVk(_io__raw_data, this, this._root);
break;
default:
this.data = this._io.readBytes((this.cellSize - 2) - 4);
break;
}
}
var NamedKey = HiveBinCell.NamedKey = (function() {
NamedKey.NkFlags = Object.freeze({
KEY_IS_VOLATILE: 1,
KEY_HIVE_EXIT: 2,
KEY_HIVE_ENTRY: 4,
KEY_NO_DELETE: 8,
KEY_SYM_LINK: 16,
KEY_COMP_NAME: 32,
KEY_PREFEF_HANDLE: 64,
KEY_VIRT_MIRRORED: 128,
KEY_VIRT_TARGET: 256,
KEY_VIRTUAL_STORE: 512,
UNKNOWN1: 4096,
UNKNOWN2: 16384,
1: "KEY_IS_VOLATILE",
2: "KEY_HIVE_EXIT",
4: "KEY_HIVE_ENTRY",
8: "KEY_NO_DELETE",
16: "KEY_SYM_LINK",
32: "KEY_COMP_NAME",
64: "KEY_PREFEF_HANDLE",
128: "KEY_VIRT_MIRRORED",
256: "KEY_VIRT_TARGET",
512: "KEY_VIRTUAL_STORE",
4096: "UNKNOWN1",
16384: "UNKNOWN2",
});
function NamedKey(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
NamedKey.prototype._read = function() {
this.flags = this._io.readU2le();
this.lastKeyWrittenDateAndTime = new Filetime(this._io, this, this._root);
this.unknown1 = this._io.readU4le();
this.parentKeyOffset = this._io.readU4le();
this.numberOfSubKeys = this._io.readU4le();
this.numberOfVolatileSubKeys = this._io.readU4le();
this.subKeysListOffset = this._io.readU4le();
this.numberOfValues = this._io.readU4le();
this.valuesListOffset = this._io.readU4le();
this.securityKeyOffset = this._io.readU4le();
this.classNameOffset = this._io.readU4le();
this.largestSubKeyNameSize = this._io.readU4le();
this.largestSubKeyClassNameSize = this._io.readU4le();
this.largestValueNameSize = this._io.readU4le();
this.largestValueDataSize = this._io.readU4le();
this.unknown2 = this._io.readU4le();
this.keyNameSize = this._io.readU2le();
this.classNameSize = this._io.readU2le();
this.unknownStringSize = this._io.readU4le();
this.unknownString = KaitaiStream.bytesToStr(this._io.readBytes(this.unknownStringSize), "ASCII");
}
return NamedKey;
})();
var SubKeyListLhLf = HiveBinCell.SubKeyListLhLf = (function() {
function SubKeyListLhLf(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
SubKeyListLhLf.prototype._read = function() {
this.count = this._io.readU2le();
this.items = [];
for (var i = 0; i < this.count; i++) {
this.items.push(new Item(this._io, this, this._root));
}
}
var Item = SubKeyListLhLf.Item = (function() {
function Item(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
Item.prototype._read = function() {
this.namedKeyOffset = this._io.readU4le();
this.hashValue = this._io.readU4le();
}
return Item;
})();
return SubKeyListLhLf;
})();
var SubKeyListLi = HiveBinCell.SubKeyListLi = (function() {
function SubKeyListLi(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
SubKeyListLi.prototype._read = function() {
this.count = this._io.readU2le();
this.items = [];
for (var i = 0; i < this.count; i++) {
this.items.push(new Item(this._io, this, this._root));
}
}
var Item = SubKeyListLi.Item = (function() {
function Item(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
Item.prototype._read = function() {
this.namedKeyOffset = this._io.readU4le();
}
return Item;
})();
return SubKeyListLi;
})();
var SubKeyListRi = HiveBinCell.SubKeyListRi = (function() {
function SubKeyListRi(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
SubKeyListRi.prototype._read = function() {
this.count = this._io.readU2le();
this.items = [];
for (var i = 0; i < this.count; i++) {
this.items.push(new Item(this._io, this, this._root));
}
}
var Item = SubKeyListRi.Item = (function() {
function Item(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
Item.prototype._read = function() {
this.subKeyListOffset = this._io.readU4le();
}
return Item;
})();
return SubKeyListRi;
})();
var SubKeyListSk = HiveBinCell.SubKeyListSk = (function() {
function SubKeyListSk(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
SubKeyListSk.prototype._read = function() {
this.unknown1 = this._io.readU2le();
this.previousSecurityKeyOffset = this._io.readU4le();
this.nextSecurityKeyOffset = this._io.readU4le();
this.referenceCount = this._io.readU4le();
}
return SubKeyListSk;
})();
var SubKeyListVk = HiveBinCell.SubKeyListVk = (function() {
SubKeyListVk.DataTypeEnum = Object.freeze({
REG_NONE: 0,
REG_SZ: 1,
REG_EXPAND_SZ: 2,
REG_BINARY: 3,
REG_DWORD: 4,
REG_DWORD_BIG_ENDIAN: 5,
REG_LINK: 6,
REG_MULTI_SZ: 7,
REG_RESOURCE_LIST: 8,
REG_FULL_RESOURCE_DESCRIPTOR: 9,
REG_RESOURCE_REQUIREMENTS_LIST: 10,
REG_QWORD: 11,
0: "REG_NONE",
1: "REG_SZ",
2: "REG_EXPAND_SZ",
3: "REG_BINARY",
4: "REG_DWORD",
5: "REG_DWORD_BIG_ENDIAN",
6: "REG_LINK",
7: "REG_MULTI_SZ",
8: "REG_RESOURCE_LIST",
9: "REG_FULL_RESOURCE_DESCRIPTOR",
10: "REG_RESOURCE_REQUIREMENTS_LIST",
11: "REG_QWORD",
});
SubKeyListVk.VkFlags = Object.freeze({
VALUE_COMP_NAME: 1,
1: "VALUE_COMP_NAME",
});
function SubKeyListVk(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
SubKeyListVk.prototype._read = function() {
this.valueNameSize = this._io.readU2le();
this.dataSize = this._io.readU4le();
this.dataOffset = this._io.readU4le();
this.dataType = this._io.readU4le();
this.flags = this._io.readU2le();
this.padding = this._io.readU2le();
if (this.flags == Regf.HiveBinCell.SubKeyListVk.VkFlags.VALUE_COMP_NAME) {
this.valueName = KaitaiStream.bytesToStr(this._io.readBytes(this.valueNameSize), "ASCII");
}
}
return SubKeyListVk;
})();
Object.defineProperty(HiveBinCell.prototype, 'cellSize', {
get: function() {
if (this._m_cellSize !== undefined)
return this._m_cellSize;
this._m_cellSize = (this.cellSizeRaw < 0 ? -1 : 1) * this.cellSizeRaw;
return this._m_cellSize;
}
});
Object.defineProperty(HiveBinCell.prototype, 'isAllocated', {
get: function() {
if (this._m_isAllocated !== undefined)
return this._m_isAllocated;
this._m_isAllocated = this.cellSizeRaw < 0;
return this._m_isAllocated;
}
});
return HiveBinCell;
})();
var HiveBinHeader = Regf.HiveBinHeader = (function() {
function HiveBinHeader(_io, _parent, _root) {
this._io = _io;
this._parent = _parent;
this._root = _root;
this._read();
}
HiveBinHeader.prototype._read = function() {
this.signature = this._io.readBytes(4);
if (!((KaitaiStream.byteArrayCompare(this.signature, new Uint8Array([104, 98, 105, 110])) == 0))) {
throw new KaitaiStream.ValidationNotEqualError(new Uint8Array([104, 98, 105, 110]), this.signature, this._io, "/types/hive_bin_header/seq/0");
}
this.offset = this._io.readU4le();
this.size = this._io.readU4le();
this.unknown1 = this._io.readU4le();
this.unknown2 = this._io.readU4le();
this.timestamp = new Filetime(this._io, this, this._root);
this.unknown4 = this._io.readU4le();
}
/**
* The offset of the hive bin, Value in bytes and relative from
* the start of the hive bin data
*/
/**
* Size of the hive bin
*/
/**
* 0 most of the time, can contain remnant data
*/
/**
* 0 most of the time, can contain remnant data
*/
/**
* Only the root (first) hive bin seems to contain a valid FILETIME
*/
/**
* Contains number of bytes
*/
return HiveBinHeader;
})();
return Regf;
})();
Regf_.Regf = Regf;
});