获取没有WMI的进程的命令行

时间:2016-05-22 16:09:58

标签: c#

我发现wj32 post 关于如何通过WinAPI读取指定进程的命令行。我尝试在C#上翻译这个例子,我有几个问题。我可以获得一个指向RTL_USER_PROCESS_PARAMETERS结构的字段CommandLine的有效指针,但是difficalty正在获取字符串本身。我应该使用不安全的代码吗?如何使用wj32的示例正确获取进程的CommandLine?

using System;
using System.Runtime.InteropServices;

namespace CommandLine {
  internal static class NativeMethods {
    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern Boolean CloseHandle(
        IntPtr hObject
    );

    [DllImport("kernel32.dll", SetLastError = true)]
    internal static extern IntPtr OpenProcess(
        UInt32  dwDesiredAccess,
        [MarshalAs(UnmanagedType.Bool)]
        Boolean bInheritHandle,
        Int32   dwProcessId
    );

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern Boolean ReadProcessMemory(
        IntPtr hProcess,
        IntPtr lpBaseAddress,
        out IntPtr lpBuffer,
        Int32  nSize,
        out IntPtr lpNumberOfBytesRead
    );

    [DllImport("ntdll.dll")]
    internal static extern Int32 NtQueryInformationProcess(
        IntPtr ProcessHandle,
        UInt32 ProcessInformationClass,
        ref PROCESS_BASIC_INFORMATION ProcessInformation,
        UInt32 ProcessInformationLength,
        IntPtr ReturnLength
    );

    [StructLayout(LayoutKind.Sequential)]
    internal struct PROCESS_BASIC_INFORMATION {
      internal Int32  ExitProcess;
      internal IntPtr PebBaseAddress;
      internal IntPtr AffinityMask;
      internal Int32  BasePriority;
      internal IntPtr UniqueProcessId;
      internal IntPtr InheritedFromUniqueProcessId;

      internal UInt32 Size {
        get { return (UInt32)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)); }
      }
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct UNICODE_STRING {
      internal UInt16 Length;
      internal UInt16 MaximumLength;
      [MarshalAs(UnmanagedType.LPWStr)]
      internal String Buffer;
    }
  }

  internal sealed class Program {
    private const UInt32 PROCESS_QUERY_INFORMATION = 0x400;
    private const UInt32 PROCESS_VM_READ = 0x010;

    [STAThread()]
    static void Main(String[] args) {
      if (args.Length != 1) return;

      Int32 pid;
      if (!Int32.TryParse(args[0], out pid)) return;

      IntPtr proc;
      NativeMethods.PROCESS_BASIC_INFORMATION pbi = new NativeMethods.PROCESS_BASIC_INFORMATION();
      IntPtr rupp; //RTL_USER_PROCESS_PARAMETERS
      IntPtr cmdl; //CommandLine field
      IntPtr read;

      if ((proc = NativeMethods.OpenProcess(
          PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, pid
      )) == IntPtr.Zero) return;

      if (NativeMethods.NtQueryInformationProcess(proc, 0, ref pbi, pbi.Size, IntPtr.Zero) == 0) {
        if (NativeMethods.ReadProcessMemory(
            proc, (IntPtr)(pbi.PebBaseAddress.ToInt32() + 0x10), out rupp, IntPtr.Size, out read
        )) {
          if (NativeMethods.ReadProcessMemory(
              proc, (IntPtr)(rupp.ToInt32() + 0x40), out cmdl,
              Marshal.SizeOf(typeof(NativeMethods.UNICODE_STRING)), out read
          )) {
            // what I need to do to get command line?
          }
        }
      }

      NativeMethods.CloseHandle(proc);
    }
  }
}

1 个答案:

答案 0 :(得分:3)

好的,我已经在几个流程上测试了这个版本。请注意,它仅适用于32位进程,因为64位的内存布局不同。我没有时间写下为什么我做了改变,但希望你能用到这个。如果我有时间,我会回来更新答案

SELECT CREATED FROM v$DATABASE