public RegistryKey GetKey(string keyPath)
        {
            var rawRoot = GetRawRecord(Header.RootCellOffset);

            var rootNk = new NkCellRecord(rawRoot.Length, Header.RootCellOffset, this);

            var newPath = keyPath.ToLowerInvariant();

            // when getting child keys, the name may start with the root key name. if so, strip it
            if (newPath.StartsWith(rootNk.Name, StringComparison.OrdinalIgnoreCase))
            {
                var segs = keyPath.Split('\\');
                newPath = string.Join("\\", segs.Skip(1));
            }

            var rootKey = new RegistryKey(rootNk, null);

            var keyNames = newPath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);

            rootKey.SubKeys.AddRange(GetSubkeys(rootKey.NkRecord.SubkeyListsStableCellIndex, rootKey));

            var finalKey = rootKey;

            for (var i = 0; i < keyNames.Length; i++)
            {
                finalKey =
                    finalKey.SubKeys.SingleOrDefault(
                        r => string.Equals(r.KeyName, keyNames[i], StringComparison.OrdinalIgnoreCase));

                if (finalKey == null)
                {
                    return(null);
                }

                if (finalKey.NkRecord.SubkeyListsStableCellIndex > 0)
                {
                    finalKey.SubKeys.AddRange(GetSubkeys(finalKey.NkRecord.SubkeyListsStableCellIndex, finalKey));
                }
            }

            finalKey.Values.AddRange(GetKeyValues(finalKey.NkRecord.ValueListCellIndex,
                                                  finalKey.NkRecord.ValueListCount));

            if (finalKey.NkRecord.ClassCellIndex > 0)
            {
                Logger.Trace("Getting Class cell information at relative offset 0x{0:X}",
                             finalKey.NkRecord.ClassCellIndex);
                var d = GetDataNodeFromOffset(finalKey.NkRecord.ClassCellIndex);
                d.IsReferenced = true;
                var clsName = Encoding.Unicode.GetString(d.Data, 0, finalKey.NkRecord.ClassLength);
                finalKey.ClassName = clsName;
                Logger.Debug("Class name found {0}", clsName);
            }

            return(finalKey);
        }
Example #2
0
        // public constructors...
        public RegistryKey(NkCellRecord nk, RegistryKey parent)
        {
            NkRecord = nk;

            Parent = parent;

            InternalGuid = Guid.NewGuid().ToString();

            SubKeys = new List <RegistryKey>();
            Values  = new List <KeyValue>();

            ClassName = string.Empty;
        }
