.NET Linux环境下隐藏进程名中的启动参数
解决Linux下C#控制台进程命令行参数隐藏问题
针对Linux下C#控制台进程命令行参数暴露的问题,以下是几种无需改为交互式输入的解决方法:
方法1:直接修改进程的argv数组(Linux专属)
Linux系统允许进程修改自身的argv数组,从而让ps、Screen等工具读取不到原始敏感参数。可以通过P/Invoke调用Linux系统函数实现:
using System; using System.Runtime.InteropServices; class Program { [DllImport("libc", SetLastError = true)] private static extern IntPtr getenv(string name); [DllImport("libc", SetLastError = true)] private static extern IntPtr memcpy(IntPtr dest, IntPtr src, UIntPtr count); static void Main(string[] args) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { // 通过环境变量指针推导argv的地址 IntPtr environ = getenv("__environ"); if (environ != IntPtr.Zero) { // argv[0]的地址为environ减去指针大小(64位系统为8字节) IntPtr argv = environ - IntPtr.Size; // 替换进程名,覆盖原始命令行开头 string newProcessName = "./MyProgram"; byte[] nameBytes = System.Text.Encoding.ASCII.GetBytes(newProcessName + '\0'); memcpy(argv, Marshal.StringToHGlobalAnsi(newProcessName), (UIntPtr)nameBytes.Length); // 将后续参数置为null,清除敏感信息残留 for (int i = 1; i < args.Length; i++) { IntPtr argPtr = argv + i * IntPtr.Size; Marshal.WriteIntPtr(argPtr, IntPtr.Zero); } } } // 后续业务逻辑执行 Console.WriteLine("程序运行中..."); Console.ReadLine(); } }
注意:该方法仅在Linux生效,需要程序具备基础运行权限,修改后/proc/self/cmdline将不再包含敏感参数。
方法2:通过子进程传递敏感参数(跨平台兼容)
主进程接收命令行参数后,启动子进程执行核心逻辑,将敏感参数通过标准输入或环境变量传递,主进程随即退出。子进程的命令行不会包含敏感参数:
using System; using System.Diagnostics; using System.Runtime.InteropServices; class Program { static void Main(string[] args) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { // 通过环境变量标记是否为子进程 string isChild = Environment.GetEnvironmentVariable("MY_PROCESS_CHILD"); if (string.IsNullOrEmpty(isChild)) { // 主进程:启动子进程并传递参数到标准输入 ProcessStartInfo psi = new ProcessStartInfo(); psi.FileName = Process.GetCurrentProcess().MainModule.FileName; psi.EnvironmentVariables["MY_PROCESS_CHILD"] = "1"; psi.RedirectStandardInput = true; psi.UseShellExecute = false; using (Process childProcess = Process.Start(psi)) { foreach (string arg in args) { childProcess.StandardInput.WriteLine(arg); } childProcess.StandardInput.Close(); // 主进程退出,子进程独立运行 return; } } else { // 子进程:从标准输入读取原始参数 var childArgs = new System.Collections.Generic.List<string>(); string line; while ((line = Console.ReadLine()) != null) { childArgs.Add(line); } args = childArgs.ToArray(); } } // 核心业务逻辑,使用读取到的参数 Console.WriteLine("子进程运行中,参数已加载"); Console.ReadLine(); } }
此方法跨平台可用,子进程的命令行仅显示程序路径,完全隐藏敏感参数。
方法3:使用prctl修改进程显示名(补充优化)
配合上述方法,可以调用Linux的prctl函数设置进程的显示名称,让监控工具显示自定义名称而非默认路径:
[DllImport("libc", SetLastError = true)] private static extern int prctl(int option, IntPtr arg2, IntPtr arg3, IntPtr arg4, IntPtr arg5); // 在Linux代码块中调用: const int PR_SET_NAME = 15; string processDisplayName = "MyProgram"; prctl(PR_SET_NAME, Marshal.StringToHGlobalAnsi(processDisplayName), IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
该方法仅修改进程显示名,不会改变/proc/self/cmdline内容,建议和方法1或2配合使用。
内容的提问来源于stack exchange,提问作者Boyfinn
相关产品推荐
相关产品推荐

