简体   繁体   中英

Getting command line of a process without WMI

I found wj32 post about how to read the command line of specified process via WinAPI. I try to translate that example on C# and I've a few questions. I can get a valid pointer to the field CommandLine of RTL_USER_PROCESS_PARAMETERS structure but the difficalty is getting the string itself. Should I use unsafe code? How to correctly get CommandLine of a process using wj32's example?

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);
    }
  }
}

OK, I've tested this version on a couple of processes. Note that it works on 32-bit processes only as the memory layout is different for 64-bit. I'm short of time to write up why I've made the changes I have but hopefully you can work with this. If I get some time I'll come back and update the answer

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,
            byte[] 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, Pack=1)]
        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, Pack=1)]
        internal struct UNICODE_STRING
        {
            internal UInt16 Length;
            internal UInt16 MaximumLength;
            internal IntPtr 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 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)
            {
                byte[] rupp = new byte[IntPtr.Size];
                if (NativeMethods.ReadProcessMemory(
                    proc, (IntPtr)(pbi.PebBaseAddress.ToInt32() + 0x10), rupp, IntPtr.Size, out read
                ))
                {
                    Int32 ruppPtr = BitConverter.ToInt32(rupp,0);
                    byte[] cmdl = new byte[Marshal.SizeOf(typeof(NativeMethods.UNICODE_STRING))];

                    if (NativeMethods.ReadProcessMemory(
                        proc, (IntPtr)(ruppPtr + 0x40), cmdl,
                        Marshal.SizeOf(typeof(NativeMethods.UNICODE_STRING)), out read
                    ))
                    {
                        NativeMethods.UNICODE_STRING ucsData;
                        ucsData = ByteArrayToStructure<NativeMethods.UNICODE_STRING>(cmdl);
                        byte[] parms =new byte[ucsData.Length];
                        if (NativeMethods.ReadProcessMemory(
                            proc, ucsData.buffer, parms,
                            ucsData.Length, out read
                            ))
                        {
                            var s = System.Text.Encoding.Unicode.GetString(parms);
                            Console.WriteLine("Parameters = {0}", s);
                        }
                    }
                }
            }

            NativeMethods.CloseHandle(proc);
        }
        static T ByteArrayToStructure<T>(byte[] bytes) where T : struct
        {
            GCHandle handle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
            T stuff = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
            handle.Free();
            return stuff;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM