Files
Michael Zhmailo a655de2076 Initial Commit
2024-06-24 22:44:32 +05:00

154 lines
5.4 KiB
C#

//class from https://github.com/brandonprry/gray_hat_csharp_code/tree/master/ch14_reading_offline_hives
//author @BrandonPrry
using System;
using System.Collections.Generic;
using System.IO;
namespace RemoteKrbRelay.HiveParser
{
public class NodeKey
{
public NodeKey(BinaryReader hive)
{
ReadNodeStructure(hive);
ReadChildrenNodes(hive);
ReadChildValues(hive);
}
public List<NodeKey> ChildNodes { get; set; }
public List<ValueKey> ChildValues { get; set; }
public DateTime Timestamp { get; set; }
public int ParentOffset { get; set; }
public int SubkeysCount { get; set; }
public int LFRecordOffset { get; set; }
public int ClassnameOffset { get; set; }
public int SecurityKeyOffset { get; set; }
public int ValuesCount { get; set; }
public int ValueListOffset { get; set; }
public short NameLength { get; set; }
public bool IsRootKey { get; set; }
public short ClassnameLength { get; set; }
public string Name { get; set; }
public byte[] ClassnameData { get; set; }
public NodeKey ParentNodeKey { get; set; }
private void ReadNodeStructure(BinaryReader hive)
{
byte[] buf = hive.ReadBytes(4);
if (buf[0] != 0x6e || buf[1] != 0x6b)
throw new NotSupportedException("Bad nk header");
long startingOffset = hive.BaseStream.Position;
this.IsRootKey = (buf[2] == 0x2c) ? true : false;
this.Timestamp = DateTime.FromFileTime(hive.ReadInt64());
hive.BaseStream.Position += 4;
this.ParentOffset = hive.ReadInt32();
this.SubkeysCount = hive.ReadInt32();
hive.BaseStream.Position += 4;
this.LFRecordOffset = hive.ReadInt32();
hive.BaseStream.Position += 4;
this.ValuesCount = hive.ReadInt32();
this.ValueListOffset = hive.ReadInt32();
this.SecurityKeyOffset = hive.ReadInt32();
this.ClassnameOffset = hive.ReadInt32();
hive.BaseStream.Position += (startingOffset + 68) - hive.BaseStream.Position;
this.NameLength = hive.ReadInt16();
this.ClassnameLength = hive.ReadInt16();
buf = hive.ReadBytes(this.NameLength);
this.Name = System.Text.Encoding.UTF8.GetString(buf);
hive.BaseStream.Position = this.ClassnameOffset + 4 + 4096;
this.ClassnameData = hive.ReadBytes(this.ClassnameLength);
}
private void ReadChildrenNodes(BinaryReader hive)
{
this.ChildNodes = new List<NodeKey>();
if (this.LFRecordOffset != -1)
{
hive.BaseStream.Position = 4096 + this.LFRecordOffset + 4;
byte[] buf = hive.ReadBytes(2);
//ri
if (buf[0] == 0x72 && buf[1] == 0x69)
{
int count = hive.ReadInt16();
for (int i = 0; i < count; i++)
{
long pos = hive.BaseStream.Position;
int offset = hive.ReadInt32();
hive.BaseStream.Position = 4096 + offset + 4;
buf = hive.ReadBytes(2);
if (!(buf[0] == 0x6c && (buf[1] == 0x66 || buf[1] == 0x68)))
throw new Exception("Bad LF/LH record at: " + hive.BaseStream.Position);
ParseChildNodes(hive);
hive.BaseStream.Position = pos + 4; //go to next record list
}
}
//lf or lh
else if (buf[0] == 0x6c && (buf[1] == 0x66 || buf[1] == 0x68))
ParseChildNodes(hive);
else
throw new Exception("Bad LF/LH/RI Record at: " + hive.BaseStream.Position);
}
}
private void ParseChildNodes(BinaryReader hive)
{
int count = hive.ReadInt16();
long topOfList = hive.BaseStream.Position;
for (int i = 0; i < count; i++)
{
hive.BaseStream.Position = topOfList + (i * 8);
int newoffset = hive.ReadInt32();
hive.BaseStream.Position += 4;
//byte[] check = hive.ReadBytes(4);
hive.BaseStream.Position = 4096 + newoffset + 4;
NodeKey nk = new NodeKey(hive) { ParentNodeKey = this };
this.ChildNodes.Add(nk);
}
hive.BaseStream.Position = topOfList + (count * 8);
}
private void ReadChildValues(BinaryReader hive)
{
this.ChildValues = new List<ValueKey>();
if (this.ValueListOffset != -1)
{
hive.BaseStream.Position = 4096 + this.ValueListOffset + 4;
for (int i = 0; i < this.ValuesCount; i++)
{
hive.BaseStream.Position = 4096 + this.ValueListOffset + 4 + (i * 4);
int offset = hive.ReadInt32();
hive.BaseStream.Position = 4096 + offset + 4;
this.ChildValues.Add(new ValueKey(hive));
}
}
}
public byte[] getChildValues(string valueName)
{
ValueKey targetData = this.ChildValues.Find(x => x.Name.Contains(valueName));
return targetData.Data;
}
}
}