Example #3
0
        private List <RegistryKey> GetSubkeys(uint subkeyListsStableCellIndex, RegistryKey parent)
        {
            var keys = new List <RegistryKey>();

            Logger.Trace("Looking for list record at relative offset 0x{0:X}", subkeyListsStableCellIndex);

            var rawList = GetRawRecord(subkeyListsStableCellIndex);

            var l = GetListFromRawBytes(rawList, subkeyListsStableCellIndex);

            var sig = BitConverter.ToInt16(l.RawBytes, 4);

            switch (sig)
            {
            case LfSignature:
            case LhSignature:
                var lxRecord = l as LxListRecord;
                foreach (var offset in lxRecord.Offsets)
                {
                    Logger.Trace("In lf or lh, looking for nk record at relative offset 0x{0:X}", offset);
                    var rawCell = GetRawRecord(offset.Key);
                    var nk      = new NkCellRecord(rawCell.Length, offset.Key, this);

                    Logger.Debug("In lf or lh, found nk record at relative offset 0x{0:X}. Name: {1}", offset, nk.Name);

                    var tempKey = new RegistryKey(nk, parent);

                    keys.Add(tempKey);
                }

                break;

            case RiSignature:
                var riRecord = l as RiListRecord;
                foreach (var offset in riRecord.Offsets)
                {
                    Logger.Trace("In ri, looking for list record at relative offset 0x{0:X}", offset);
                    rawList = GetRawRecord(offset);

                    var tempList = GetListFromRawBytes(rawList, offset);

                    //templist is now an li or lh list

                    if (tempList.Signature == "li")
                    {
                        var sk3 = tempList as LiListRecord;

                        foreach (var offset1 in sk3.Offsets)
                        {
                            Logger.Trace("In ri/li, looking for nk record at relative offset 0x{0:X}", offset1);
                            var rawCell = GetRawRecord(offset1);
                            var nk      = new NkCellRecord(rawCell.Length, offset1, this);

                            var tempKey = new RegistryKey(nk, parent);

                            keys.Add(tempKey);
                        }
                    }
                    else
                    {
                        var lxRecord1 = tempList as LxListRecord;

                        foreach (var offset3 in lxRecord1.Offsets)
                        {
                            Logger.Trace("In ri/li, looking for nk record at relative offset 0x{0:X}", offset3);
                            var rawCell = GetRawRecord(offset3.Key);
                            var nk      = new NkCellRecord(rawCell.Length, offset3.Key, this);

                            var tempKey = new RegistryKey(nk, parent);

                            keys.Add(tempKey);
                        }
                    }
                }

                break;

            //this is a safety net, but li's are typically only seen in RI lists. as such, don't use it in metrics

            case LiSignature:
                var liRecord = l as LiListRecord;
                foreach (var offset in liRecord.Offsets)
                {
                    Logger.Debug("In li, looking for nk record at relative offset 0x{0:X}", offset);
                    var rawCell = GetRawRecord(offset);
                    var nk      = new NkCellRecord(rawCell.Length, offset, this);

                    var tempKey = new RegistryKey(nk, parent);
                    keys.Add(tempKey);
                }

                break;

            default:
                throw new Exception($"Unknown subkey list type {l.Signature}!");
            }

            return(keys);
        }
Example #4
0
        private List <IRecordBase> ExtractRecordsFromSlack(byte[] remainingData, long relativeoffset)
        {
            var records = new List <IRecordBase>();

//            if (remainingData.Length == 4064 && _registryHive.HivePath.Contains("DeletedBags"))
//            {
//                Debug.WriteLine(1);
//            }

            var offsetList2 = new List <int>();

            byte[] raw = null;

            _registryHive.Logger.Trace("Looking for cell signatures at absolute offset 0x{0:X}",
                                       relativeoffset + 0x1000);

            for (var i = 0; i < remainingData.Length; i++)
            {
                if (remainingData[i] == 0x6b)                                         //6b == k
                {
                    if (remainingData[i - 1] == 0x6e || remainingData[i - 1] == 0x76) //6e = n, 76 = v
                    {
                        //if we are here we have a good signature, nk or vk
                        //check what is before that to see if its 0x00 or 0xFF
                        if (remainingData[i - 2] == 0x00 || remainingData[i - 2] == 0xFF)
                        {
                            //winner! since we initially hit on ZZ, subtract 5 to get to the beginning of the record, XX XX XX XX YY ZZ
                            offsetList2.Add(i - 5);
                        }
                    }
                }
            }

            //offsetList2 now has offset of every record signature we are interested in
            foreach (var i in offsetList2)
            {
                try
                {
                    var actualStart = i;

                    var size = BitConverter.ToInt32(remainingData, actualStart);

                    if (Math.Abs(size) <= 3 || remainingData.Length - actualStart < size)
                    {
                        //if its empty or the size is beyond the data that is left, move on
                        continue;
                    }

                    raw = new ArraySegment <byte>(remainingData, actualStart, Math.Abs(size)).ToArray();

                    if (raw.Length < 6)
                    {
                        continue;
                    }
                    // since we need 4 bytes for the size and 2 for sig, if its smaller than 6, go to next one

                    var sig2 = BitConverter.ToInt16(raw, 4);

                    switch (sig2)
                    {
                    case NkSignature:
                        if (raw.Length <= 0x30)
                        {
                            continue;
                        }

                        var nk = new NkCellRecord(raw.Length, relativeoffset + actualStart, _registryHive);
                        if (nk.LastWriteTimestamp.Year > 1900)
                        {
                            _registryHive.Logger.Trace("Found nk record in slack at absolute offset 0x{0:X}",
                                                       relativeoffset + actualStart + 0x1000);
                            records.Add(nk);
                        }

                        break;

                    case VkSignature:
                        if (raw.Length < 0x18)
                        {
                            //cant have a record shorter than this, even when no name is present
                            continue;
                        }

                        var vk = new VkCellRecord(raw.Length, relativeoffset + actualStart, _minorVersion,
                                                  _registryHive);
                        _registryHive.Logger.Trace("Found vk record in slack at absolute offset 0x{0:X}",
                                                   relativeoffset + actualStart + 0x1000);
                        records.Add(vk);
                        break;
                    }
                }
                catch (Exception ex) //ncrunch: no coverage
                {
                    //ncrunch: no coverage
                    // this is a corrupted/unusable record
                    _registryHive.Logger.Debug( //ncrunch: no coverage
                        ex,
                        $"When recovering from slack at absolute offset 0x{relativeoffset + i + 0x1000:X8}, an error happened! raw Length: 0x{raw?.Length:x}");

                    RegistryHive.SoftParsingErrorsInternal += 1; //ncrunch: no coverage
                } //ncrunch: no coverage
            }


            return(records);
        }
