读取c#中其他进程的当前目录

本文关键字:当前目录 进程 其他 读取 | 更新日期: 2023-09-27 18:10:15

我试图获得所选进程的当前工作目录。我确信这是可能的,因为Process Explorer之类的工具可以显示这些信息。我发现这个信息存储在PEB中。

此外,我找到了Oleksiy的博客帖子:http://eazfuscator.blogspot.com/2011/06/reading-environment-variables-from.html,但我所有的修改都是完全除非。

所以我的问题是我如何在c#中读取这些信息?如果Oleksiy代码是一个好方法,我应该如何修改他的代码来获得这些信息?

读取c#中其他进程的当前目录

正如其他人指出的那样,这是完全没有文档记录的,但是这里有一段代码可以做到这一点(截至今天,它似乎可以工作)。当然,它需要以管理员身份运行。注意,它可以在任何编译目标(x86或x64)下工作于任何进程位,32位或64位(某些进程可能报告访问被拒绝,甚至以管理员身份运行)。它还能够读取命令行。使用风险自负!

// All offset values below have been tested on Windows 7 & 8 only
// but you can use WinDbg "dt ntdll!_PEB" command and search for ProcessParameters offset to find the truth, depending on the OS version
public static class ProcessUtilities
{
    public static string GetCurrentDirectory(int processId)
    {
        return GetProcessParametersString(processId, Environment.Is64BitOperatingSystem ? 0x38 : 0x24);
    }
    public static string GetCurrentDirectory(this Process process)
    {
        if (process == null)
            throw new ArgumentNullException("process");
        return GetCurrentDirectory(process.Id);
    }
    public static string GetCommandLine(int processId)
    {
        return GetProcessParametersString(processId, Environment.Is64BitOperatingSystem ? 0x70 : 0x40);
    }
    public static string GetCommandLine(this Process process)
    {
        if (process == null)
            throw new ArgumentNullException("process");
        return GetCommandLine(process.Id);
    }
    private static string GetProcessParametersString(int processId, int offset)
    {
        IntPtr handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId);
        if (handle == IntPtr.Zero)
            throw new Win32Exception(Marshal.GetLastWin32Error());
        int processParametersOffset = Environment.Is64BitOperatingSystem ? 0x20 : 0x10;
        try
        {
            if (Environment.Is64BitOperatingSystem && !Environment.Is64BitProcess) // are we running in WOW?
            {
                PROCESS_BASIC_INFORMATION_WOW64 pbi = new PROCESS_BASIC_INFORMATION_WOW64();
                int hr = NtWow64QueryInformationProcess64(handle, 0, ref pbi, Marshal.SizeOf(pbi), IntPtr.Zero);
                if (hr != 0)
                    throw new Win32Exception(hr);
                long pp = 0;
                hr = NtWow64ReadVirtualMemory64(handle, pbi.PebBaseAddress + processParametersOffset, ref pp, Marshal.SizeOf(pp), IntPtr.Zero);
                if (hr != 0)
                    throw new Win32Exception(hr);
                UNICODE_STRING_WOW64 us = new UNICODE_STRING_WOW64();
                hr = NtWow64ReadVirtualMemory64(handle, pp + offset, ref us, Marshal.SizeOf(us), IntPtr.Zero);
                if (hr != 0)
                    throw new Win32Exception(hr);
                if ((us.Buffer == 0) || (us.Length == 0))
                    return null;
                string s = new string(''0', us.Length / 2);
                hr = NtWow64ReadVirtualMemory64(handle, us.Buffer, s, us.Length, IntPtr.Zero);
                if (hr != 0)
                    throw new Win32Exception(hr);
                return s;
            }
            else // we are running with the same bitness as the OS, 32 or 64
            {
                PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
                int hr = NtQueryInformationProcess(handle, 0, ref pbi, Marshal.SizeOf(pbi), IntPtr.Zero);
                if (hr != 0)
                    throw new Win32Exception(hr);
                IntPtr pp = new IntPtr();
                if (!ReadProcessMemory(handle, pbi.PebBaseAddress + processParametersOffset, ref pp, new IntPtr(Marshal.SizeOf(pp)), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                UNICODE_STRING us = new UNICODE_STRING();
                if (!ReadProcessMemory(handle, pp + offset, ref us, new IntPtr(Marshal.SizeOf(us)), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                if ((us.Buffer == IntPtr.Zero) || (us.Length == 0))
                    return null;
                string s = new string(''0', us.Length / 2);
                if (!ReadProcessMemory(handle, us.Buffer, s, new IntPtr(us.Length), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return s;
            }
        }
        finally
        {
            CloseHandle(handle);
        }
    }
    private const int PROCESS_QUERY_INFORMATION = 0x400;
    private const int PROCESS_VM_READ = 0x10;
    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESS_BASIC_INFORMATION
    {
        public IntPtr Reserved1;
        public IntPtr PebBaseAddress;
        public IntPtr Reserved2_0;
        public IntPtr Reserved2_1;
        public IntPtr UniqueProcessId;
        public IntPtr Reserved3;
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct UNICODE_STRING
    {
        public short Length;
        public short MaximumLength;
        public IntPtr Buffer;
    }
    // for 32-bit process in a 64-bit OS only
    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESS_BASIC_INFORMATION_WOW64
    {
        public long Reserved1;
        public long PebBaseAddress;
        public long Reserved2_0;
        public long Reserved2_1;
        public long UniqueProcessId;
        public long Reserved3;
    }
    // for 32-bit process in a 64-bit OS only
    [StructLayout(LayoutKind.Sequential)]
    private struct UNICODE_STRING_WOW64
    {
        public short Length;
        public short MaximumLength;
        public long Buffer;
    }
    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationProcess(IntPtr ProcessHandle, int ProcessInformationClass, ref PROCESS_BASIC_INFORMATION ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref IntPtr lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref UNICODE_STRING lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    [DllImport("kernel32.dll")]
    private static extern bool CloseHandle(IntPtr hObject);
    // for 32-bit process in a 64-bit OS only
    [DllImport("ntdll.dll")]
    private static extern int NtWow64QueryInformationProcess64(IntPtr ProcessHandle, int ProcessInformationClass, ref PROCESS_BASIC_INFORMATION_WOW64 ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength);
    [DllImport("ntdll.dll")]
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, ref long lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("ntdll.dll")]
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, ref UNICODE_STRING_WOW64 lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("ntdll.dll")]
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, [MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead);
}

"Simon Mourier"源代码在OS,Executor,Target是32位运行良好。但其他人则不然。所以我添加源代码来处理32位,64位的所有组合。有5种可能的32位、64位进程组合。首先,操作系统、执行器、目标都是32位的。第二,操作系统是64位的,执行器、目标器是32位、64位进程的组合。这段代码在我的笔记本Win7 64Bit操作系统,32,64位进程中工作良好。目标32位,64位进程,WinXp 32位,执行器,目标均为32位。但是,使用风险自负!

// ref: http://www.microsoft.com/whdc/system/Sysinternals/MoreThan64proc.mspx
public enum PROCESSINFOCLASS : int
{
    ProcessBasicInformation = 0, // 0, q: PROCESS_BASIC_INFORMATION, PROCESS_EXTENDED_BASIC_INFORMATION
    ProcessWow64Information = 26, // q: ULONG_PTR
}
[Flags]
public enum PEB_OFFSET
{
    CurrentDirectory,
    //DllPath,
    //ImagePathName,
    CommandLine,
    //WindowTitle,
    //DesktopInfo,
    //ShellInfo,
    //RuntimeData,
    //TypeMask = 0xffff,
    //Wow64 = 0x10000,
};
public class Is64BitChecker
{
    [DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool IsWow64Process(
        [In] IntPtr hProcess,
        [Out] out bool wow64Process
    );
    public static bool GetProcessIsWow64(IntPtr hProcess)
    {
        if ((Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) ||
            Environment.OSVersion.Version.Major >= 6)
        {
            bool retVal;
            if (!IsWow64Process(hProcess, out retVal))
            {
                return false;
            }
            return retVal;
        }
        else
        {
            return false;
        }
    }
    public static bool InternalCheckIsWow64()
    {
        if ((Environment.OSVersion.Version.Major == 5 && Environment.OSVersion.Version.Minor >= 1) ||
            Environment.OSVersion.Version.Major >= 6)
        {
            using (Process p = Process.GetCurrentProcess())
            {
                bool retVal;
                if (!IsWow64Process(p.Handle, out retVal))
                {
                    return false;
                }
                return retVal;
            }
        }
        else
        {
            return false;
        }
    }
}
// All offset values below have been tested on Windows 7 & 8 only
// but you can use WinDbg "dt ntdll!_PEB" command and search for ProcessParameters offset to find the truth, depending on the OS version
public static class ProcessUtilities
{
    public static readonly bool Is64BitProcess = IntPtr.Size > 4;
    public static readonly bool Is64BitOperatingSystem = Is64BitProcess || Is64BitChecker.InternalCheckIsWow64();
    public static string GetCurrentDirectory(int processId)
    {
        return GetProcessParametersString(processId, PEB_OFFSET.CurrentDirectory);
    }
    public static string GetCurrentDirectory(this Process process)
    {
        if (process == null)
            throw new ArgumentNullException("process");
        return GetCurrentDirectory(process.Id);
    }
    #region GetCommandLine
    //public static string GetCommandLine(int processId)
    //{
    //    return null;// GetProcessParametersString(processId, Is64BitOperatingSystem ? 0x70 : 0x40);
    //}
    //public static string GetCommandLine(this Process process)
    //{
    //    if (process == null)
    //        throw new ArgumentNullException("process");
    //    return GetCommandLine(process.Id);
    //} 
    #endregion
    private static string GetProcessParametersString(int processId, PEB_OFFSET Offset)
    {
        IntPtr handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, false, processId);
        if (handle == IntPtr.Zero)
            throw new Win32Exception(Marshal.GetLastWin32Error());
        bool IsWow64Process = Is64BitChecker.InternalCheckIsWow64();
        bool IsTargetWow64Process = Is64BitChecker.GetProcessIsWow64(handle);
        bool IsTarget64BitProcess = Is64BitOperatingSystem && !IsTargetWow64Process;
        long offset = 0;
        long processParametersOffset = IsTarget64BitProcess ? 0x20 : 0x10;
        switch (Offset)
        {
            case PEB_OFFSET.CurrentDirectory:
                offset = IsTarget64BitProcess ? 0x38 : 0x24;
                break;
            case PEB_OFFSET.CommandLine:
            default:
                return null;
        }
        try
        {
            long pebAddress = 0;
            if (IsTargetWow64Process) // OS : 64Bit, Cur : 32 or 64, Tar: 32bit
            {
                IntPtr peb32 = new IntPtr();
                int hr = NtQueryInformationProcess(handle, (int)PROCESSINFOCLASS.ProcessWow64Information, ref peb32, IntPtr.Size, IntPtr.Zero);
                if (hr != 0) throw new Win32Exception(hr);
                pebAddress = peb32.ToInt64();
                IntPtr pp = new IntPtr();
                if (!ReadProcessMemory(handle, new IntPtr(pebAddress + processParametersOffset), ref pp, new IntPtr(Marshal.SizeOf(pp)), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                UNICODE_STRING_32 us = new UNICODE_STRING_32();
                if (!ReadProcessMemory(handle, new IntPtr(pp.ToInt64() + offset), ref us, new IntPtr(Marshal.SizeOf(us)), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                if ((us.Buffer == 0) || (us.Length == 0))
                    return null;
                string s = new string(''0', us.Length / 2);
                if (!ReadProcessMemory(handle, new IntPtr(us.Buffer), s, new IntPtr(us.Length), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return s;
            }
            else if (IsWow64Process)//Os : 64Bit, Cur 32, Tar 64
            {
                PROCESS_BASIC_INFORMATION_WOW64 pbi = new PROCESS_BASIC_INFORMATION_WOW64();
                int hr = NtWow64QueryInformationProcess64(handle, (int)PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, Marshal.SizeOf(pbi), IntPtr.Zero);
                if (hr != 0) throw new Win32Exception(hr);
                pebAddress = pbi.PebBaseAddress;
                long pp = 0;
                hr = NtWow64ReadVirtualMemory64(handle, pebAddress + processParametersOffset, ref pp, Marshal.SizeOf(pp), IntPtr.Zero);
                if (hr != 0)
                    throw new Win32Exception(hr);
                UNICODE_STRING_WOW64 us = new UNICODE_STRING_WOW64();
                hr = NtWow64ReadVirtualMemory64(handle, pp + offset, ref us, Marshal.SizeOf(us), IntPtr.Zero);
                if (hr != 0)
                    throw new Win32Exception(hr);
                if ((us.Buffer == 0) || (us.Length == 0))
                    return null;
                string s = new string(''0', us.Length / 2);
                hr = NtWow64ReadVirtualMemory64(handle, us.Buffer, s, us.Length, IntPtr.Zero);
                if (hr != 0)
                    throw new Win32Exception(hr);
                return s;
            }
            else// Os,Cur,Tar : 64 or 32
            {
                PROCESS_BASIC_INFORMATION pbi = new PROCESS_BASIC_INFORMATION();
                int hr = NtQueryInformationProcess(handle, (int)PROCESSINFOCLASS.ProcessBasicInformation, ref pbi, Marshal.SizeOf(pbi), IntPtr.Zero);
                if (hr != 0) throw new Win32Exception(hr);
                pebAddress = pbi.PebBaseAddress.ToInt64();
                IntPtr pp = new IntPtr();
                if (!ReadProcessMemory(handle, new IntPtr(pebAddress + processParametersOffset), ref pp, new IntPtr(Marshal.SizeOf(pp)), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                UNICODE_STRING us = new UNICODE_STRING();
                if (!ReadProcessMemory(handle, new IntPtr((long)pp + offset), ref us, new IntPtr(Marshal.SizeOf(us)), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                if ((us.Buffer == IntPtr.Zero) || (us.Length == 0))
                    return null;
                string s = new string(''0', us.Length / 2);
                if (!ReadProcessMemory(handle, us.Buffer, s, new IntPtr(us.Length), IntPtr.Zero))
                    throw new Win32Exception(Marshal.GetLastWin32Error());
                return s;
            }
        }
        finally
        {
            CloseHandle(handle);
        }
    }
    private const int PROCESS_QUERY_INFORMATION = 0x400;
    private const int PROCESS_VM_READ = 0x10;
    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESS_BASIC_INFORMATION
    {
        public IntPtr Reserved1;
        public IntPtr PebBaseAddress;
        public IntPtr Reserved2_0;
        public IntPtr Reserved2_1;
        public IntPtr UniqueProcessId;
        public IntPtr Reserved3;
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct UNICODE_STRING
    {
        public short Length;
        public short MaximumLength;
        public IntPtr Buffer;
    }
    // for 32-bit process in a 64-bit OS only
    [StructLayout(LayoutKind.Sequential)]
    private struct PROCESS_BASIC_INFORMATION_WOW64
    {
        public long Reserved1;
        public long PebBaseAddress;
        public long Reserved2_0;
        public long Reserved2_1;
        public long UniqueProcessId;
        public long Reserved3;
    }
    // for 32-bit process
    [StructLayout(LayoutKind.Sequential)]
    private struct UNICODE_STRING_WOW64
    {
        public short Length;
        public short MaximumLength;
        public long Buffer;
    }
    [StructLayout(LayoutKind.Sequential)]
    private struct UNICODE_STRING_32
    {
        public short Length;
        public short MaximumLength;
        public int Buffer;
    }
    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationProcess(IntPtr ProcessHandle, int ProcessInformationClass, ref PROCESS_BASIC_INFORMATION ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength);
    //ProcessWow64Information, // q: ULONG_PTR
    [DllImport("ntdll.dll")]
    private static extern int NtQueryInformationProcess(IntPtr ProcessHandle, int ProcessInformationClass, ref IntPtr ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref IntPtr lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref UNICODE_STRING lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref UNICODE_STRING_32 lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead);
    //[DllImport("kernel32.dll", SetLastError = true)]
    //private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref UNICODE_STRING_WOW64 lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, IntPtr dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr OpenProcess(int dwDesiredAccess, bool bInheritHandle, int dwProcessId);
    [DllImport("kernel32.dll")]
    private static extern bool CloseHandle(IntPtr hObject);
    // for 32-bit process in a 64-bit OS only
    [DllImport("ntdll.dll")]
    private static extern int NtWow64QueryInformationProcess64(IntPtr ProcessHandle, int ProcessInformationClass, ref PROCESS_BASIC_INFORMATION_WOW64 ProcessInformation, int ProcessInformationLength, IntPtr ReturnLength);
    [DllImport("ntdll.dll")]
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, ref long lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("ntdll.dll")]
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, ref UNICODE_STRING_WOW64 lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead);
    [DllImport("ntdll.dll")]
    private static extern int NtWow64ReadVirtualMemory64(IntPtr hProcess, long lpBaseAddress, [MarshalAs(UnmanagedType.LPWStr)] string lpBuffer, long dwSize, IntPtr lpNumberOfBytesRead);
}