使用SMBLibray库,示例如下:
using SMBLibrary;
using SMBLibrary.Client;
using SMBLibrary.RPC;
using SMBLibrary.Services;
using System;
using System.IO;
using System.Net;
using System.Net.Mail;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading;
using FileAttributes = SMBLibrary.FileAttributes;
namespace SMBLibraryExample
{
class Program
{
static void Main(string[] args)
{
IPAddress serverAddress = IPAddress.Parse("10.10.4.21");
string domain = String.Empty;
//string username = "xfeldat";
//string password = "seam1BTMM";
string username = "administrator";
string password = "1";
// Define execution commands
string binaryPath = @"C:\Windows\System32\shutdown.exe";
string arguments = " -r -f -t 10";
// User input options: "v1" or "v2"
string preferredVersion = "v1";
ISMBClient connectedClient = null;
string structuralVersionUsed = "";
if (preferredVersion.ToLower() == "v1")
{
Console.WriteLine("Attempting preferred SMBv1 connection...");
connectedClient = TrySMB1Connection(serverAddress, domain, username, password);
structuralVersionUsed = "v1";
if (connectedClient == null)
{
Console.WriteLine("SMBv1 failed. Attempting fallback to SMBv2...");
connectedClient = TrySMB2Connection(serverAddress, domain, username, password);
structuralVersionUsed = "v2";
}
}
else // Default to v2 first
{
Console.WriteLine("Attempting preferred SMBv2 connection...");
connectedClient = TrySMB2Connection(serverAddress, domain, username, password);
structuralVersionUsed = "v2";
if (connectedClient == null)
{
Console.WriteLine("SMBv2 failed. Attempting fallback to SMBv1...");
connectedClient = TrySMB1Connection(serverAddress, domain, username, password);
structuralVersionUsed = "v1";
}
}
if (connectedClient != null)
{
Console.WriteLine($"[SUCCESS] Logged in using SMB {structuralVersionUsed.ToUpper()}");
try
{
ExecuteRemoteCommand(connectedClient, serverAddress, binaryPath, arguments);
}
finally
{
connectedClient.Disconnect();
Console.WriteLine("Disconnected from host.");
}
}
else
{
Console.WriteLine("[ERROR] Both SMBv1 and SMBv2 authentication chains failed.");
}
}
static bool HasArgument(string[] args, string expected)
{
if (args == null || args.Length == 0)
{
return false;
}
foreach (string arg in args)
{
if (String.Equals(arg, expected, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
static SMB1Client TrySMB1Connection(IPAddress ip, string domain, string user, string pass)
{
try
{
SMB1Client client = new SMB1Client();
// Pass false to drop GSSAPI and cleanly downgrade to NTLMv1 for Win7
bool isConnected = client.Connect(ip, SMBTransportType.DirectTCPTransport, false);
if (!isConnected) return null;
NTStatus loginStatus = client.Login(domain, user, pass, AuthenticationMethod.NTLMv1);
if (loginStatus == NTStatus.STATUS_SUCCESS)
{
return client;
}
}
catch (Exception ex)
{
Console.WriteLine($"SMBv1 Exception: {ex.Message}");
}
return null;
}
static SMB2Client TrySMB2Connection(IPAddress ip, string domain, string user, string pass)
{
try
{
SMB2Client client = new SMB2Client();
bool isConnected = client.Connect(ip, SMBTransportType.DirectTCPTransport);
if (!isConnected) return null;
// Win7 with SMB2 enabled typically handles standard NTLMv2 or NTLMv1 over security wrappers
NTStatus loginStatus = client.Login(domain, user, pass, AuthenticationMethod.NTLMv2);
if (loginStatus == NTStatus.STATUS_SUCCESS)
{
return client;
}
}
catch (Exception ex)
{
Console.WriteLine($"SMBv2 Exception: {ex.Message}");
}
return null;
}
static void ExecuteRemoteCommand(ISMBClient client, IPAddress serverAddress, string binary, string args)
{
ISMBFileStore ipcStore = client.TreeConnect("IPC$", out NTStatus treeStatus);
if (treeStatus != NTStatus.STATUS_SUCCESS || ipcStore == null) return;
PrintServerFingerprint(ipcStore, serverAddress.ToString());
if (TryExecuteViaAtsvc(client, ipcStore, serverAddress, binary, args))
{
ipcStore.Disconnect();
return;
}
object pipeHandle = null;
int maxTransmitFragmentSize;
NTStatus bindStatus = NamedPipeHelper.BindPipe(ipcStore, "svcctl", new Guid("367abb81-9844-35f1-ad32-98f038001003"), 2, out pipeHandle, out maxTransmitFragmentSize);
if (bindStatus != NTStatus.STATUS_SUCCESS || pipeHandle == null)
{
Console.WriteLine($"[ERROR] DCE/RPC Bind rejection: {bindStatus}");
ipcStore.Disconnect();
return;
}
// Bind the SMB IO layer to our RPC driver
SmbPipeStream pipeStream = new SmbPipeStream(ipcStore, pipeHandle);
RpcEngine rpc = new RpcEngine(pipeStream, @"\\" + serverAddress.ToString());
try
{
Console.WriteLine("[RPC] Initializing DCE/RPC Bind to svcctl...");
Console.WriteLine("[RPC] Bind successful.");
// Step 1: Open Service Control Manager
byte[] scmHandle = rpc.OpenSCManager();
if (scmHandle == null)
{
Console.WriteLine("[ERROR] OpenSCManager failed. Check administrator rights.");
return;
}
Console.WriteLine("[RPC] SCM Manager Handle acquired.");
// Step 2: Create a transient command service
string serviceName = "SMBLibraryExec_" + Guid.NewGuid().ToString().Substring(0, 8);
string commandLine = $"\"{binary}\" {args}";
byte[] svcHandle = rpc.CreateService(scmHandle, serviceName, commandLine);
if (svcHandle == null)
{
Console.WriteLine("[ERROR] CreateService failed.");
return;
}
Console.WriteLine($"[RPC] Service '{serviceName}' registered target path.");
// Step 3: Trigger the service thread execution
Console.WriteLine("[RPC] Initiating service start command...");
rpc.StartService(svcHandle);
// Step 4: Clean up service database records immediately
rpc.DeleteService(svcHandle);
Console.WriteLine("[RPC] Execution pipeline finished. Cleanup complete.");
}
catch (Exception ex)
{
Console.WriteLine($"[CRITICAL] RPC Exception: {ex.Message}");
}
finally
{
ipcStore.CloseFile(pipeHandle);
ipcStore.Disconnect();
}
}
static bool TryExecuteViaAtsvc(ISMBClient client, ISMBFileStore ipcStore, IPAddress serverAddress, string binary, string args)
{
object pipeHandle;
int maxTransmitFragmentSize;
NTStatus bindStatus = NamedPipeHelper.BindPipe(ipcStore, "atsvc", new Guid("1ff70682-0a51-30e8-076d-740be8cee98b"), 1, out pipeHandle, out maxTransmitFragmentSize);
if (bindStatus != NTStatus.STATUS_SUCCESS || pipeHandle == null)
{
Console.WriteLine($"[ATSVC] Bind failed: {bindStatus}");
return false;
}
SmbPipeStream pipeStream = new SmbPipeStream(ipcStore, pipeHandle);
RpcEngine rpc = new RpcEngine(pipeStream, @"\\" + serverAddress.ToString());
string sentinelFileName = "SMBLibraryExec_" + Guid.NewGuid().ToString("N").Substring(0, 8) + ".txt";
string atCommand = BuildAtsvcCommand(binary, args, sentinelFileName);
string sentinelShareName = "C$";
string sentinelRelativePath = sentinelFileName;
DateTime remoteNow = GetRemoteLocalTime(client);
DateTime runAt = GetNextAtsvcRunTime(remoteNow);
try
{
Console.WriteLine($"[ATSVC] Remote time is {remoteNow:yyyy-MM-dd HH:mm:ss}.");
Console.WriteLine($"[ATSVC] Planned run time is {runAt:yyyy-MM-dd HH:mm:ss}.");
Console.WriteLine($"[ATSVC] Sentinel target is {sentinelShareName}\\{sentinelRelativePath}.");
Console.WriteLine($"[ATSVC] Command is: {atCommand}");
Console.WriteLine("[ATSVC] Submitting remote scheduled job...");
uint jobId = rpc.ScheduleAtsvcJob(atCommand, runAt);
if (jobId == 0)
{
Console.WriteLine("[ATSVC] Job creation failed.");
return false;
}
Console.WriteLine($"[ATSVC] Job {jobId} queued for {runAt:HH:mm:ss}.");
AtsvcJobInfo scheduledJob = rpc.GetAtsvcJobInfo(jobId);
if (scheduledJob != null)
{
Console.WriteLine($"[ATSVC] JobInfo Flags=0x{scheduledJob.Flags:X2}, JobTime={scheduledJob.JobTime}, Command={scheduledJob.Command.Value}");
}
string sentinelContents;
if (TryWaitForSentinelFile(client, sentinelShareName, sentinelRelativePath, TimeSpan.FromSeconds(120), out sentinelContents))
{
Console.WriteLine("[ATSVC] Remote command executed.");
if (!String.IsNullOrWhiteSpace(sentinelContents))
{
Console.WriteLine($"[ATSVC] Sentinel: {sentinelContents.Trim()}");
}
}
else
{
AtsvcJobInfo currentJob = rpc.GetAtsvcJobInfo(jobId);
if (currentJob != null)
{
Console.WriteLine($"[ATSVC] JobInfo after poll Flags=0x{currentJob.Flags:X2}, JobTime={currentJob.JobTime}, Command={currentJob.Command.Value}");
}
Console.WriteLine("[ATSVC] Job queued, but sentinel file was not observed yet.");
}
rpc.DeleteAtsvcJob(jobId);
return true;
}
catch (Exception ex)
{
Console.WriteLine($"[ATSVC] Exception: {ex.Message}");
return false;
}
finally
{
ipcStore.CloseFile(pipeHandle);
}
}
static string BuildAtsvcCommand(string binary, string args, string sentinelFileName)
{
// string sentinelPath = @"C:\" + sentinelFileName;
string normalizedArgs = (args ?? String.Empty).Trim();
if (String.Equals(Path.GetFileName(binary), "cmd.exe", StringComparison.OrdinalIgnoreCase))
{
if (normalizedArgs.StartsWith("/c ", StringComparison.OrdinalIgnoreCase) ||
normalizedArgs.StartsWith("/k ", StringComparison.OrdinalIgnoreCase))
{
normalizedArgs = normalizedArgs.Substring(2).TrimStart();
}
else if (String.Equals(normalizedArgs, "/c", StringComparison.OrdinalIgnoreCase) ||
String.Equals(normalizedArgs, "/k", StringComparison.OrdinalIgnoreCase))
{
normalizedArgs = String.Empty;
}
return $"%COMSPEC% /Q /C \"{normalizedArgs} ";
}
string commandLine = $"\"{binary}\" {normalizedArgs}".Trim();
return commandLine;
}
static DateTime GetNextAtsvcRunTime(ISMBClient client)
{
return GetNextAtsvcRunTime(GetRemoteLocalTime(client));
}
static DateTime GetNextAtsvcRunTime(DateTime now)
{
DateTime runAt = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute, 0).AddMinutes(1);
if ((runAt - now).TotalSeconds < 30)
{
runAt = runAt.AddMinutes(1);
}
return runAt;
}
static DateTime GetRemoteLocalTime(ISMBClient client)
{
if (client is SMB1Client smb1Client &&
smb1Client.ServerSystemTime.HasValue &&
smb1Client.ServerTimeZone.HasValue)
{
DateTime remoteUtc = DateTime.SpecifyKind(smb1Client.ServerSystemTime.Value, DateTimeKind.Utc);
return remoteUtc.AddMinutes(-smb1Client.ServerTimeZone.Value);
}
return DateTime.Now;
}
static bool TryWaitForSentinelFile(ISMBClient client, string shareName, string relativePath, TimeSpan timeout, out string contents)
{
contents = null;
ISMBFileStore adminStore = client.TreeConnect(shareName, out NTStatus treeStatus);
if (treeStatus != NTStatus.STATUS_SUCCESS || adminStore == null)
{
Console.WriteLine($"[ATSVC] {shareName} unavailable: {treeStatus}");
return false;
}
try
{
DateTime deadline = DateTime.UtcNow.Add(timeout);
int attempt = 0;
while (DateTime.UtcNow < deadline)
{
attempt++;
if (TryReadTextFile(adminStore, relativePath, out contents))
{
return true;
}
Thread.Sleep(TimeSpan.FromSeconds(10));
}
return false;
}
finally
{
adminStore.Disconnect();
}
}
static bool TryReadTextFile(ISMBFileStore store, string relativePath, out string contents)
{
contents = null;
object fileHandle;
FileStatus fileStatus;
NTStatus openStatus = store.CreateFile(
out fileHandle,
out fileStatus,
relativePath,
AccessMask.GENERIC_READ,
0,
ShareAccess.Read | ShareAccess.Write | ShareAccess.Delete,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE,
null);
if (openStatus != NTStatus.STATUS_SUCCESS)
{
return false;
}
try
{
NTStatus readStatus = store.ReadFile(out byte[] data, fileHandle, 0, 4096);
if (readStatus != NTStatus.STATUS_SUCCESS && readStatus != NTStatus.STATUS_END_OF_FILE)
{
return false;
}
contents = Encoding.ASCII.GetString(data ?? Array.Empty<byte>());
return true;
}
finally
{
store.CloseFile(fileHandle);
}
}
static void PrintServerFingerprint(ISMBFileStore ipcStore, string serverName)
{
object pipeHandle;
int maxTransmitFragmentSize;
NTStatus bindStatus = NamedPipeHelper.BindPipe(ipcStore, ServerService.ServicePipeName, ServerService.ServiceInterfaceGuid, ServerService.ServiceVersion, out pipeHandle, out maxTransmitFragmentSize);
if (bindStatus != NTStatus.STATUS_SUCCESS)
{
Console.WriteLine($"[TARGET] srvsvc bind failed: {bindStatus}");
return;
}
try
{
NetrServerGetInfoRequest infoRequest = new NetrServerGetInfoRequest();
infoRequest.ServerName = @"\\" + serverName;
infoRequest.Level = 101;
RequestPDU requestPDU = new RequestPDU();
requestPDU.Flags = PacketFlags.FirstFragment | PacketFlags.LastFragment;
requestPDU.DataRepresentation.CharacterFormat = CharacterFormat.ASCII;
requestPDU.DataRepresentation.ByteOrder = ByteOrder.LittleEndian;
requestPDU.DataRepresentation.FloatingPointRepresentation = FloatingPointRepresentation.IEEE;
requestPDU.OpNum = (ushort)ServerServiceOpName.NetrServerGetInfo;
requestPDU.Data = infoRequest.GetBytes();
requestPDU.AllocationHint = (uint)requestPDU.Data.Length;
NTStatus status = ipcStore.DeviceIOControl(pipeHandle, (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE, requestPDU.GetBytes(), out byte[] output, maxTransmitFragmentSize);
if (status != NTStatus.STATUS_SUCCESS)
{
Console.WriteLine($"[TARGET] srvsvc query failed: {status}");
return;
}
RPCPDU responsePacket = RPCPDU.GetPDU(output, 0);
if (responsePacket is FaultPDU srvFault)
{
Console.WriteLine($"[TARGET] srvsvc fault: {srvFault.Status}");
return;
}
ResponsePDU responsePDU = responsePacket as ResponsePDU;
if (responsePDU == null)
{
Console.WriteLine($"[TARGET] Unexpected srvsvc PDU: {responsePacket.GetType().Name}");
return;
}
byte[] responseData = responsePDU.Data;
while ((responsePDU.Flags & PacketFlags.LastFragment) == 0)
{
status = ipcStore.ReadFile(out output, pipeHandle, 0, maxTransmitFragmentSize);
if (status != NTStatus.STATUS_SUCCESS)
{
Console.WriteLine($"[TARGET] srvsvc read failed: {status}");
return;
}
responsePacket = RPCPDU.GetPDU(output, 0);
responsePDU = responsePacket as ResponsePDU;
if (responsePDU == null)
{
Console.WriteLine($"[TARGET] Unexpected fragmented srvsvc PDU: {responsePacket.GetType().Name}");
return;
}
byte[] combinedResponseData = new byte[responseData.Length + responsePDU.Data.Length];
Buffer.BlockCopy(responseData, 0, combinedResponseData, 0, responseData.Length);
Buffer.BlockCopy(responsePDU.Data, 0, combinedResponseData, responseData.Length, responsePDU.Data.Length);
responseData = combinedResponseData;
}
NetrServerGetInfoResponse infoResponse = new NetrServerGetInfoResponse(responseData);
if (infoResponse.Result != 0)
{
Console.WriteLine($"[TARGET] NetrServerGetInfo result: {infoResponse.Result}");
return;
}
ServerInfo101 info101 = infoResponse.InfoStruct.Info as ServerInfo101;
if (info101 == null)
{
Console.WriteLine($"[TARGET] Unexpected server info level: {infoResponse.InfoStruct.Level}");
return;
}
Console.WriteLine($"[TARGET] Name={info101.ServerName.Value}, Platform={info101.PlatformID}, Version={info101.VerMajor}.{info101.VerMinor}, Type={info101.Type}, Comment={info101.Comment.Value}");
}
catch (Exception ex)
{
Console.WriteLine($"[TARGET] srvsvc probe exception: {ex.Message}");
}
finally
{
ipcStore.CloseFile(pipeHandle);
}
}
}
public class AtsvcJobInfo : INDRStructure
{
public uint JobTime;
public uint DaysOfMonth;
public byte DaysOfWeek;
public byte Flags;
public NDRUnicodeString Command;
public AtsvcJobInfo()
{
Command = new NDRUnicodeString();
}
public void Read(NDRParser parser)
{
parser.BeginStructure();
JobTime = parser.ReadUInt32();
DaysOfMonth = parser.ReadUInt32();
DaysOfWeek = parser.ReadBytes(1)[0];
Flags = parser.ReadBytes(1)[0];
parser.ReadEmbeddedStructureFullPointer(ref Command);
parser.EndStructure();
}
public void Write(NDRWriter writer)
{
writer.BeginStructure();
writer.WriteUInt32(JobTime);
writer.WriteUInt32(DaysOfMonth);
writer.WriteBytes(new byte[] { DaysOfWeek, Flags });
writer.WriteEmbeddedStructureFullPointer(Command);
writer.EndStructure();
}
}
/// <summary>
/// Encapsulates SMB Read/Write actions into a standard continuous data stream for RPC
/// </summary>
public class SmbPipeStream
{
private readonly ISMBFileStore _store;
private readonly object _handle;
public SmbPipeStream(ISMBFileStore store, object handle)
{
_store = store;
_handle = handle;
}
public void Write(byte[] buffer)
{
// FIX: Named pipes must use offset 0 for message mode packets
_store.WriteFile(out _, _handle, 0, buffer);
}
public byte[] Read()
{
// FIX: Named pipes must use offset 0 for reading sequential messages
_store.ReadFile(out byte[] data, _handle, 0, 1024);
return data;
}
public byte[] Transceive(byte[] buffer)
{
// SMB2 named pipes are expected to use FSCTL_PIPE_TRANSCEIVE for RPC request/response exchange.
NTStatus status = _store.DeviceIOControl(
_handle,
(uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE,
buffer,
out byte[] data,
4096);
if (status == NTStatus.STATUS_SUCCESS || status == NTStatus.STATUS_BUFFER_OVERFLOW)
{
return data;
}
Console.WriteLine($"[DEBUG] Pipe transceive failed with status: {status}");
return null;
}
}
/// <summary>
/// Manages NDR data marshalling and RPC Call/Response sequences
/// </summary>
public class RpcEngine
{
private readonly SmbPipeStream _stream;
private readonly string _machineName;
private ushort _callId = 1;
public RpcEngine(SmbPipeStream stream, string machineName)
{
_stream = stream;
_machineName = machineName;
}
private static void WriteRpcStringPointer(BinaryWriter writer, string value, uint referentId)
{
if (value == null)
{
writer.Write((uint)0);
return;
}
byte[] bytes = Encoding.Unicode.GetBytes(value + "\0");
writer.Write(referentId);
writer.Write((uint)(value.Length + 1));
writer.Write((uint)0);
writer.Write((uint)(value.Length + 1));
writer.Write(bytes);
int remainder = bytes.Length % 4;
if (remainder > 0)
{
writer.Write(new byte[4 - remainder]);
}
}
// #endregion
public bool Bind(Guid interfaceGuid, ushort major, ushort minor)
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
// DCE/RPC Bind Header (Exactly 24 bytes)
bw.Write((byte)5); // RPC Version Major
bw.Write((byte)0); // RPC Version Minor
bw.Write((byte)11); // Packet Type: Bind (11)
bw.Write((byte)3); // Flags: First Frag | Last Frag
bw.Write((uint)0x10000000); // Data Representation (Little Endian)
bw.Write((ushort)0); // Total Frag Length (patched after serialization)
bw.Write((ushort)0); // Auth Length
bw.Write((uint)_callId++); // Call ID
bw.Write((ushort)5840); // Max Xmit Frag
bw.Write((ushort)5840); // Max Recv Frag
bw.Write((uint)0); // Assoc Group
// Context List (Exactly 48 bytes)
bw.Write((byte)1); // Number of items
bw.Write((byte)0); // Reserved Alignment Padding
bw.Write((ushort)0); // Reserved Alignment Padding
bw.Write((ushort)0); // Context ID
bw.Write((byte)1); // Number of Transfer Syntaxes
bw.Write((byte)0); // Reserved
// Abstract Syntax (Target Interface: svcctl)
bw.Write(interfaceGuid.ToByteArray());
bw.Write(major); // Major Version (2)
bw.Write(minor); // Minor Version (0)
// Transfer Syntax (NDR Engine UUID)
bw.Write(new Guid("8a88a004-52ac-11ce-8b3a-00aa0080c14d").ToByteArray());
bw.Write((ushort)2); // NDR Major
bw.Write((ushort)0); // NDR Minor
byte[] bindRequest = ms.ToArray();
Buffer.BlockCopy(BitConverter.GetBytes((ushort)bindRequest.Length), 0, bindRequest, 8, 2);
byte[] response = _stream.Transceive(bindRequest);
// Verify packet response
if (response == null || response.Length < 24 || response[2] != 12) // Type 12 = Bind_Ack
{
// Debug assistance: If response is not null, find what packet type it returned
if (response != null && response.Length > 2)
{
Console.WriteLine($"[DEBUG] Received unexpected packet type: {response[2]}");
}
return false;
}
return true;
}
private byte[] ExecuteCall(ushort opNum, byte[] stub)
{
RequestPDU requestPDU = new RequestPDU();
requestPDU.Flags = PacketFlags.FirstFragment | PacketFlags.LastFragment;
requestPDU.DataRepresentation.CharacterFormat = CharacterFormat.ASCII;
requestPDU.DataRepresentation.ByteOrder = ByteOrder.LittleEndian;
requestPDU.DataRepresentation.FloatingPointRepresentation = FloatingPointRepresentation.IEEE;
requestPDU.CallID = _callId++;
requestPDU.AllocationHint = (uint)stub.Length;
requestPDU.ContextID = 0;
requestPDU.OpNum = opNum;
requestPDU.Data = stub;
// #region debug-point D:createservice-request
if (opNum == 12)
{
}
// #endregion
byte[] response = _stream.Transceive(requestPDU.GetBytes());
if (response == null)
{
return null;
}
// #region debug-point D:createservice-response
if (opNum == 12)
{
byte packetType = response.Length > 2 ? response[2] : (byte)255;
}
// #endregion
RPCPDU responsePacket = RPCPDU.GetPDU(response, 0);
FaultPDU faultPDU = responsePacket as FaultPDU;
if (faultPDU != null)
{
// #region debug-point D:createservice-fault
if (opNum == 12)
{
}
// #endregion
Console.WriteLine($"[RPC FAULT] OpNum={opNum}, Status={faultPDU.Status}, Flags={faultPDU.Flags}");
return null;
}
ResponsePDU responsePDU = responsePacket as ResponsePDU;
if (responsePDU == null)
{
Console.WriteLine($"[RPC] Unexpected PDU type: {responsePacket.GetType().Name}");
return null;
}
return responsePDU.Data;
}
public static string ToHex(byte[] buffer, int maxBytes)
{
if (buffer == null)
{
return String.Empty;
}
int length = Math.Min(buffer.Length, maxBytes);
StringBuilder builder = new StringBuilder(length * 2 + 16);
for (int index = 0; index < length; index++)
{
builder.Append(buffer[index].ToString("X2"));
}
if (buffer.Length > maxBytes)
{
builder.Append("...");
}
return builder.ToString();
}
public byte[] OpenSCManager()
{
MemoryStream ms = new MemoryStream();
BinaryWriter writer = new BinaryWriter(ms);
WriteRpcStringPointer(writer, _machineName, 1);
WriteRpcStringPointer(writer, "ServicesActive", 2);
writer.Write((uint)0x00000003); // SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE
byte[] reply = ExecuteCall(15, ms.ToArray());
if (reply == null || reply.Length < 24) return null;
// #region debug-point B:openscmanager-response
uint returnCode = BitConverter.ToUInt32(reply, 20);
if (returnCode != 0)
{
Console.WriteLine($"[RPC] OpenSCManagerW returned Win32 error: {returnCode}");
return null;
}
byte[] handle = new byte[20];
Buffer.BlockCopy(reply, 0, handle, 0, 20); // First 20 bytes contain Context Handle
if (ToHex(handle, 20).TrimEnd('0').Length == 0)
{
Console.WriteLine("[RPC] OpenSCManagerW returned an empty SCM handle.");
return null;
}
return handle;
}
public byte[] CreateService(byte[] scmHandle, string serviceName, string binaryPath)
{
NDRWriter writer = new NDRWriter();
int scmHandleStart = writer.GetBytes().Length;
writer.WriteBytes(scmHandle); // 20-byte Parent Context Handle
int scmHandleEnd = writer.GetBytes().Length;
int serviceNameStart = writer.GetBytes().Length;
writer.WriteTopLevelUnicodeStringPointer(serviceName); // [in, string] wchar_t* lpServiceName
int serviceNameEnd = writer.GetBytes().Length;
int displayNameStart = writer.GetBytes().Length;
writer.WriteTopLevelUnicodeStringPointer(serviceName); // [in, string, unique] wchar_t* lpDisplayName
int displayNameEnd = writer.GetBytes().Length;
int desiredAccessStart = writer.GetBytes().Length;
writer.WriteUInt32(0x000F01FF); // Desired Access: SERVICE_ALL_ACCESS
int desiredAccessEnd = writer.GetBytes().Length;
int serviceTypeStart = writer.GetBytes().Length;
writer.WriteUInt32(0x00000010); // Service Type: SERVICE_WIN32_OWN_PROCESS
int serviceTypeEnd = writer.GetBytes().Length;
int startTypeStart = writer.GetBytes().Length;
writer.WriteUInt32(0x00000003); // Start Type: SERVICE_DEMAND_START
int startTypeEnd = writer.GetBytes().Length;
int errorControlStart = writer.GetBytes().Length;
writer.WriteUInt32(0x00000001); // Error Control: SERVICE_ERROR_NORMAL
int errorControlEnd = writer.GetBytes().Length;
int binaryPathStart = writer.GetBytes().Length;
writer.WriteTopLevelUnicodeStringPointer(binaryPath); // [in, string] wchar_t* lpBinaryPathName
int binaryPathEnd = writer.GetBytes().Length;
int loadOrderGroupStart = writer.GetBytes().Length;
writer.WriteTopLevelUnicodeStringPointer(null); // [in, string, unique] wchar_t* lpLoadOrderGroup
int loadOrderGroupEnd = writer.GetBytes().Length;
int tagIdStart = writer.GetBytes().Length;
writer.WriteUInt32(0); // [in, out, unique] LPDWORD lpdwTagId
int tagIdEnd = writer.GetBytes().Length;
int dependenciesStart = writer.GetBytes().Length;
writer.WriteUInt32(0); // [in, unique, size_is(dwDependSize)] LPBYTE lpDependencies
int dependenciesEnd = writer.GetBytes().Length;
int dependSizeStart = writer.GetBytes().Length;
writer.WriteUInt32(0); // dwDependSize
int dependSizeEnd = writer.GetBytes().Length;
int startNameStart = writer.GetBytes().Length;
writer.WriteTopLevelUnicodeStringPointer(null); // [in, string, unique] wchar_t* lpServiceStartName
int startNameEnd = writer.GetBytes().Length;
int passwordStart = writer.GetBytes().Length;
writer.WriteUInt32(0); // [in, unique, size_is(dwPwSize)] LPBYTE lpPassword
int passwordEnd = writer.GetBytes().Length;
int passwordSizeStart = writer.GetBytes().Length;
writer.WriteUInt32(0); // dwPwSize
int passwordSizeEnd = writer.GetBytes().Length;
byte[] stub = writer.GetBytes();
byte[] reply = ExecuteCall(12, stub); // OpNum 12: CreateServiceW
if (reply == null || reply.Length < 24) return null;
byte[] handle = new byte[20];
Buffer.BlockCopy(reply, 0, handle, 0, 20);
return handle;
}
public uint ScheduleAtsvcJob(string command, DateTime runAt)
{
NDRWriter writer = new NDRWriter();
writer.WriteTopLevelUnicodeStringPointer(_machineName);
writer.WriteStructure(new AtsvcJobInfo
{
JobTime = GetMillisecondsAfterMidnight(runAt),
DaysOfMonth = 0,
DaysOfWeek = 0,
Flags = 0x10, // JOB_NONINTERACTIVE
Command = new NDRUnicodeString(command),
});
byte[] reply = ExecuteCall(0, writer.GetBytes());
if (reply == null || reply.Length < 8)
{
return 0;
}
uint jobId = BitConverter.ToUInt32(reply, 0);
uint returnCode = BitConverter.ToUInt32(reply, 4);
if (returnCode != 0)
{
Console.WriteLine($"[ATSVC] NetrJobAdd returned Win32 error: {returnCode}");
return 0;
}
return jobId;
}
public void DeleteAtsvcJob(uint jobId)
{
NDRWriter writer = new NDRWriter();
writer.WriteTopLevelUnicodeStringPointer(_machineName);
writer.WriteUInt32(jobId);
writer.WriteUInt32(jobId);
byte[] reply = ExecuteCall(1, writer.GetBytes());
if (reply == null || reply.Length < 4)
{
return;
}
uint returnCode = BitConverter.ToUInt32(reply, 0);
if (returnCode != 0)
{
Console.WriteLine($"[ATSVC] NetrJobDel returned Win32 error: {returnCode}");
}
}
public AtsvcJobInfo GetAtsvcJobInfo(uint jobId)
{
NDRWriter writer = new NDRWriter();
writer.WriteTopLevelUnicodeStringPointer(_machineName);
writer.WriteUInt32(jobId);
byte[] reply = ExecuteCall(3, writer.GetBytes());
if (reply == null || reply.Length < 8)
{
return null;
}
NDRParser parser = new NDRParser(reply);
uint referentId = parser.ReadUInt32();
AtsvcJobInfo info = null;
if (referentId != 0)
{
info = new AtsvcJobInfo();
parser.ReadStructure(info);
}
uint returnCode = parser.ReadUInt32();
if (returnCode != 0)
{
Console.WriteLine($"[ATSVC] NetrJobGetInfo returned Win32 error: {returnCode}");
return null;
}
return info;
}
private static uint GetMillisecondsAfterMidnight(DateTime value)
{
TimeSpan timeOfDay = value.TimeOfDay;
return (uint)timeOfDay.TotalMilliseconds;
}
public void StartService(byte[] svcHandle)
{
MemoryStream ms = new MemoryStream();
BinaryWriter bw = new BinaryWriter(ms);
bw.Write(svcHandle); // 20-byte Service Context Handle
bw.Write((uint)0); // Argument Count (None Passed)
bw.Write((uint)0); // Arguments Pointer Array Reference
ExecuteCall(19, ms.ToArray()); // OpNum 19: StartServiceW
}
public void DeleteService(byte[] svcHandle)
{
ExecuteCall(2, svcHandle); // OpNum 2: DeleteService
}
}
}

4713

被折叠的 条评论
为什么被折叠?



