/// <summary> /// Sends a Wake-on-LAN magic packet containing the specified <see cref="PhysicalAddress" /> to UDP broadcast on port 9 including a password. /// <para>Packet bytes: FF FF FF FF FF FF | 16 repetitions of <see cref="PhysicalAddress" /> | contents of <paramref name="password" /></para> /// <para>Total number of bytes: 102.</para> /// </summary> /// <param name="physicalAddress">The <see cref="PhysicalAddress" /> which is contained within the UDP broadcast packet.</param> /// <param name="password">The binary representation of the password. <paramref name="password" /> must either contain 4 or 6 bytes, or be <see langword="null" />.</param> public static void WakeOnLan(PhysicalAddress physicalAddress, byte[] password) { Check.ArgumentNull(physicalAddress, nameof(physicalAddress)); Check.Argument(password == null || CSharp.EqualsAny(password.Length, 4, 6), nameof(password), "The password must be either 4 or 6 bytes long or null."); byte[] packet = Enumerable.Repeat <byte>(0xff, 6) .Concat(Enumerable.Repeat(physicalAddress.GetAddressBytes(), 16).SelectMany(b => b)) .Concat(password ?? new byte[0]) .ToArray(); using UdpClient client = new UdpClient(); client.Connect(IPAddress.Broadcast, 9); client.Send(packet, packet.Length); }
/// <summary> /// Determines whether the specified set of <see cref="MessageBoxButtons" /> can raise the specified <see cref="MessageBoxEvent" />. /// </summary> /// <param name="buttons">A <see cref="MessageBoxButtons" /> value.</param> /// <param name="e">A <see cref="MessageBoxEvent" /> event.</param> /// <returns> /// <see langword="true" />, if the specified set of <see cref="MessageBoxButtons" /> can raise the specified <see cref="MessageBoxEvent" />; /// otherwise, <see langword="false" />. /// </returns> public static bool HasEvent(MessageBoxButtons buttons, MessageBoxEvent e) { switch (e) { case MessageBoxEvent.Ok: return(CSharp.EqualsAny(buttons, MessageBoxButtons.Ok, MessageBoxButtons.OkCancel)); case MessageBoxEvent.Cancel: return(CSharp.EqualsAny(buttons, MessageBoxButtons.OkCancel, MessageBoxButtons.YesNoCancel, MessageBoxButtons.RetryCancel)); case MessageBoxEvent.Yes: return(CSharp.EqualsAny(buttons, MessageBoxButtons.YesNo, MessageBoxButtons.YesNoCancel)); case MessageBoxEvent.No: return(CSharp.EqualsAny(buttons, MessageBoxButtons.YesNo, MessageBoxButtons.YesNoCancel)); case MessageBoxEvent.Abort: return(CSharp.EqualsAny(buttons, MessageBoxButtons.AbortRetryIgnore)); case MessageBoxEvent.Retry: return(CSharp.EqualsAny(buttons, MessageBoxButtons.AbortRetryIgnore, MessageBoxButtons.RetryCancel)); case MessageBoxEvent.Ignore: return(CSharp.EqualsAny(buttons, MessageBoxButtons.AbortRetryIgnore)); default: throw new InvalidEnumArgumentException(); } }
/// <summary> /// Validates the project file after it has been loaded from an INI file. /// </summary> public void ValidateProject() { // Validate stub ValidateStubIcon(); ValidateStubPadding(); ValidateManifest(); // Validate sources ValidateSources(); ValidateCompression(); ValidateEofData(); // Validate actions ValidateActions(); ValidateRunPE(); ValidateInvoke(); ValidateDrop(); ValidateMessageBox(); void ValidateStubIcon() { // Validate stub icon if (Project.Stub.IconPath != null) { // Validate that stub icon has .ico or .exe extension string extension = Path.GetExtension(Project.Stub.IconPath); if (extension.Equals(".ico", StringComparison.OrdinalIgnoreCase)) { // Validate that stub icon is a valid .ico file if (!IconExtractor.HasIcon(Project.Stub.IconPath)) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "File '" + Path.GetFileName(Project.Stub.IconPath) + "' is not a valid icon."); } } else if (extension.Equals(".exe", StringComparison.OrdinalIgnoreCase)) { // Validate that stub icon is an executable file with an icon if (!IconExtractor.HasIcon(Project.Stub.IconPath)) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "Could not extract icon from '" + Path.GetFileName(Project.Stub.IconPath) + "'."); } } else { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "Stub icon must have '.ico' or '.exe' extension."); } } } void ValidateStubPadding() { // Validate that stub has padding if (Project.Stub.Padding < 50) { Errors.Add(ErrorSource.Project, ErrorSeverity.Warning, "Padding is less than 50. The compiled binary will be of high-entropy and may be detected as a packer."); } } void ValidateManifest() { // Validate that manifest is not set to both template and cutom file if (Project.Manifest.Template != null && Project.Manifest.Path != null) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "Both manifest template and path specified. Please specify only one."); } } void ValidateSources() { // Validate duplicate source ID's for (int i = 0; i < Project.Sources.Count; i++) { if (Project.Sources.Skip(i + 1).Any(source => source.Id == Project.Sources[i].Id)) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "Duplicate source ID '" + Project.Sources[i].Id + "'."); } } // Exclude unused sources foreach (ProjectSource source in Project.Sources.ToArray()) { if (Project.Actions.None(action => action.Source == source)) { Project.RemoveSource(source); Errors.Add(ErrorSource.Project, ErrorSeverity.Warning, "Source '" + source.Id + "' was excluded, because it is not used."); } } } void ValidateCompression() { // Validate that compressed files are smaller than 100 MB foreach (EmbeddedSource source in Project.Sources.OfType <EmbeddedSource>()) { if (source.Compress && source.Path != null && new FileInfo(source.Path).Length > 1024 * 1024 * 100) { Errors.Add(ErrorSource.Project, ErrorSeverity.Warning, "File '" + Path.GetFileName(source.Path) + "' is bigger than 100 MB. It is recommended to disable compression."); } } } void ValidateEofData() { IEnumerable <EmbeddedSource> eofSources = Project.Sources.OfType <EmbeddedSource>().Where(source => source.EofData); // Validate that only PE files are used as EOF data sources foreach (EmbeddedSource source in eofSources) { if (new[] { ".exe", ".dll" }.None(extension => Path.GetExtension(source.Path).Equals(extension, StringComparison.OrdinalIgnoreCase))) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "Cannot write EOF data of file '" + Path.GetFileName(source.Path) + "'. Only executable files contain EOF data."); } } // Validate that only one file's EOF data is written foreach (EmbeddedSource source in eofSources.Skip(1)) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "Cannot write EOF data of file '" + Path.GetFileName(source.Path) + "'. Only one file's EOF data can be written."); } } void ValidateActions() { // Validate that at least one action exists if (Project.Actions.None()) { Errors.Add(ErrorSource.Project, ErrorSeverity.Warning, "The project is empty."); } } void ValidateRunPE() { // Validate that RunPE files have an .exe extension foreach (RunPEAction action in Project.Actions.OfType <RunPEAction>()) { if (action.Source is EmbeddedSource embeddedSource && embeddedSource.Path != null && !Path.GetExtension(embeddedSource.Path).Equals(".exe", StringComparison.OrdinalIgnoreCase)) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "RunPE file must have '.exe' extension."); } } } void ValidateInvoke() { // Validate that invoke files have an .exe extension foreach (InvokeAction action in Project.Actions.OfType <InvokeAction>()) { if (action.Source is EmbeddedSource embeddedSource && embeddedSource.Path != null && !Path.GetExtension(embeddedSource.Path).Equals(".exe", StringComparison.OrdinalIgnoreCase)) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, "Invoked file must have '.exe' extension."); } } // Validate that invoke actions are only used in a .NET stub if (CSharp.EqualsNone(Project.Stub.Type, StubType.DotNet32, StubType.DotNet64) && Project.Actions.OfType <InvokeAction>().Any()) { Errors.Add(ErrorSource.Project, ErrorSeverity.Error, ".NET invocation is only supported in a .NET stub."); } } void ValidateDrop() { // Validate that a UAC manifest is included, if files are dropped in privileged directories IEnumerable <string> privilegedDropFileNames = Project.Actions .OfType <DropAction>() .Where(action => CSharp.EqualsAny(action.Location, DropLocation.WindowsDirectory, DropLocation.SystemDirectory, DropLocation.ProgramFiles, DropLocation.CDrive)) .Select(action => { if (action.FileName != null) { return(action.FileName); } else if (action.Source is EmbeddedSource embeddedSource && embeddedSource.Path != null) { return(Path.GetFileName(embeddedSource.Path)); }
/// <summary> /// Gets a specified portion of the table of <see cref="TcpViewEntry" /> objects that represent a snapshot of the current TCP and/or UDP connections in either IPv4, IPv6 or both. If <paramref name="resolveProtocolNames" /> is set to <see langword="true" />, Protocol names are resolved according to the services file in %systemroot%\drivers\etc\services. /// </summary> /// <param name="tcp4"><see langword="true" /> to include TCPv4 entries.</param> /// <param name="tcp6"><see langword="true" /> to include TCPv6 entries.</param> /// <param name="udp4"><see langword="true" /> to include UDPv4 entries.</param> /// <param name="udp6"><see langword="true" /> to include UDPv6 entries.</param> /// <param name="resolveProtocolNames"><see langword="true" /> to resolve Protocol names according to the services file in %systemroot%\drivers\etc\services.</param> /// <returns> /// A new <see cref="TcpViewEntry" />[] object with the TCP and/or UDP table in either IPv4, IPv6 or both. If <paramref name="resolveProtocolNames" /> is set to <see langword="true" />, Protocol names are resolved according to the services file in %systemroot%\drivers\etc\services. /// </returns> public static TcpViewEntry[] GetEntries(bool tcp4, bool tcp6, bool udp4, bool udp6, bool resolveProtocolNames) { List <TcpViewEntry> entries = new List <TcpViewEntry>(); if (tcp4) { entries.AddRange ( GetConnections <Native.TcpTable, Native.TcpRow>(false, 2) .Select(row => new TcpViewEntry { Protocol = TcpViewEntryProtocol.Tcp4, LocalAddress = new IPAddress(BitConverter.GetBytes(row.LocalAddress)), LocalPort = BitConverter.ToUInt16(new[] { row.LocalPort[1], row.LocalPort[0] }, 0), RemoteAddress = new IPAddress(BitConverter.GetBytes(row.RemoteAddress)), RemotePort = BitConverter.ToUInt16(new[] { row.RemotePort[1], row.RemotePort[0] }, 0), TcpState = (TcpState)row.State, ProcessId = (int)row.OwningProcessId }) ); } if (tcp6) { entries.AddRange ( GetConnections <Native.Tcp6Table, Native.Tcp6Row>(false, 23) .Select(row => new TcpViewEntry { Protocol = TcpViewEntryProtocol.Tcp6, LocalAddress = new IPAddress(row.LocalAddress), LocalPort = BitConverter.ToUInt16(new[] { row.LocalPort[1], row.LocalPort[0] }, 0), RemoteAddress = new IPAddress(row.RemoteAddress), RemotePort = BitConverter.ToUInt16(new[] { row.RemotePort[1], row.RemotePort[0] }, 0), TcpState = (TcpState)row.State, ProcessId = (int)row.OwningProcessId }) ); } if (udp4) { entries.AddRange ( GetConnections <Native.UdpTable, Native.UdpRow>(true, 2) .Select(row => new TcpViewEntry { Protocol = TcpViewEntryProtocol.Udp4, LocalAddress = new IPAddress(row.LocalAddress), LocalPort = BitConverter.ToUInt16(new[] { row.LocalPort[1], row.LocalPort[0] }, 0), ProcessId = (int)row.OwningProcessId }) ); } if (udp6) { entries.AddRange ( GetConnections <Native.Udp6Table, Native.Udp6Row>(true, 23) .Select(row => new TcpViewEntry { Protocol = TcpViewEntryProtocol.Udp6, LocalAddress = new IPAddress(row.LocalAddress), LocalPort = (int)row.LocalPort, ProcessId = (int)row.OwningProcessId }) ); } return(entries .Select(entry => { entry.LocalProtocolName = ResolvePort(entry.LocalPort, CSharp.EqualsAny(entry.Protocol, TcpViewEntryProtocol.Udp4, TcpViewEntryProtocol.Udp6)); entry.RemoteProtocolName = entry.RemotePort == null ? null : ResolvePort(entry.RemotePort.Value, CSharp.EqualsAny(entry.Protocol, TcpViewEntryProtocol.Udp4, TcpViewEntryProtocol.Udp6)); return entry; }) .ToArray()); TRow[] GetConnections <TTable, TRow>(bool udp, int version) { int bufferSize = 0; FieldInfo numEntriesField = typeof(TTable).GetField("EntryCount"); GetTable(IntPtr.Zero); IntPtr tcpTable = Marshal.AllocHGlobal(bufferSize); try { if (GetTable(tcpTable) == 0) { TTable table = Marshal.PtrToStructure <TTable>(tcpTable); int rowSize = Marshal.SizeOf <TRow>(); uint entryCount = numEntriesField.GetValue <uint>(table); TRow[] tableRows = new TRow[entryCount]; IntPtr ptr = tcpTable + 4; for (int i = 0; i < entryCount; i++, ptr += rowSize) { tableRows[i] = Marshal.PtrToStructure <TRow>(ptr); } return(tableRows); } else { return(new TRow[0]); } } finally { Marshal.FreeHGlobal(tcpTable); } uint GetTable(IntPtr table) => udp?Native.GetExtendedUdpTable(table, ref bufferSize, true, version, 1) : Native.GetExtendedTcpTable(table, ref bufferSize, true, version, 5); } string ResolvePort(int port, bool udp) { if (resolveProtocolNames) { if (ProtocolMap == null) { ProtocolMap = ProtocolMappingEntry.GetProtocolMappingEntries(); } return(ProtocolMap.FirstOrDefault(entry => entry.Protocol == (udp ? ProtocolMappingProtocol.Udp : ProtocolMappingProtocol.Tcp) && entry.Port == port)?.Name); } else { return(null); } } }
/// <summary> /// Escapes a SendKeys sequence. The characters +^%~(){}[] are encapsulated by braces. The returned <see cref="string" /> can be then passed to SendKeys. /// </summary> /// <param name="str">The <see cref="string" /> value to be escaped.</param> /// <returns> /// A <see cref="string" /> with the escaped representation of <paramref name="str" />. /// </returns> public static string EscapeSendKeys(string str) { Check.ArgumentNull(str, nameof(str)); return(str.Select(key => CSharp.EqualsAny(key, "+^%~(){}[]") ? "{" + key + "}" : key.ToString()).AsString()); }