Example #5
0
        public List <IRecordBase> Process()
        {
            var records = new List <IRecordBase>();

            //additional cell data starts 32 bytes (0x20) in
            var offsetInHbin = 0x20;

            _registryHive.TotalBytesRead += 0x20;

            while (offsetInHbin < Size)
            {
                var recordSize = BitConverter.ToUInt32(_rawBytes, offsetInHbin);

                var readSize = (int)recordSize;

                if (!_recoverDeleted && readSize > 0)
                {
                    //since we do not want to get deleted stuff, if the cell size > 0, its free, so skip it
                    offsetInHbin += readSize;
                    continue;
                }

                // if we get a negative number here the record is allocated, but we cant read negative bytes, so get absolute value
                readSize = Math.Abs(readSize);

                _registryHive.Logger.Trace(
                    $"Getting rawRecord at hbin relative offset 0x{offsetInHbin:X} (Absolute offset: 0x{offsetInHbin + RelativeOffset + 0x1000:X}). readsize: {readSize}");

                var rawRecord = new ArraySegment <byte>(_rawBytes, offsetInHbin, readSize).ToArray();

                _registryHive.TotalBytesRead += readSize;

                var cellSignature  = Encoding.ASCII.GetString(rawRecord, 4, 2);
                var cellSignature2 = BitConverter.ToInt16(rawRecord, 4);

                //ncrunch: no coverage start
                if (_registryHive.Logger.IsDebugEnabled)
                {
                    var foundMatch = false;

                    foundMatch = Regex.IsMatch(cellSignature, @"\A[a-z]{2}\z");

                    //only process records with 2 letter signatures. this avoids crazy output for data cells
                    if (foundMatch)
                    {
                        _registryHive.Logger.Trace(
                            $"Processing {cellSignature} record at hbin relative offset 0x{offsetInHbin:X} (Absolute offset: 0x{offsetInHbin + RelativeOffset + 0x1000:X})");
                    }
                    else
                    {
                        _registryHive.Logger.Trace(
                            $"Processing data record at hbin relative offset 0x{offsetInHbin:X} (Absolute offset: 0x{offsetInHbin + RelativeOffset + 0x1000:X})");
                    }
                }
                //ncrunch: no coverage end

                ICellTemplate cellRecord = null;
                IListTemplate listRecord = null;
                DataNode      dataRecord = null;



                try
                {
                    switch (cellSignature2)
                    {
                    case LfSignature:
                    case LhSignature:
                        listRecord = new LxListRecord(rawRecord, offsetInHbin + RelativeOffset);
                        break;

                    case LiSignature:
                        listRecord = new LiListRecord(rawRecord, offsetInHbin + RelativeOffset);
                        break;

                    case RiSignature:
                        listRecord = new RiListRecord(rawRecord, offsetInHbin + RelativeOffset);
                        break;

                    case DbSignature:
                        listRecord = new DbListRecord(rawRecord, offsetInHbin + RelativeOffset);
                        break;

                    case LkSignature:
                        cellRecord = new LkCellRecord(rawRecord, offsetInHbin + RelativeOffset);
                        break;     //ncrunch: no coverage

                    case NkSignature:
                        if (rawRecord.Length >= 0x30)     // the minimum length for a recoverable record
                        {
                            cellRecord = new NkCellRecord(rawRecord.Length, offsetInHbin + RelativeOffset,
                                                          _registryHive);
                        }

                        break;

                    case SkSignature:
                        if (rawRecord.Length >= 0x14)     // the minimum length for a recoverable record
                        {
                            cellRecord = new SkCellRecord(rawRecord, offsetInHbin + RelativeOffset);
                        }

                        break;

                    case VkSignature:
                        if (rawRecord.Length >= 0x18)     // the minimum length for a recoverable record
                        {
                            cellRecord = new VkCellRecord(rawRecord.Length, offsetInHbin + RelativeOffset,
                                                          _minorVersion, _registryHive);
                        }

                        break;

                    default:
                        dataRecord = new DataNode(rawRecord, offsetInHbin + RelativeOffset);
                        break;
                    }
                }
                catch (Exception ex)
                {
                    //check size and see if its free. if so, dont worry about it. too small to be of value, but store it somewhere else?

                    var size = BitConverter.ToInt32(rawRecord, 0);

                    if (size < 0)
                    {
                        //ncrunch: no coverage
                        RegistryHive.HardParsingErrorsInternal += 1; //ncrunch: no coverage

                        _registryHive.Logger.Error(                  //ncrunch: no coverage
                            ex,
                            $"Hard error processing record with cell signature {cellSignature} at Absolute Offset: 0x{offsetInHbin + RelativeOffset + 4096:X} with raw data: {BitConverter.ToString(rawRecord)}");

                        //TODO store it somewhere else as a placeholder if its in use. include relative offset and other critical stuff
                    } //ncrunch: no coverage
                    else
                    {
                        _registryHive.Logger.Warn(
                            ex,
                            $"Soft error processing record with cell signature {cellSignature} at Absolute Offset: 0x{offsetInHbin + RelativeOffset + 4096:X} with raw data: {BitConverter.ToString(rawRecord)}");
                        //This record is marked 'Free' so its not as important of an error
                        RegistryHive.SoftParsingErrorsInternal += 1;
                    }
                }

                List <IRecordBase> carvedRecords = null;

                if (cellRecord != null)
                {
                    if (cellRecord.IsFree)
                    {
                        carvedRecords = ExtractRecordsFromSlack(cellRecord.RawBytes, cellRecord.RelativeOffset);
                    }
                    else
                    {
                        records.Add((IRecordBase)cellRecord);
                    }
                }

                if (listRecord != null)
                {
                    if (_recoverDeleted)
                    {
                        carvedRecords = ExtractRecordsFromSlack(listRecord.RawBytes, listRecord.RelativeOffset);
                    }

                    records.Add((IRecordBase)listRecord);
                }

                if (dataRecord != null && _recoverDeleted)
                {
                    carvedRecords = ExtractRecordsFromSlack(dataRecord.RawBytes, dataRecord.RelativeOffset);
                }

                if (carvedRecords != null)
                {
                    if (carvedRecords.Count > 0)
                    {
                        records.AddRange(carvedRecords);
                    }
                }

                offsetInHbin += readSize;
            }

            _rawBytes = null;
            return(records);
        }