调用Windows API实现命令行工具:Sharp4Cmd
字数 1542 2025-08-22 12:22:42
Sharp4Cmd 工具详细教学文档
1. 工具概述
Sharp4Cmd 是一款基于.NET框架开发的Windows命令行交互工具,其主要特点是通过直接调用Windows API实现命令执行,不依赖系统的cmd.exe,在内网渗透测试中能够有效规避安全防护设备的检测。
2. 核心功能
- 直接调用kernel32.dll中的CreateProcess函数执行命令
- 通过管道机制实现父子进程间通信
- 支持命令执行结果的实时获取
- 可配置进程创建策略,增强隐蔽性
3. 使用方法
3.1 编译与运行
- 编译Sharp4Cmd项目生成Sharp4Cmd.exe
- 命令行执行格式:
Sharp4Cmd.exe [command] - 示例:
Sharp4Cmd.exe whoami /priv
4. 技术原理详解
4.1 核心代码结构
程序主要由两部分组成:
- Main方法:程序入口,接收并处理命令行参数
- UnmanagedExecute类:封装Windows API调用,实现进程创建和管道通信
4.2 关键API函数
4.2.1 OpenProcess
[DllImport("kernel32.dll", SetLastError = true)]
public static extern IntPtr OpenProcess(
ProcessAccessFlags processAccess,
bool bInheritHandle,
int processId
);
- 功能:打开已存在的进程
- 参数:
- processAccess:进程访问权限标志
- bInheritHandle:是否允许子进程继承句柄
- processId:目标进程ID
4.2.2 InitializeProcThreadAttributeList
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool InitializeProcThreadAttributeList(
IntPtr lpAttributeList,
int dwAttributeCount,
int dwFlags,
ref IntPtr lpSize
);
- 功能:初始化进程属性列表
- 参数:
- lpAttributeList:属性列表指针
- dwAttributeCount:属性数量
- dwFlags:保留标志,通常为0
- lpSize:返回所需缓冲区大小
4.2.3 UpdateProcThreadAttribute
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UpdateProcThreadAttribute(
IntPtr lpAttributeList,
uint dwFlags,
IntPtr Attribute,
IntPtr lpValue,
IntPtr cbSize,
IntPtr lpPreviousValue,
IntPtr lpReturnSize
);
- 功能:更新进程属性列表
- 重要参数:
- Attribute:要设置的属性类型
- lpValue:属性值指针
4.2.4 CreatePipe
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool CreatePipe(
out IntPtr hReadPipe,
out IntPtr hWritePipe,
ref SECURITY_ATTRIBUTES lpPipeAttributes,
uint nSize
);
- 功能:创建匿名管道
- 参数:
- hReadPipe:返回读取端句柄
- hWritePipe:返回写入端句柄
- lpPipeAttributes:安全属性结构
- nSize:缓冲区大小,0表示默认
4.3 关键数据结构
4.3.1 SECURITY_ATTRIBUTES
public struct SECURITY_ATTRIBUTES {
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
- 功能:定义对象的安全属性
- 成员:
- nLength:结构体大小
- lpSecurityDescriptor:安全描述符指针
- bInheritHandle:句柄继承标志
4.4 核心实现流程
4.4.1 管道创建与配置
-
初始化安全属性结构:
var saHandles = new SECURITY_ATTRIBUTES(); saHandles.nLength = Marshal.SizeOf(saHandles); saHandles.bInheritHandle = true; saHandles.lpSecurityDescriptor = IntPtr.Zero; -
创建管道:
IntPtr hStdOutRead; IntPtr hStdOutWrite; CreatePipe(out hStdOutRead, out hStdOutWrite, ref saHandles, 0); SetHandleInformation(hStdOutRead, HANDLE_FLAGS.INHERIT, 0);
4.4.2 进程策略配置
-
初始化属性列表:
var lpSize = IntPtr.Zero; var success = InitializeProcThreadAttributeList(IntPtr.Zero, 2, 0, ref lpSize); siEx.lpAttributeList = Marshal.AllocHGlobal(lpSize); success = InitializeProcThreadAttributeList(siEx.lpAttributeList, 2, 0, ref lpSize); -
设置安全策略(仅允许微软签名DLL):
IntPtr lpMitigationPolicy = Marshal.AllocHGlobal(IntPtr.Size); Marshal.WriteInt64(lpMitigationPolicy, PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON); success = UpdateProcThreadAttribute(siEx.lpAttributeList, 0, (IntPtr)PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY, lpMitigationPolicy, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero);
4.4.3 进程创建与数据重定向
-
打开父进程并更新属性:
IntPtr parentHandle = OpenProcess( ProcessAccessFlags.CreateProcess | ProcessAccessFlags.DuplicateHandle, false, parentProcessId); lpValueProc = Marshal.AllocHGlobal(IntPtr.Size); Marshal.WriteIntPtr(lpValueProc, parentHandle); success = UpdateProcThreadAttribute(siEx.lpAttributeList, 0, (IntPtr)PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, lpValueProc, (IntPtr)IntPtr.Size, IntPtr.Zero, IntPtr.Zero); -
复制句柄实现数据重定向:
IntPtr hCurrent = System.Diagnostics.Process.GetCurrentProcess().Handle; IntPtr hNewParent = OpenProcess(ProcessAccessFlags.DuplicateHandle, true, parentProcessId); success = DuplicateHandle(hCurrent, hStdOutWrite, hNewParent, ref hDupStdOutWrite, 0, true, DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS); siEx.StartupInfo.hStdError = hDupStdOutWrite; siEx.StartupInfo.hStdOutput = hDupStdOutWrite; -
创建新进程:
siEx.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; siEx.StartupInfo.wShowWindow = SW_HIDE; var ps = new SECURITY_ATTRIBUTES(); var ts = new SECURITY_ATTRIBUTES(); ps.nLength = Marshal.SizeOf(ps); ts.nLength = Marshal.SizeOf(ts); bool ret = CreateProcess(null, command, ref ps, ref ts, true, EXTENDED_STARTUPINFO_PRESENT | CREATE_NO_WINDOW, IntPtr.Zero, null, ref siEx, out pInfo);
4.4.4 输出数据读取
-
创建读取管道数据的流:
SafeFileHandle safeHandle = new SafeFileHandle(hStdOutRead, false); var encoding = Encoding.GetEncoding(GetConsoleOutputCP()); var reader = new StreamReader( new FileStream(safeHandle, FileAccess.Read, 4096, false), encoding, true); -
循环读取输出数据:
string result = ""; bool exit = false; do { if (WaitForSingleObject(pInfo.hProcess, 100) == 0) { exit = true; } char[] buf = null; int bytesRead; uint bytesToRead = 0; bool peekRet = PeekNamedPipe(hStdOutRead, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, ref bytesToRead, IntPtr.Zero); if (peekRet == true && bytesToRead == 0) { if (exit == true) break; else continue; } if (bytesToRead > 4096) bytesToRead = 4096; buf = new char[bytesToRead]; bytesRead = reader.Read(buf, 0, buf.Length); if (bytesRead > 0) { result += new string(buf); } } while (true);
5. 技术要点总结
- 进程创建机制:直接调用CreateProcess API,不依赖cmd.exe
- 管道通信:通过CreatePipe创建匿名管道,实现父子进程间数据传递
- 安全策略:配置PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY限制非微软签名DLL加载
- 输出重定向:使用DuplicateHandle复制句柄,将子进程输出重定向到父进程
- 隐蔽性设计:
- 设置CREATE_NO_WINDOW标志不显示窗口
- 使用SW_HIDE隐藏窗口显示
- 通过管道而非标准控制台获取输出
6. 应用场景
- 内网渗透测试中规避安全设备检测
- 需要隐蔽执行命令的红队活动
- 需要精细控制进程创建属性的场景
- 需要绕过传统命令行监控的安全测试
7. 注意事项
- 需要.NET框架支持
- 在高度受限的环境中可能无法执行
- 父进程ID为0时会排除系统空闲进程
- 输出编码依赖于控制台代码页(GetConsoleOutputCP)